aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bootstrap/bin/start.bootbin5343 -> 5391 bytes
-rw-r--r--bootstrap/bin/start_clean.bootbin5343 -> 5391 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_block.beambin9688 -> 9612 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_validator.beambin30804 -> 30824 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/rec_env.beambin4916 -> 4652 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/sys_core_fold.beambin52348 -> 52400 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/v3_codegen.beambin56232 -> 56552 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/v3_core.beambin54404 -> 54484 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/v3_life.beambin19044 -> 19044 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/gen_sctp.beambin3604 -> 3392 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/gen_tcp.beambin2404 -> 2216 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/gen_udp.beambin1616 -> 1400 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet.beambin23380 -> 24024 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet6_sctp.beambin1536 -> 1532 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet6_tcp.beambin3032 -> 3092 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet6_udp.beambin1728 -> 1796 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_sctp.beambin2304 -> 2300 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_tcp.beambin2744 -> 2776 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_udp.beambin1916 -> 1940 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/kernel.app2
-rw-r--r--bootstrap/lib/kernel/ebin/local_tcp.beambin0 -> 2352 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/local_udp.beambin0 -> 1436 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/zip.beambin26632 -> 26632 bytes
-rw-r--r--erts/configure.in8
-rw-r--r--erts/doc/src/erl_nif.xml29
-rw-r--r--erts/emulator/beam/beam_emu.c77
-rw-r--r--erts/emulator/beam/erl_bif_port.c2
-rw-r--r--erts/emulator/beam/erl_db_hash.c34
-rw-r--r--erts/emulator/beam/erl_db_hash.h2
-rw-r--r--erts/emulator/beam/erl_nif.c33
-rw-r--r--erts/emulator/beam/erl_nif.h11
-rw-r--r--erts/emulator/beam/erl_nif_api_funcs.h4
-rw-r--r--erts/emulator/beam/erl_process.c2
-rw-r--r--erts/emulator/beam/erl_process_dump.c5
-rw-r--r--erts/emulator/beam/erlang_lttng.h48
-rw-r--r--erts/emulator/beam/lttng-wrapper.h12
-rw-r--r--erts/emulator/beam/sys.h3
-rw-r--r--erts/emulator/drivers/common/inet_drv.c430
-rw-r--r--erts/emulator/test/dirty_nif_SUITE_data/dirty_nif_SUITE.c11
-rw-r--r--erts/emulator/test/lttng_SUITE.erl218
-rw-r--r--erts/emulator/test/process_SUITE.erl6
-rw-r--r--erts/etc/common/heart.c18
-rw-r--r--erts/preloaded/ebin/prim_inet.beambin72544 -> 76348 bytes
-rw-r--r--erts/preloaded/src/prim_inet.erl340
-rw-r--r--lib/common_test/src/ct.erl2
-rw-r--r--lib/common_test/src/ct_config.erl47
-rw-r--r--lib/common_test/src/ct_framework.erl10
-rw-r--r--lib/common_test/src/ct_ftp.erl2
-rw-r--r--lib/common_test/src/ct_groups.erl16
-rw-r--r--lib/common_test/src/ct_hooks.erl3
-rw-r--r--lib/common_test/src/ct_hooks_lock.erl2
-rw-r--r--lib/common_test/src/ct_logs.erl72
-rw-r--r--lib/common_test/src/ct_master.erl24
-rw-r--r--lib/common_test/src/ct_master_logs.erl43
-rw-r--r--lib/common_test/src/ct_property_test.erl8
-rw-r--r--lib/common_test/src/ct_release_test.erl38
-rw-r--r--lib/common_test/src/ct_repeat.erl6
-rw-r--r--lib/common_test/src/ct_rpc.erl6
-rw-r--r--lib/common_test/src/ct_run.erl98
-rw-r--r--lib/common_test/src/ct_slave.erl6
-rw-r--r--lib/common_test/src/ct_snmp.erl80
-rw-r--r--lib/common_test/src/ct_ssh.erl4
-rw-r--r--lib/common_test/src/ct_telnet.erl6
-rw-r--r--lib/common_test/src/ct_telnet_client.erl4
-rw-r--r--lib/common_test/src/ct_util.erl23
-rw-r--r--lib/common_test/src/ct_webtool.erl39
-rw-r--r--lib/common_test/src/cth_conn_log.erl2
-rw-r--r--lib/common_test/src/erl2html2.erl18
-rw-r--r--lib/common_test/src/test_server.erl135
-rw-r--r--lib/common_test/src/test_server_ctrl.erl67
-rw-r--r--lib/common_test/src/test_server_gl.erl5
-rw-r--r--lib/common_test/src/test_server_io.erl17
-rw-r--r--lib/common_test/src/test_server_node.erl12
-rw-r--r--lib/common_test/src/test_server_sup.erl5
-rw-r--r--lib/common_test/src/vts.erl19
-rw-r--r--lib/common_test/test/Makefile3
-rw-r--r--lib/common_test/test/ct_log_SUITE.erl328
-rw-r--r--lib/common_test/test/ct_repeat_testrun_SUITE.erl60
-rw-r--r--lib/compiler/doc/src/compile.xml16
-rw-r--r--lib/compiler/src/beam_block.erl17
-rw-r--r--lib/compiler/src/beam_validator.erl4
-rw-r--r--lib/compiler/src/compile.erl9
-rw-r--r--lib/compiler/src/rec_env.erl174
-rw-r--r--lib/compiler/src/sys_core_fold.erl14
-rw-r--r--lib/compiler/src/v3_codegen.erl60
-rw-r--r--lib/compiler/src/v3_core.erl11
-rw-r--r--lib/compiler/test/beam_block_SUITE.erl21
-rw-r--r--lib/compiler/test/compile_SUITE.erl22
-rw-r--r--lib/compiler/test/core_fold_SUITE.erl49
-rw-r--r--lib/compiler/test/map_SUITE.erl24
-rw-r--r--lib/compiler/test/misc_SUITE.erl7
-rw-r--r--lib/debugger/src/dbg_debugged.erl5
-rw-r--r--lib/debugger/src/dbg_icmd.erl8
-rw-r--r--lib/debugger/src/dbg_iserver.erl17
-rw-r--r--lib/debugger/src/dbg_wx_break_win.erl34
-rw-r--r--lib/debugger/src/dbg_wx_code.erl10
-rw-r--r--lib/debugger/src/dbg_wx_filedialog_win.erl16
-rw-r--r--lib/debugger/src/dbg_wx_mon.erl4
-rw-r--r--lib/debugger/src/dbg_wx_mon_win.erl24
-rw-r--r--lib/debugger/src/dbg_wx_src_view.erl2
-rw-r--r--lib/debugger/src/dbg_wx_trace.erl2
-rw-r--r--lib/debugger/src/dbg_wx_trace_win.erl57
-rw-r--r--lib/debugger/src/dbg_wx_win.erl13
-rw-r--r--lib/debugger/src/dbg_wx_winman.erl4
-rw-r--r--lib/debugger/src/i.erl2
-rw-r--r--lib/debugger/src/int.erl24
-rw-r--r--lib/dialyzer/src/dialyzer_contracts.erl11
-rw-r--r--lib/dialyzer/src/dialyzer_dataflow.erl58
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/higher_order_discrepancy5
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/higher_order_discrepancy.erl5
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/loopy.erl17
-rw-r--r--lib/dialyzer/test/user_SUITE_data/results/wpc_hlines3
-rw-r--r--lib/dialyzer/test/user_SUITE_data/src/wpc_hlines.erl22
-rw-r--r--lib/edoc/priv/edoc.dtd6
-rw-r--r--lib/edoc/src/edoc_layout.erl24
-rw-r--r--lib/edoc/src/edoc_parser.yrl17
-rw-r--r--lib/edoc/src/edoc_run.erl11
-rw-r--r--lib/edoc/src/edoc_scanner.erl2
-rw-r--r--lib/edoc/src/edoc_specs.erl6
-rw-r--r--lib/edoc/src/edoc_types.erl4
-rw-r--r--lib/edoc/src/edoc_types.hrl2
-rw-r--r--lib/eldap/test/eldap_basic_SUITE.erl2
-rw-r--r--lib/erl_docgen/src/docgen_otp_specs.erl38
-rw-r--r--lib/erl_interface/src/misc/ei_portio.h9
-rw-r--r--lib/inets/src/ftp/ftp.erl26
-rw-r--r--lib/inets/src/ftp/ftp_response.erl1
-rw-r--r--lib/inets/test/ftp_SUITE.erl518
-rw-r--r--lib/inets/test/ftp_format_SUITE.erl2
-rw-r--r--lib/inets/test/httpc_SUITE.erl7
-rw-r--r--lib/kernel/doc/src/gen_tcp.xml23
-rw-r--r--lib/kernel/doc/src/gen_udp.xml21
-rw-r--r--lib/kernel/doc/src/heart.xml11
-rw-r--r--lib/kernel/doc/src/inet.xml53
-rw-r--r--lib/kernel/src/Makefile4
-rw-r--r--lib/kernel/src/gen_sctp.erl33
-rw-r--r--lib/kernel/src/gen_tcp.erl50
-rw-r--r--lib/kernel/src/gen_udp.erl46
-rw-r--r--lib/kernel/src/inet.erl189
-rw-r--r--lib/kernel/src/inet6_sctp.erl26
-rw-r--r--lib/kernel/src/inet6_tcp.erl88
-rw-r--r--lib/kernel/src/inet6_udp.erl42
-rw-r--r--lib/kernel/src/inet_int.hrl5
-rw-r--r--lib/kernel/src/inet_sctp.erl19
-rw-r--r--lib/kernel/src/inet_tcp.erl86
-rw-r--r--lib/kernel/src/inet_udp.erl52
-rw-r--r--lib/kernel/src/kernel.app.src2
-rw-r--r--lib/kernel/src/local_tcp.erl178
-rw-r--r--lib/kernel/src/local_udp.erl106
-rw-r--r--lib/kernel/test/heart_SUITE.erl40
-rw-r--r--lib/kernel/test/inet_SUITE.erl117
-rw-r--r--lib/kernel/test/inet_res_SUITE.erl15
-rw-r--r--lib/megaco/src/app/megaco.appup.src29
-rw-r--r--lib/observer/src/crashdump_viewer.erl3
-rw-r--r--lib/observer/src/observer_procinfo.erl2
-rw-r--r--lib/public_key/doc/src/Makefile11
-rw-r--r--lib/public_key/doc/src/public_key.xml33
-rw-r--r--lib/public_key/doc/src/public_key_app.xml85
-rw-r--r--lib/public_key/doc/src/ref_man.xml1
-rw-r--r--lib/public_key/src/pubkey_cert.erl4
-rw-r--r--lib/public_key/test/public_key_SUITE.erl23
-rw-r--r--lib/runtime_tools/c_src/dyntrace_lttng.h50
-rw-r--r--lib/runtime_tools/doc/src/LTTng.xml26
-rw-r--r--lib/runtime_tools/test/dyntrace_lttng_SUITE.erl146
-rw-r--r--lib/sasl/test/release_handler_SUITE.erl2
-rw-r--r--lib/ssh/doc/src/ssh.xml20
-rw-r--r--lib/ssh/doc/src/ssh_sftp.xml11
-rw-r--r--lib/ssh/src/ssh.erl192
-rw-r--r--lib/ssh/src/ssh_acceptor.erl3
-rw-r--r--lib/ssh/src/ssh_system_sup.erl5
-rw-r--r--lib/ssh/test/ssh_algorithms_SUITE.erl60
-rw-r--r--lib/ssh/test/ssh_basic_SUITE.erl3
-rw-r--r--lib/ssh/test/ssh_connection_SUITE.erl208
-rw-r--r--lib/ssh/test/ssh_echo_server.erl35
-rw-r--r--lib/ssh/test/ssh_options_SUITE.erl4
-rw-r--r--lib/ssh/test/ssh_protocol_SUITE.erl3
-rw-r--r--lib/ssh/test/ssh_renegotiate_SUITE.erl3
-rw-r--r--lib/ssh/test/ssh_sftp_SUITE.erl14
-rw-r--r--lib/ssh/test/ssh_sftpd_SUITE.erl20
-rw-r--r--lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl26
-rw-r--r--lib/ssh/test/ssh_sup_SUITE.erl13
-rw-r--r--lib/ssh/test/ssh_test_lib.hrl10
-rw-r--r--lib/ssh/test/ssh_to_openssh_SUITE.erl15
-rw-r--r--lib/ssh/test/ssh_upgrade_SUITE.erl17
-rw-r--r--lib/ssl/doc/src/ssl.xml25
-rw-r--r--lib/ssl/src/ssl.erl36
-rw-r--r--lib/ssl/src/ssl_connection.erl8
-rw-r--r--lib/ssl/src/ssl_crl.erl16
-rw-r--r--lib/ssl/src/ssl_internal.hrl3
-rw-r--r--lib/ssl/src/ssl_manager.erl11
-rw-r--r--lib/ssl/src/ssl_socket.erl7
-rw-r--r--lib/ssl/src/tls_connection.erl7
-rw-r--r--lib/ssl/src/tls_handshake.erl48
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl76
-rw-r--r--lib/ssl/test/ssl_handshake_SUITE.erl3
-rw-r--r--lib/ssl/test/ssl_npn_hello_SUITE.erl8
-rw-r--r--lib/ssl/test/ssl_to_openssl_SUITE.erl18
-rw-r--r--lib/stdlib/src/supervisor.erl17
-rw-r--r--lib/stdlib/test/ets_SUITE.erl24
-rw-r--r--lib/stdlib/test/id_transform_SUITE.erl9
-rw-r--r--lib/stdlib/test/supervisor_SUITE.erl12
-rw-r--r--lib/wx/src/wxe_master.erl4
-rw-r--r--lib/wx/src/wxe_util.erl8
-rw-r--r--lib/wx/test/wx_basic_SUITE.erl4
-rwxr-xr-xotp_build3
204 files changed, 4389 insertions, 2192 deletions
diff --git a/bootstrap/bin/start.boot b/bootstrap/bin/start.boot
index cc0edd5427..ef962190a4 100644
--- a/bootstrap/bin/start.boot
+++ b/bootstrap/bin/start.boot
Binary files differ
diff --git a/bootstrap/bin/start_clean.boot b/bootstrap/bin/start_clean.boot
index cc0edd5427..ef962190a4 100644
--- a/bootstrap/bin/start_clean.boot
+++ b/bootstrap/bin/start_clean.boot
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_block.beam b/bootstrap/lib/compiler/ebin/beam_block.beam
index cccf21d9ab..ea91a62b56 100644
--- a/bootstrap/lib/compiler/ebin/beam_block.beam
+++ b/bootstrap/lib/compiler/ebin/beam_block.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_validator.beam b/bootstrap/lib/compiler/ebin/beam_validator.beam
index 5722578840..fcb2202d2a 100644
--- a/bootstrap/lib/compiler/ebin/beam_validator.beam
+++ b/bootstrap/lib/compiler/ebin/beam_validator.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/rec_env.beam b/bootstrap/lib/compiler/ebin/rec_env.beam
index a7c78175c3..068108dab2 100644
--- a/bootstrap/lib/compiler/ebin/rec_env.beam
+++ b/bootstrap/lib/compiler/ebin/rec_env.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/sys_core_fold.beam b/bootstrap/lib/compiler/ebin/sys_core_fold.beam
index 7d01ed81d5..68cc4e3ff3 100644
--- a/bootstrap/lib/compiler/ebin/sys_core_fold.beam
+++ b/bootstrap/lib/compiler/ebin/sys_core_fold.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/v3_codegen.beam b/bootstrap/lib/compiler/ebin/v3_codegen.beam
index 648cd3dea1..6afb674a9f 100644
--- a/bootstrap/lib/compiler/ebin/v3_codegen.beam
+++ b/bootstrap/lib/compiler/ebin/v3_codegen.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/v3_core.beam b/bootstrap/lib/compiler/ebin/v3_core.beam
index 110d376a0a..e8e120e145 100644
--- a/bootstrap/lib/compiler/ebin/v3_core.beam
+++ b/bootstrap/lib/compiler/ebin/v3_core.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/v3_life.beam b/bootstrap/lib/compiler/ebin/v3_life.beam
index d8822f929f..b220e475ee 100644
--- a/bootstrap/lib/compiler/ebin/v3_life.beam
+++ b/bootstrap/lib/compiler/ebin/v3_life.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/gen_sctp.beam b/bootstrap/lib/kernel/ebin/gen_sctp.beam
index fe2ff17ff1..fca569c779 100644
--- a/bootstrap/lib/kernel/ebin/gen_sctp.beam
+++ b/bootstrap/lib/kernel/ebin/gen_sctp.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/gen_tcp.beam b/bootstrap/lib/kernel/ebin/gen_tcp.beam
index e40f1f2e45..cf4757a568 100644
--- a/bootstrap/lib/kernel/ebin/gen_tcp.beam
+++ b/bootstrap/lib/kernel/ebin/gen_tcp.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/gen_udp.beam b/bootstrap/lib/kernel/ebin/gen_udp.beam
index ec4eda12f7..fec430304e 100644
--- a/bootstrap/lib/kernel/ebin/gen_udp.beam
+++ b/bootstrap/lib/kernel/ebin/gen_udp.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet.beam b/bootstrap/lib/kernel/ebin/inet.beam
index 9058389555..8eaf2fbe74 100644
--- a/bootstrap/lib/kernel/ebin/inet.beam
+++ b/bootstrap/lib/kernel/ebin/inet.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet6_sctp.beam b/bootstrap/lib/kernel/ebin/inet6_sctp.beam
index 5c827589bd..c3aac09fbe 100644
--- a/bootstrap/lib/kernel/ebin/inet6_sctp.beam
+++ b/bootstrap/lib/kernel/ebin/inet6_sctp.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet6_tcp.beam b/bootstrap/lib/kernel/ebin/inet6_tcp.beam
index f1ab2912bb..80e8e389a2 100644
--- a/bootstrap/lib/kernel/ebin/inet6_tcp.beam
+++ b/bootstrap/lib/kernel/ebin/inet6_tcp.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet6_udp.beam b/bootstrap/lib/kernel/ebin/inet6_udp.beam
index 2eb8c09701..39b9f0343b 100644
--- a/bootstrap/lib/kernel/ebin/inet6_udp.beam
+++ b/bootstrap/lib/kernel/ebin/inet6_udp.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet_sctp.beam b/bootstrap/lib/kernel/ebin/inet_sctp.beam
index 835c7b2928..e2f574b514 100644
--- a/bootstrap/lib/kernel/ebin/inet_sctp.beam
+++ b/bootstrap/lib/kernel/ebin/inet_sctp.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet_tcp.beam b/bootstrap/lib/kernel/ebin/inet_tcp.beam
index 698a94770b..d0c9f09f6f 100644
--- a/bootstrap/lib/kernel/ebin/inet_tcp.beam
+++ b/bootstrap/lib/kernel/ebin/inet_tcp.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet_udp.beam b/bootstrap/lib/kernel/ebin/inet_udp.beam
index 6876ba3892..11eb4f840f 100644
--- a/bootstrap/lib/kernel/ebin/inet_udp.beam
+++ b/bootstrap/lib/kernel/ebin/inet_udp.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/kernel.app b/bootstrap/lib/kernel/ebin/kernel.app
index 15bc34e789..a4600713e5 100644
--- a/bootstrap/lib/kernel/ebin/kernel.app
+++ b/bootstrap/lib/kernel/ebin/kernel.app
@@ -55,6 +55,8 @@
inet_tcp_dist,
kernel,
kernel_config,
+ local_tcp,
+ local_udp,
net,
net_adm,
net_kernel,
diff --git a/bootstrap/lib/kernel/ebin/local_tcp.beam b/bootstrap/lib/kernel/ebin/local_tcp.beam
new file mode 100644
index 0000000000..153aad2936
--- /dev/null
+++ b/bootstrap/lib/kernel/ebin/local_tcp.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/local_udp.beam b/bootstrap/lib/kernel/ebin/local_udp.beam
new file mode 100644
index 0000000000..29c9b01faa
--- /dev/null
+++ b/bootstrap/lib/kernel/ebin/local_udp.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/zip.beam b/bootstrap/lib/stdlib/ebin/zip.beam
index 1a19b1f28a..6ef3732965 100644
--- a/bootstrap/lib/stdlib/ebin/zip.beam
+++ b/bootstrap/lib/stdlib/ebin/zip.beam
Binary files differ
diff --git a/erts/configure.in b/erts/configure.in
index a34dfc6dbd..81ecad4f51 100644
--- a/erts/configure.in
+++ b/erts/configure.in
@@ -2116,7 +2116,7 @@ fi
dnl Need by run_erl.
AC_CHECK_FUNCS([openpty])
-AC_CHECK_HEADERS(net/if_dl.h ifaddrs.h netpacket/packet.h)
+AC_CHECK_HEADERS(net/if_dl.h ifaddrs.h netpacket/packet.h sys/un.h)
AC_CHECK_FUNCS([getifaddrs])
dnl Checks for variables in6addr_any and in6addr_loopback,
@@ -3858,15 +3858,15 @@ if test "$enable_lttng_test" = "yes" ; then
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM(
[#include <lttng/tracepoint.h>
- #define TRACEPOINT_PROVIDER com_ericsson_otp
+ #define TRACEPOINT_PROVIDER org_erlang_otp
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
dummy,
TP_ARGS(int, my_int),
TP_FIELDS(ctf_integer(int, my_int, my_int)))
#define TRACEPOINT_CREATE_PROBES
#define TRACEPOINT_DEFINE],
- [if(tracepoint_enabled(com_ericsson_otp,dummy)) do {} while(0)])],
+ [if(tracepoint_enabled(org_erlang_otp,dummy)) do {} while(0)])],
[AC_MSG_RESULT([yes])],
[AC_MSG_ERROR([no (available in lttng-ust v2.7)])])
if test "x$ac_cv_header_lttng_tracepoint_h" = "xyes" \
diff --git a/erts/doc/src/erl_nif.xml b/erts/doc/src/erl_nif.xml
index 4efd155b09..b2e2254a65 100644
--- a/erts/doc/src/erl_nif.xml
+++ b/erts/doc/src/erl_nif.xml
@@ -1101,15 +1101,6 @@ typedef enum {
Erlang operators <c>=:=</c> and
<c>=/=</c>.</p></desc>
</func>
- <func><name><ret>int</ret><nametext>enif_is_on_dirty_scheduler(ErlNifEnv* env)</nametext></name>
- <fsummary>Check to see if executing on a dirty scheduler thread</fsummary>
- <desc>
- <p>Check to see if the current NIF is executing on a dirty scheduler thread. If
- executing on a dirty scheduler thread true returned; otherwise false.</p>
- <p>This function can only be used from a NIF-calling thread, and with an
- environment corresponding to currently executing processes.</p>
- </desc>
- </func>
<func><name><ret>int</ret><nametext>enif_is_pid(ErlNifEnv* env, ERL_NIF_TERM term)</nametext></name>
<fsummary>Determine if a term is a pid</fsummary>
<desc><p>Return true if <c>term</c> is a pid.</p></desc>
@@ -1820,7 +1811,25 @@ enif_map_iterator_destroy(env, &amp;iter);
<desc><p>Same as <seealso marker="erl_driver#erl_drv_thread_self">erl_drv_thread_self</seealso>.
</p></desc>
</func>
-
+ <func><name><ret>int</ret><nametext>enif_thread_type(void)</nametext></name>
+ <fsummary>Determine type of current thread</fsummary>
+ <desc>
+ <p>Determine the type of currently executing thread. A positive value
+ indicates a scheduler thread while a negative value or zero indicates
+ another type of thread. Currently the following specific types exist
+ (which may be extended in the future):</p>
+ <taglist>
+ <tag><c>ERL_NIF_THR_UNDEFINED</c></tag>
+ <value><p>Undefined thread that is not a scheduler thread.</p></value>
+ <tag><c>ERL_NIF_THR_NORMAL_SCHEDULER</c></tag>
+ <value><p>A normal scheduler thread.</p></value>
+ <tag><c>ERL_NIF_THR_DIRTY_CPU_SCHEDULER</c></tag>
+ <value><p>A dirty CPU scheduler thread.</p></value>
+ <tag><c>ERL_NIF_THR_DIRTY_IO_SCHEDULER</c></tag>
+ <value><p>A dirty I/O scheduler thread.</p></value>
+ </taglist>
+ </desc>
+ </func>
<func>
<name><ret>ErlNifTime</ret><nametext>enif_time_offset(ErlNifTimeUnit time_unit)</nametext></name>
<fsummary>Get current Time Offset</fsummary>
diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c
index 0a59f8785c..4716460a6b 100644
--- a/erts/emulator/beam/beam_emu.c
+++ b/erts/emulator/beam/beam_emu.c
@@ -5318,10 +5318,14 @@ void erts_dirty_process_main(ErtsSchedulerData *esdp)
ASSERT(BeamOp(op_call_nif) == (BeamInstr *) *I);
- if (ERTS_PROC_GET_SAVED_CALLS_BUF(c_p)
- && (ERTS_TRACE_FLAGS(c_p) & F_SENSITIVE) == 0) {
- c_p->fcalls = REDS_IN(c_p) = 0;
- }
+ /*
+ * Set fcalls even though we ignore it, so we don't
+ * confuse code accessing it...
+ */
+ if (ERTS_PROC_GET_SAVED_CALLS_BUF(c_p))
+ c_p->fcalls = 0;
+ else
+ c_p->fcalls = CONTEXT_REDS;
SWAPIN;
@@ -5341,7 +5345,7 @@ void erts_dirty_process_main(ErtsSchedulerData *esdp)
NULL, fun_buf);
} else {
erts_snprintf(fun_buf, sizeof(DTRACE_CHARBUF_NAME(fun_buf)),
- "<unknown/%p>", next);
+ "<unknown/%p>", *I);
}
}
@@ -5351,8 +5355,10 @@ void erts_dirty_process_main(ErtsSchedulerData *esdp)
}
{
- Eterm nif_bif_result;
- Eterm bif_nif_arity;
+#ifdef DEBUG
+ Eterm result;
+#endif
+ Eterm arity;
{
/*
@@ -5374,7 +5380,7 @@ void erts_dirty_process_main(ErtsSchedulerData *esdp)
c_p->current = I-3; /* current and vbf set to please handle_error */
SWAPOUT;
PROCESS_MAIN_CHK_LOCKS(c_p);
- bif_nif_arity = I[-1];
+ arity = I[-1];
ERTS_SMP_UNREQ_PROC_MAIN_LOCK(c_p);
ASSERT(!ERTS_PROC_IS_EXITING(c_p));
@@ -5383,50 +5389,39 @@ void erts_dirty_process_main(ErtsSchedulerData *esdp)
NifF* fp = vbf = (NifF*) I[1];
struct enif_environment_t env;
ASSERT(!c_p->scheduler_data);
- erts_pre_dirty_nif(esdp, &env, c_p, (struct erl_module_nif*)I[2], NULL);
- nif_bif_result = (*fp)(&env, bif_nif_arity, reg);
- if (env.exception_thrown)
- nif_bif_result = THE_NON_VALUE;
+
+ erts_pre_dirty_nif(esdp, &env, c_p,
+ (struct erl_module_nif*)I[2], NULL);
+
+#ifdef DEBUG
+ result =
+#else
+ (void)
+#endif
+ (*fp)(&env, arity, reg);
+
erts_post_nif(&env);
+
+ ASSERT(!is_value(result));
+ ASSERT(c_p->freason == TRAP);
+ ASSERT(!(c_p->flags & F_HIBERNATE_SCHED));
+
PROCESS_MAIN_CHK_LOCKS(c_p);
+ ERTS_SMP_REQ_PROC_MAIN_LOCK(c_p);
ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p);
ERTS_MSACC_SET_STATE_CACHED_M_X(ERTS_MSACC_STATE_EMULATOR);
- if (env.exiting) {
- ERTS_SMP_REQ_PROC_MAIN_LOCK(c_p);
+ if (env.exiting)
goto do_dirty_schedule;
- }
ASSERT(!ERTS_PROC_IS_EXITING(c_p));
}
+
DTRACE_NIF_RETURN(c_p, (Eterm)I[-3], (Eterm)I[-2], (Uint)I[-1]);
- ERTS_SMP_REQ_PROC_MAIN_LOCK(c_p);
ERTS_HOLE_CHECK(c_p);
- if (ERTS_IS_GC_DESIRED(c_p)) {
- nif_bif_result = erts_gc_after_bif_call(c_p,
- nif_bif_result,
- reg, bif_nif_arity);
- }
- SWAPIN; /* There might have been a garbage collection. */
- if (is_value(nif_bif_result)) {
- r(0) = nif_bif_result;
- CHECK_TERM(r(0));
- I = c_p->cp;
- c_p->cp = 0;
- Goto(*I);
- } else if (c_p->freason == TRAP) {
- I = c_p->i;
- ASSERT(!(c_p->flags & F_HIBERNATE_SCHED));
- goto context_switch;
- }
- I = handle_error(c_p, c_p->cp, reg, vbf);
+ SWAPIN;
+ I = c_p->i;
+ goto context_switch;
}
}
- if (I == 0) {
- goto do_dirty_schedule;
- } else {
- ASSERT(!is_value(r(0)));
- SWAPIN;
- goto context_switch;
- }
#endif /* ERTS_DIRTY_SCHEDULERS */
}
diff --git a/erts/emulator/beam/erl_bif_port.c b/erts/emulator/beam/erl_bif_port.c
index 37f4e1de49..fefa9d8391 100644
--- a/erts/emulator/beam/erl_bif_port.c
+++ b/erts/emulator/beam/erl_bif_port.c
@@ -1411,7 +1411,7 @@ BIF_RETTYPE decode_packet_3(BIF_ALIST_3)
trunc_len = val;
goto next_option;
case am_line_delimiter:
- if (type == TCP_PB_LINE_LF && val >= 0 && val <= 255) {
+ if (type == TCP_PB_LINE_LF && val <= 255) {
delimiter = (char)val;
goto next_option;
}
diff --git a/erts/emulator/beam/erl_db_hash.c b/erts/emulator/beam/erl_db_hash.c
index 74979f984a..074ac6d64e 100644
--- a/erts/emulator/beam/erl_db_hash.c
+++ b/erts/emulator/beam/erl_db_hash.c
@@ -95,7 +95,8 @@
/*
* The following symbols can be manipulated to "tune" the linear hash array
*/
-#define CHAIN_LEN 6 /* Medium bucket chain len */
+#define GROW_LIMIT(NACTIVE) ((NACTIVE)*2)
+#define SHRINK_LIMIT(NACTIVE) ((NACTIVE) / 2)
/* Number of slots per segment */
#define SEGSZ_EXP 8
@@ -463,7 +464,7 @@ db_finalize_dbterm_hash(int cret, DbUpdateHandle* handle);
static ERTS_INLINE void try_shrink(DbTableHash* tb)
{
int nactive = NACTIVE(tb);
- if (nactive > SEGSZ && NITEMS(tb) < (nactive * CHAIN_LEN)
+ if (nactive > SEGSZ && NITEMS(tb) < SHRINK_LIMIT(nactive)
&& !IS_FIXED(tb)) {
shrink(tb, nactive);
}
@@ -670,8 +671,8 @@ int db_create_hash(Process *p, DbTable *tbl)
tb->nsegs = NSEG_1;
tb->nslots = SEGSZ;
- erts_smp_atomic_init_nob(&tb->is_resizing, 0);
#ifdef ERTS_SMP
+ erts_smp_atomic_init_nob(&tb->is_resizing, 0);
if (tb->common.type & DB_FINE_LOCKED) {
erts_smp_rwmtx_opt_t rwmtx_opt = ERTS_SMP_RWMTX_OPT_DEFAULT_INITER;
int i;
@@ -862,7 +863,7 @@ Lnew:
WUNLOCK_HASH(lck);
{
int nactive = NACTIVE(tb);
- if (nitems > nactive * (CHAIN_LEN+1) && !IS_FIXED(tb)) {
+ if (nitems > GROW_LIMIT(nactive) && !IS_FIXED(tb)) {
grow(tb, nactive);
}
}
@@ -2250,12 +2251,12 @@ static int db_free_table_continue_hash(DbTable *tbl)
done /= 2;
while(tb->nslots != 0) {
- free_seg(tb, 1);
+ done += 1 + SEGSZ/64 + free_seg(tb, 1);
/*
* If we have done enough work, get out here.
*/
- if (++done >= (DELETE_RECORD_LIMIT / CHAIN_LEN / SEGSZ)) {
+ if (done >= DELETE_RECORD_LIMIT) {
return 0; /* Not done */
}
}
@@ -2604,23 +2605,22 @@ static Eterm build_term_list(Process* p, HashDbTerm* ptr1, HashDbTerm* ptr2,
static ERTS_INLINE int
begin_resizing(DbTableHash* tb)
{
+#ifdef ERTS_SMP
if (DB_USING_FINE_LOCKING(tb))
- return !erts_smp_atomic_xchg_acqb(&tb->is_resizing, 1);
- else {
- if (erts_smp_atomic_read_nob(&tb->is_resizing))
- return 0;
- erts_smp_atomic_set_nob(&tb->is_resizing, 1);
- return 1;
- }
+ return !erts_atomic_xchg_acqb(&tb->is_resizing, 1);
+ else
+ ERTS_LC_ASSERT(erts_lc_rwmtx_is_rwlocked(&tb->common.rwlock));
+#endif
+ return 1;
}
static ERTS_INLINE void
done_resizing(DbTableHash* tb)
{
+#ifdef ERTS_SMP
if (DB_USING_FINE_LOCKING(tb))
- erts_smp_atomic_set_relb(&tb->is_resizing, 0);
- else
- erts_smp_atomic_set_nob(&tb->is_resizing, 0);
+ erts_atomic_set_relb(&tb->is_resizing, 0);
+#endif
}
/* Grow table with one new bucket.
@@ -2871,7 +2871,7 @@ db_lookup_dbterm_hash(Process *p, DbTable *tbl, Eterm key, Eterm obj,
int nitems = erts_smp_atomic_inc_read_nob(&tb->common.nitems);
int nactive = NACTIVE(tb);
- if (nitems > nactive * (CHAIN_LEN + 1) && !IS_FIXED(tb)) {
+ if (nitems > GROW_LIMIT(nactive) && !IS_FIXED(tb)) {
grow(tb, nactive);
}
}
diff --git a/erts/emulator/beam/erl_db_hash.h b/erts/emulator/beam/erl_db_hash.h
index e654363cd5..081ff8fafc 100644
--- a/erts/emulator/beam/erl_db_hash.h
+++ b/erts/emulator/beam/erl_db_hash.h
@@ -60,8 +60,8 @@ typedef struct db_table_hash {
/* List of slots where elements have been deleted while table was fixed */
erts_smp_atomic_t fixdel; /* (FixedDeletion*) */
erts_smp_atomic_t nactive; /* Number of "active" slots */
- erts_smp_atomic_t is_resizing; /* grow/shrink in progress */
#ifdef ERTS_SMP
+ erts_smp_atomic_t is_resizing; /* grow/shrink in progress */
DbTableHashFineLocks* locks;
#endif
#ifdef VALGRIND
diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c
index f1c35cd5a5..039f97ef43 100644
--- a/erts/emulator/beam/erl_nif.c
+++ b/erts/emulator/beam/erl_nif.c
@@ -803,19 +803,13 @@ ERL_NIF_TERM enif_make_copy(ErlNifEnv* dst_env, ERL_NIF_TERM src_term)
{
Uint sz;
Eterm* hp;
-#ifdef SHCOPY
- erts_shcopy_t info;
- INITIALIZE_SHCOPY(info);
- sz = copy_shared_calculate(src_term, &info);
- hp = alloc_heap(dst_env, sz);
- src_term = copy_shared_perform(src_term, sz, &info, &hp, &MSO(dst_env->proc));
- DESTROY_SHCOPY(info);
- return src_term;
-#else
+ /*
+ * No preserved sharing allowed as long as literals are also preserved.
+ * Process independent environment can not be reached by purge.
+ */
sz = size_object(src_term);
hp = alloc_heap(dst_env, sz);
return copy_struct(src_term, sz, &hp, &MSO(dst_env->proc));
-#endif
}
@@ -2664,18 +2658,21 @@ done:
}
int
-enif_is_on_dirty_scheduler(ErlNifEnv* env)
+enif_thread_type(void)
{
- int scheduler;
- Process *c_p;
+ ErtsSchedulerData *esdp = erts_get_scheduler_data();
- execution_state(env, &c_p, &scheduler);
+ if (!esdp)
+ return ERL_NIF_THR_UNDEFINED;
+
+ if (!ERTS_SCHEDULER_IS_DIRTY(esdp))
+ return ERL_NIF_THR_NORMAL_SCHEDULER;
- if (!c_p || !scheduler)
- erts_exit(ERTS_ABORT_EXIT, "enif_is_on_dirty_scheduler: "
- "Invalid env");
+ if (ERTS_SCHEDULER_IS_DIRTY_CPU(esdp))
+ return ERL_NIF_THR_DIRTY_CPU_SCHEDULER;
- return scheduler < 0;
+ ASSERT(ERTS_SCHEDULER_IS_DIRTY_IO(esdp));
+ return ERL_NIF_THR_DIRTY_IO_SCHEDULER;
}
/* Maps */
diff --git a/erts/emulator/beam/erl_nif.h b/erts/emulator/beam/erl_nif.h
index da7a754757..494971e118 100644
--- a/erts/emulator/beam/erl_nif.h
+++ b/erts/emulator/beam/erl_nif.h
@@ -209,6 +209,17 @@ typedef enum {
ERL_NIF_BIN2TERM_SAFE = 0x20000000
} ErlNifBinaryToTerm;
+/*
+ * Return values from enif_thread_type(). Negative values
+ * reserved for specific types of non-scheduler threads.
+ * Positive values reserved for scheduler thread types.
+ */
+
+#define ERL_NIF_THR_UNDEFINED 0
+#define ERL_NIF_THR_NORMAL_SCHEDULER 1
+#define ERL_NIF_THR_DIRTY_CPU_SCHEDULER 2
+#define ERL_NIF_THR_DIRTY_IO_SCHEDULER 3
+
#if (defined(__WIN32__) || defined(_WIN32) || defined(_WIN32_))
# define ERL_NIF_API_FUNC_DECL(RET_TYPE, NAME, ARGS) RET_TYPE (*NAME) ARGS
typedef struct {
diff --git a/erts/emulator/beam/erl_nif_api_funcs.h b/erts/emulator/beam/erl_nif_api_funcs.h
index b211ab4b16..9a8f216773 100644
--- a/erts/emulator/beam/erl_nif_api_funcs.h
+++ b/erts/emulator/beam/erl_nif_api_funcs.h
@@ -173,7 +173,7 @@ ERL_NIF_API_FUNC_DECL(int, enif_get_local_port, (ErlNifEnv* env, ERL_NIF_TERM, E
ERL_NIF_API_FUNC_DECL(int, enif_term_to_binary, (ErlNifEnv *env, ERL_NIF_TERM term, ErlNifBinary *bin));
ERL_NIF_API_FUNC_DECL(size_t, enif_binary_to_term, (ErlNifEnv *env, const unsigned char* data, size_t sz, ERL_NIF_TERM *term, unsigned int opts));
ERL_NIF_API_FUNC_DECL(int, enif_port_command, (ErlNifEnv *env, const ErlNifPort* to_port, ErlNifEnv *msg_env, ERL_NIF_TERM msg));
-ERL_NIF_API_FUNC_DECL(int,enif_is_on_dirty_scheduler,(ErlNifEnv*));
+ERL_NIF_API_FUNC_DECL(int,enif_thread_type,(void));
ERL_NIF_API_FUNC_DECL(int,enif_snprintf,(char * buffer, size_t size, const char *format, ...));
/*
@@ -330,7 +330,7 @@ ERL_NIF_API_FUNC_DECL(int,enif_snprintf,(char * buffer, size_t size, const char
# define enif_term_to_binary ERL_NIF_API_FUNC_MACRO(enif_term_to_binary)
# define enif_binary_to_term ERL_NIF_API_FUNC_MACRO(enif_binary_to_term)
# define enif_port_command ERL_NIF_API_FUNC_MACRO(enif_port_command)
-# define enif_is_on_dirty_scheduler ERL_NIF_API_FUNC_MACRO(enif_is_on_dirty_scheduler)
+# define enif_thread_type ERL_NIF_API_FUNC_MACRO(enif_thread_type)
# define enif_snprintf ERL_NIF_API_FUNC_MACRO(enif_snprintf)
/*
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index c0b1d7246c..5193be85b4 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -10082,7 +10082,7 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls)
}
}
- if (ERTS_IS_GC_DESIRED(p)) {
+ if (ERTS_IS_GC_DESIRED(p) && !ERTS_SCHEDULER_IS_DIRTY_IO(esdp)) {
if (!(state & ERTS_PSFLG_EXITING) && !(p->flags & (F_DELAY_GC|F_DISABLE_GC))) {
int cost = scheduler_gc_proc(p, reds);
calls += cost;
diff --git a/erts/emulator/beam/erl_process_dump.c b/erts/emulator/beam/erl_process_dump.c
index eeaa9a569c..a70dfb8e73 100644
--- a/erts/emulator/beam/erl_process_dump.c
+++ b/erts/emulator/beam/erl_process_dump.c
@@ -560,6 +560,11 @@ dump_externally(int to, void *to_arg, Eterm term)
}
}
+ /* Do not handle maps */
+ if (is_map(term)) {
+ term = am_undefined;
+ }
+
s = p = sbuf;
erts_encode_ext(term, &p);
erts_print(to, to_arg, "E%X:", p-s);
diff --git a/erts/emulator/beam/erlang_lttng.h b/erts/emulator/beam/erlang_lttng.h
index 12f68e477b..4e869671f7 100644
--- a/erts/emulator/beam/erlang_lttng.h
+++ b/erts/emulator/beam/erlang_lttng.h
@@ -20,7 +20,7 @@
#ifdef USE_LTTNG
#undef TRACEPOINT_PROVIDER
-#define TRACEPOINT_PROVIDER com_ericsson_otp
+#define TRACEPOINT_PROVIDER org_erlang_otp
#undef TRACEPOINT_INCLUDE
#define TRACEPOINT_INCLUDE "erlang_lttng.h"
@@ -33,7 +33,7 @@
/* Schedulers */
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
scheduler_poll,
TP_ARGS(
int, id,
@@ -62,7 +62,7 @@ typedef struct {
/* Port and Driver Scheduling */
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
driver_start,
TP_ARGS(
char*, pid,
@@ -77,7 +77,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
driver_init,
TP_ARGS(
char*, driver,
@@ -94,7 +94,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
driver_outputv,
TP_ARGS(
char*, pid,
@@ -111,7 +111,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
driver_output,
TP_ARGS(
char*, pid,
@@ -128,7 +128,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
driver_ready_input,
TP_ARGS(
char*, pid,
@@ -143,7 +143,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
driver_ready_output,
TP_ARGS(
char*, pid,
@@ -158,7 +158,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
driver_event,
TP_ARGS(
char*, pid,
@@ -173,7 +173,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
driver_timeout,
TP_ARGS(
char*, pid,
@@ -188,7 +188,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
driver_stop_select,
TP_ARGS(
char*, driver
@@ -199,7 +199,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
driver_flush,
TP_ARGS(
char*, pid,
@@ -214,7 +214,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
driver_stop,
TP_ARGS(
char*, pid,
@@ -229,7 +229,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
driver_process_exit,
TP_ARGS(
char*, pid,
@@ -244,7 +244,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
driver_ready_async,
TP_ARGS(
char*, pid,
@@ -259,7 +259,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
driver_finish,
TP_ARGS(
char*, driver
@@ -270,7 +270,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
driver_call,
TP_ARGS(
char*, pid,
@@ -289,7 +289,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
driver_control,
TP_ARGS(
char*, pid,
@@ -310,7 +310,7 @@ TRACEPOINT_EVENT(
/* Async pool */
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
aio_pool_get,
TP_ARGS(
char*, port,
@@ -323,7 +323,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
aio_pool_put,
TP_ARGS(
char*, port,
@@ -339,7 +339,7 @@ TRACEPOINT_EVENT(
/* Memory Allocator */
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
carrier_create,
TP_ARGS(
const char*, type,
@@ -365,7 +365,7 @@ TRACEPOINT_EVENT(
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
carrier_destroy,
TP_ARGS(
const char*, type,
@@ -390,7 +390,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
carrier_pool_put,
TP_ARGS(
const char*, name,
@@ -405,7 +405,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
carrier_pool_get,
TP_ARGS(
const char*, name,
diff --git a/erts/emulator/beam/lttng-wrapper.h b/erts/emulator/beam/lttng-wrapper.h
index 294872c365..0bc75c1552 100644
--- a/erts/emulator/beam/lttng-wrapper.h
+++ b/erts/emulator/beam/lttng-wrapper.h
@@ -77,23 +77,23 @@
(RQ)->scheduler->no
#define LTTNG_ENABLED(Name) \
- tracepoint_enabled(com_ericsson_otp, Name)
+ tracepoint_enabled(org_erlang_otp, Name)
/* include a special LTTNG_DO for do_tracepoint ? */
#define LTTNG1(Name, Arg1) \
- tracepoint(com_ericsson_otp, Name, (Arg1))
+ tracepoint(org_erlang_otp, Name, (Arg1))
#define LTTNG2(Name, Arg1, Arg2) \
- tracepoint(com_ericsson_otp, Name, (Arg1), (Arg2))
+ tracepoint(org_erlang_otp, Name, (Arg1), (Arg2))
#define LTTNG3(Name, Arg1, Arg2, Arg3) \
- tracepoint(com_ericsson_otp, Name, (Arg1), (Arg2), (Arg3))
+ tracepoint(org_erlang_otp, Name, (Arg1), (Arg2), (Arg3))
#define LTTNG4(Name, Arg1, Arg2, Arg3, Arg4) \
- tracepoint(com_ericsson_otp, Name, (Arg1), (Arg2), (Arg3), (Arg4))
+ tracepoint(org_erlang_otp, Name, (Arg1), (Arg2), (Arg3), (Arg4))
#define LTTNG5(Name, Arg1, Arg2, Arg3, Arg4, Arg5) \
- tracepoint(com_ericsson_otp, Name, (Arg1), (Arg2), (Arg3), (Arg4), (Arg5))
+ tracepoint(org_erlang_otp, Name, (Arg1), (Arg2), (Arg3), (Arg4), (Arg5))
#else /* USE_LTTNG */
diff --git a/erts/emulator/beam/sys.h b/erts/emulator/beam/sys.h
index 9a205d50d3..dfe82cab44 100644
--- a/erts/emulator/beam/sys.h
+++ b/erts/emulator/beam/sys.h
@@ -154,8 +154,9 @@ typedef ERTS_SYS_FD_TYPE ErtsSysFdType;
# define ERTS_WRITE_UNLIKELY(X) X
#endif
+/* clang may have too low __GNUC__ versions but can handle it */
#ifdef __GNUC__
-# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 5)
+# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 5) || defined(__clang__)
# define ERTS_DECLARE_DUMMY(X) X __attribute__ ((unused))
# else
# define ERTS_DECLARE_DUMMY(X) X
diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c
index e87d141ddb..93ea9f5dcb 100644
--- a/erts/emulator/drivers/common/inet_drv.c
+++ b/erts/emulator/drivers/common/inet_drv.c
@@ -34,6 +34,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <stddef.h>
#include <ctype.h>
#include <sys/types.h>
#include <errno.h>
@@ -58,6 +59,9 @@
#ifdef HAVE_NETPACKET_PACKET_H
#include <netpacket/packet.h>
#endif
+#ifdef HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
/* All platforms fail on malloc errors. */
#define FATAL_MALLOC
@@ -573,7 +577,7 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n)
#ifdef HAVE_SOCKLEN_T
# define SOCKLEN_T socklen_t
#else
-# define SOCKLEN_T int
+# define SOCKLEN_T size_t
#endif
#include "packet_parser.h"
@@ -587,6 +591,22 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n)
(((unsigned char*) (s))[1] << 8) | \
(((unsigned char*) (s))[0]))
+/* strnlen doesn't exist everywhere */
+static size_t my_strnlen(const char *s, size_t maxlen)
+{
+ size_t i = 0;
+ while (i < maxlen && s[i] != '\0')
+ i++;
+ return i;
+}
+
+/* Check that some character in the buffer != '\0' */
+static int is_nonzero(const char *s, size_t n)
+{
+ size_t i;
+ for (i = 0; i < n; i++) if (s[i] != '\0') return !0;
+ return 0;
+}
#ifdef VALGRIND
# include <valgrind/memcheck.h>
@@ -607,10 +627,13 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n)
*/
/* general address encode/decode tag */
+#define INET_AF_UNSPEC 0
#define INET_AF_INET 1
#define INET_AF_INET6 2
#define INET_AF_ANY 3 /* INADDR_ANY or IN6ADDR_ANY_INIT */
#define INET_AF_LOOPBACK 4 /* INADDR_LOOPBACK or IN6ADDR_LOOPBACK_INIT */
+#define INET_AF_LOCAL 5
+#define INET_AF_UNDEFINED 6 /* Unknown */
/* open and INET_REQ_GETTYPE enumeration */
#define INET_TYPE_STREAM 1
@@ -633,7 +656,7 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n)
/* INET_REQ_GETSTATUS enumeration */
#define INET_F_OPEN 0x0001
-#define INET_F_BOUND 0x0002
+/* INET_F_BOUND removed - renumber when there comes a bigger rewrite */
#define INET_F_ACTIVE 0x0004
#define INET_F_LISTEN 0x0008
#define INET_F_CON 0x0010
@@ -831,19 +854,15 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n)
#define INET_STATE_CLOSED (0)
#define INET_STATE_OPEN (INET_F_OPEN)
-#define INET_STATE_BOUND (INET_STATE_OPEN | INET_F_BOUND)
-#define INET_STATE_CONNECTED (INET_STATE_BOUND | INET_F_ACTIVE)
-#define INET_STATE_LISTENING (INET_STATE_BOUND | INET_F_LISTEN)
-#define INET_STATE_CONNECTING (INET_STATE_BOUND | INET_F_CON)
+#define INET_STATE_CONNECTED (INET_STATE_OPEN | INET_F_ACTIVE)
+#define INET_STATE_LISTENING (INET_STATE_OPEN | INET_F_LISTEN)
+#define INET_STATE_CONNECTING (INET_STATE_OPEN | INET_F_CON)
#define INET_STATE_ACCEPTING (INET_STATE_LISTENING | INET_F_ACC)
#define INET_STATE_MULTI_ACCEPTING (INET_STATE_ACCEPTING | INET_F_MULTI_CLIENT)
#define IS_OPEN(d) \
(((d)->state & INET_F_OPEN) == INET_F_OPEN)
-#define IS_BOUND(d) \
- (((d)->state & INET_F_BOUND) == INET_F_BOUND)
-
#define IS_CONNECTED(d) \
(((d)->state & INET_STATE_CONNECTED) == INET_STATE_CONNECTED)
@@ -896,19 +915,35 @@ typedef union {
#ifdef HAVE_IN6
struct sockaddr_in6 sai6;
#endif
+#ifdef HAVE_SYS_UN_H
+ struct sockaddr_un sal;
+#endif
} inet_address;
-/* for AF_INET & AF_INET6 */
-#define inet_address_port(x) ((x)->sai.sin_port)
+#define inet_address_port(x) \
+ ((((x)->sai.sin_family == AF_INET) || \
+ ((x)->sai.sin_family == AF_INET6)) ? \
+ ((x)->sai.sin_port) : -1)
+
+#ifdef HAVE_SYS_UN_H
+#define localaddrlen(data) \
+ ((((unsigned char*)(data))[0] == INET_AF_LOCAL) ? \
+ (1 + 1 + ((unsigned char*)(data))[1]) : 1)
+#else
+#define localaddrlen(data) (1)
+#endif
#if defined(HAVE_IN6) && defined(AF_INET6)
-#define addrlen(family) \
- ((family == AF_INET) ? sizeof(struct in_addr) : \
- ((family == AF_INET6) ? sizeof(struct in6_addr) : 0))
+#define addrlen(data) \
+ ((((unsigned char*)(data))[0] == INET_AF_INET) ? \
+ (1 + 2 + 4) : \
+ ((((unsigned char*)(data))[0] == INET_AF_INET6) ? \
+ (1 + 2 + 16) : localaddrlen(data)))
#else
-#define addrlen(family) \
- ((family == AF_INET) ? sizeof(struct in_addr) : 0)
+#define addrlen(data) \
+ ((((unsigned char*)(data))[0] == INET_AF_INET) ? \
+ (1 + 2 + 4) : localaddrlen(data))
#endif
typedef struct _multi_timer_data {
@@ -999,8 +1034,10 @@ typedef struct {
inet_address peer_addr; /* fake peer address */
inet_address name_addr; /* fake local address */
- inet_address* peer_ptr; /* fake peername or NULL */
- inet_address* name_ptr; /* fake sockname or NULL */
+ inet_address* peer_ptr; /* fake peername or NULL */
+ inet_address* name_ptr; /* fake sockname or NULL */
+ SOCKLEN_T peer_addr_len; /* fake peername size */
+ SOCKLEN_T name_addr_len; /* fake sockname size */
int bufsz; /* minimum buffer constraint */
unsigned int hsz; /* the list header size, -1 is large !!! */
@@ -1246,6 +1283,8 @@ static int async_ref = 0; /* async reference id generator */
} while (0)
static ErlDrvTermData am_ok;
+static ErlDrvTermData am_undefined;
+static ErlDrvTermData am_unspec;
static ErlDrvTermData am_tcp;
static ErlDrvTermData am_error;
static ErlDrvTermData am_einval;
@@ -1262,6 +1301,7 @@ static ErlDrvTermData am_ssl_tls;
static ErlDrvTermData am_udp;
static ErlDrvTermData am_udp_passive;
static ErlDrvTermData am_udp_error;
+static ErlDrvTermData am_local;
#endif
#ifdef HAVE_SCTP
static ErlDrvTermData am_sctp;
@@ -1471,40 +1511,67 @@ static void *realloc_wrapper(void *current, ErlDrvSizeT size){
#endif
#ifdef HAVE_UDP
-static int load_ip_port(ErlDrvTermData* spec, int i, char* buf)
-{
- spec[i++] = ERL_DRV_INT;
- spec[i++] = (ErlDrvTermData) get_int16(buf);
- return i;
-}
-
-static int load_ip_address(ErlDrvTermData* spec, int i, int family, char* buf)
+static int load_address(ErlDrvTermData* spec, int i, char* buf)
{
int n;
- if (family == AF_INET) {
- for (n = 0; n < 4; n++) {
+ switch (*buf++) { /* Family */
+ case INET_AF_INET: {
+ for (n = 2; n < 2+4; n++) {
spec[i++] = ERL_DRV_INT;
spec[i++] = (ErlDrvTermData) ((unsigned char)buf[n]);
}
spec[i++] = ERL_DRV_TUPLE;
spec[i++] = 4;
+ spec[i++] = ERL_DRV_INT;
+ spec[i++] = (ErlDrvTermData) get_int16(buf);
+ break;
}
#if defined(HAVE_IN6) && defined(AF_INET6)
- else if (family == AF_INET6) {
- for (n = 0; n < 16; n += 2) {
+ case INET_AF_INET6: {
+ for (n = 2; n < 2+16; n += 2) {
spec[i++] = ERL_DRV_INT;
spec[i++] = (ErlDrvTermData) get_int16(buf+n);
}
spec[i++] = ERL_DRV_TUPLE;
spec[i++] = 8;
+ spec[i++] = ERL_DRV_INT;
+ spec[i++] = (ErlDrvTermData) get_int16(buf);
+ break;
}
#endif
- else {
+#ifdef HAVE_SYS_UN_H
+ case INET_AF_LOCAL: {
+ int len = *(unsigned char*)buf++;
+ i = LOAD_ATOM(spec, i, am_local);
+ i = LOAD_BUF2BINARY(spec, i, buf, len);
+ spec[i++] = ERL_DRV_TUPLE;
+ spec[i++] = 2;
+ spec[i++] = ERL_DRV_INT;
+ spec[i++] = 0;
+ break;
+ }
+#endif
+ case INET_AF_UNSPEC: {
+ i = LOAD_ATOM(spec, i, am_unspec);
+ i = LOAD_BUF2BINARY(spec, i, buf, 0);
spec[i++] = ERL_DRV_TUPLE;
+ spec[i++] = 2;
+ spec[i++] = ERL_DRV_INT;
spec[i++] = 0;
+ break;
+ }
+ default: { /* INET_AF_UNDEFINED */
+ i = LOAD_ATOM(spec, i, am_undefined);
+ i = LOAD_BUF2BINARY(spec, i, buf, 0);
+ spec[i++] = ERL_DRV_TUPLE;
+ spec[i++] = 2;
+ spec[i++] = ERL_DRV_INT;
+ spec[i++] = 0;
+ break;
+ }
}
return i;
-}
+ }
#endif
@@ -1512,10 +1579,13 @@ static int load_ip_address(ErlDrvTermData* spec, int i, int family, char* buf)
/* For SCTP, we often need to return {IP, Port} tuples: */
static int inet_get_address(char* dst, inet_address* src, unsigned int* len);
-#define LOAD_IP_AND_PORT_CNT \
+/* Max of {{int()*8},int()} | {{int()*4},int()} |
+ * {{'local',binary()},int()}
+ */
+#define LOAD_INET_GET_ADDRESS_CNT \
(8*LOAD_INT_CNT + LOAD_TUPLE_CNT + LOAD_INT_CNT + LOAD_TUPLE_CNT)
-static int load_ip_and_port
+static int load_inet_get_address
(ErlDrvTermData* spec, int i, inet_descriptor* desc,
struct sockaddr_storage* addr)
{
@@ -1533,8 +1603,7 @@ static int load_ip_and_port
/* NB: the following functions are safe to use, as they create tuples
of copied Ints on the "spec", and do not install any String pts --
a ptr to "abuf" would be dangling upon exiting this function: */
- i = load_ip_address(spec, i, desc->sfamily, abuf+3);
- i = load_ip_port (spec, i, abuf+1);
+ i = load_address(spec, i, abuf); /* IP,Port | Family,Addr */
i = LOAD_TUPLE (spec, i, 2);
return i;
}
@@ -2226,7 +2295,6 @@ static ErlDrvTermData am_http_error;
static ErlDrvTermData am_abs_path;
static ErlDrvTermData am_absoluteURI;
static ErlDrvTermData am_star;
-static ErlDrvTermData am_undefined;
static ErlDrvTermData am_http;
static ErlDrvTermData am_https;
static ErlDrvTermData am_scheme;
@@ -2917,7 +2985,7 @@ static int sctp_parse_async_event
ASSERT(sptr->spc_length <= sz); /* No buffer overrun */
i = LOAD_ATOM (spec, i, am_sctp_paddr_change);
- i = load_ip_and_port(spec, i, desc, &sptr->spc_aaddr);
+ i = load_inet_get_address(spec, i, desc, &sptr->spc_aaddr);
switch (sptr->spc_state)
{
@@ -3344,10 +3412,11 @@ static int tcp_error_message(tcp_descriptor* desc, int err)
#ifdef HAVE_UDP
/*
** active mode message:
-** {udp, S, IP, Port, [H1,...Hsz | Data]} or
-** {sctp, S, IP, Port, {[AncilData], Event_or_Data}}
+** {udp, S, IP, Port, [H1,...Hsz | Data]} or
+** {sctp, S, IP, Port, {[AncilData], Event_or_Data}}
** where
** [H1,...,HSz] are msg headers (without IP/Port, UDP only),
+** [AddrLen, H2,...,HSz] are msg headers for UDP AF_UNIX only
** Data : List() | Binary()
*/
static int packet_binary_message
@@ -3357,6 +3426,7 @@ static int packet_binary_message
ErlDrvTermData spec [PACKET_ERL_DRV_TERM_DATA_LEN];
int i = 0;
int alen;
+ char* data = bin->orig_bytes+offs;
DEBUGF(("packet_binary_message(%ld): len = %d\r\n",
(long)desc->port, len));
@@ -3366,13 +3436,12 @@ static int packet_binary_message
i = LOAD_ATOM(spec, i, am_udp ); /* UDP only */
# endif
i = LOAD_PORT(spec, i, desc->dport); /* S */
-
- alen = addrlen(desc->sfamily);
- i = load_ip_address(spec, i, desc->sfamily, bin->orig_bytes+offs+3);
- i = load_ip_port(spec, i, bin->orig_bytes+offs+1); /* IP, Port */
-
- offs += (alen + 3);
- len -= (alen + 3);
+
+ alen = addrlen(data);
+ i = load_address(spec, i, data); /* IP,Port | Family,Addr */
+
+ offs += alen;
+ len -= alen;
# ifdef HAVE_SCTP
if (!IS_SCTP(desc))
@@ -3759,6 +3828,8 @@ static int inet_init()
# endif
INIT_ATOM(ok);
+ INIT_ATOM(undefined);
+ INIT_ATOM(unspec);
INIT_ATOM(tcp);
#ifdef HAVE_UDP
INIT_ATOM(udp);
@@ -3775,6 +3846,7 @@ static int inet_init()
#ifdef HAVE_UDP
INIT_ATOM(udp_passive);
INIT_ATOM(udp_error);
+ INIT_ATOM(local);
#endif
INIT_ATOM(empty_out_q);
INIT_ATOM(ssl_tls);
@@ -3787,7 +3859,6 @@ static int inet_init()
INIT_ATOM(abs_path);
INIT_ATOM(absoluteURI);
am_star = driver_mk_atom("*");
- INIT_ATOM(undefined);
INIT_ATOM(http);
INIT_ATOM(https);
INIT_ATOM(scheme);
@@ -3883,7 +3954,7 @@ static int inet_init()
/*
-** Set a inaddr structure:
+** Set an inaddr structure:
** src = [P1,P0,X1,X2,.....]
** dst points to a structure large enugh to keep any kind
** of inaddr.
@@ -3923,6 +3994,18 @@ static char* inet_set_address(int family, inet_address* dst,
return src + 2+16;
}
#endif
+#ifdef HAVE_SYS_UN_H
+ else if ((family == AF_UNIX) && (*len >= 1)) {
+ int n = *((unsigned char*)src);
+ if ((*len < 1+n) || (sizeof(dst->sal.sun_path) < n+1))
+ return NULL;
+ sys_memzero((char*)dst, sizeof(struct sockaddr_un));
+ dst->sal.sun_family = family;
+ sys_memcpy(dst->sal.sun_path, src+1, n);
+ *len = offsetof(struct sockaddr_un, sun_path) + n;
+ return src + 1 + n;
+ }
+#endif
return NULL;
}
@@ -3931,7 +4014,7 @@ static char* inet_set_address(int family, inet_address* dst,
** or from argument if source data specifies constant address.
**
** src = [TAG,P1,P0] when TAG = INET_AF_ANY | INET_AF_LOOPBACK
-** src = [TAG,P1,P0,X1,X2,...] when TAG = INET_AF_INET | INET_AF_INET6
+** src = [TAG,P1,P0,X1,X2,...] when TAG = INET_AF_INET | INET_AF_INET6 | INET_AF_LOCAL
*/
static char *inet_set_faddress(int family, inet_address* dst,
char *src, ErlDrvSizeT* len) {
@@ -3949,6 +4032,12 @@ static char *inet_set_faddress(int family, inet_address* dst,
family = AF_INET6;
break;
# endif
+# ifdef HAVE_SYS_UN_H
+ case INET_AF_LOCAL: {
+ family = AF_UNIX;
+ break;
+ }
+# endif
case INET_AF_ANY:
case INET_AF_LOOPBACK: {
int port;
@@ -4012,7 +4101,6 @@ static char *inet_set_faddress(int family, inet_address* dst,
return inet_set_address(family, dst, src, len);
}
-
/* Get a inaddr structure
** src = inaddr structure
** *len is the lenght of structure
@@ -4023,6 +4111,7 @@ static char *inet_set_faddress(int family, inet_address* dst,
*/
static int inet_get_address(char* dst, inet_address* src, unsigned int* len)
{
+ /* Compare the code with inet_address_to_erlang() */
int family;
short port;
@@ -4045,6 +4134,36 @@ static int inet_get_address(char* dst, inet_address* src, unsigned int* len)
return 0;
}
#endif
+#ifdef HAVE_SYS_UN_H
+ else if (family == AF_UNIX) {
+ size_t n, m;
+ if (*len < offsetof(struct sockaddr_un, sun_path)) return -1;
+ n = *len - offsetof(struct sockaddr_un, sun_path);
+ if (255 < n) return -1;
+ /* Portability fix: Assume that the address is a zero terminated
+ * string, except when the first byte is \0 i.e the
+ * string length is 0. Then use the reported length instead.
+ * This fix handles Linux's abstract socket address
+ * nonportable extension.
+ */
+ m = my_strnlen(src->sal.sun_path, n);
+ if ((m == 0) && is_nonzero(src->sal.sun_path, n))
+ m = n;
+ dst[0] = INET_AF_LOCAL;
+ dst[1] = (char) ((unsigned char) m);
+ sys_memcpy(dst+2, src->sal.sun_path, m);
+ *len = 1 + 1 + m;
+ return 0;
+ }
+#endif
+ else if (family == AF_UNSPEC) {
+ dst[0] = INET_AF_UNSPEC;
+ *len = 1;
+ }
+ else {
+ dst[0] = INET_AF_UNDEFINED;
+ *len = 1;
+ }
return -1;
}
@@ -4053,7 +4172,9 @@ static int inet_get_address(char* dst, inet_address* src, unsigned int* len)
** according to the size of the current,
** and return the resulting encoded size
*/
-static int inet_address_to_erlang(char *dst, inet_address **src) {
+static int
+inet_address_to_erlang(char *dst, inet_address **src, SOCKLEN_T sz) {
+ /* Compare the code with inet_get_address() */
short port;
switch ((*src)->sa.sa_family) {
@@ -4078,6 +4199,30 @@ static int inet_address_to_erlang(char *dst, inet_address **src) {
(*src) = (inet_address *) (&(*src)->sai6 + 1);
return 1 + 2 + 16;
#endif
+#ifdef HAVE_SYS_UN_H
+ case AF_UNIX: {
+ size_t n, m;
+ if (sz < offsetof(struct sockaddr_un, sun_path)) return -1;
+ n = sz - offsetof(struct sockaddr_un, sun_path);
+ if (255 < n) return -1;
+ /* Portability fix: Assume that the address is a zero terminated
+ * string, except when the first byte is \0 i.e the
+ * string length is 0. Then use the reported length instead.
+ * This fix handles Linux's abstract socket address
+ * nonportable extension.
+ */
+ m = my_strnlen((*src)->sal.sun_path, n);
+ if ((m == 0) && is_nonzero((*src)->sal.sun_path, n))
+ m = n;
+ if (dst) {
+ dst[0] = INET_AF_LOCAL;
+ dst[1] = (char) ((unsigned char) m);
+ sys_memcpy(dst+2, (*src)->sal.sun_path, m);
+ }
+ (*src) = (inet_address *) (&(*src)->sal + 1);
+ return 1 + 1 + m;
+ }
+#endif
default:
return -1;
}
@@ -4086,7 +4231,7 @@ static int inet_address_to_erlang(char *dst, inet_address **src) {
/* Encode n encoded addresses from addrs in the result buffer
*/
static ErlDrvSizeT reply_inet_addrs
-(int n, inet_address *addrs, char **rbuf, ErlDrvSizeT rsize) {
+(int n, inet_address *addrs, char **rbuf, ErlDrvSizeT rsize, SOCKLEN_T sz) {
inet_address *ia;
int i, s;
ErlDrvSizeT rlen;
@@ -4094,11 +4239,19 @@ static ErlDrvSizeT reply_inet_addrs
if (IS_SOCKET_ERROR(n)) return ctl_error(sock_errno(), rbuf, rsize);
if (n == 0) return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize);
+ /* The sz argument is only used when we have got an actual size
+ * of addrs[0] from e.g getsockname() and then n == 1
+ * so we will loop over 1 element below. Otherwise sz
+ * would be expected to differ between addresses but that
+ * can only happen for AF_UNIX and we will only be called with
+ * n > 1 for SCTP and that will never (?) happen with AF_UNIX
+ */
+
/* Calculate result length */
rlen = 1;
ia = addrs;
for (i = 0; i < n; i++) {
- s = inet_address_to_erlang(NULL, &ia);
+ s = inet_address_to_erlang(NULL, &ia, sz);
if (s < 0) break;
rlen += s;
}
@@ -4109,7 +4262,7 @@ static ErlDrvSizeT reply_inet_addrs
rlen = 1;
ia = addrs;
for (i = 0; i < n; i++) {
- s = inet_address_to_erlang((*rbuf)+rlen, &ia);
+ s = inet_address_to_erlang((*rbuf)+rlen, &ia, sz);
if (s < 0) break;
rlen += s;
}
@@ -4180,6 +4333,7 @@ static ErlDrvSSizeT inet_ctl_open(inet_descriptor* desc, int domain, int type,
char** rbuf, ErlDrvSizeT rsize)
{
int save_errno;
+ int protocol;
#ifdef HAVE_SETNS
int current_ns, new_ns;
current_ns = new_ns = 0;
@@ -4218,7 +4372,11 @@ static ErlDrvSSizeT inet_ctl_open(inet_descriptor* desc, int domain, int type,
}
}
#endif
- if ((desc->s = sock_open(domain, type, desc->sprotocol)) == INVALID_SOCKET)
+ protocol = desc->sprotocol;
+#ifdef HAVE_SYS_UN_H
+ if (domain == AF_UNIX) protocol = 0;
+#endif
+ if ((desc->s = sock_open(domain, type, protocol)) == INVALID_SOCKET)
save_errno = sock_errno();
#ifdef HAVE_SETNS
if (desc->netns != NULL) {
@@ -4272,10 +4430,12 @@ static ErlDrvSSizeT inet_ctl_fdopen(inet_descriptor* desc, int domain, int type,
char** rbuf, ErlDrvSizeT rsize)
{
inet_address name;
- unsigned int sz = sizeof(name);
+ unsigned int sz;
if (bound) {
/* check that it is a socket and that the socket is bound */
+ sz = sizeof(name);
+ sys_memzero((char *) &name, sz);
if (IS_SOCKET_ERROR(sock_name(s, (struct sockaddr*) &name, &sz)))
return ctl_error(sock_errno(), rbuf, rsize);
if (name.sa.sa_family != domain)
@@ -4290,10 +4450,7 @@ static ErlDrvSSizeT inet_ctl_fdopen(inet_descriptor* desc, int domain, int type,
driver_select(desc->port, desc->event, ERL_DRV_READ, 1);
#endif
- if (bound)
- desc->state = INET_STATE_BOUND;
- else
- desc->state = INET_STATE_OPEN;
+ desc->state = INET_STATE_OPEN;
if (type == SOCK_STREAM) { /* check if connected */
sz = sizeof(name);
@@ -7119,14 +7276,14 @@ static ErlDrvSSizeT inet_fill_opts(inet_descriptor* desc,
#ifdef HAVE_SCTP
#define LOAD_PADDRINFO_CNT \
- (2*LOAD_ATOM_CNT + LOAD_ASSOC_ID_CNT + LOAD_IP_AND_PORT_CNT + \
+ (2*LOAD_ATOM_CNT + LOAD_ASSOC_ID_CNT + LOAD_INET_GET_ADDRESS_CNT + \
4*LOAD_INT_CNT + LOAD_TUPLE_CNT)
static int load_paddrinfo (ErlDrvTermData * spec, int i,
inet_descriptor* desc, struct sctp_paddrinfo* pai)
{
i = LOAD_ATOM (spec, i, am_sctp_paddrinfo);
i = LOAD_ASSOC_ID (spec, i, pai->spinfo_assoc_id);
- i = load_ip_and_port(spec, i, desc, &pai->spinfo_address);
+ i = load_inet_get_address(spec, i, desc, &pai->spinfo_address);
switch(pai->spinfo_state)
{
case SCTP_ACTIVE:
@@ -7542,7 +7699,7 @@ static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc,
/* Fill in the response: */
PLACE_FOR(spec, i,
2*LOAD_ATOM_CNT + LOAD_ASSOC_ID_CNT +
- LOAD_IP_AND_PORT_CNT + 2*LOAD_TUPLE_CNT);
+ LOAD_INET_GET_ADDRESS_CNT + 2*LOAD_TUPLE_CNT);
switch (eopt) {
case SCTP_OPT_PRIMARY_ADDR:
i = LOAD_ATOM(spec, i, am_sctp_primary_addr);
@@ -7556,7 +7713,7 @@ static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc,
ASSERT(0);
}
i = LOAD_ASSOC_ID (spec, i, sp.sspp_assoc_id);
- i = load_ip_and_port(spec, i, desc, &sp.sspp_addr);
+ i = load_inet_get_address(spec, i, desc, &sp.sspp_addr);
i = LOAD_TUPLE (spec, i, 3);
i = LOAD_TUPLE (spec, i, 2);
break;
@@ -7603,11 +7760,11 @@ static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc,
/* Fill in the response: */
PLACE_FOR(spec, i,
2*LOAD_ATOM_CNT + LOAD_ASSOC_ID_CNT +
- LOAD_IP_AND_PORT_CNT + 4*LOAD_INT_CNT);
+ LOAD_INET_GET_ADDRESS_CNT + 4*LOAD_INT_CNT);
i = LOAD_ATOM (spec, i, am_sctp_peer_addr_params);
i = LOAD_ATOM (spec, i, am_sctp_paddrparams);
i = LOAD_ASSOC_ID (spec, i, ap.spp_assoc_id);
- i = load_ip_and_port(spec, i, desc, &ap.spp_address);
+ i = load_inet_get_address(spec, i, desc, &ap.spp_address);
i = LOAD_INT (spec, i, ap.spp_hbinterval);
i = LOAD_INT (spec, i, ap.spp_pathmaxrxt);
@@ -8248,6 +8405,11 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf,
put_int32(INET_AF_INET6, &tbuf[0]);
}
#endif
+#ifdef HAVE_SYS_UN_H
+ else if (desc->sfamily == AF_UNIX) {
+ put_int32(INET_AF_LOCAL, &tbuf[0]);
+ }
+#endif
else
return ctl_error(EINVAL, rbuf, rsize);
@@ -8296,7 +8458,6 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf,
if (len != 4) return ctl_error(EINVAL, rbuf, rsize);
if (! IS_OPEN(desc)) return ctl_xerror(EXBADPORT, rbuf, rsize);
- if (! IS_BOUND(desc)) return ctl_xerror(EXBADSEQ, rbuf, rsize);
#ifdef HAVE_SCTP
if (IS_SCTP(desc) && p_sctp_getpaddrs) {
@@ -8307,19 +8468,19 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf,
assoc_id = get_int32(buf);
n = p_sctp_getpaddrs(desc->s, assoc_id, &sa);
- rlen = reply_inet_addrs(n, (inet_address *) sa, rbuf, rsize);
+ rlen = reply_inet_addrs(n, (inet_address *) sa, rbuf, rsize, 0);
if (n > 0) p_sctp_freepaddrs(sa);
return rlen;
}
#endif
{ /* Fallback to sock_peer */
inet_address addr;
- unsigned int sz;
+ SOCKLEN_T sz;
int i;
sz = sizeof(addr);
i = sock_peer(desc->s, (struct sockaddr *) &addr, &sz);
- return reply_inet_addrs(i >= 0 ? 1 : i, &addr, rbuf, rsize);
+ return reply_inet_addrs(i >= 0 ? 1 : i, &addr, rbuf, rsize, sz);
}
}
@@ -8327,15 +8488,21 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf,
char tbuf[sizeof(inet_address)];
inet_address peer;
inet_address* ptr;
- unsigned int sz = sizeof(peer);
+ unsigned int sz;
DEBUGF(("inet_ctl(%ld): PEER\r\n", (long)desc->port));
if (!(desc->state & INET_F_ACTIVE))
return ctl_error(ENOTCONN, rbuf, rsize);
- if ((ptr = desc->peer_ptr) == NULL) {
+ if ((ptr = desc->peer_ptr) != NULL) {
+ sz = desc->peer_addr_len;
+ }
+ else {
ptr = &peer;
- if (IS_SOCKET_ERROR(sock_peer(desc->s, (struct sockaddr*)ptr,&sz)))
+ sz = sizeof(peer);
+ if (IS_SOCKET_ERROR
+ (sock_peer
+ (desc->s, (struct sockaddr*)ptr, &sz)))
return ctl_error(sock_errno(), rbuf, rsize);
}
if (inet_get_address(tbuf, ptr, &sz) < 0)
@@ -8350,11 +8517,12 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf,
}
else if (len < 2)
return ctl_error(EINVAL, rbuf, rsize);
- else if (inet_set_address(desc->sfamily, &desc->peer_addr,
- buf, &len) == NULL)
+ else if (inet_set_faddress
+ (desc->sfamily, &desc->peer_addr, buf, &len) == NULL)
return ctl_error(EINVAL, rbuf, rsize);
else {
desc->peer_ptr = &desc->peer_addr;
+ desc->peer_addr_len = (SOCKLEN_T) len;
return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize);
}
}
@@ -8365,7 +8533,6 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf,
if (len != 4) return ctl_error(EINVAL, rbuf, rsize);
if (! IS_OPEN(desc)) return ctl_xerror(EXBADPORT, rbuf, rsize);
- if (! IS_BOUND(desc)) return ctl_xerror(EXBADSEQ, rbuf, rsize);
#ifdef HAVE_SCTP
if (IS_SCTP(desc) && p_sctp_getladdrs) {
@@ -8376,19 +8543,20 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf,
assoc_id = get_int32(buf);
n = p_sctp_getladdrs(desc->s, assoc_id, &sa);
- rlen = reply_inet_addrs(n, (inet_address *) sa, rbuf, rsize);
+ rlen = reply_inet_addrs(n, (inet_address *) sa, rbuf, rsize, 0);
if (n > 0) p_sctp_freeladdrs(sa);
return rlen;
}
#endif
{ /* Fallback to sock_name */
inet_address addr;
- unsigned int sz;
+ SOCKLEN_T sz;
int i;
sz = sizeof(addr);
+ sys_memzero((char *) &addr, sz);
i = sock_name(desc->s, (struct sockaddr *) &addr, &sz);
- return reply_inet_addrs(i >= 0 ? 1 : i, &addr, rbuf, rsize);
+ return reply_inet_addrs(i >= 0 ? 1 : i, &addr, rbuf, rsize, sz);
}
}
@@ -8396,16 +8564,19 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf,
char tbuf[sizeof(inet_address)];
inet_address name;
inet_address* ptr;
- unsigned int sz = sizeof(name);
+ unsigned int sz;
DEBUGF(("inet_ctl(%ld): NAME\r\n", (long)desc->port));
- if (!IS_BOUND(desc))
- return ctl_error(EINVAL, rbuf, rsize); /* address is not valid */
-
- if ((ptr = desc->name_ptr) == NULL) {
+ if ((ptr = desc->name_ptr) != NULL) {
+ sz = desc->name_addr_len;
+ }
+ else {
ptr = &name;
- if (IS_SOCKET_ERROR(sock_name(desc->s, (struct sockaddr*)ptr, &sz)))
+ sz = sizeof(name);
+ sys_memzero((char *) &name, sz);
+ if (IS_SOCKET_ERROR
+ (sock_name(desc->s, (struct sockaddr*)ptr, &sz)))
return ctl_error(sock_errno(), rbuf, rsize);
}
if (inet_get_address(tbuf, ptr, &sz) < 0)
@@ -8413,18 +8584,19 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf,
return ctl_reply(INET_REP_OK, tbuf, sz, rbuf, rsize);
}
- case INET_REQ_SETNAME: { /* set fake peername Port Address */
+ case INET_REQ_SETNAME: { /* set fake sockname Port Address */
if (len == 0) {
desc->name_ptr = NULL;
return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize);
}
else if (len < 2)
return ctl_error(EINVAL, rbuf, rsize);
- else if (inet_set_address(desc->sfamily, &desc->name_addr,
- buf, &len) == NULL)
+ else if (inet_set_faddress
+ (desc->sfamily, &desc->name_addr, buf, &len) == NULL)
return ctl_error(EINVAL, rbuf, rsize);
else {
desc->name_ptr = &desc->name_addr;
+ desc->name_addr_len = (SOCKLEN_T) len;
return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize);
}
}
@@ -8432,7 +8604,7 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf,
case INET_REQ_BIND: { /* bind socket */
char tbuf[2];
inet_address local;
- short port;
+ int port;
DEBUGF(("inet_ctl(%ld): BIND\r\n", (long)desc->port));
@@ -8447,15 +8619,17 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf,
if (IS_SOCKET_ERROR(sock_bind(desc->s,(struct sockaddr*) &local, len)))
return ctl_error(sock_errno(), rbuf, rsize);
- desc->state = INET_STATE_BOUND;
+ desc->state = INET_STATE_OPEN;
- if ((port = inet_address_port(&local)) == 0) {
+ port = inet_address_port(&local);
+ if (port == 0) {
SOCKLEN_T adrlen = sizeof(local);
+ sys_memzero((char *) &local, adrlen);
sock_name(desc->s, &local.sa, &adrlen);
port = inet_address_port(&local);
}
- port = sock_ntohs(port);
- put_int16(port, tbuf);
+ else if (port == -1) port = 0;
+ put_int16(sock_ntohs((Uint16) port), tbuf);
return ctl_reply(INET_REP_OK, tbuf, 2, rbuf, rsize);
}
@@ -8912,6 +9086,11 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd,
return ctl_xerror("eafnosupport", rbuf, rsize);
break;
#endif
+#ifdef HAVE_SYS_UN_H
+ case INET_AF_LOCAL:
+ domain = AF_UNIX;
+ break;
+#endif
default:
return ctl_error(EINVAL, rbuf, rsize);
}
@@ -8938,6 +9117,11 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd,
return ctl_xerror("eafnosupport", rbuf, rsize);
break;
#endif
+#ifdef HAVE_SYS_UN_H
+ case INET_AF_LOCAL:
+ domain = AF_UNIX;
+ break;
+#endif
default:
return ctl_error(EINVAL, rbuf, rsize);
}
@@ -8960,8 +9144,6 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd,
return ctl_xerror(EXBADPORT, rbuf, rsize);
if (!IS_OPEN(INETP(desc)))
return ctl_xerror(EXBADPORT, rbuf, rsize);
- if (!IS_BOUND(INETP(desc)))
- return ctl_xerror(EXBADSEQ, rbuf, rsize);
if (len != 2)
return ctl_error(EINVAL, rbuf, rsize);
backlog = get_int16(buf);
@@ -8984,8 +9166,6 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd,
return ctl_xerror(EXBADPORT, rbuf, rsize);
if (IS_CONNECTED(INETP(desc)))
return ctl_error(EISCONN, rbuf, rsize);
- if (!IS_BOUND(INETP(desc)))
- return ctl_xerror(EXBADSEQ, rbuf, rsize);
if (IS_CONNECTING(INETP(desc)))
return ctl_error(EINVAL, rbuf, rsize);
if (len < 6)
@@ -8993,8 +9173,8 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd,
timeout = get_int32(buf);
buf += 4;
len -= 4;
- if (inet_set_address(desc->inet.sfamily, &desc->inet.remote,
- buf, &len) == NULL)
+ if (inet_set_faddress
+ (desc->inet.sfamily, &desc->inet.remote, buf, &len) == NULL)
return ctl_error(EINVAL, rbuf, rsize);
code = sock_connect(desc->inet.s,
@@ -9086,6 +9266,7 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd,
return ctl_reply(INET_REP_OK, tbuf, 2, rbuf, rsize);
} else {
n = sizeof(desc->inet.remote);
+ sys_memzero((char *) &remote, n);
s = sock_accept(desc->inet.s, (struct sockaddr*) &remote, &n);
if (s == INVALID_SOCKET) {
if (sock_errno() == ERRNO_BLOCK) {
@@ -9971,6 +10152,7 @@ static int tcp_inet_input(tcp_descriptor* desc, HANDLE event)
inet_async_op *this_op = desc->inet.opt;
len = sizeof(desc->inet.remote);
+ sys_memzero((char *) &remote, len);
s = sock_accept(desc->inet.s, (struct sockaddr*) &remote, &len);
if (s == INVALID_SOCKET && sock_errno() == ERRNO_BLOCK) {
/* Just try again, no real error, just a ghost trigger from poll,
@@ -10037,6 +10219,7 @@ static int tcp_inet_input(tcp_descriptor* desc, HANDLE event)
while (desc->inet.state == INET_STATE_MULTI_ACCEPTING) {
len = sizeof(desc->inet.remote);
+ sys_memzero((char *) &remote, len);
s = sock_accept(desc->inet.s, (struct sockaddr*) &remote, &len);
if (s == INVALID_SOCKET && sock_errno() == ERRNO_BLOCK) {
/* Just try again, no real error, keep the last return code */
@@ -10477,7 +10660,7 @@ static int tcp_inet_output(tcp_descriptor* desc, HANDLE event)
(struct sockaddr*) &desc->inet.remote, &sz);
if (IS_SOCKET_ERROR(code)) {
- desc->inet.state = INET_STATE_BOUND; /* restore state */
+ desc->inet.state = INET_STATE_OPEN; /* restore state */
ret = async_error(INETP(desc), sock_errno());
goto done;
}
@@ -10490,7 +10673,7 @@ static int tcp_inet_output(tcp_descriptor* desc, HANDLE event)
(void *)&error, &sz);
if ((code < 0) || error) {
- desc->inet.state = INET_STATE_BOUND; /* restore state */
+ desc->inet.state = INET_STATE_OPEN; /* restore state */
ret = async_error(INETP(desc), error);
goto done;
}
@@ -10777,6 +10960,9 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf,
return ctl_xerror("eafnosupport", rbuf, rsize);
break;
#endif
+#ifdef HAVE_SYS_UN_H
+ case INET_AF_LOCAL: af = AF_UNIX; break;
+#endif
default:
return ctl_error(EINVAL, rbuf, rsize);
}
@@ -10827,6 +11013,9 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf,
return ctl_xerror("eafnosupport", rbuf, rsize);
break;
#endif
+#ifdef HAVE_SYS_UN_H
+ case INET_AF_LOCAL: af = AF_UNIX; break;
+#endif
default:
return ctl_error(EINVAL, rbuf, rsize);
}
@@ -10893,8 +11082,6 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf,
if (!IS_OPEN(desc))
return ctl_xerror(EXBADPORT, rbuf, rsize);
- if (!IS_BOUND(desc))
- return ctl_xerror(EXBADSEQ, rbuf, rsize);
#ifdef HAVE_SCTP
if (IS_SCTP(desc)) {
inet_address remote;
@@ -10909,7 +11096,7 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf,
/* For SCTP, we do not set the peer's addr in desc->remote, as
multiple peers are possible: */
- if (inet_set_address(desc->sfamily, &remote, buf, &len) == NULL)
+ if (inet_set_faddress(desc->sfamily, &remote, buf, &len) == NULL)
return ctl_error(EINVAL, rbuf, rsize);
sock_select(desc, FD_CONNECT, 1);
@@ -10949,8 +11136,8 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf,
/* Ignore timeout */
buf += 4;
len -= 4;
- if (inet_set_address(desc->sfamily,
- &desc->remote, buf, &len) == NULL)
+ if (inet_set_faddress
+ (desc->sfamily, &desc->remote, buf, &len) == NULL)
return ctl_error(EINVAL, rbuf, rsize);
code = sock_connect(desc->s,
@@ -10981,8 +11168,6 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf,
return ctl_xerror(EXBADPORT, rbuf, rsize);
if (!IS_OPEN(desc))
return ctl_xerror(EXBADPORT, rbuf, rsize);
- if (!IS_BOUND(desc))
- return ctl_xerror(EXBADSEQ, rbuf, rsize);
if (len != 2)
return ctl_error(EINVAL, rbuf, rsize);
@@ -11029,7 +11214,7 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf,
return ctl_error(sock_errno(), rbuf, rsize);
}
- desc->state = INET_STATE_BOUND;
+ desc->state = INET_STATE_OPEN;
return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize);
}
@@ -11046,8 +11231,6 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf,
return ctl_xerror(EXBADPORT, rbuf, rsize);
if (!IS_OPEN(desc))
return ctl_xerror(EXBADPORT, rbuf, rsize);
- if (!IS_BOUND(desc))
- return ctl_xerror(EXBADSEQ, rbuf, rsize);
if (! p_sctp_peeloff)
return ctl_error(ENOTSUP, rbuf, rsize);
@@ -11088,8 +11271,6 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf,
/* INPUT: Timeout(4), Length(4) */
if (!IS_OPEN(desc))
return ctl_xerror(EXBADPORT, rbuf, rsize);
- if (!IS_BOUND(desc))
- return ctl_error(EINVAL, rbuf, rsize);
if (desc->active || (len != 8))
return ctl_error(EINVAL, rbuf, rsize);
timeout = get_int32(buf);
@@ -11130,12 +11311,12 @@ static void packet_inet_timeout(ErlDrvData e)
/* THIS IS A "send*" REQUEST; on the Erlang side: "port_command".
-** input should be: P1 P0 Address buffer .
+** input should be: Family Address buffer .
** For UDP, buffer (after Address) is just data to be sent.
** For SCTP, buffer contains a list representing 2 items:
** (1) 6 parms for sctp_sndrcvinfo, as in sctp_get_sendparams();
** (2) 0+ real data bytes.
-** There is no destination address -- SCTYP send is performed over
+** There is no destination address -- SCTP send is performed over
** an existing association, using "sctp_sndrcvinfo" specified.
*/
static void packet_inet_command(ErlDrvData e, char* buf, ErlDrvSizeT len)
@@ -11154,10 +11335,6 @@ static void packet_inet_command(ErlDrvData e, char* buf, ErlDrvSizeT len)
inet_reply_error(desc, EINVAL);
return;
}
- if (!IS_BOUND(desc)) {
- inet_reply_error(desc, EINVAL);
- return;
- }
#ifdef HAVE_SCTP
if (IS_SCTP(desc))
@@ -11210,7 +11387,7 @@ static void packet_inet_command(ErlDrvData e, char* buf, ErlDrvSizeT len)
/* UDP socket. Even if it is connected, there is an address prefix
here -- ignored for connected sockets: */
sz = len;
- qtr = inet_set_address(desc->sfamily, &other, ptr, &sz);
+ qtr = inet_set_faddress(desc->sfamily, &other, ptr, &sz);
if (qtr == NULL) {
inet_reply_error(desc, EINVAL);
return;
@@ -11288,6 +11465,8 @@ static int packet_inet_input(udp_descriptor* udesc, HANDLE event)
while(packet_count--) {
unsigned int len = sizeof(other);
+ sys_memzero((char *) &other, sizeof(other));
+
/* udesc->i_buf is only kept between SCTP fragments */
if (udesc->i_buf == NULL) {
udesc->i_bufsz = desc->bufsz + len;
@@ -11483,7 +11662,7 @@ static int packet_inet_output(udp_descriptor* udesc, HANDLE event)
(struct sockaddr*) &desc->remote, &sz);
if (IS_SOCKET_ERROR(code)) {
- desc->state = INET_STATE_BOUND; /* restore state */
+ desc->state = INET_STATE_OPEN; /* restore state */
ret = async_error(desc, sock_errno());
goto done;
}
@@ -11496,7 +11675,7 @@ static int packet_inet_output(udp_descriptor* udesc, HANDLE event)
(void *)&error, &sz);
if ((code < 0) || error) {
- desc->state = INET_STATE_BOUND; /* restore state */
+ desc->state = INET_STATE_OPEN; /* restore state */
ret = async_error(desc, error);
goto done;
}
@@ -11809,9 +11988,8 @@ int erts_sock_connect(erts_sock_t socket, byte *ip_addr, int len, Uint16 port)
if (!inet_set_address(AF_INET, &addr, buf, &blen))
return 0;
- if (IS_SOCKET_ERROR(sock_connect(s,
- (struct sockaddr *) &addr,
- sizeof(struct sockaddr_in))))
+ if (IS_SOCKET_ERROR
+ (sock_connect(s, (struct sockaddr *) &addr, blen)))
return 0;
return 1;
}
diff --git a/erts/emulator/test/dirty_nif_SUITE_data/dirty_nif_SUITE.c b/erts/emulator/test/dirty_nif_SUITE_data/dirty_nif_SUITE.c
index e38bececde..d92933a096 100644
--- a/erts/emulator/test/dirty_nif_SUITE_data/dirty_nif_SUITE.c
+++ b/erts/emulator/test/dirty_nif_SUITE_data/dirty_nif_SUITE.c
@@ -48,7 +48,8 @@ static ERL_NIF_TERM dirty_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
char s[10];
ErlNifBinary b;
if (have_dirty_schedulers()) {
- assert(enif_is_on_dirty_scheduler(env));
+ assert(ERL_NIF_THR_DIRTY_CPU_SCHEDULER == enif_thread_type()
+ || ERL_NIF_THR_DIRTY_IO_SCHEDULER == enif_thread_type());
}
assert(argc == 3);
enif_get_int(env, argv[0], &n);
@@ -65,7 +66,7 @@ static ERL_NIF_TERM call_dirty_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
int n;
char s[10];
ErlNifBinary b;
- assert(!enif_is_on_dirty_scheduler(env));
+ assert(ERL_NIF_THR_NORMAL_SCHEDULER == enif_thread_type());
if (argc != 3)
return enif_make_badarg(env);
if (have_dirty_schedulers()) {
@@ -151,7 +152,8 @@ dirty_sleeper(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
ErlNifPid pid;
ErlNifEnv* msg_env = NULL;
- assert(enif_is_on_dirty_scheduler(env));
+ assert(ERL_NIF_THR_DIRTY_CPU_SCHEDULER == enif_thread_type()
+ || ERL_NIF_THR_DIRTY_IO_SCHEDULER == enif_thread_type());
/* If we get a pid argument, it indicates a process involved in the
test wants a message from us. Prior to the sleep we send a 'ready'
@@ -221,7 +223,8 @@ static ERL_NIF_TERM dirty_heap_access_nif(ErlNifEnv* env, int argc, const ERL_NI
{
ERL_NIF_TERM res = enif_make_list(env, 0);
int i;
- assert(enif_is_on_dirty_scheduler(env));
+ assert(ERL_NIF_THR_DIRTY_CPU_SCHEDULER == enif_thread_type()
+ || ERL_NIF_THR_DIRTY_IO_SCHEDULER == enif_thread_type());
for (i = 0; i < 1000; i++)
res = enif_make_list_cell(env, enif_make_copy(env, argv[0]), res);
diff --git a/erts/emulator/test/lttng_SUITE.erl b/erts/emulator/test/lttng_SUITE.erl
index c64ddc40da..6b7ad836f5 100644
--- a/erts/emulator/test/lttng_SUITE.erl
+++ b/erts/emulator/test/lttng_SUITE.erl
@@ -44,6 +44,7 @@ suite() ->
all() ->
[t_lttng_list,
+ t_memory_carrier,
t_carrier_pool,
t_async_io_pool,
t_driver_start_stop,
@@ -52,8 +53,7 @@ all() ->
t_driver_timeout,
t_driver_caller,
t_driver_flush,
- t_scheduler_poll,
- t_memory_carrier].
+ t_scheduler_poll].
init_per_suite(Config) ->
@@ -80,34 +80,34 @@ end_per_testcase(Case, _Config) ->
ok.
%% Not tested yet
-%% com_ericsson_otp:driver_process_exit
-%% com_ericsson_otp:driver_event
+%% org_erlang_otp:driver_process_exit
+%% org_erlang_otp:driver_event
%% tracepoints
%%
-%% com_ericsson_otp:carrier_pool_get
-%% com_ericsson_otp:carrier_pool_put
-%% com_ericsson_otp:carrier_destroy
-%% com_ericsson_otp:carrier_create
-%% com_ericsson_otp:aio_pool_put
-%% com_ericsson_otp:aio_pool_get
-%% com_ericsson_otp:driver_control
-%% com_ericsson_otp:driver_call
-%% com_ericsson_otp:driver_finish
-%% com_ericsson_otp:driver_ready_async
-%% com_ericsson_otp:driver_process_exit
-%% com_ericsson_otp:driver_stop
-%% com_ericsson_otp:driver_flush
-%% com_ericsson_otp:driver_stop_select
-%% com_ericsson_otp:driver_timeout
-%% com_ericsson_otp:driver_event
-%% com_ericsson_otp:driver_ready_output
-%% com_ericsson_otp:driver_ready_input
-%% com_ericsson_otp:driver_output
-%% com_ericsson_otp:driver_outputv
-%% com_ericsson_otp:driver_init
-%% com_ericsson_otp:driver_start
-%% com_ericsson_otp:scheduler_poll
+%% org_erlang_otp:carrier_pool_get
+%% org_erlang_otp:carrier_pool_put
+%% org_erlang_otp:carrier_destroy
+%% org_erlang_otp:carrier_create
+%% org_erlang_otp:aio_pool_put
+%% org_erlang_otp:aio_pool_get
+%% org_erlang_otp:driver_control
+%% org_erlang_otp:driver_call
+%% org_erlang_otp:driver_finish
+%% org_erlang_otp:driver_ready_async
+%% org_erlang_otp:driver_process_exit
+%% org_erlang_otp:driver_stop
+%% org_erlang_otp:driver_flush
+%% org_erlang_otp:driver_stop_select
+%% org_erlang_otp:driver_timeout
+%% org_erlang_otp:driver_event
+%% org_erlang_otp:driver_ready_output
+%% org_erlang_otp:driver_ready_input
+%% org_erlang_otp:driver_output
+%% org_erlang_otp:driver_outputv
+%% org_erlang_otp:driver_init
+%% org_erlang_otp:driver_start
+%% org_erlang_otp:scheduler_poll
%%
%% Testcases
@@ -117,48 +117,48 @@ t_lttng_list(_Config) ->
{ok, _} = cmd("lttng list -u"),
ok.
-%% com_ericsson_otp:carrier_pool_get
-%% com_ericsson_otp:carrier_pool_put
+%% org_erlang_otp:carrier_pool_get
+%% org_erlang_otp:carrier_pool_put
t_carrier_pool(Config) ->
case have_carriers(ets_alloc) of
false ->
{skip, "No Memory Carriers configured on system."};
true ->
- ok = lttng_start_event("com_ericsson_otp:carrier_pool*", Config),
+ ok = lttng_start_event("org_erlang_otp:carrier_pool*", Config),
ok = ets_load(),
Res = lttng_stop_and_view(Config),
- ok = check_tracepoint("com_ericsson_otp:carrier_pool_get", Res),
- ok = check_tracepoint("com_ericsson_otp:carrier_pool_put", Res),
+ ok = check_tracepoint("org_erlang_otp:carrier_pool_get", Res),
+ ok = check_tracepoint("org_erlang_otp:carrier_pool_put", Res),
ok
end.
-%% com_ericsson_otp:carrier_destroy
-%% com_ericsson_otp:carrier_create
+%% org_erlang_otp:carrier_destroy
+%% org_erlang_otp:carrier_create
t_memory_carrier(Config) ->
case have_carriers(ets_alloc) of
false ->
{skip, "No Memory Carriers configured on system."};
true ->
- ok = lttng_start_event("com_ericsson_otp:carrier_*", Config),
+ ok = lttng_start_event("org_erlang_otp:carrier_*", Config),
ok = ets_load(),
Res = lttng_stop_and_view(Config),
- ok = check_tracepoint("com_ericsson_otp:carrier_destroy", Res),
- ok = check_tracepoint("com_ericsson_otp:carrier_create", Res),
+ ok = check_tracepoint("org_erlang_otp:carrier_destroy", Res),
+ ok = check_tracepoint("org_erlang_otp:carrier_create", Res),
ok
end.
-%% com_ericsson_otp:aio_pool_put
-%% com_ericsson_otp:aio_pool_get
+%% org_erlang_otp:aio_pool_put
+%% org_erlang_otp:aio_pool_get
t_async_io_pool(Config) ->
case have_async_threads() of
false ->
{skip, "No Async Threads configured on system."};
true ->
- ok = lttng_start_event("com_ericsson_otp:aio_pool_*", Config),
+ ok = lttng_start_event("org_erlang_otp:aio_pool_*", Config),
Path1 = proplists:get_value(priv_dir, Config),
{ok, [[Path2]]} = init:get_argument(home),
@@ -168,51 +168,54 @@ t_async_io_pool(Config) ->
{ok, _} = file:list_dir(Path2),
Res = lttng_stop_and_view(Config),
- ok = check_tracepoint("com_ericsson_otp:aio_pool_put", Res),
- ok = check_tracepoint("com_ericsson_otp:aio_pool_get", Res),
+ ok = check_tracepoint("org_erlang_otp:aio_pool_put", Res),
+ ok = check_tracepoint("org_erlang_otp:aio_pool_get", Res),
ok
end.
-%% com_ericsson_otp:driver_start
-%% com_ericsson_otp:driver_stop
+%% org_erlang_otp:driver_start
+%% org_erlang_otp:driver_stop
t_driver_start_stop(Config) ->
- ok = lttng_start_event("com_ericsson_otp:driver_*", Config),
+ ok = lttng_start_event("org_erlang_otp:driver_*", Config),
+ timer:sleep(500),
Path = proplists:get_value(priv_dir, Config),
Name = filename:join(Path, "sometext.txt"),
Bin = txt(),
ok = file:write_file(Name, Bin),
{ok, Bin} = file:read_file(Name),
+ timer:sleep(500),
Res = lttng_stop_and_view(Config),
- ok = check_tracepoint("com_ericsson_otp:driver_start", Res),
- ok = check_tracepoint("com_ericsson_otp:driver_stop", Res),
- ok = check_tracepoint("com_ericsson_otp:driver_control", Res),
- ok = check_tracepoint("com_ericsson_otp:driver_outputv", Res),
- ok = check_tracepoint("com_ericsson_otp:driver_ready_async", Res),
+ ok = check_tracepoint("org_erlang_otp:driver_start", Res),
+ ok = check_tracepoint("org_erlang_otp:driver_stop", Res),
+ ok = check_tracepoint("org_erlang_otp:driver_control", Res),
+ ok = check_tracepoint("org_erlang_otp:driver_outputv", Res),
+ ok = check_tracepoint("org_erlang_otp:driver_ready_async", Res),
ok.
-%% com_ericsson_otp:driver_control
-%% com_ericsson_otp:driver_outputv
-%% com_ericsson_otp:driver_ready_async
+%% org_erlang_otp:driver_control
+%% org_erlang_otp:driver_outputv
+%% org_erlang_otp:driver_ready_async
t_driver_control_ready_async(Config) ->
- ok = lttng_start_event("com_ericsson_otp:driver_control", Config),
- ok = lttng_start_event("com_ericsson_otp:driver_outputv", Config),
- ok = lttng_start_event("com_ericsson_otp:driver_ready_async", Config),
+ ok = lttng_start_event("org_erlang_otp:driver_control", Config),
+ ok = lttng_start_event("org_erlang_otp:driver_outputv", Config),
+ ok = lttng_start_event("org_erlang_otp:driver_ready_async", Config),
Path = proplists:get_value(priv_dir, Config),
Name = filename:join(Path, "sometext.txt"),
Bin = txt(),
ok = file:write_file(Name, Bin),
{ok, Bin} = file:read_file(Name),
Res = lttng_stop_and_view(Config),
- ok = check_tracepoint("com_ericsson_otp:driver_control", Res),
- ok = check_tracepoint("com_ericsson_otp:driver_outputv", Res),
- ok = check_tracepoint("com_ericsson_otp:driver_ready_async", Res),
+ ok = check_tracepoint("org_erlang_otp:driver_control", Res),
+ ok = check_tracepoint("org_erlang_otp:driver_outputv", Res),
+ ok = check_tracepoint("org_erlang_otp:driver_ready_async", Res),
ok.
-%% com_ericsson_otp:driver_ready_input
-%% com_ericsson_otp:driver_ready_output
+%% org_erlang_otp:driver_ready_input
+%% org_erlang_otp:driver_ready_output
t_driver_ready_input_output(Config) ->
- ok = lttng_start_event("com_ericsson_otp:driver_ready_*", Config),
+ ok = lttng_start_event("org_erlang_otp:driver_ready_*", Config),
+ timer:sleep(500),
Me = self(),
Pid = spawn_link(fun() -> tcp_server(Me, active) end),
receive {Pid, accept} -> ok end,
@@ -225,16 +228,17 @@ t_driver_ready_input_output(Config) ->
ok = gen_tcp:close(Sock),
receive {Pid, done} -> ok end,
+ timer:sleep(500),
Res = lttng_stop_and_view(Config),
- ok = check_tracepoint("com_ericsson_otp:driver_ready_input", Res),
- ok = check_tracepoint("com_ericsson_otp:driver_ready_output", Res),
+ ok = check_tracepoint("org_erlang_otp:driver_ready_input", Res),
+ ok = check_tracepoint("org_erlang_otp:driver_ready_output", Res),
ok.
-%% com_ericsson_otp:driver_stop_select
-%% com_ericsson_otp:driver_timeout
+%% org_erlang_otp:driver_stop_select
+%% org_erlang_otp:driver_timeout
t_driver_timeout(Config) ->
- ok = lttng_start_event("com_ericsson_otp:driver_*", Config),
+ ok = lttng_start_event("org_erlang_otp:driver_*", Config),
Me = self(),
Pid = spawn_link(fun() -> tcp_server(Me, timeout) end),
receive {Pid, accept} -> ok end,
@@ -243,16 +247,16 @@ t_driver_timeout(Config) ->
receive {Pid, done} -> ok end,
ok = gen_tcp:close(Sock),
Res = lttng_stop_and_view(Config),
- ok = check_tracepoint("com_ericsson_otp:driver_timeout", Res),
- ok = check_tracepoint("com_ericsson_otp:driver_stop_select", Res),
+ ok = check_tracepoint("org_erlang_otp:driver_timeout", Res),
+ ok = check_tracepoint("org_erlang_otp:driver_stop_select", Res),
ok.
-%% com_ericsson_otp:driver_call
-%% com_ericsson_otp:driver_output
-%% com_ericsson_otp:driver_init
-%% com_ericsson_otp:driver_finish
+%% org_erlang_otp:driver_call
+%% org_erlang_otp:driver_output
+%% org_erlang_otp:driver_init
+%% org_erlang_otp:driver_finish
t_driver_caller(Config) ->
- ok = lttng_start_event("com_ericsson_otp:driver_*", Config),
+ ok = lttng_start_event("org_erlang_otp:driver_*", Config),
Drv = 'caller_drv',
os:putenv("CALLER_DRV_USE_OUTPUTV", "false"),
@@ -278,25 +282,25 @@ t_driver_caller(Config) ->
erl_ddll:unload_driver(Drv),
Res = lttng_stop_and_view(Config),
- ok = check_tracepoint("com_ericsson_otp:driver_call", Res),
- ok = check_tracepoint("com_ericsson_otp:driver_output", Res),
- ok = check_tracepoint("com_ericsson_otp:driver_init", Res),
- ok = check_tracepoint("com_ericsson_otp:driver_finish", Res),
+ ok = check_tracepoint("org_erlang_otp:driver_call", Res),
+ ok = check_tracepoint("org_erlang_otp:driver_output", Res),
+ ok = check_tracepoint("org_erlang_otp:driver_init", Res),
+ ok = check_tracepoint("org_erlang_otp:driver_finish", Res),
ok.
-%% com_ericsson_otp:scheduler_poll
+%% org_erlang_otp:scheduler_poll
t_scheduler_poll(Config) ->
- ok = lttng_start_event("com_ericsson_otp:scheduler_poll", Config),
+ ok = lttng_start_event("org_erlang_otp:scheduler_poll", Config),
ok = memory_load(),
Res = lttng_stop_and_view(Config),
- ok = check_tracepoint("com_ericsson_otp:scheduler_poll", Res),
+ ok = check_tracepoint("org_erlang_otp:scheduler_poll", Res),
ok.
-%% com_ericsson_otp:driver_flush
+%% org_erlang_otp:driver_flush
t_driver_flush(Config) ->
- ok = lttng_start_event("com_ericsson_otp:driver_flush", Config),
+ ok = lttng_start_event("org_erlang_otp:driver_flush", Config),
Me = self(),
Pid = spawn_link(fun() -> tcp_server(Me, passive_no_read) end),
@@ -320,7 +324,7 @@ t_driver_flush(Config) ->
receive {Pid, done} -> ok end,
Res = lttng_stop_and_view(Config),
- ok = check_tracepoint("com_ericsson_otp:driver_flush", Res),
+ ok = check_tracepoint("org_erlang_otp:driver_flush", Res),
ok.
%%
@@ -412,29 +416,29 @@ tcp_server(Pid, Type) ->
txt() ->
<<"%% tracepoints\n"
"%%\n"
- "%% com_ericsson_otp:carrier_pool_get\n"
- "%% com_ericsson_otp:carrier_pool_put\n"
- "%% com_ericsson_otp:carrier_destroy\n"
- "%% com_ericsson_otp:carrier_create\n"
- "%% com_ericsson_otp:aio_pool_put\n"
- "%% com_ericsson_otp:aio_pool_get\n"
- "%% com_ericsson_otp:driver_control\n"
- "%% com_ericsson_otp:driver_call\n"
- "%% com_ericsson_otp:driver_finish\n"
- "%% com_ericsson_otp:driver_ready_async\n"
- "%% com_ericsson_otp:driver_process_exit\n"
- "%% com_ericsson_otp:driver_stop\n"
- "%% com_ericsson_otp:driver_flush\n"
- "%% com_ericsson_otp:driver_stop_select\n"
- "%% com_ericsson_otp:driver_timeout\n"
- "%% com_ericsson_otp:driver_event\n"
- "%% com_ericsson_otp:driver_ready_output\n"
- "%% com_ericsson_otp:driver_ready_input\n"
- "%% com_ericsson_otp:driver_output\n"
- "%% com_ericsson_otp:driver_outputv\n"
- "%% com_ericsson_otp:driver_init\n"
- "%% com_ericsson_otp:driver_start\n"
- "%% com_ericsson_otp:scheduler_poll">>.
+ "%% org_erlang_otp:carrier_pool_get\n"
+ "%% org_erlang_otp:carrier_pool_put\n"
+ "%% org_erlang_otp:carrier_destroy\n"
+ "%% org_erlang_otp:carrier_create\n"
+ "%% org_erlang_otp:aio_pool_put\n"
+ "%% org_erlang_otp:aio_pool_get\n"
+ "%% org_erlang_otp:driver_control\n"
+ "%% org_erlang_otp:driver_call\n"
+ "%% org_erlang_otp:driver_finish\n"
+ "%% org_erlang_otp:driver_ready_async\n"
+ "%% org_erlang_otp:driver_process_exit\n"
+ "%% org_erlang_otp:driver_stop\n"
+ "%% org_erlang_otp:driver_flush\n"
+ "%% org_erlang_otp:driver_stop_select\n"
+ "%% org_erlang_otp:driver_timeout\n"
+ "%% org_erlang_otp:driver_event\n"
+ "%% org_erlang_otp:driver_ready_output\n"
+ "%% org_erlang_otp:driver_ready_input\n"
+ "%% org_erlang_otp:driver_output\n"
+ "%% org_erlang_otp:driver_outputv\n"
+ "%% org_erlang_otp:driver_init\n"
+ "%% org_erlang_otp:driver_start\n"
+ "%% org_erlang_otp:scheduler_poll">>.
load_driver(Dir, Driver) ->
case erl_ddll:load_driver(Dir, Driver) of
diff --git a/erts/emulator/test/process_SUITE.erl b/erts/emulator/test/process_SUITE.erl
index eaa4026a8a..4ebc1f5782 100644
--- a/erts/emulator/test/process_SUITE.erl
+++ b/erts/emulator/test/process_SUITE.erl
@@ -147,11 +147,7 @@ spawn_with_binaries(Config) when is_list(Config) ->
TwoMeg = lists:duplicate(1024, L),
Fun = fun() -> spawn(?MODULE, binary_owner, [list_to_binary(TwoMeg)]),
receive after 1 -> ok end end,
- Iter = case test_server:purify_is_running() of
- true -> 10;
- false -> 150
- end,
- test_server:do_times(Iter, Fun),
+ test_server:do_times(150, Fun),
ok.
binary_owner(Bin) when is_binary(Bin) ->
diff --git a/erts/etc/common/heart.c b/erts/etc/common/heart.c
index e931ae4641..a4008186c4 100644
--- a/erts/etc/common/heart.c
+++ b/erts/etc/common/heart.c
@@ -119,6 +119,8 @@
#define HEART_COMMAND_ENV "HEART_COMMAND"
#define ERL_CRASH_DUMP_SECONDS_ENV "ERL_CRASH_DUMP_SECONDS"
#define HEART_KILL_SIGNAL "HEART_KILL_SIGNAL"
+#define HEART_NO_KILL "HEART_NO_KILL"
+
#define MSG_HDR_SIZE (2)
#define MSG_HDR_PLUS_OP_SIZE (3)
@@ -524,6 +526,12 @@ static void
kill_old_erlang(void){
HANDLE erlh;
DWORD exit_code;
+ char* envvar = NULL;
+
+ envvar = get_env(HEART_NO_KILL);
+ if (!envvar || strcmp(envvar, "TRUE") == 0)
+ return;
+
if(heart_beat_kill_pid != 0){
if((erlh = OpenProcess(PROCESS_TERMINATE |
SYNCHRONIZE |
@@ -555,10 +563,14 @@ kill_old_erlang(void){
pid_t pid;
int i, res;
int sig = SIGKILL;
- char *sigenv = NULL;
+ char *envvar = NULL;
+
+ envvar = get_env(HEART_NO_KILL);
+ if (!envvar || strcmp(envvar, "TRUE") == 0)
+ return;
- sigenv = get_env(HEART_KILL_SIGNAL);
- if (sigenv && strcmp(sigenv, "SIGABRT") == 0) {
+ envvar = get_env(HEART_KILL_SIGNAL);
+ if (envvar && strcmp(envvar, "SIGABRT") == 0) {
print_error("kill signal SIGABRT requested");
sig = SIGABRT;
}
diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam
index 0521060e34..fdf8bbf4e2 100644
--- a/erts/preloaded/ebin/prim_inet.beam
+++ b/erts/preloaded/ebin/prim_inet.beam
Binary files differ
diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl
index 4872ffd00c..560810d222 100644
--- a/erts/preloaded/src/prim_inet.erl
+++ b/erts/preloaded/src/prim_inet.erl
@@ -70,11 +70,13 @@ open(Protocol, Family, Type) ->
open(Protocol, Family, Type, Opts) ->
open(Protocol, Family, Type, Opts, ?INET_REQ_OPEN, []).
+%% FDOPEN(tcp|udp|sctp, inet|inet6|local, stream|dgram|seqpacket, integer())
+
fdopen(Protocol, Family, Type, Fd) when is_integer(Fd) ->
fdopen(Protocol, Family, Type, Fd, true).
fdopen(Protocol, Family, Type, Fd, Bound)
- when is_integer(Fd), Bound == true orelse Bound == false ->
+ when is_integer(Fd), is_boolean(Bound) ->
open(Protocol, Family, Type, [], ?INET_REQ_FDOPEN,
[?int32(Fd), enc_value_2(bool, Bound)]).
@@ -104,8 +106,9 @@ open(Protocol, Family, Type, Opts, Req, Data) ->
error:system_limit -> {error, system_limit}
end.
-enc_family(inet) -> ?INET_AF_INET;
-enc_family(inet6) -> ?INET_AF_INET6.
+enc_family(inet) -> ?INET_AF_INET;
+enc_family(inet6) -> ?INET_AF_INET6;
+enc_family(local) -> ?INET_AF_LOCAL.
enc_type(stream) -> ?INET_TYPE_STREAM;
enc_type(dgram) -> ?INET_TYPE_DGRAM;
@@ -189,41 +192,52 @@ close_port(S) ->
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-bind(S,IP,Port) when is_port(S), is_integer(Port), Port >= 0, Port =< 65535 ->
- case ctl_cmd(S,?INET_REQ_BIND,enc_value(set, addr, {IP,Port})) of
- {ok, [P1,P0]} -> {ok, ?u16(P1, P0)};
- {error,_}=Error -> Error
- end;
-
%% Multi-homed "bind": sctp_bindx(). The Op is 'add' or 'remove'.
%% If no addrs are specified, it just does nothing.
%% Function returns {ok, S} on success, unlike TCP/UDP "bind":
-bind(S, Op, Addrs) when is_port(S), is_list(Addrs) ->
- case Op of
- add ->
- bindx(S, 1, Addrs);
- remove ->
- bindx(S, 0, Addrs);
- _ -> {error, einval}
+bind(S, add, Addrs) when is_port(S), is_list(Addrs) ->
+ bindx(S, 1, Addrs);
+bind(S, remove, Addrs) when is_port(S), is_list(Addrs) ->
+ bindx(S, 0, Addrs);
+bind(S, Addr, _) when is_port(S), tuple_size(Addr) =:= 2 ->
+ case type_value(set, addr, Addr) of
+ true ->
+ case ctl_cmd(S,?INET_REQ_BIND,enc_value(set, addr, Addr)) of
+ {ok, [P1,P0]} -> {ok, ?u16(P1, P0)};
+ {error, _} = Error -> Error
+ end;
+ false ->
+ {error, einval}
end;
-bind(_, _, _) -> {error, einval}.
+bind(S, IP, Port) ->
+ bind(S, {IP, Port}, 0).
bindx(S, AddFlag, Addrs) ->
case getprotocol(S) of
sctp ->
- %% Really multi-homed "bindx". Stringified args:
- %% [AddFlag, (AddrBytes see enc_value_2(addr,X))+]:
- Args =
- [?int8(AddFlag)|
- [enc_value(set, addr, {IP,Port}) ||
- {IP, Port} <- Addrs]],
- case ctl_cmd(S, ?SCTP_REQ_BINDX, Args) of
- {ok,_} -> {ok, S};
- {error,_}=Error -> Error
+ case bindx_check_addrs(Addrs) of
+ true ->
+ %% Really multi-homed "bindx". Stringified args:
+ %% [AddFlag, (AddrBytes see enc_value_2(addr,X))+]:
+ Args =
+ [?int8(AddFlag)|
+ [enc_value(set, addr, Addr) || Addr <- Addrs]],
+ case ctl_cmd(S, ?SCTP_REQ_BINDX, Args) of
+ {ok, _} -> {ok, S};
+ {error, _}=Error -> Error
+ end;
+ false ->
+ {error, einval}
end;
- _ -> {error, einval}
+ _ ->
+ {error, einval}
end.
+bindx_check_addrs([Addr|Addrs]) ->
+ type_value(set, addr, Addr) andalso bindx_check_addrs(Addrs);
+bindx_check_addrs([]) ->
+ true.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% CONNECT(insock(), IP, Port [,Timeout]) -> ok | {error, Reason}
@@ -242,14 +256,24 @@ bindx(S, AddFlag, Addrs) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% For TCP, UDP or SCTP sockets.
%%
-connect(S, IP, Port) -> connect0(S, IP, Port, -1).
-connect(S, IP, Port, infinity) -> connect0(S, IP, Port, -1);
-connect(S, IP, Port, Time) -> connect0(S, IP, Port, Time).
+connect(S, IP, Port) ->
+ connect(S, IP, Port, infinity).
+%%
+connect(S, Addr, _, Time) when is_port(S), tuple_size(Addr) =:= 2 ->
+ case type_value(set, addr, Addr) of
+ true when Time =:= infinity ->
+ connect0(S, Addr, -1);
+ true when is_integer(Time) ->
+ connect0(S, Addr, Time);
+ false ->
+ {error, einval}
+ end;
+connect(S, IP, Port, Time) ->
+ connect(S, {IP, Port}, 0, Time).
-connect0(S, IP, Port, Time) when is_port(S), Port > 0, Port =< 65535,
- is_integer(Time) ->
- case async_connect(S, IP, Port, Time) of
+connect0(S, Addr, Time) ->
+ case async_connect0(S, Addr, Time) of
{ok, S, Ref} ->
receive
{inet_async, S, Ref, Status} ->
@@ -258,11 +282,27 @@ connect0(S, IP, Port, Time) when is_port(S), Port > 0, Port =< 65535,
Error -> Error
end.
+
+async_connect(S, Addr, _, Time) when is_port(S), tuple_size(Addr) =:= 2 ->
+ case type_value(set, addr, Addr) of
+ true when Time =:= infinity ->
+ async_connect0(S, Addr, -1);
+ true when is_integer(Time) ->
+ async_connect0(S, Addr, Time);
+ false ->
+ {error, einval}
+ end;
+%%
async_connect(S, IP, Port, Time) ->
- case ctl_cmd(S, ?INET_REQ_CONNECT,
- [enc_time(Time),?int16(Port),ip_to_bytes(IP)]) of
+ async_connect(S, {IP, Port}, 0, Time).
+
+async_connect0(S, Addr, Time) ->
+ case ctl_cmd(
+ S, ?INET_REQ_CONNECT,
+ [enc_time(Time),enc_value(set, addr, Addr)])
+ of
{ok, [R1,R0]} -> {ok, S, ?u16(R1,R0)};
- {error,_}=Error -> Error
+ {error, _}=Error -> Error
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -400,20 +440,34 @@ send(S, Data) ->
%% "sendto" is for UDP. IP and Port are set by the caller to 0 if the socket
%% is known to be connected.
-sendto(S, IP, Port, Data) when is_port(S), Port >= 0, Port =< 65535 ->
- ?DBG_FORMAT("prim_inet:sendto(~p, ~p, ~p, ~p)~n", [S,IP,Port,Data]),
- try erlang:port_command(S, [?int16(Port),ip_to_bytes(IP),Data]) of
- true ->
- receive
- {inet_reply,S,Reply} ->
- ?DBG_FORMAT("prim_inet:sendto() -> ~p~n", [Reply]),
- Reply
- end
- catch
- error:_ ->
- ?DBG_FORMAT("prim_inet:sendto() -> {error,einval}~n", []),
- {error,einval}
- end.
+sendto(S, Addr, _, Data) when is_port(S), tuple_size(Addr) =:= 2 ->
+ case type_value(set, addr, Addr) of
+ true ->
+ ?DBG_FORMAT("prim_inet:sendto(~p, ~p, ~p)~n", [S,Addr,Data]),
+ try
+ erlang:port_command(S, [enc_value(set, addr, Addr),Data])
+ of
+ true ->
+ receive
+ {inet_reply,S,Reply} ->
+ ?DBG_FORMAT(
+ "prim_inet:sendto() -> ~p~n", [Reply]),
+ Reply
+ end
+ catch
+ error:_ ->
+ ?DBG_FORMAT(
+ "prim_inet:sendto() -> {error,einval}~n", []),
+ {error,einval}
+ end;
+ false ->
+ ?DBG_FORMAT(
+ "prim_inet:sendto() -> {error,einval}~n", []),
+ {error,einval}
+ end;
+sendto(S, IP, Port, Data) ->
+ sendto(S, {IP, Port}, 0, Data).
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
@@ -484,29 +538,37 @@ async_recv(S, Length, Time) ->
%% oriented: preserved here only for API compatibility.
%%
recvfrom(S, Length) ->
- recvfrom0(S, Length, -1).
+ recvfrom(S, Length, infinity).
-recvfrom(S, Length, infinity) ->
+recvfrom(S, Length, infinity) when is_port(S) ->
recvfrom0(S, Length, -1);
-recvfrom(S, Length, Time) when is_integer(Time), Time < 16#ffffffff ->
- recvfrom0(S, Length, Time);
-recvfrom(_, _, _) -> {error,einval}.
+recvfrom(S, Length, Time) when is_port(S) ->
+ if
+ is_integer(Time), 0 =< Time, Time < 16#ffffffff ->
+ recvfrom0(S, Length, Time);
+ true ->
+ {error, einval}
+ end.
recvfrom0(S, Length, Time)
- when is_port(S), is_integer(Length), Length >= 0, Length =< 16#ffffffff ->
+ when is_integer(Length), 0 =< Length, Length =< 16#ffffffff ->
case ctl_cmd(S, ?PACKET_REQ_RECV,[enc_time(Time),?int32(Length)]) of
{ok,[R1,R0]} ->
Ref = ?u16(R1,R0),
receive
% Success, UDP:
- {inet_async, S, Ref, {ok, [F,P1,P0 | AddrData]}} ->
- {IP,Data} = get_ip(F, AddrData),
- {ok, {IP, ?u16(P1,P0), Data}};
+ {inet_async, S, Ref, {ok, [F | AddrData]}} ->
+ case get_addr(F, AddrData) of
+ {{Family, _} = Addr, Data} when is_atom(Family) ->
+ {ok, {Addr, 0, Data}};
+ {{IP, Port}, Data} ->
+ {ok, {IP, Port, Data}}
+ end;
% Success, SCTP:
{inet_async, S, Ref, {ok, {[F,P1,P0 | Addr], AncData, DE}}} ->
- {IP, _} = get_ip(F, Addr),
- {ok, {IP, ?u16(P1,P0), AncData, DE}};
+ {IP, _} = get_ip(F, Addr),
+ {ok, {IP, ?u16(P1, P0), AncData, DE}};
% Back-end error:
{inet_async, S, Ref, Error={error, _}} ->
@@ -525,21 +587,26 @@ recvfrom0(_, _, _) -> {error,einval}.
peername(S) when is_port(S) ->
case ctl_cmd(S, ?INET_REQ_PEER, []) of
- {ok, [F, P1,P0 | Addr]} ->
- {IP, _} = get_ip(F, Addr),
- {ok, { IP, ?u16(P1, P0) }};
- {error,_}=Error -> Error
+ {ok, [F | Addr]} ->
+ {A, _} = get_addr(F, Addr),
+ {ok, A};
+ {error, _} = Error -> Error
end.
-setpeername(S, {IP,Port}) when is_port(S) ->
- case ctl_cmd(S, ?INET_REQ_SETPEER, [?int16(Port),ip_to_bytes(IP)]) of
- {ok,[]} -> ok;
- {error,_}=Error -> Error
- end;
setpeername(S, undefined) when is_port(S) ->
case ctl_cmd(S, ?INET_REQ_SETPEER, []) of
- {ok,[]} -> ok;
- {error,_}=Error -> Error
+ {ok, []} -> ok;
+ {error, _} = Error -> Error
+ end;
+setpeername(S, Addr) when is_port(S) ->
+ case type_value(set, addr, Addr) of
+ true ->
+ case ctl_cmd(S, ?INET_REQ_SETPEER, enc_value(set, addr, Addr)) of
+ {ok, []} -> ok;
+ {error, _} = Error -> Error
+ end;
+ false ->
+ {error, einval}
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -580,21 +647,28 @@ peernames(S, AssocId)
sockname(S) when is_port(S) ->
case ctl_cmd(S, ?INET_REQ_NAME, []) of
- {ok, [F, P1, P0 | Addr]} ->
- {IP, _} = get_ip(F, Addr),
- {ok, { IP, ?u16(P1, P0) }};
- {error,_}=Error -> Error
+ {ok, [F | Addr]} ->
+ {A, _} = get_addr(F, Addr),
+ {ok, A};
+ {error, _} = Error -> Error
end.
-setsockname(S, {IP,Port}) when is_port(S) ->
- case ctl_cmd(S, ?INET_REQ_SETNAME, [?int16(Port),ip_to_bytes(IP)]) of
- {ok,[]} -> ok;
- {error,_}=Error -> Error
- end;
setsockname(S, undefined) when is_port(S) ->
case ctl_cmd(S, ?INET_REQ_SETNAME, []) of
- {ok,[]} -> ok;
- {error,_}=Error -> Error
+ {ok, []} -> ok;
+ {error, _} = Error -> Error
+ end;
+setsockname(S, Addr) when is_port(S) ->
+ case type_value(set, addr, Addr) of
+ true ->
+ case
+ ctl_cmd(S, ?INET_REQ_SETNAME, enc_value(set, addr, Addr))
+ of
+ {ok, []} -> ok;
+ {error, _} = Error -> Error
+ end;
+ false ->
+ {error, einval}
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1496,14 +1570,49 @@ type_value_2(uint8, X) when X band 16#ff =:= X -> true;
type_value_2(time, infinity) -> true;
type_value_2(time, X) when is_integer(X), X >= 0 -> true;
type_value_2(ip,{A,B,C,D}) when ?ip(A,B,C,D) -> true;
+%%
type_value_2(addr, {any,Port}) ->
type_value_2(uint16, Port);
type_value_2(addr, {loopback,Port}) ->
type_value_2(uint16, Port);
-type_value_2(addr, {{A,B,C,D},Port}) when ?ip(A,B,C,D) ->
+type_value_2(addr, {IP,_} = Addr) when tuple_size(IP) =:= 4 ->
+ type_value_2(addr, {inet,Addr});
+type_value_2(addr, {IP,_} = Addr) when tuple_size(IP) =:= 8 ->
+ type_value_2(addr, {inet6,Addr});
+type_value_2(addr, {Local,_}) when is_list(Local); is_binary(Local) ->
+ type_value_2(addr, {local,Local});
+%%
+type_value_2(addr, {Family,{Tag,Port}})
+ when (Family =:= inet orelse Family =:= inet6) andalso
+ (Tag =:= any orelse Tag =:= loopback) ->
+ type_value_2(uint16, Port);
+type_value_2(addr, {inet,{{A,B,C,D},Port}})
+ when ?ip(A,B,C,D) ->
type_value_2(uint16, Port);
-type_value_2(addr, {{A,B,C,D,E,F,G,H},Port}) when ?ip6(A,B,C,D,E,F,G,H) ->
+type_value_2(addr, {inet6,{{A,B,C,D,E,F,G,H},Port}})
+ when ?ip6(A,B,C,D,E,F,G,H) ->
type_value_2(uint16, Port);
+type_value_2(addr, {local,Addr}) ->
+ if
+ is_binary(Addr) ->
+ byte_size(Addr) =< 255;
+ true ->
+ try
+ %% We either get a badarg from byte_size
+ %% or from characters_to_binary
+ byte_size(
+ unicode:characters_to_binary(
+ Addr, file:native_name_encoding()))
+ of
+ N when N =< 255 ->
+ true;
+ _ ->
+ false
+ catch error:badarg ->
+ false
+ end
+ end;
+%%
type_value_2(ether,[X1,X2,X3,X4,X5,X6])
when ?ether(X1,X2,X3,X4,X5,X6) -> true;
type_value_2({enum,List}, Enum) ->
@@ -1611,6 +1720,7 @@ enc_value_2(time, Val) -> ?int32(Val);
enc_value_2(ip,{A,B,C,D}) -> [A,B,C,D];
enc_value_2(ip, any) -> [0,0,0,0];
enc_value_2(ip, loopback) -> [127,0,0,1];
+%%
enc_value_2(addr, {any,Port}) ->
[?INET_AF_ANY|?int16(Port)];
enc_value_2(addr, {loopback,Port}) ->
@@ -1619,6 +1729,35 @@ enc_value_2(addr, {IP,Port}) when tuple_size(IP) =:= 4 ->
[?INET_AF_INET,?int16(Port)|ip4_to_bytes(IP)];
enc_value_2(addr, {IP,Port}) when tuple_size(IP) =:= 8 ->
[?INET_AF_INET6,?int16(Port)|ip6_to_bytes(IP)];
+enc_value_2(addr, {File,_}) when is_list(File); is_binary(File) ->
+ [?INET_AF_LOCAL,iolist_size(File)|File];
+%%
+enc_value_2(addr, {inet,{any,Port}}) ->
+ [?INET_AF_INET,?int16(Port),0,0,0,0];
+enc_value_2(addr, {inet,{loopback,Port}}) ->
+ [?INET_AF_INET,?int16(Port),127,0,0,1];
+enc_value_2(addr, {inet,{IP,Port}}) ->
+ [?INET_AF_INET,?int16(Port)|ip4_to_bytes(IP)];
+enc_value_2(addr, {inet6,{any,Port}}) ->
+ [?INET_AF_INET6,?int16(Port),0,0,0,0,0,0,0,0];
+enc_value_2(addr, {inet6,{loopback,Port}}) ->
+ [?INET_AF_INET6,?int16(Port),0,0,0,0,0,0,0,1];
+enc_value_2(addr, {inet6,{IP,Port}}) ->
+ [?INET_AF_INET6,?int16(Port)|ip6_to_bytes(IP)];
+enc_value_2(addr, {local,Addr}) ->
+ %% A binary is passed as is, but anything else will be
+ %% regarded as a filename and therefore encoded according to
+ %% the current system filename encoding mode.
+ Bin =
+ if
+ is_binary(Addr) ->
+ Addr;
+ true ->
+ unicode:characters_to_binary(
+ Addr, file:native_name_encoding())
+ end,
+ [?INET_AF_LOCAL,byte_size(Bin),Bin];
+%%
enc_value_2(ether, [_,_,_,_,_,_]=Xs) -> Xs;
enc_value_2(sockaddr, any) ->
[?INET_AF_ANY];
@@ -2249,9 +2388,6 @@ utf8_to_characters(Bs, U, 0) ->
utf8_to_characters([B|Bs], U, N) when ((B band 16#3F) bor 16#80) =:= B ->
utf8_to_characters(Bs, (U bsl 6) bor (B band 16#3F), N-1).
-ip_to_bytes(IP) when tuple_size(IP) =:= 4 -> ip4_to_bytes(IP);
-ip_to_bytes(IP) when tuple_size(IP) =:= 8 -> ip6_to_bytes(IP).
-
ip4_to_bytes({A,B,C,D}) ->
[A band 16#ff, B band 16#ff, C band 16#ff, D band 16#ff].
@@ -2261,18 +2397,32 @@ ip6_to_bytes({A,B,C,D,E,F,G,H}) ->
get_addrs([]) ->
[];
-get_addrs([F,P1,P0|Addr]) ->
- {IP,Addrs} = get_ip(F, Addr),
- [{IP,?u16(P1, P0)}|get_addrs(Addrs)].
-
-get_ip(?INET_AF_INET, Addr) -> get_ip4(Addr);
-get_ip(?INET_AF_INET6, Addr) -> get_ip6(Addr).
+get_addrs([F|Addrs]) ->
+ {Addr,Rest} = get_addr(F, Addrs),
+ [Addr|get_addrs(Rest)].
+
+get_addr(?INET_AF_LOCAL, [0]) ->
+ {{local,<<>>},[]};
+get_addr(?INET_AF_LOCAL, [N|Addr]) ->
+ {A,Rest} = lists:split(N, Addr),
+ {{local,iolist_to_binary(A)},Rest};
+get_addr(?INET_AF_UNDEFINED, Rest) ->
+ {{undefined,0},Rest};
+get_addr(Family, [P1,P0|Addr]) ->
+ {IP,Rest} = get_ip(Family, Addr),
+ {{IP,?u16(P1, P0)},Rest}.
+
+get_ip(?INET_AF_INET, Addr) ->
+ get_ip4(Addr);
+get_ip(?INET_AF_INET6, Addr) ->
+ get_ip6(Addr).
get_ip4([A,B,C,D | T]) -> {{A,B,C,D},T}.
get_ip6([X1,X2,X3,X4,X5,X6,X7,X8,X9,X10,X11,X12,X13,X14,X15,X16 | T]) ->
{ { ?u16(X1,X2),?u16(X3,X4),?u16(X5,X6),?u16(X7,X8),
- ?u16(X9,X10),?u16(X11,X12),?u16(X13,X14),?u16(X15,X16)}, T}.
+ ?u16(X9,X10),?u16(X11,X12),?u16(X13,X14),?u16(X15,X16)},
+ T }.
%% Control command
diff --git a/lib/common_test/src/ct.erl b/lib/common_test/src/ct.erl
index cae7bea406..d7ae81a5ce 100644
--- a/lib/common_test/src/ct.erl
+++ b/lib/common_test/src/ct.erl
@@ -282,7 +282,7 @@ step(TestDir,Suite,Case,Opts) ->
%%% <c>&gt; ct_telnet:cmd(unix_telnet, "ls .").</c><br/>
%%% <c>{ok,["ls","file1 ...",...]}</c></p>
start_interactive() ->
- ct_util:start(interactive),
+ _ = ct_util:start(interactive),
ok.
%%%-----------------------------------------------------------------
diff --git a/lib/common_test/src/ct_config.erl b/lib/common_test/src/ct_config.erl
index b499bc8b05..99de311570 100644
--- a/lib/common_test/src/ct_config.erl
+++ b/lib/common_test/src/ct_config.erl
@@ -119,7 +119,8 @@ call(Msg) ->
end.
return({To,Ref},Result) ->
- To ! {Ref, Result}.
+ To ! {Ref, Result},
+ ok.
loop(StartDir) ->
receive
@@ -128,11 +129,11 @@ loop(StartDir) ->
return(From,Result),
loop(StartDir);
{{set_default_config,{Config,Scope}},From} ->
- set_config(Config,{true,Scope}),
+ _ = set_config(Config,{true,Scope}),
return(From,ok),
loop(StartDir);
{{set_default_config,{Name,Config,Scope}},From} ->
- set_config(Name,Config,{true,Scope}),
+ _ = set_config(Name,Config,{true,Scope}),
return(From,ok),
loop(StartDir);
{{delete_default_config,Scope},From} ->
@@ -149,7 +150,7 @@ loop(StartDir) ->
loop(StartDir);
{{stop},From} ->
ets:delete(?attr_table),
- file:set_cwd(StartDir),
+ ok = file:set_cwd(StartDir),
return(From,ok)
end.
@@ -257,7 +258,7 @@ read_config_files(Opts) ->
read_config_files_int([{Callback, File}|Files], FunToSave) ->
case Callback:read_config(File) of
{ok, Config} ->
- FunToSave(Config, Callback, File),
+ _ = FunToSave(Config, Callback, File),
read_config_files_int(Files, FunToSave);
{error, {ErrorName, ErrorDetail}} ->
{user_error, {ErrorName, File, ErrorDetail}};
@@ -267,6 +268,15 @@ read_config_files_int([{Callback, File}|Files], FunToSave) ->
read_config_files_int([], _FunToSave) ->
ok.
+
+read_config_files(ConfigFiles, FunToSave) ->
+ case read_config_files_int(ConfigFiles, FunToSave) of
+ {user_error, Error} ->
+ {error, Error};
+ ok ->
+ ok
+ end.
+
store_config(Config, Callback, File) when is_tuple(Config) ->
store_config([Config], Callback, File);
@@ -455,8 +465,12 @@ reload_conf(KeyOrName) ->
undefined;
HandlerList ->
HandlerList2 = lists:usort(HandlerList),
- read_config_files_int(HandlerList2, fun rewrite_config/3),
- get_config(KeyOrName)
+ case read_config_files(HandlerList2, fun rewrite_config/3) of
+ ok ->
+ get_config(KeyOrName);
+ Error ->
+ Error
+ end
end.
release_allocated() ->
@@ -490,16 +504,16 @@ associate(Name,_Key,Configs) ->
associate_int(Name,Configs,os:getenv("COMMON_TEST_ALIAS_TOP")).
associate_int(Name,Configs,"true") ->
- lists:map(fun({K,_Config}) ->
+ lists:foreach(fun({K,_Config}) ->
Cs = ets:match_object(
?attr_table,
#ct_conf{key=element(1,K),
name='_UNDEF',_='_'}),
[ets:insert(?attr_table,C#ct_conf{name=Name})
|| C <- Cs]
- end,Configs);
+ end,Configs);
associate_int(Name,Configs,_) ->
- lists:map(fun({K,Config}) ->
+ lists:foreach(fun({K,Config}) ->
Key = if is_tuple(K) -> element(1,K);
is_atom(K) -> K
end,
@@ -511,7 +525,7 @@ associate_int(Name,Configs,_) ->
[ets:insert(?attr_table,C#ct_conf{name=Name,
value=Config})
|| C <- Cs]
- end,Configs).
+ end,Configs).
@@ -576,7 +590,7 @@ encrypt_config_file(SrcFileName, EncryptFileName, {file,KeyFile}) ->
end;
encrypt_config_file(SrcFileName, EncryptFileName, {key,Key}) ->
- crypto:start(),
+ _ = crypto:start(),
{Key,IVec} = make_crypto_key(Key),
case file:read_file(SrcFileName) of
{ok,Bin0} ->
@@ -615,7 +629,7 @@ decrypt_config_file(EncryptFileName, TargetFileName, {file,KeyFile}) ->
end;
decrypt_config_file(EncryptFileName, TargetFileName, {key,Key}) ->
- crypto:start(),
+ _ = crypto:start(),
{Key,IVec} = make_crypto_key(Key),
case file:read_file(EncryptFileName) of
{ok,Bin} ->
@@ -778,14 +792,13 @@ prepare_config_list(Args) ->
% TODO: add logging of the loaded configuration file to the CT FW log!!!
add_config(Callback, []) ->
- read_config_files_int([{Callback, []}], fun store_config/3);
+ read_config_files([{Callback, []}], fun store_config/3);
add_config(Callback, [File|_Files]=Config) when is_list(File) ->
lists:foreach(fun(CfgStr) ->
- read_config_files_int([{Callback, CfgStr}], fun store_config/3) end,
+ read_config_files([{Callback, CfgStr}], fun store_config/3) end,
Config);
add_config(Callback, [C|_]=Config) when is_integer(C) ->
- read_config_files_int([{Callback, Config}], fun store_config/3),
- ok.
+ read_config_files([{Callback, Config}], fun store_config/3).
remove_config(Callback, Config) ->
ets:match_delete(?attr_table,
diff --git a/lib/common_test/src/ct_framework.erl b/lib/common_test/src/ct_framework.erl
index eb32f7f3fc..104515e57e 100644
--- a/lib/common_test/src/ct_framework.erl
+++ b/lib/common_test/src/ct_framework.erl
@@ -128,7 +128,7 @@ init_tc1(?MODULE,_,error_in_suite,_,[Config0]) when is_list(Config0) ->
ct_event:notify(#event{name=tc_start,
node=node(),
data={?MODULE,error_in_suite}}),
- ct_suite_init(?MODULE,error_in_suite,[],Config0),
+ _ = ct_suite_init(?MODULE,error_in_suite,[],Config0),
case ?val(error,Config0) of
undefined ->
{fail,"unknown_error_in_suite"};
@@ -212,7 +212,7 @@ init_tc2(Mod,Suite,Func,HookFunc,SuiteInfo,MergeResult,Config) ->
%% timetrap must be handled before require
MergedInfo = timetrap_first(MergeResult, [], []),
%% tell logger to use specified style sheet
- case lists:keysearch(stylesheet,1,MergeResult++Config) of
+ _ = case lists:keysearch(stylesheet,1,MergeResult++Config) of
{value,{stylesheet,SSFile}} ->
ct_logs:set_stylesheet(Func,add_data_dir(SSFile,Config));
_ ->
@@ -632,10 +632,10 @@ try_set_default(Name,Key,Info,Where) ->
{_,[]} ->
no_default;
{'_UNDEF',_} ->
- [ct_config:set_default_config([CfgVal],Where) || CfgVal <- CfgElems],
+ _ = [ct_config:set_default_config([CfgVal],Where) || CfgVal <- CfgElems],
ok;
_ ->
- [ct_config:set_default_config(Name,[CfgVal],Where) || CfgVal <- CfgElems],
+ _ = [ct_config:set_default_config(Name,[CfgVal],Where) || CfgVal <- CfgElems],
ok
end.
@@ -1315,7 +1315,7 @@ report(What,Data) ->
%% top level test index page needs to be refreshed
TestName = filename:basename(?val(topdir, Data), ".logs"),
RunDir = ?val(rundir, Data),
- ct_logs:make_all_suites_index({TestName,RunDir}),
+ _ = ct_logs:make_all_suites_index({TestName,RunDir}),
ok;
tests_start ->
ok;
diff --git a/lib/common_test/src/ct_ftp.erl b/lib/common_test/src/ct_ftp.erl
index 48914864e4..84e664b387 100644
--- a/lib/common_test/src/ct_ftp.erl
+++ b/lib/common_test/src/ct_ftp.erl
@@ -292,7 +292,7 @@ init(KeyOrName,{IP,Port},{Username,Password}) ->
end.
ftp_connect(IP,Port,Username,Password) ->
- inets:start(),
+ _ = inets:start(),
case inets:start(ftpc,[{host,IP},{port,Port}]) of
{ok,FtpPid} ->
case ftp:user(FtpPid,Username,Password) of
diff --git a/lib/common_test/src/ct_groups.erl b/lib/common_test/src/ct_groups.erl
index dd04c5410a..1375e7dcc7 100644
--- a/lib/common_test/src/ct_groups.erl
+++ b/lib/common_test/src/ct_groups.erl
@@ -402,12 +402,7 @@ expand(Mod, Name, Defs) ->
end.
make_all_conf(Dir, Mod, Props, TestSpec) ->
- case code:is_loaded(Mod) of
- false ->
- code:load_abs(filename:join(Dir,atom_to_list(Mod)));
- _ ->
- ok
- end,
+ _ = load_abs(Dir, Mod),
make_all_conf(Mod, Props, TestSpec).
make_all_conf(Mod, Props, TestSpec) ->
@@ -428,16 +423,19 @@ make_all_conf(Mod, Props, TestSpec) ->
end.
make_conf(Dir, Mod, Name, Props, TestSpec) ->
+ _ = load_abs(Dir, Mod),
+ make_conf(Mod, Name, Props, TestSpec).
+
+load_abs(Dir, Mod) ->
case code:is_loaded(Mod) of
false ->
code:load_abs(filename:join(Dir,atom_to_list(Mod)));
_ ->
ok
- end,
- make_conf(Mod, Name, Props, TestSpec).
+ end.
make_conf(Mod, Name, Props, TestSpec) ->
- case code:is_loaded(Mod) of
+ _ = case code:is_loaded(Mod) of
false ->
code:load_file(Mod);
_ ->
diff --git a/lib/common_test/src/ct_hooks.erl b/lib/common_test/src/ct_hooks.erl
index 5422d449fd..c9a4abb5ee 100644
--- a/lib/common_test/src/ct_hooks.erl
+++ b/lib/common_test/src/ct_hooks.erl
@@ -408,7 +408,8 @@ catch_apply(M,F,A, Default) ->
maybe_start_locker(Mod,GroupName,Opts) ->
case lists:member(parallel,Opts) of
true ->
- {ok, _Pid} = ct_hooks_lock:start({Mod,GroupName});
+ {ok, _Pid} = ct_hooks_lock:start({Mod,GroupName}),
+ ok;
false ->
ok
end.
diff --git a/lib/common_test/src/ct_hooks_lock.erl b/lib/common_test/src/ct_hooks_lock.erl
index f41f259f7b..fea298e535 100644
--- a/lib/common_test/src/ct_hooks_lock.erl
+++ b/lib/common_test/src/ct_hooks_lock.erl
@@ -82,7 +82,7 @@ init(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],
+ _ = [gen_server:reply(Req, locker_stopped) || {Req,_ReqId} <- Reqs],
{stop, normal, stopped, State};
handle_call({stop,_Id}, _From, State) ->
{reply, stopped, State};
diff --git a/lib/common_test/src/ct_logs.erl b/lib/common_test/src/ct_logs.erl
index e6d683c8a9..455864efb6 100644
--- a/lib/common_test/src/ct_logs.erl
+++ b/lib/common_test/src/ct_logs.erl
@@ -149,7 +149,7 @@ close(Info, StartDir) ->
ok;
CacheBin ->
%% save final version of the log cache to file
- file:write_file(?log_cache_name,CacheBin),
+ _ = file:write_file(?log_cache_name,CacheBin),
put(ct_log_cache,undefined)
end
end,
@@ -175,12 +175,12 @@ close(Info, StartDir) ->
Error ->
io:format("Warning! Cleanup failed: ~p~n", [Error])
end,
- make_all_suites_index(stop),
+ _ = make_all_suites_index(stop),
make_all_runs_index(stop),
Cache2File();
true ->
- file:set_cwd(".."),
- make_all_suites_index(stop),
+ ok = file:set_cwd(".."),
+ _ = make_all_suites_index(stop),
make_all_runs_index(stop),
Cache2File(),
case ct_util:get_profile_data(browser, StartDir) of
@@ -251,16 +251,30 @@ call(Msg) ->
end.
return({To,Ref},Result) ->
- To ! {Ref, Result}.
+ To ! {Ref, Result},
+ ok.
cast(Msg) ->
case whereis(?MODULE) of
undefined ->
- {error,does_not_exist};
+ io:format("Warning: ct_logs not started~n"),
+ {_,_,_,_,_,_,Content,_} = Msg,
+ FormatArgs = get_format_args(Content),
+ _ = [io:format(Format, Args) || {Format, Args} <- FormatArgs],
+ ok;
_Pid ->
- ?MODULE ! Msg
+ ?MODULE ! Msg,
+ ok
end.
+get_format_args(Content) ->
+ lists:map(fun(C) ->
+ case C of
+ {_, FA, _} -> FA;
+ {_, _} -> C
+ end
+ end, Content).
+
%%%-----------------------------------------------------------------
%%% @spec init_tc(RefreshLog) -> ok
%%%
@@ -631,7 +645,7 @@ logger(Parent, Mode, Verbosity) ->
end,
%%! <---
- file:make_dir(Dir),
+ _ = file:make_dir(Dir),
AbsDir = ?abs(Dir),
put(ct_run_dir, AbsDir),
@@ -671,7 +685,7 @@ logger(Parent, Mode, Verbosity) ->
end
end,
- test_server_io:start_link(),
+ _ = test_server_io:start_link(),
MiscIoName = filename:join(Dir, ?misc_io_log),
{ok,MiscIoFd} = file:open(MiscIoName,
[write,{encoding,utf8}]),
@@ -701,13 +715,13 @@ logger(Parent, Mode, Verbosity) ->
ct_event:notify(#event{name=start_logging,node=node(),
data=AbsDir}),
make_all_runs_index(start),
- make_all_suites_index(start),
+ _ = make_all_suites_index(start),
case Mode of
interactive -> interactive_link();
_ -> ok
end,
- file:set_cwd(Dir),
- make_last_run_index(Time),
+ ok = file:set_cwd(Dir),
+ _ = make_last_run_index(Time),
CtLogFd = open_ctlog(?misc_io_log),
io:format(CtLogFd,int_header()++int_footer(),
[log_timestamp(?now),"Common Test Logger started"]),
@@ -721,13 +735,13 @@ logger(Parent, Mode, Verbosity) ->
GenLvl -> io:format(CtLogFd, "~-25s~3w~n",
["general level",GenLvl])
end,
- [begin put({verbosity,Cat},VLvl),
- if Cat == '$unspecified' ->
+ _ = [begin put({verbosity,Cat},VLvl),
+ if Cat == '$unspecified' ->
ok;
- true ->
+ true ->
io:format(CtLogFd, "~-25w~3w~n", [Cat,VLvl])
- end
- end || {Cat,VLvl} <- Verbosity],
+ end
+ end || {Cat,VLvl} <- Verbosity],
io:nl(CtLogFd),
TcEscChars = case application:get_env(common_test, esc_chars) of
{ok,ECBool} -> ECBool;
@@ -804,7 +818,7 @@ logger_loop(State) ->
print_style(GL, IoFormat, State#logger_state.stylesheet),
set_evmgr_gl(GL),
TCGLs = add_tc_gl(TCPid,GL,State),
- if not RefreshLog ->
+ _ = if not RefreshLog ->
ok;
true ->
make_last_run_index(State#logger_state.start_time)
@@ -831,7 +845,7 @@ logger_loop(State) ->
return(From,{ok,filename:basename(State#logger_state.log_dir)}),
logger_loop(State);
{make_last_run_index,From} ->
- make_last_run_index(State#logger_state.start_time),
+ _ = make_last_run_index(State#logger_state.start_time),
return(From,get(ct_log_cache)),
logger_loop(State);
{set_stylesheet,_,SSFile} when State#logger_state.stylesheet ==
@@ -1169,7 +1183,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()], []),
- file:close(Fd).
+ ok = file:close(Fd).
%%%-----------------------------------------------------------------
%%% tc_io_format/3
@@ -1773,7 +1787,7 @@ count_cases(Dir) ->
%% file yet.
{0,0,0,0};
Summary ->
- write_summary(SumFile, Summary),
+ _ = write_summary(SumFile, Summary),
Summary
end;
{error, Reason} ->
@@ -2088,7 +2102,7 @@ interactive_link() ->
"</body>\n",
"</html>\n"
],
- file:write_file("last_interactive.html",unicode:characters_to_binary(Body)),
+ _ = file:write_file("last_interactive.html",unicode:characters_to_binary(Body)),
io:format("~n~nUpdated ~ts\n"
"Any CT activities will be logged here\n",
[?abs("last_interactive.html")]).
@@ -2219,9 +2233,9 @@ runentry(Dir, _, _) ->
write_totals_file(Name,Label,Logs,Totals) ->
AbsName = ?abs(Name),
notify_and_lock_file(AbsName),
- force_write_file(AbsName,
- term_to_binary({atom_to_list(node()),
- Label,Logs,Totals})),
+ _ = force_write_file(AbsName,
+ term_to_binary({atom_to_list(node()),
+ Label,Logs,Totals})),
notify_and_unlock_file(AbsName).
%% this function needs to convert from old formats to new so that old
@@ -2266,7 +2280,7 @@ read_totals_file(Name) ->
Result.
force_write_file(Name,Contents) ->
- force_delete(Name),
+ _ = force_delete(Name),
file:write_file(Name,Contents).
force_delete(Name) ->
@@ -2817,18 +2831,18 @@ get_cache_data({ok,CacheBin}) ->
true ->
{ok,CacheRec};
false ->
- file:delete(?log_cache_name),
+ _ = file:delete(?log_cache_name),
{error,old_cache_file}
end;
_ ->
- file:delete(?log_cache_name),
+ _ = file:delete(?log_cache_name),
{error,invalid_cache_file}
end;
get_cache_data(NoCache) ->
NoCache.
cache_vsn() ->
- application:load(common_test),
+ _ = application:load(common_test),
case application:get_key(common_test,vsn) of
{ok,VSN} ->
VSN;
diff --git a/lib/common_test/src/ct_master.erl b/lib/common_test/src/ct_master.erl
index c4905b316f..4eef27d2a5 100644
--- a/lib/common_test/src/ct_master.erl
+++ b/lib/common_test/src/ct_master.erl
@@ -376,7 +376,7 @@ init_master(Parent,NodeOptsList,EvHandlers,MasterLogDir,LogDirs,
end,
%% start master event manager and add default handler
- ct_master_event:start_link(),
+ {ok, _} = start_ct_master_event(),
ct_master_event:add_handler(),
%% add user handlers for master event manager
Add = fun({H,Args}) ->
@@ -398,6 +398,14 @@ init_master(Parent,NodeOptsList,EvHandlers,MasterLogDir,LogDirs,
end,
init_master1(Parent,NodeOptsList,InitOptions,LogDirs).
+start_ct_master_event() ->
+ case ct_master_event:start_link() of
+ {error, {already_started, Pid}} ->
+ {ok, Pid};
+ Else ->
+ Else
+ end.
+
init_master1(Parent,NodeOptsList,InitOptions,LogDirs) ->
{Inaccessible,NodeOptsList1,InitOptions1} = init_nodes(NodeOptsList,
InitOptions),
@@ -658,7 +666,7 @@ refresh_logs([D|Dirs],Refreshed) ->
{ok,Cwd} = file:get_cwd(),
case catch ct_run:refresh_logs(D) of
{'EXIT',Reason} ->
- file:set_cwd(Cwd),
+ ok = file:set_cwd(Cwd),
refresh_logs(Dirs,[{D,{error,Reason}}|Refreshed]);
Result ->
refresh_logs(Dirs,[{D,Result}|Refreshed])
@@ -701,7 +709,7 @@ init_node_ctrl(MasterPid,Cookie,Opts) ->
end,
%% start a local event manager
- ct_event:start_link(),
+ {ok, _} = start_ct_event(),
ct_event:add_handler([{master,MasterPid}]),
%% log("Running test with options: ~p~n", [Opts]),
@@ -721,6 +729,14 @@ init_node_ctrl(MasterPid,Cookie,Opts) ->
"Can't report result!~n~n", [MasterNode])
end.
+start_ct_event() ->
+ case ct_event:start_link() of
+ {error, {already_started, Pid}} ->
+ {ok, Pid};
+ Else ->
+ Else
+ end.
+
%%%-----------------------------------------------------------------
%%% Event handling
%%%-----------------------------------------------------------------
@@ -778,7 +794,7 @@ reply(Result,To) ->
ok.
init_nodes(NodeOptions, InitOptions)->
- ping_nodes(NodeOptions),
+ _ = ping_nodes(NodeOptions),
start_nodes(InitOptions),
eval_on_nodes(InitOptions),
{Inaccessible, NodeOptions1}=ping_nodes(NodeOptions),
diff --git a/lib/common_test/src/ct_master_logs.erl b/lib/common_test/src/ct_master_logs.erl
index 39f87a7f09..a2542171f8 100644
--- a/lib/common_test/src/ct_master_logs.erl
+++ b/lib/common_test/src/ct_master_logs.erl
@@ -91,8 +91,8 @@ init(Parent,LogDir,Nodes) ->
Time = calendar:local_time(),
RunDir = make_dirname(Time),
RunDirAbs = filename:join(LogDir,RunDir),
- file:make_dir(RunDirAbs),
- write_details_file(RunDirAbs,{node(),Nodes}),
+ ok = make_dir(RunDirAbs),
+ _ = write_details_file(RunDirAbs,{node(),Nodes}),
case basic_html() of
true ->
@@ -128,7 +128,7 @@ init(Parent,LogDir,Nodes) ->
end
end,
- make_all_runs_index(LogDir),
+ _ = make_all_runs_index(LogDir),
CtLogFd = open_ct_master_log(RunDirAbs),
NodeStr =
lists:flatten(lists:map(fun(N) ->
@@ -181,7 +181,7 @@ loop(State) ->
lists:foreach(Fun,List),
loop(State);
{make_all_runs_index,From} ->
- make_all_runs_index(State#state.logdir),
+ _ = make_all_runs_index(State#state.logdir),
return(From,State#state.logdir),
loop(State);
{{nodedir,Node,RunDir},From} ->
@@ -189,12 +189,12 @@ loop(State) ->
return(From,ok),
loop(State);
stop ->
- make_all_runs_index(State#state.logdir),
+ _ = make_all_runs_index(State#state.logdir),
io:format(State#state.log_fd,
int_header()++int_footer(),
[log_timestamp(?now),"Finished!"]),
- close_ct_master_log(State#state.log_fd),
- close_nodedir_index(State#state.nodedir_ix_fd),
+ _ = close_ct_master_log(State#state.log_fd),
+ _ = close_nodedir_index(State#state.nodedir_ix_fd),
ok
end.
@@ -496,7 +496,7 @@ make_relative(Dir) ->
ct_logs:make_relative(Dir).
force_write_file(Name,Contents) ->
- force_delete(Name),
+ _ = force_delete(Name),
file:write_file(Name,Contents).
force_delete(Name) ->
@@ -534,13 +534,34 @@ call(Msg) ->
end.
return({To,Ref},Result) ->
- To ! {Ref, Result}.
+ To ! {Ref, Result},
+ ok.
cast(Msg) ->
case whereis(?MODULE) of
undefined ->
- {error,does_not_exist};
+ io:format("Warning: ct_master_logs not started~n"),
+ {_,_,Content} = Msg,
+ FormatArgs = get_format_args(Content),
+ _ = [io:format(Format, Args) || {Format, Args} <- FormatArgs],
+ ok;
_Pid ->
- ?MODULE ! Msg
+ ?MODULE ! Msg,
+ ok
end.
+get_format_args(Content) ->
+ lists:map(fun(C) ->
+ case C of
+ {_, FA, _} -> FA;
+ _ -> C
+ end
+ end, Content).
+
+make_dir(Dir) ->
+ case file:make_dir(Dir) of
+ {error, exist} ->
+ ok;
+ Else ->
+ Else
+ end.
diff --git a/lib/common_test/src/ct_property_test.erl b/lib/common_test/src/ct_property_test.erl
index 7dc78e949a..12c3d726d3 100644
--- a/lib/common_test/src/ct_property_test.erl
+++ b/lib/common_test/src/ct_property_test.erl
@@ -161,7 +161,9 @@ property_tests_path(Dir, Config) ->
add_code_pathz(Dir) ->
case lists:member(Dir, code:get_path()) of
true -> ok;
- false -> code:add_pathz(Dir)
+ false ->
+ true = code:add_pathz(Dir),
+ ok
end.
compile_tests(Path, ToolModule) ->
@@ -171,10 +173,10 @@ compile_tests(Path, ToolModule) ->
{ok,FileNames} = file:list_dir("."),
BeamFiles = [F || F<-FileNames,
filename:extension(F) == ".beam"],
- [file:delete(F) || F<-BeamFiles],
+ _ = [file:delete(F) || F<-BeamFiles],
ct:pal("Compiling in ~p:~n Deleted ~p~n MacroDefs=~p",[Path,BeamFiles,MacroDefs]),
Result = make:all([load|MacroDefs]),
- file:set_cwd(Cwd),
+ ok = file:set_cwd(Cwd),
Result.
diff --git a/lib/common_test/src/ct_release_test.erl b/lib/common_test/src/ct_release_test.erl
index 4e0f88cf5f..d783f8d04e 100644
--- a/lib/common_test/src/ct_release_test.erl
+++ b/lib/common_test/src/ct_release_test.erl
@@ -342,7 +342,7 @@ cleanup(Config) ->
end
end,
AllNodes),
- [rpc:call(Node,erlang,halt,[]) || Node <- Nodes],
+ _ = [rpc:call(Node,erlang,halt,[]) || Node <- Nodes],
Config.
%%-----------------------------------------------------------------
@@ -552,14 +552,14 @@ target_system(Apps,CreateDir,InstallDir,{FromVsn,_,AllAppsVsns,Path}) ->
%% Add bin and log dirs
BinDir = filename:join([InstallDir, "bin"]),
- file:make_dir(BinDir),
- file:make_dir(filename:join(InstallDir,"log")),
+ ok = make_dir(BinDir),
+ ok = make_dir(filename:join(InstallDir,"log")),
%% Delete start scripts - they will be added later
ErtsBinDir = filename:join([InstallDir, "erts-" ++ ErtsVsn, "bin"]),
- file:delete(filename:join([ErtsBinDir, "erl"])),
- file:delete(filename:join([ErtsBinDir, "start"])),
- file:delete(filename:join([ErtsBinDir, "start_erl"])),
+ ok = delete_file(filename:join([ErtsBinDir, "erl"])),
+ ok = delete_file(filename:join([ErtsBinDir, "start"])),
+ ok = delete_file(filename:join([ErtsBinDir, "start_erl"])),
%% Copy .boot to bin/start.boot
copy_file(RelName++".boot",filename:join([BinDir, "start.boot"])),
@@ -680,7 +680,7 @@ do_upgrade({Cb,InitState},FromVsn,FromAppsVsns,ToRel,ToAppsVsns,InstallDir) ->
%% even if install_release returned {ok,...} there might be an
%% emulator restart (instruction restart_emulator), so we must
%% always make sure the node is running.
- wait_node_up(current,ToVsn,ToAppsVsns),
+ {ok, _} = wait_node_up(current,ToVsn,ToAppsVsns),
[{"OTP upgrade test",ToVsn,_,current},
{"OTP upgrade test",FromVsn,_,permanent}] =
@@ -703,7 +703,7 @@ do_upgrade({Cb,InitState},FromVsn,FromAppsVsns,ToRel,ToAppsVsns,InstallDir) ->
%% even if install_release returned {ok,...} there might be an
%% emulator restart (instruction restart_emulator), so we must
%% always make sure the node is running.
- wait_node_up(current,FromVsn,FromAppsVsns),
+ {ok, _} = wait_node_up(current,FromVsn,FromAppsVsns),
[{"OTP upgrade test",ToVsn,_,permanent},
{"OTP upgrade test",FromVsn,_,current}] =
@@ -854,7 +854,7 @@ copy_file(Src, Dest, Opts) ->
case lists:member(preserve, Opts) of
true ->
{ok, FileInfo} = file:read_file_info(Src),
- file:write_file_info(Dest, FileInfo);
+ ok = file:write_file_info(Dest, FileInfo);
false ->
ok
end.
@@ -862,8 +862,8 @@ copy_file(Src, Dest, Opts) ->
write_file(FName, Conts) ->
Enc = file:native_name_encoding(),
{ok, Fd} = file:open(FName, [write]),
- file:write(Fd, unicode:characters_to_binary(Conts,Enc,Enc)),
- file:close(Fd).
+ ok = file:write(Fd, unicode:characters_to_binary(Conts,Enc,Enc)),
+ ok = file:close(Fd).
%% Substitute all occurrences of %Var% for Val in the given scripts
subst_src_scripts(Scripts, SrcDir, DestDir, Vars, Opts) ->
@@ -944,3 +944,19 @@ rm_rf(Dir) ->
_ ->
ok
end.
+
+delete_file(FileName) ->
+ case file:delete(FileName) of
+ {error, enoent} ->
+ ok;
+ Else ->
+ Else
+ end.
+
+make_dir(Dir) ->
+ case file:make_dir(Dir) of
+ {error, eexist} ->
+ ok;
+ Else ->
+ Else
+ end.
diff --git a/lib/common_test/src/ct_repeat.erl b/lib/common_test/src/ct_repeat.erl
index 31c5755c7e..dac596a135 100644
--- a/lib/common_test/src/ct_repeat.erl
+++ b/lib/common_test/src/ct_repeat.erl
@@ -44,13 +44,13 @@ loop_test(If,Args) when is_list(Args) ->
false;
E = {error,_} ->
io:format("Common Test error: ~p\n\n",[E]),
- file:set_cwd(Cwd),
+ ok = file:set_cwd(Cwd),
E;
{repeat,N} ->
io:format("\nCommon Test: Will repeat tests ~w times.\n\n",[N]),
Args1 = [{loop_info,[{repeat,1,N}]} | Args],
Result = loop(If,repeat,0,N,undefined,Args1,undefined,[]),
- file:set_cwd(Cwd),
+ ok = file:set_cwd(Cwd),
Result;
{stop_time,StopTime} ->
Result =
@@ -76,7 +76,7 @@ loop_test(If,Args) when is_list(Args) ->
Args1 = [{loop_info,[{stop_time,Secs,StopTime,1}]} | Args],
loop(If,stop_time,0,Secs,StopTime,Args1,TPid,[])
end,
- file:set_cwd(Cwd),
+ ok = file:set_cwd(Cwd),
Result
end.
diff --git a/lib/common_test/src/ct_rpc.erl b/lib/common_test/src/ct_rpc.erl
index cbcc212bb8..b4a0bc9d74 100644
--- a/lib/common_test/src/ct_rpc.erl
+++ b/lib/common_test/src/ct_rpc.erl
@@ -81,7 +81,7 @@ app_node(App, [], _, _) ->
app_node(App, _Candidates = [CandidateNode | Nodes], FailOnBadRPC, Cookie) ->
Cookie0 = set_the_cookie(Cookie),
Result = rpc:call(CandidateNode, application, which_applications, []),
- set_the_cookie(Cookie0),
+ _ = set_the_cookie(Cookie0),
case Result of
{badrpc,Reason} when FailOnBadRPC == true ->
ct:fail({Reason,CandidateNode});
@@ -145,7 +145,7 @@ call({Fun, FunArgs}, Module, Function, Args, TimeOut, Cookie) ->
call(Node, Module, Function, Args, TimeOut, Cookie) when is_atom(Node) ->
Cookie0 = set_the_cookie(Cookie),
Result = rpc:call(Node, Module, Function, Args, TimeOut),
- set_the_cookie(Cookie0),
+ _ = set_the_cookie(Cookie0),
Result.
%%% @spec cast(Node, Module, Function, Args) -> ok
@@ -190,7 +190,7 @@ cast({Fun, FunArgs}, Module, Function, Args, Cookie) ->
cast(Node, Module, Function, Args, Cookie) when is_atom(Node) ->
Cookie0 = set_the_cookie(Cookie),
true = rpc:cast(Node, Module, Function, Args),
- set_the_cookie(Cookie0),
+ _ = set_the_cookie(Cookie0),
ok.
diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl
index 1e5f935198..fbb9c7ab60 100644
--- a/lib/common_test/src/ct_run.erl
+++ b/lib/common_test/src/ct_run.erl
@@ -400,21 +400,21 @@ run_or_refresh(Opts = #opts{logdir = LogDir}, Args) ->
[RefreshDir] -> ?abs(RefreshDir)
end,
{ok,Cwd} = file:get_cwd(),
- file:set_cwd(LogDir1),
+ ok = file:set_cwd(LogDir1),
%% give the shell time to print version etc
timer:sleep(500),
io:nl(),
case catch ct_logs:make_all_runs_index(refresh) of
{'EXIT',ARReason} ->
- file:set_cwd(Cwd),
+ ok = file:set_cwd(Cwd),
{error,{all_runs_index,ARReason}};
_ ->
case catch ct_logs:make_all_suites_index(refresh) of
{'EXIT',ASReason} ->
- file:set_cwd(Cwd),
+ ok = file:set_cwd(Cwd),
{error,{all_suites_index,ASReason}};
_ ->
- file:set_cwd(Cwd),
+ ok = file:set_cwd(Cwd),
io:format("Logs in ~ts refreshed!~n~n",
[LogDir1]),
timer:sleep(500), % time to flush io before quitting
@@ -756,8 +756,8 @@ script_start4(#opts{label = Label, profile = Profile,
{ct_hooks, CTHooks},
{enable_builtin_hooks,EnableBuiltinHooks}]) of
ok ->
- ct_util:start(interactive, LogDir,
- add_verbosity_defaults(Verbosity)),
+ _ = ct_util:start(interactive, LogDir,
+ add_verbosity_defaults(Verbosity)),
ct_util:set_testdata({logopts, LogOpts}),
log_ts_names(Specs),
io:nl(),
@@ -901,9 +901,8 @@ install(Opts, LogDir) ->
VarFile = variables_file_name(LogDir),
case file:open(VarFile, [write]) of
{ok,Fd} ->
- [io:format(Fd, "~p.\n", [Opt]) || Opt <- ConfOpts ],
- file:close(Fd),
- ok;
+ _ = [io:format(Fd, "~p.\n", [Opt]) || Opt <- ConfOpts],
+ ok = file:close(Fd);
{error,Reason} ->
io:format("CT failed to install configuration data. Please "
"verify that the log directory exists and that "
@@ -960,7 +959,7 @@ run_test1(StartOpts) when is_list(StartOpts) ->
false ->
case catch run_test2(StartOpts) of
{'EXIT',Reason} ->
- file:set_cwd(Cwd),
+ ok = file:set_cwd(Cwd),
{error,Reason};
Result ->
Result
@@ -971,7 +970,7 @@ run_test1(StartOpts) when is_list(StartOpts) ->
stop_trace(Tracing),
exit(Res);
RefreshDir ->
- refresh_logs(?abs(RefreshDir)),
+ ok = refresh_logs(?abs(RefreshDir)),
exit(done)
end.
@@ -1209,7 +1208,6 @@ run_all_specs([], _, _, TotResult) ->
end;
run_all_specs([{Specs,TS} | TSs], Opts, StartOpts, TotResult) ->
- log_ts_names(Specs),
Combined = #opts{config = TSConfig} = combine_test_opts(TS, Specs, Opts),
AllConfig = merge_vals([Opts#opts.config, TSConfig]),
try run_one_spec(TS,
@@ -1430,7 +1428,7 @@ run_testspec1(TestSpec) ->
io:format("~nCommon Test starting (cwd is ~ts)~n~n", [Cwd]),
case catch run_testspec2(TestSpec) of
{'EXIT',Reason} ->
- file:set_cwd(Cwd),
+ ok = file:set_cwd(Cwd),
exit({error,Reason});
Result ->
exit(Result)
@@ -1562,15 +1560,15 @@ refresh_logs(LogDir) ->
_ ->
case catch ct_logs:make_all_suites_index(refresh) of
{'EXIT',ASReason} ->
- file:set_cwd(Cwd),
+ ok = file:set_cwd(Cwd),
{error,{all_suites_index,ASReason}};
_ ->
case catch ct_logs:make_all_runs_index(refresh) of
{'EXIT',ARReason} ->
- file:set_cwd(Cwd),
+ ok = file:set_cwd(Cwd),
{error,{all_runs_index,ARReason}};
_ ->
- file:set_cwd(Cwd),
+ ok = file:set_cwd(Cwd),
io:format("Logs in ~ts refreshed!~n",[LogDir]),
ok
end
@@ -1610,22 +1608,34 @@ delistify(E) -> E.
%%% @hidden
%%% @equiv ct:run/3
run(TestDir, Suite, Cases) ->
- install([]),
- reformat_result(catch do_run(tests(TestDir, Suite, Cases), [])).
+ case install([]) of
+ ok ->
+ reformat_result(catch do_run(tests(TestDir, Suite, Cases), []));
+ Error ->
+ Error
+ end.
%%%-----------------------------------------------------------------
%%% @hidden
%%% @equiv ct:run/2
run(TestDir, Suite) when is_list(TestDir), is_integer(hd(TestDir)) ->
- install([]),
- reformat_result(catch do_run(tests(TestDir, Suite), [])).
+ case install([]) of
+ ok ->
+ reformat_result(catch do_run(tests(TestDir, Suite), []));
+ Error ->
+ Error
+ end.
%%%-----------------------------------------------------------------
%%% @hidden
%%% @equiv ct:run/1
run(TestDirs) ->
- install([]),
- reformat_result(catch do_run(tests(TestDirs), [])).
+ case install([]) of
+ ok ->
+ reformat_result(catch do_run(tests(TestDirs), []));
+ Error ->
+ Error
+ end.
reformat_result({'EXIT',{user_error,Reason}}) ->
{error,Reason};
@@ -2017,7 +2027,7 @@ save_make_errors(Errors) ->
"Error compiling or locating the "
"following suites: ~n~p",[Suites]),
%% save the info for logger
- file:write_file(?missing_suites_info,term_to_binary(Errors)),
+ ok = file:write_file(?missing_suites_info,term_to_binary(Errors)),
Errors.
get_bad_suites([{{_TestDir,_Suite},Failed}|Errors], BadSuites) ->
@@ -2234,7 +2244,7 @@ do_run_test(Tests, Skip, Opts0) ->
end,
application:set_env(test_server, esc_chars, EscChars),
- test_server_ctrl:start_link(local),
+ {ok, _} = test_server_ctrl:start_link(local),
%% let test_server expand the test tuples and count no of cases
{Suites,NoOfCases} = count_test_cases(Tests, Skip),
@@ -2295,7 +2305,7 @@ do_run_test(Tests, Skip, Opts0) ->
lists:foreach(fun(Suite) ->
maybe_cleanup_interpret(Suite, Opts#opts.step)
end, CleanUp),
- [code:del_path(Dir) || Dir <- AddedToPath],
+ _ = [code:del_path(Dir) || Dir <- AddedToPath],
%% If a severe error has occurred in the test_server,
%% we will generate an exception here.
@@ -2422,7 +2432,7 @@ count_test_cases(Tests, Skip) ->
SendResult = fun(Me, Result) -> Me ! {no_of_cases,Result} end,
TSPid = test_server_ctrl:start_get_totals(SendResult),
Ref = erlang:monitor(process, TSPid),
- add_jobs(Tests, Skip, #opts{}, []),
+ _ = add_jobs(Tests, Skip, #opts{}, []),
Counted = (catch count_test_cases1(length(Tests), 0, [], Ref)),
erlang:demonitor(Ref, [flush]),
case Counted of
@@ -2776,14 +2786,14 @@ maybe_interpret1(Suite, Cases, StepOpts) when is_list(Cases) ->
maybe_interpret2(Suite, Cases, StepOpts) ->
set_break_on_config(Suite, StepOpts),
- [begin try i:ib(Suite, Case, 1) of
+ _ = [begin try i:ib(Suite, Case, 1) of
_ -> ok
catch
_:_Error ->
io:format(user, "Invalid breakpoint: ~w:~w/1~n",
[Suite,Case])
end
- end || Case <- Cases, is_atom(Case)],
+ end || Case <- Cases, is_atom(Case)],
test_server_ctrl:multiply_timetraps(infinity),
WinOp = case lists:member(keep_inactive, ensure_atom(StepOpts)) of
true -> no_kill;
@@ -2802,12 +2812,12 @@ set_break_on_config(Suite, StepOpts) ->
false -> ok
end
end,
- SetBPIfExists(init_per_suite, 1),
- SetBPIfExists(init_per_group, 2),
- SetBPIfExists(init_per_testcase, 2),
- SetBPIfExists(end_per_testcase, 2),
- SetBPIfExists(end_per_group, 2),
- SetBPIfExists(end_per_suite, 1);
+ ok = SetBPIfExists(init_per_suite, 1),
+ ok = SetBPIfExists(init_per_group, 2),
+ ok = SetBPIfExists(init_per_testcase, 2),
+ ok = SetBPIfExists(end_per_testcase, 2),
+ ok = SetBPIfExists(end_per_group, 2),
+ ok = SetBPIfExists(end_per_suite, 1);
false ->
ok
end.
@@ -2984,31 +2994,31 @@ add_verbosity_defaults(VLvls) ->
%% relative dirs "post run_test erl_args" is not kept!
rel_to_abs(CtArgs) ->
{PA,PZ} = get_pa_pz(CtArgs, [], []),
- [begin
+ _ = [begin
Dir = rm_trailing_slash(D),
Abs = make_abs(Dir),
- if Dir /= Abs ->
- code:del_path(Dir),
- code:del_path(Abs),
+ _ = if Dir /= Abs ->
+ _ = code:del_path(Dir),
+ _ = code:del_path(Abs),
io:format(user, "Converting ~p to ~p and re-inserting "
"with add_pathz/1~n",
[Dir, Abs]);
true ->
- code:del_path(Dir)
+ _ = code:del_path(Dir)
end,
code:add_pathz(Abs)
end || D <- PZ],
- [begin
+ _ = [begin
Dir = rm_trailing_slash(D),
Abs = make_abs(Dir),
- if Dir /= Abs ->
- code:del_path(Dir),
- code:del_path(Abs),
+ _ = if Dir /= Abs ->
+ _ = code:del_path(Dir),
+ _ = code:del_path(Abs),
io:format(user, "Converting ~p to ~p and re-inserting "
"with add_patha/1~n",
[Dir, Abs]);
true ->
- code:del_path(Dir)
+ _ = code:del_path(Dir)
end,
code:add_patha(Abs)
end || D <- PA],
diff --git a/lib/common_test/src/ct_slave.erl b/lib/common_test/src/ct_slave.erl
index 3ad3937548..571958ca03 100644
--- a/lib/common_test/src/ct_slave.erl
+++ b/lib/common_test/src/ct_slave.erl
@@ -325,7 +325,7 @@ do_start(Host, Node, Options) ->
Functions
end,
MasterHost = gethostname(),
- if
+ _ = if
MasterHost == Host ->
spawn_local_node(Node, Options);
true->
@@ -359,7 +359,7 @@ do_start(Host, Node, Options) ->
pang->
{error, boot_timeout, ENode}
end,
- case Result of
+ _ = case Result of
{ok, ENode}->
ok;
{error, Timeout, ENode}
@@ -422,7 +422,7 @@ spawn_remote_node(Host, Node, Options) ->
{_, _}->
[{user, Username}, {password, Password}]
end ++ [{silently_accept_hosts, true}] ++ SSHOpts,
- application:ensure_all_started(ssh),
+ {ok, _} = application:ensure_all_started(ssh),
{ok, SSHConnRef} = ssh:connect(atom_to_list(Host), SSHPort, SSHOptions),
{ok, SSHChannelId} = ssh_connection:session_channel(SSHConnRef, infinity),
ssh_setenv(SSHConnRef, SSHChannelId, Env),
diff --git a/lib/common_test/src/ct_snmp.erl b/lib/common_test/src/ct_snmp.erl
index bb0167eb22..2c59b19196 100644
--- a/lib/common_test/src/ct_snmp.erl
+++ b/lib/common_test/src/ct_snmp.erl
@@ -221,9 +221,17 @@ start(Config, MgrAgentConfName, SnmpAppConfName) ->
Config, SysName, AgentManagerIP, IP),
setup_manager(StartManager, MgrAgentConfName, SnmpAppConfName,
Config, AgentManagerIP),
- application:start(snmp),
+ ok = start_application(snmp),
manager_register(StartManager, MgrAgentConfName).
+
+start_application(App) ->
+ case application:start(App) of
+ {error, {already_started, App}} ->
+ ok;
+ Else ->
+ Else
+ end.
%%% @spec stop(Config) -> ok
%%% Config = [{Key, Value}]
@@ -233,8 +241,8 @@ start(Config, MgrAgentConfName, SnmpAppConfName) ->
%%% @doc Stops the snmp manager and/or agent removes all files created.
stop(Config) ->
PrivDir = ?config(priv_dir, Config),
- application:stop(snmp),
- application:stop(mnesia),
+ ok = application:stop(snmp),
+ ok = application:stop(mnesia),
MgrDir = filename:join(PrivDir,"mgr"),
ConfDir = filename:join(PrivDir, "conf"),
DbDir = filename:join(PrivDir,"db"),
@@ -311,7 +319,7 @@ set_info(Config) ->
SetLogFile = filename:join(PrivDir, ?CT_SNMP_LOG_FILE),
case file:consult(SetLogFile) of
{ok, SetInfo} ->
- file:delete(SetLogFile),
+ ok = delete_file(SetLogFile),
lists:reverse(SetInfo);
_ ->
[]
@@ -513,7 +521,7 @@ unload_mibs(Mibs) ->
prepare_snmp_env() ->
%% To make sure application:set_env is not overwritten by any
%% app-file settings.
- application:load(snmp),
+ _ = application:load(snmp),
%% Fix for older versions of snmp where there are some
%% inappropriate default values for alway starting an
@@ -533,7 +541,7 @@ setup_manager(true, MgrConfName, SnmpConfName, Config, IP) ->
Users = [],
Agents = [],
Usms = [],
- file:make_dir(MgrDir),
+ ok = make_dir(MgrDir),
snmp_config:write_manager_snmp_files(MgrDir, IP, Port, MaxMsgSize,
EngineID, Users, Agents, Usms),
@@ -549,7 +557,7 @@ setup_agent(false,_, _, _, _, _, _) ->
ok;
setup_agent(true, AgentConfName, SnmpConfName,
Config, SysName, ManagerIP, AgentIP) ->
- application:start(mnesia),
+ ok = start_application(mnesia),
PrivDir = ?config(priv_dir, Config),
Vsns = ct:get_config({AgentConfName, agent_vsns}, ?CONF_FILE_VER),
TrapUdp = ct:get_config({AgentConfName, agent_trap_udp}, ?TRAP_UDP),
@@ -565,8 +573,8 @@ setup_agent(true, AgentConfName, SnmpConfName,
ConfDir = filename:join(PrivDir, "conf"),
DbDir = filename:join(PrivDir,"db"),
- file:make_dir(ConfDir),
- file:make_dir(DbDir),
+ ok = make_dir(ConfDir),
+ ok = make_dir(DbDir),
snmp_config:write_agent_snmp_files(ConfDir, Vsns, ManagerIP, TrapUdp,
AgentIP, AgentUdp, SysName,
NotifType, SecType, Passwd,
@@ -684,7 +692,7 @@ log(PrivDir, Agent, {_, _, Varbinds}, NewVarsAndVals) ->
File = filename:join(PrivDir, ?CT_SNMP_LOG_FILE),
{ok, Fd} = file:open(File, [write, append]),
io:format(Fd, "~p.~n", [{Agent, OldVarsAndVals, NewVarsAndVals}]),
- file:close(Fd),
+ ok = file:close(Fd),
ok.
%%%---------------------------------------------------------------------------
del_dir(Dir) ->
@@ -692,7 +700,7 @@ del_dir(Dir) ->
FullPathFiles = lists:map(fun(File) -> filename:join(Dir, File) end,
Files),
lists:foreach(fun file:delete/1, FullPathFiles),
- file:del_dir(Dir),
+ ok = delete_dir(Dir),
ok.
%%%---------------------------------------------------------------------------
agent_conf(Agent, MgrAgentConfName) ->
@@ -738,8 +746,8 @@ override_contexts(Config, {data_dir_file, File}) ->
override_contexts(Config, Contexts) ->
Dir = filename:join(?config(priv_dir, Config),"conf"),
File = filename:join(Dir,"context.conf"),
- file:delete(File),
- snmp_config:write_agent_context_config(Dir, "", Contexts).
+ ok = delete_file(File),
+ ok = snmp_config:write_agent_context_config(Dir, "", Contexts).
%%%---------------------------------------------------------------------------
override_sysinfo(_, undefined) ->
@@ -754,8 +762,8 @@ override_sysinfo(Config, {data_dir_file, File}) ->
override_sysinfo(Config, SysInfo) ->
Dir = filename:join(?config(priv_dir, Config),"conf"),
File = filename:join(Dir,"standard.conf"),
- file:delete(File),
- snmp_config:write_agent_standard_config(Dir, "", SysInfo).
+ ok = delete_file(File),
+ ok = snmp_config:write_agent_standard_config(Dir, "", SysInfo).
%%%---------------------------------------------------------------------------
override_target_address(_, undefined) ->
@@ -769,8 +777,8 @@ override_target_address(Config, {data_dir_file, File}) ->
override_target_address(Config, TargetAddressConf) ->
Dir = filename:join(?config(priv_dir, Config),"conf"),
File = filename:join(Dir,"target_addr.conf"),
- file:delete(File),
- snmp_config:write_agent_target_addr_config(Dir, "", TargetAddressConf).
+ ok = delete_file(File),
+ ok = snmp_config:write_agent_target_addr_config(Dir, "", TargetAddressConf).
%%%---------------------------------------------------------------------------
@@ -785,8 +793,8 @@ override_target_params(Config, {data_dir_file, File}) ->
override_target_params(Config, TargetParamsConf) ->
Dir = filename:join(?config(priv_dir, Config),"conf"),
File = filename:join(Dir,"target_params.conf"),
- file:delete(File),
- snmp_config:write_agent_target_params_config(Dir, "", TargetParamsConf).
+ ok = delete_file(File),
+ ok = snmp_config:write_agent_target_params_config(Dir, "", TargetParamsConf).
%%%---------------------------------------------------------------------------
override_notify(_, undefined) ->
@@ -800,8 +808,8 @@ override_notify(Config, {data_dir_file, File}) ->
override_notify(Config, NotifyConf) ->
Dir = filename:join(?config(priv_dir, Config),"conf"),
File = filename:join(Dir,"notify.conf"),
- file:delete(File),
- snmp_config:write_agent_notify_config(Dir, "", NotifyConf).
+ ok = delete_file(File),
+ ok = snmp_config:write_agent_notify_config(Dir, "", NotifyConf).
%%%---------------------------------------------------------------------------
override_usm(_, undefined) ->
@@ -815,8 +823,8 @@ override_usm(Config, {data_dir_file, File}) ->
override_usm(Config, UsmConf) ->
Dir = filename:join(?config(priv_dir, Config),"conf"),
File = filename:join(Dir,"usm.conf"),
- file:delete(File),
- snmp_config:write_agent_usm_config(Dir, "", UsmConf).
+ ok = delete_file(File),
+ ok = snmp_config:write_agent_usm_config(Dir, "", UsmConf).
%%%--------------------------------------------------------------------------
override_community(_, undefined) ->
@@ -830,8 +838,8 @@ override_community(Config, {data_dir_file, File}) ->
override_community(Config, CommunityConf) ->
Dir = filename:join(?config(priv_dir, Config),"conf"),
File = filename:join(Dir,"community.conf"),
- file:delete(File),
- snmp_config:write_agent_community_config(Dir, "", CommunityConf).
+ ok = delete_file(File),
+ ok = snmp_config:write_agent_community_config(Dir, "", CommunityConf).
%%%---------------------------------------------------------------------------
@@ -846,8 +854,8 @@ override_vacm(Config, {data_dir_file, File}) ->
override_vacm(Config, VacmConf) ->
Dir = filename:join(?config(priv_dir, Config),"conf"),
File = filename:join(Dir,"vacm.conf"),
- file:delete(File),
- snmp_config:write_agent_vacm_config(Dir, "", VacmConf).
+ ok = delete_file(File),
+ ok = snmp_config:write_agent_vacm_config(Dir, "", VacmConf).
%%%---------------------------------------------------------------------------
@@ -861,3 +869,21 @@ while_ok(Fun,[H|T]) ->
end;
while_ok(_Fun,[]) ->
ok.
+
+delete_file(FileName) ->
+ case file:delete(FileName) of
+ {error, enoent} -> ok;
+ Else -> Else
+ end.
+
+make_dir(Dir) ->
+ case file:make_dir(Dir) of
+ {error, eexist} -> ok;
+ Else -> Else
+ end.
+
+delete_dir(Dir) ->
+ case file:del_dir(Dir) of
+ {error, enoent} -> ok;
+ Else -> Else
+ end.
diff --git a/lib/common_test/src/ct_ssh.erl b/lib/common_test/src/ct_ssh.erl
index 92d912052e..6ab3bf036c 100644
--- a/lib/common_test/src/ct_ssh.erl
+++ b/lib/common_test/src/ct_ssh.erl
@@ -962,8 +962,8 @@ init(KeyOrName, {ConnType,Addr,Port}, AllOpts) ->
end, [], AllOpts1),
FinalOptions = [{silently_accept_hosts,true},
{user_interaction,false} | Options],
- crypto:start(),
- ssh:start(),
+ _ = crypto:start(),
+ _ = ssh:start(),
Result = case ConnType of
ssh ->
ssh:connect(Addr, Port, FinalOptions);
diff --git a/lib/common_test/src/ct_telnet.erl b/lib/common_test/src/ct_telnet.erl
index f5f4f648f4..8fb411ec4f 100644
--- a/lib/common_test/src/ct_telnet.erl
+++ b/lib/common_test/src/ct_telnet.erl
@@ -605,7 +605,7 @@ init(Name,{Ip,Port,Type},{TargetMod,KeepAlive,Extra}) ->
set_telnet_defaults(Settings,#state{})
end,
%% Handle old user versions of TargetMod
- code:ensure_loaded(TargetMod),
+ _ = code:ensure_loaded(TargetMod),
try
case erlang:function_exported(TargetMod,connect,7) of
true ->
@@ -688,7 +688,7 @@ handle_msg({cmd,Cmd,Opts},State) ->
debug_cont_gen_log("Throwing Buffer:",[]),
debug_log_lines(State#state.buffer),
- case {State#state.type,State#state.prompt} of
+ _ = case {State#state.type,State#state.prompt} of
{ts,_} ->
silent_teln_expect(State#state.name,
State#state.teln_pid,
@@ -735,7 +735,7 @@ handle_msg({send,Cmd,Opts},State) ->
debug_cont_gen_log("Throwing Buffer:",[]),
debug_log_lines(State#state.buffer),
- case {State#state.type,State#state.prompt} of
+ _ = case {State#state.type,State#state.prompt} of
{ts,_} ->
silent_teln_expect(State#state.name,
State#state.teln_pid,
diff --git a/lib/common_test/src/ct_telnet_client.erl b/lib/common_test/src/ct_telnet_client.erl
index 1f1311776f..5df7e279ac 100644
--- a/lib/common_test/src/ct_telnet_client.erl
+++ b/lib/common_test/src/ct_telnet_client.erl
@@ -272,7 +272,7 @@ send(Data, Sock, ConnName) ->
_:_ -> ok
end
end,
- gen_tcp:send(Sock, Data),
+ ok = gen_tcp:send(Sock, Data),
ok.
%% [IAC,IAC] = buffer data value 255
@@ -284,7 +284,7 @@ check_msg(Sock, [?IAC | Cs], Acc) ->
case get_cmd(Cs) of
{Cmd,Cs1} ->
cmd_dbg("Got",Cmd),
- respond_cmd(Cmd, Sock),
+ ok = respond_cmd(Cmd, Sock),
check_msg(Sock, Cs1, Acc);
error ->
Acc
diff --git a/lib/common_test/src/ct_util.erl b/lib/common_test/src/ct_util.erl
index d5a8e3fbc0..82a8743cf0 100644
--- a/lib/common_test/src/ct_util.erl
+++ b/lib/common_test/src/ct_util.erl
@@ -131,14 +131,14 @@ do_start(Parent, Mode, LogDir, Verbosity) ->
create_table(?suite_table,#suite_data.key),
create_table(?verbosity_table,1),
- [ets:insert(?verbosity_table,{Cat,Lvl}) || {Cat,Lvl} <- Verbosity],
+ _ = [ets:insert(?verbosity_table,{Cat,Lvl}) || {Cat,Lvl} <- Verbosity],
{ok,StartDir} = file:get_cwd(),
case file:set_cwd(LogDir) of
ok -> ok;
E -> exit(E)
end,
- DoExit = fun(Reason) -> file:set_cwd(StartDir), exit(Reason) end,
+ DoExit = fun(Reason) -> ok = file:set_cwd(StartDir), exit(Reason) end,
Opts = case read_opts() of
{ok,Opts1} ->
Opts1;
@@ -169,7 +169,7 @@ do_start(Parent, Mode, LogDir, Verbosity) ->
end,
%% add user event handlers
- case lists:keysearch(event_handler,1,Opts) of
+ _ = case lists:keysearch(event_handler,1,Opts) of
{value,{_,Handlers}} ->
Add = fun({H,Args}) ->
case catch gen_event:add_handler(?CT_EVMGR_REF,H,Args) of
@@ -195,7 +195,7 @@ do_start(Parent, Mode, LogDir, Verbosity) ->
data={StartTime,
lists:flatten(TestLogDir)}}),
%% Initialize ct_hooks
- try ct_hooks:init(Opts) of
+ _ = try ct_hooks:init(Opts) of
ok ->
Parent ! {self(),started};
{fail,CTHReason} ->
@@ -228,7 +228,8 @@ create_table(TableName,KeyPos) ->
create_table(TableName,set,KeyPos).
create_table(TableName,Type,KeyPos) ->
catch ets:delete(TableName),
- ets:new(TableName,[Type,named_table,public,{keypos,KeyPos}]).
+ _ = ets:new(TableName,[Type,named_table,public,{keypos,KeyPos}]),
+ ok.
read_opts() ->
case file:consult(ct_run:variables_file_name("./")) of
@@ -473,7 +474,7 @@ loop(Mode,TestData,StartDir) ->
ct_logs:close(Info, StartDir),
ct_event:stop(),
ct_config:stop(),
- file:set_cwd(StartDir),
+ ok = file:set_cwd(StartDir),
return(From, Info);
{Ref, _Msg} when is_reference(Ref) ->
%% This clause is used when doing cast operations.
@@ -505,7 +506,7 @@ loop(Mode,TestData,StartDir) ->
%% Let process crash in case of error, this shouldn't happen!
io:format("\n\nct_util_server got EXIT "
"from ~w: ~p\n\n", [Pid,Reason]),
- file:set_cwd(StartDir),
+ ok = file:set_cwd(StartDir),
exit(Reason)
end
end.
@@ -1035,10 +1036,12 @@ call(Msg, Timeout) ->
end.
return({To,Ref},Result) ->
- To ! {Ref, Result}.
+ To ! {Ref, Result},
+ ok.
cast(Msg) ->
- ct_util_server ! {Msg, {ct_util_server, make_ref()}}.
+ ct_util_server ! {Msg, {ct_util_server, make_ref()}},
+ ok.
seconds(T) ->
test_server:seconds(T).
@@ -1074,7 +1077,7 @@ abs_name2([],Acc) ->
open_url(iexplore, Args, URL) ->
{ok,R} = win32reg:open([read]),
ok = win32reg:change_key(R,"applications\\iexplore.exe\\shell\\open\\command"),
- case win32reg:values(R) of
+ _ = case win32reg:values(R) of
{ok, Paths} ->
Path = proplists:get_value(default, Paths),
[Cmd | _] = string:tokens(Path, "%"),
diff --git a/lib/common_test/src/ct_webtool.erl b/lib/common_test/src/ct_webtool.erl
index 6cbcd98cc3..87af442fd3 100644
--- a/lib/common_test/src/ct_webtool.erl
+++ b/lib/common_test/src/ct_webtool.erl
@@ -84,27 +84,27 @@
%% Function = {FunctionName,Arity} | FunctionName |
%% {Module, FunctionName, Arity} | {Module,FunctionName}
debug(F) ->
- ttb:tracer(all,[{file,"webtool.trc"}]), % tracing all nodes
- ttb:p(all,[call,timestamp]),
+ {ok, _} = ttb:tracer(all,[{file,"webtool.trc"}]), % tracing all nodes
+ {ok, _} = ttb:p(all,[call,timestamp]),
MS = [{'_',[],[{return_trace},{message,{caller}}]}],
- tp(F,MS),
- ttb:ctp(?MODULE,stop_debug), % don't want tracing of the stop_debug func
+ _ = tp(F,MS),
+ {ok, _} = ttb:ctp(?MODULE,stop_debug), % don't want tracing of the stop_debug func
ok.
tp(local,MS) -> % all functions
ttb:tpl(?MODULE,MS);
tp(global,MS) -> % all exported functions
ttb:tp(?MODULE,MS);
tp([{M,F,A}|T],MS) -> % Other module
- ttb:tpl(M,F,A,MS),
+ {ok, _} = ttb:tpl(M,F,A,MS),
tp(T,MS);
tp([{M,F}|T],MS) when is_atom(F) -> % Other module
- ttb:tpl(M,F,MS),
+ {ok, _} = ttb:tpl(M,F,MS),
tp(T,MS);
tp([{F,A}|T],MS) -> % function/arity
- ttb:tpl(?MODULE,F,A,MS),
+ {ok, _} = ttb:tpl(?MODULE,F,A,MS),
tp(T,MS);
tp([F|T],MS) -> % function
- ttb:tpl(?MODULE,F,MS),
+ {ok, _} = ttb:tpl(?MODULE,F,MS),
tp(T,MS);
tp([],_MS) ->
ok.
@@ -112,10 +112,10 @@ stop_debug() ->
ttb:stop([format]).
debug_app(Mod) ->
- ttb:tracer(all,[{file,"webtool_app.trc"},{handler,{fun out/4,true}}]),
- ttb:p(all,[call,timestamp]),
+ {ok, _} = ttb:tracer(all,[{file,"webtool_app.trc"},{handler,{fun out/4,true}}]),
+ {ok, _} = ttb:p(all,[call,timestamp]),
MS = [{'_',[],[{return_trace},{message,{caller}}]}],
- ttb:tp(Mod,MS),
+ {ok, _} = ttb:tp(Mod,MS),
ok.
out(_,{trace_ts,Pid,call,MFA={M,F,A},{W,_,_},TS},_,S)
@@ -145,7 +145,7 @@ script_start([App]) ->
script_start([App,DefaultBrowser]);
script_start([App,Browser]) ->
io:format("Starting webtool...\n"),
- start(),
+ {ok, _} = start(),
AvailableApps = get_applications(),
{OSType,_} = os:type(),
case lists:keysearch(App,1,AvailableApps) of
@@ -159,14 +159,14 @@ script_start([App,Browser]) ->
_ ->
"http://localhost:" ++ PortStr ++ "/" ++ StartPage
end,
- case Browser of
+ _ = case Browser of
none ->
ok;
iexplore when OSType == win32->
io:format("Starting internet explorer...\n"),
{ok,R} = win32reg:open(""),
Key="\\local_machine\\SOFTWARE\\Microsoft\\IE Setup\\Setup",
- win32reg:change_key(R,Key),
+ ok = win32reg:change_key(R,Key),
{ok,Val} = win32reg:value(R,"Path"),
IExplore=filename:join(win32reg:expand(Val),"iexplore.exe"),
os:cmd("\"" ++ IExplore ++ "\" " ++ Url);
@@ -186,7 +186,7 @@ script_start([App,Browser]) ->
{Port,{exit_status,_Error}} ->
io:format(" not running, starting ~w...\n",
[Browser]),
- os:cmd(BStr ++ " " ++ Url),
+ _ = os:cmd(BStr ++ " " ++ Url),
ok
after ?SEND_URL_TIMEOUT ->
io:format(" failed, starting ~w...\n",[Browser]),
@@ -206,7 +206,7 @@ script_start([App,Browser]) ->
usage() ->
io:format("Starting webtool...\n"),
- start(),
+ {ok, _} = start(),
Apps = lists:map(fun({A,_}) -> A end,get_applications()),
io:format(
"\nUsage: start_webtool application [ browser ]\n"
@@ -254,7 +254,12 @@ start(Path,Port) when is_integer(Port)->
start(Path,Data0)->
Data = Data0 ++ rest_of_standard_data(),
- gen_server:start({local,ct_web_tool},ct_webtool,{Path,Data},[]).
+ case gen_server:start({local,ct_web_tool},ct_webtool,{Path,Data},[]) of
+ {error, {already_started, Pid}} ->
+ {ok, Pid};
+ Else ->
+ Else
+ end.
stop()->
gen_server:call(ct_web_tool,stoppit).
diff --git a/lib/common_test/src/cth_conn_log.erl b/lib/common_test/src/cth_conn_log.erl
index 0501c6ed1c..883da0da0a 100644
--- a/lib/common_test/src/cth_conn_log.erl
+++ b/lib/common_test/src/cth_conn_log.erl
@@ -170,7 +170,7 @@ post_end_per_testcase(TestCase,_Config,Return,CthState) ->
end,
case ct_util:update_testdata(?MODULE, Update) of
deleted ->
- [ct_util:delete_testdata({?MODULE,ConnMod}) ||
+ _ = [ct_util:delete_testdata({?MODULE,ConnMod}) ||
{ConnMod,_} <- CthState],
error_logger:delete_report_handler(ct_conn_log_h);
{error,no_response} ->
diff --git a/lib/common_test/src/erl2html2.erl b/lib/common_test/src/erl2html2.erl
index a1e0bf3879..e819f345de 100644
--- a/lib/common_test/src/erl2html2.erl
+++ b/lib/common_test/src/erl2html2.erl
@@ -62,15 +62,15 @@ convert(File, Dest, InclPath, Header) ->
{ok,SFd} ->
case file:open(Dest,[write,raw]) of
{ok,DFd} ->
- file:write(DFd,[Header,"<pre>\n"]),
+ ok = file:write(DFd,[Header,"<pre>\n"]),
_Lines = build_html(SFd,DFd,encoding(File),Functions),
- file:write(DFd,["</pre>\n",footer(),
+ ok = file:write(DFd,["</pre>\n",footer(),
"</body>\n</html>\n"]),
%% {_, Time2} = statistics(runtime),
%% io:format("Converted ~p lines in ~.2f Seconds.~n",
%% [_Lines, Time2/1000]),
- file:close(SFd),
- file:close(DFd),
+ ok = file:close(SFd),
+ ok = file:close(DFd),
ok;
Error ->
Error
@@ -138,7 +138,7 @@ parse_non_preprocessed_file(File) ->
case file:open(File, []) of
{ok,Epp} ->
Forms = parse_non_preprocessed_file(Epp, File, 1),
- file:close(Epp),
+ ok = file:close(Epp),
{ok,Forms};
Error = {error,_E} ->
Error
@@ -205,14 +205,14 @@ build_html(SFd,DFd,Encoding,FuncsAndCs) ->
%% line of last expression in function found
build_html(SFd,DFd,Enc,{ok,Str},LastL,FuncsAndCs,_IsFuncDef,{F,LastL}) ->
LastLineLink = test_server_ctrl:uri_encode(F++"-last_expr",utf8),
- file:write(DFd,["<a name=\"",
- to_raw_list(LastLineLink,Enc),"\"/>"]),
+ ok = file:write(DFd,["<a name=\"",
+ to_raw_list(LastLineLink,Enc),"\"/>"]),
build_html(SFd,DFd,Enc,{ok,Str},LastL,FuncsAndCs,true,undefined);
%% function start line found
build_html(SFd,DFd,Enc,{ok,Str},L0,[{F,A,L0,LastL}|FuncsAndCs],
_IsFuncDef,_FAndLastL) ->
FALink = test_server_ctrl:uri_encode(F++"-"++integer_to_list(A),utf8),
- file:write(DFd,["<a name=\"",to_raw_list(FALink,Enc),"\"/>"]),
+ ok = file:write(DFd,["<a name=\"",to_raw_list(FALink,Enc),"\"/>"]),
build_html(SFd,DFd,Enc,{ok,Str},L0,FuncsAndCs,true,{F,LastL});
build_html(SFd,DFd,Enc,{ok,Str},L,[{clause,L}|FuncsAndCs],
_IsFuncDef,FAndLastL) ->
@@ -220,7 +220,7 @@ build_html(SFd,DFd,Enc,{ok,Str},L,[{clause,L}|FuncsAndCs],
build_html(SFd,DFd,Enc,{ok,Str},L,FuncsAndCs,IsFuncDef,FAndLastL) ->
LStr = line_number(L),
Str1 = line(Str,IsFuncDef),
- file:write(DFd,[LStr,Str1]),
+ ok = file:write(DFd,[LStr,Str1]),
build_html(SFd,DFd,Enc,file:read_line(SFd),L+1,FuncsAndCs,false,FAndLastL);
build_html(_SFd,_DFd,_Enc,eof,L,_FuncsAndCs,_IsFuncDef,_FAndLastL) ->
L.
diff --git a/lib/common_test/src/test_server.erl b/lib/common_test/src/test_server.erl
index 919526c5d7..924086f2bd 100644
--- a/lib/common_test/src/test_server.erl
+++ b/lib/common_test/src/test_server.erl
@@ -21,7 +21,7 @@
-define(DEFAULT_TIMETRAP_SECS, 60).
%%% TEST_SERVER_CTRL INTERFACE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--export([run_test_case_apply/1,init_target_info/0,init_purify/0]).
+-export([run_test_case_apply/1,init_target_info/0]).
-export([cover_compile/1,cover_analyse/2]).
%%% TEST_SERVER_SUP INTERFACE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -49,10 +49,6 @@
-export([break/1,break/2,break/3,continue/0,continue/1]).
-%%% DEBUGGER INTERFACE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--export([purify_new_leaks/0, purify_format/2, purify_new_fds_inuse/0,
- purify_is_running/0]).
-
%%% PRIVATE EXPORTED %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-export([]).
@@ -73,10 +69,6 @@ init_target_info() ->
username=test_server_sup:get_username(),
cookie=atom_to_list(erlang:get_cookie())}.
-init_purify() ->
- purify_new_leaks().
-
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% cover_compile(#cover{app=App,incl=Include,excl=Exclude,cross=Cross}) ->
%% {ok,#cover{mods=AnalyseModules}} | {error,Reason}
@@ -100,7 +92,7 @@ cover_compile(CoverInfo=#cover{app=none,incl=Include,cross=Cross}) ->
case length(CompileMods) of
0 ->
io:fwrite("WARNING: No modules to cover compile!\n\n",[]),
- cover:start(), % start cover server anyway
+ {ok, _} = start_cover(), % start cover server anyway
{ok,CoverInfo#cover{mods=[]}};
N ->
io:fwrite("Cover compiling ~w modules - "
@@ -115,7 +107,7 @@ cover_compile(CoverInfo=#cover{app=App,excl=all,incl=Include,cross=Cross}) ->
case length(CompileMods) of
0 ->
io:fwrite("WARNING: No modules to cover compile!\n\n",[]),
- cover:start(), % start cover server anyway
+ {ok, _} = start_cover(), % start cover server anyway
{ok,CoverInfo#cover{mods=[]}};
N ->
io:fwrite("Cover compiling '~w' (~w files) - "
@@ -158,7 +150,7 @@ cover_compile(CoverInfo=#cover{app=App,excl=Exclude,
case length(CompileMods) of
0 ->
io:fwrite("WARNING: No modules to cover compile!\n\n",[]),
- cover:start(), % start cover server anyway
+ {ok, _} = start_cover(), % start cover server anyway
{ok,CoverInfo#cover{mods=[]}};
N ->
io:fwrite("Cover compiling '~w' (~w files) - "
@@ -175,11 +167,11 @@ module_names(Beams) ->
do_cover_compile(Modules) ->
- cover:start(),
+ {ok, _} = start_cover(),
Sticky = prepare_cover_compile(Modules,[]),
R = cover:compile_beam(Modules),
- [warn_compile(Error) || Error <- R,element(1,Error)=/=ok],
- [code:stick_mod(M) || M <- Sticky],
+ _ = [warn_compile(Error) || Error <- R,element(1,Error)=/=ok],
+ _ = [code:stick_mod(M) || M <- Sticky],
ok.
warn_compile({error,{Reason,Module}}) ->
@@ -366,9 +358,7 @@ stick_all_sticky(Node,Sticky) ->
%% compensate timetraps for runtime delays introduced by e.g. tools like
%% cover.
-run_test_case_apply({CaseNum,Mod,Func,Args,Name,
- RunInit,TimetrapData}) ->
- purify_format("Test case #~w ~w:~w/1", [CaseNum, Mod, Func]),
+run_test_case_apply({Mod,Func,Args,Name,RunInit,TimetrapData}) ->
case os:getenv("TS_RUN_VALGRIND") of
false ->
ok;
@@ -380,7 +370,6 @@ run_test_case_apply({CaseNum,Mod,Func,Args,Name,
Result = run_test_case_apply(Mod, Func, Args, Name, RunInit,
TimetrapData),
ProcAft = erlang:system_info(process_count),
- purify_new_leaks(),
DetFail = get(test_server_detected_fail),
{Result,DetFail,ProcBef,ProcAft}.
@@ -585,7 +574,8 @@ run_test_case_msgloop(#st{ref=Ref,pid=Pid,end_conf_pid=EndConfPid0}=St0) ->
{user_timetrap,Pid,_TrapTime,StartTime,E={user_timetrap_error,_},_} ->
case update_user_timetraps(Pid, StartTime) of
proceed ->
- self() ! {abort_current_testcase,E,Pid};
+ self() ! {abort_current_testcase,E,Pid},
+ ok;
ignore ->
ok
end,
@@ -600,7 +590,8 @@ run_test_case_msgloop(#st{ref=Ref,pid=Pid,end_conf_pid=EndConfPid0}=St0) ->
true ->
TrapTime
end,
- timetrap(TrapTime, TotalTime, Pid, Scale);
+ _ = timetrap(TrapTime, TotalTime, Pid, Scale),
+ ok;
ignore ->
ok
end,
@@ -724,7 +715,7 @@ do_call_end_conf(Starter,Mod,Func,Data,TCExitReason,Conf,TVal) ->
Supervisor = self(),
EndConfApply =
fun() ->
- timetrap(TVal),
+ _ = timetrap(TVal),
%% We can't handle fails or skips here
%% (neither input nor output). The error can
%% be read from Conf though (tc_status).
@@ -775,7 +766,8 @@ print_end_conf_result(Mod,Func,Conf,Cause,Error) ->
" ~s!\n\tReason: ~ts\n",
[Mod,Func,Conf,Cause,ErrorStr])
end,
- group_leader() ! {printout,12,Str2Print}.
+ group_leader() ! {printout,12,Str2Print},
+ ok.
spawn_fw_call(Mod,IPTC={init_per_testcase,Func},CurrConf,Pid,
@@ -1287,7 +1279,9 @@ user_callback({CBMod,CBFunc}, Mod, Func, InitOrEnd, Args) ->
init_per_testcase(Mod, Func, Args) ->
case code:is_loaded(Mod) of
- false -> code:load_file(Mod);
+ false ->
+ _ = code:load_file(Mod),
+ ok;
_ -> ok
end,
case erlang:function_exported(Mod, init_per_testcase, 2) of
@@ -1355,7 +1349,8 @@ print_init_conf_result(Line,Cause,Reason) ->
"\tLocation: ~ts\n\tReason: ~ts\n",
[Cause,FormattedLoc,ReasonStr])
end,
- group_leader() ! {printout,12,Str2Print}.
+ group_leader() ! {printout,12,Str2Print},
+ ok.
end_per_testcase(Mod, Func, Conf) ->
@@ -1426,7 +1421,8 @@ print_end_tc_warning(EndFunc,Reason,Cause,Loc) ->
"Reason: ~ts\nLine: ~ts\n",
[EndFunc,Cause,ReasonStr,FormattedLoc])
end,
- group_leader() ! {printout,12,Str2Print}.
+ group_leader() ! {printout,12,Str2Print},
+ ok.
get_loc() ->
get(test_server_loc).
@@ -1657,7 +1653,8 @@ messages_get() ->
%%
%% Make sure proceeding IO from FromPid won't get rejected
permit_io(GroupLeader, FromPid) ->
- GroupLeader ! {permit_io,FromPid}.
+ GroupLeader ! {permit_io,FromPid},
+ ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% sleep(Time) -> ok
@@ -1829,7 +1826,6 @@ timetrap_scale_factor() ->
timetrap_scale_factor([
{ 2, fun() -> has_lock_checking() end},
{ 3, fun() -> has_superfluous_schedulers() end},
- { 5, fun() -> purify_is_running() end},
{ 6, fun() -> is_debug() end},
{10, fun() -> is_cover() end}
]).
@@ -2129,7 +2125,8 @@ timetrap_cancel_all(TCPid, SendToServer) ->
ok;
Timers ->
[timetrap_cancel_one(Handle, false) ||
- {Handle,Pid,_} <- Timers, Pid == TCPid]
+ {Handle,Pid,_} <- Timers, Pid == TCPid],
+ ok
end,
case get(test_server_user_timetrap) of
undefined ->
@@ -2139,13 +2136,15 @@ timetrap_cancel_all(TCPid, SendToServer) ->
{UserTTSup,_StartTime} ->
remove_user_timetrap(UserTTSup),
put(test_server_user_timetrap,
- proplists:delete(TCPid, UserTTs));
+ proplists:delete(TCPid, UserTTs)),
+ ok;
undefined ->
ok
end
end,
if SendToServer == true ->
- group_leader() ! {timetrap_cancel_all,TCPid,self()};
+ group_leader() ! {timetrap_cancel_all,TCPid,self()},
+ ok;
true ->
ok
end,
@@ -2560,10 +2559,11 @@ run_on_shielded_node(Fun, CArgs) when is_function(Fun), is_list(CArgs) ->
-spec start_job_proxy_fun(_, _) -> fun(() -> no_return()).
start_job_proxy_fun(Master, Fun) ->
fun () ->
- start_job_proxy(),
+ _ = start_job_proxy(),
receive
Ref ->
- Master ! {Ref, Fun()}
+ Master ! {Ref, Fun()},
+ ok
end,
receive after infinity -> infinity end
end.
@@ -2729,64 +2729,25 @@ is_commercial() ->
_ -> true
end.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% DEBUGGER INTERFACE %%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% purify_is_running() -> false|true
-%%
-%% Tests if Purify is currently running.
-
-purify_is_running() ->
- case catch erlang:system_info({error_checker, running}) of
- {'EXIT', _} -> false;
- Res -> Res
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% purify_new_leaks() -> false|BytesLeaked
-%% BytesLeaked = integer()
-%%
-%% Checks for new memory leaks if Purify is active.
-%% Returns the number of bytes leaked, or false if Purify
-%% is not running.
-purify_new_leaks() ->
- case catch erlang:system_info({error_checker, memory}) of
- {'EXIT', _} -> false;
- Leaked when is_integer(Leaked) -> Leaked
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% purify_new_fds_inuse() -> false|FdsInuse
-%% FdsInuse = integer()
-%%
-%% Checks for new file descriptors in use.
-%% Returns the number of new file descriptors in use, or false
-%% if Purify is not running.
-purify_new_fds_inuse() ->
- case catch erlang:system_info({error_checker, fd}) of
- {'EXIT', _} -> false;
- Inuse when is_integer(Inuse) -> Inuse
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% purify_format(Format, Args) -> ok
-%% Format = string()
-%% Args = lists()
-%%
-%% Outputs the formatted string to Purify's logfile,if Purify is active.
-purify_format(Format, Args) ->
- (catch erlang:system_info({error_checker, io_lib:format(Format, Args)})),
- ok.
-
-
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Apply given function and reply to caller or proxy.
%%
do_sync_apply(Proxy, From, {M,F,A}) ->
Result = apply(M, F, A),
- if is_pid(Proxy) -> Proxy ! {sync_result_proxy,From,Result};
- true -> From ! {sync_result,Result}
+ if is_pid(Proxy) ->
+ Proxy ! {sync_result_proxy,From,Result},
+ ok;
+ true ->
+ From ! {sync_result,Result},
+ ok
end.
+
+start_cover() ->
+ case cover:start() of
+ {error, {already_started, Pid}} ->
+ {ok, Pid};
+ Else ->
+ Else
+ end.
+
diff --git a/lib/common_test/src/test_server_ctrl.erl b/lib/common_test/src/test_server_ctrl.erl
index ff960c22a5..b52e4bef9b 100644
--- a/lib/common_test/src/test_server_ctrl.erl
+++ b/lib/common_test/src/test_server_ctrl.erl
@@ -294,7 +294,7 @@ start_link(_) ->
start() ->
case gen_server:start({local,?MODULE}, ?MODULE, [], []) of
- {ok, Pid} ->
+ {error, {already_started, Pid}} ->
{ok, Pid};
Other ->
Other
@@ -302,7 +302,7 @@ start() ->
start_link() ->
case gen_server:start_link({local,?MODULE}, ?MODULE, [], []) of
- {ok, Pid} ->
+ {error, {already_started, Pid}} ->
{ok, Pid};
Other ->
Other
@@ -512,7 +512,7 @@ init([]) ->
TI = TI0#target_info{host=TargetHost,
naming=naming(),
master=TargetHost},
- ets:new(slave_tab, [named_table,set,public,{keypos,2}]),
+ _ = ets:new(slave_tab, [named_table,set,public,{keypos,2}]),
set_hosts([TI#target_info.host]),
{ok,State#state{target_info=TI}}.
@@ -867,7 +867,7 @@ handle_call({create_priv_dir,Value}, _From, State) ->
handle_call({testcase_callback,ModFunc}, _From, State) ->
case ModFunc of
{Mod,Func} ->
- case code:is_loaded(Mod) of
+ _ = case code:is_loaded(Mod) of
{file,_} ->
ok;
false ->
@@ -1079,8 +1079,8 @@ terminate(_Reason, State) ->
false -> ok;
Sock -> test_server_node:stop_tracer_node(Sock)
end,
- kill_all_jobs(State#state.jobs),
- test_server_node:kill_nodes(),
+ ok = kill_all_jobs(State#state.jobs),
+ _ = test_server_node:kill_nodes(),
ok.
kill_all_jobs([{_Name,JobPid}|Jobs]) ->
@@ -1125,7 +1125,7 @@ spawn_tester(Mod, Func, Args, Dir, Name, Levels, RejectIoReqs,
init_tester(Mod, Func, Args, Dir, Name, {_,_,MinLev}=Levels,
RejectIoReqs, CreatePrivDir, TCCallback, ExtraTools) ->
process_flag(trap_exit, true),
- test_server_io:start_link(),
+ _ = test_server_io:start_link(),
put(test_server_name, Name),
put(test_server_dir, Dir),
put(test_server_total_time, 0),
@@ -1199,8 +1199,7 @@ init_tester(Mod, Func, Args, Dir, Name, {_,_,MinLev}=Levels,
{UnexpectedIoName,UnexpectedIoFooter} = get(test_server_unexpected_footer),
{ok,UnexpectedIoFd} = open_html_file(UnexpectedIoName, [append]),
io:put_chars(UnexpectedIoFd, "\n</pre>\n"++UnexpectedIoFooter),
- file:close(UnexpectedIoFd),
- ok.
+ ok = file:close(UnexpectedIoFd).
report_severe_error(Reason) ->
test_server_sup:framework_call(report, [severe_error,Reason]).
@@ -1927,7 +1926,7 @@ html_convert_modules([Mod|Mods]) ->
Name = atom_to_list(Mod),
DestFile = filename:join(DestDir,
downcase(Name)++?src_listing_ext),
- html_possibly_convert(SrcFile1, SrcFileInfo, DestFile),
+ _ = html_possibly_convert(SrcFile1, SrcFileInfo, DestFile),
html_convert_modules(Mods)
end;
_Other ->
@@ -2066,7 +2065,7 @@ add_init_and_end_per_suite([], LastMod, LastRef, FwMod) ->
end.
do_add_init_and_end_per_suite(LastMod, LastRef, Mod, FwMod) ->
- case code:is_loaded(Mod) of
+ _ = case code:is_loaded(Mod) of
false -> code:load_file(Mod);
_ -> ok
end,
@@ -2140,7 +2139,6 @@ do_add_end_per_suite_and_skip(LastMod, LastRef, Mod, FwMod) ->
%% Runs the specified tests, then displays/logs the summary.
run_test_cases(TestSpec, Config, TimetrapData) ->
- test_server:init_purify(),
case lists:member(no_src, get(test_server_logopts)) of
true ->
ok;
@@ -2323,7 +2321,7 @@ run_test_cases_loop([{SkipTag,{Type,Ref,Case,Comment},SkipMode}|Cases],
Config, TimetrapData, Mode, Status) when
((SkipTag==auto_skip_case) or (SkipTag==skip_case)) and
((Type==conf) or (Type==make)) ->
- file:set_cwd(filename:dirname(get(test_server_dir))),
+ ok = file:set_cwd(filename:dirname(get(test_server_dir))),
CurrIOHandler = get(test_server_common_io_handler),
ParentMode = tl(Mode),
@@ -2339,7 +2337,7 @@ run_test_cases_loop([{SkipTag,{Type,Ref,Case,Comment},SkipMode}|Cases],
false ->
%% this is a skipped end conf for a top level parallel
%% group, buffered io can be flushed
- handle_test_case_io_and_status(),
+ _ = handle_test_case_io_and_status(),
set_io_buffering(undefined),
{Mod,Func} = skip_case(AutoOrUser, Ref, 0, Case, Comment,
false, SkipMode),
@@ -2351,7 +2349,7 @@ run_test_cases_loop([{SkipTag,{Type,Ref,Case,Comment},SkipMode}|Cases],
_ ->
%% this is a skipped end conf for a parallel group nested
%% under a parallel group (io buffering is active)
- wait_for_cases(Ref),
+ _ = wait_for_cases(Ref),
{Mod,Func} = skip_case(AutoOrUser, Ref, 0, Case, Comment,
true, SkipMode),
ConfData = {Mod,{Func,get_name(SkipMode)},Comment},
@@ -2459,7 +2457,7 @@ run_test_cases_loop([{auto_skip_case,{Case,Comment},SkipMode}|Cases],
run_test_cases_loop([{skip_case,{{Mod,all}=Case,Comment},SkipMode}|Cases],
Config, TimetrapData, Mode, Status) ->
- skip_case(user, undefined, 0, Case, Comment, false, SkipMode),
+ _ = skip_case(user, undefined, 0, Case, Comment, false, SkipMode),
test_server_sup:framework_call(report, [tc_user_skip,
{Mod,{all,get_name(SkipMode)},
Comment}]),
@@ -2489,7 +2487,7 @@ run_test_cases_loop([{conf,Ref,Props,{Mod,Func}}|_Cases]=Cs0,
%% collect results from the test case processes
%% and calc total time
OkSkipFail = handle_test_case_io_and_status(),
- file:set_cwd(filename:dirname(get(test_server_dir))),
+ ok = file:set_cwd(filename:dirname(get(test_server_dir))),
After = ?now,
Before = get(test_server_parallel_start_time),
Elapsed = timer:now_diff(After, Before)/1000000,
@@ -3582,7 +3580,7 @@ handle_io_and_exit_loop([], [{undefined,CurrPid,CaseNum,Mod,Func}|Ps] = Cases, O
handle_io_and_exit_loop(Refs, [{Ref,CurrPid,CaseNum,Mod,Func}|Ps] = Cases, Ok,Skip,Fail) ->
receive
{started,_,CurrPid,CaseNum,Mod,Func} ->
- handle_io_and_exits(self(), CurrPid, CaseNum, Mod, Func, Cases),
+ _ = handle_io_and_exits(self(), CurrPid, CaseNum, Mod, Func, Cases),
Refs1 =
case Refs of
[Ref|Rs] -> % must be end conf case for subgroup
@@ -3658,7 +3656,7 @@ handle_io_and_exits(Main, CurrPid, CaseNum, Mod, Func, Cases) ->
%% about the execution time and the return value of the test case function.
run_test_case(Ref, Num, Mod, Func, Args, RunInit, TimetrapData) ->
- file:set_cwd(filename:dirname(get(test_server_dir))),
+ ok = file:set_cwd(filename:dirname(get(test_server_dir))),
run_test_case1(Ref, Num, Mod, Func, Args, RunInit,
TimetrapData, [], self()).
@@ -3668,7 +3666,7 @@ run_test_case(Ref, Num, Mod, Func, Args, skip_init, TimetrapData, Mode) ->
TimetrapData, Mode, self());
run_test_case(Ref, Num, Mod, Func, Args, RunInit, TimetrapData, Mode) ->
- file:set_cwd(filename:dirname(get(test_server_dir))),
+ ok = file:set_cwd(filename:dirname(get(test_server_dir))),
Main = self(),
case check_prop(parallel, Mode) of
false ->
@@ -3682,7 +3680,7 @@ run_test_case(Ref, Num, Mod, Func, Args, RunInit, TimetrapData, Mode) ->
spawn_link(
fun() ->
process_flag(trap_exit, true),
- [put(Key, Val) || {Key,Val} <- Dictionary],
+ _ = [put(Key, Val) || {Key,Val} <- Dictionary],
set_io_buffering({tc,Main}),
run_test_case1(Ref, Num, Mod, Func, Args, RunInit,
TimetrapData, Mode, Main)
@@ -3699,7 +3697,8 @@ run_test_case1(Ref, Num, Mod, Func, Args, RunInit,
false -> ok;
true ->
test_server_io:start_transaction(),
- Main ! {started,Ref,self(),Num,Mod,Func}
+ Main ! {started,Ref,self(),Num,Mod,Func},
+ ok
end,
TSDir = get(test_server_dir),
@@ -3774,7 +3773,7 @@ run_test_case1(Ref, Num, Mod, Func, Args, RunInit,
%% run the test case
{Result,DetectedFail,ProcsBefore,ProcsAfter} =
- run_test_case_apply(Num, Mod, Func, [UpdatedArgs], GrName,
+ run_test_case_apply(Mod, Func, [UpdatedArgs], GrName,
RunInit, TimetrapData),
{Time,RetVal,Loc,Opts,Comment} =
case Result of
@@ -3906,7 +3905,8 @@ run_test_case1(Ref, Num, Mod, Func, Args, RunInit,
true ->
test_server_io:end_transaction(),
Main ! {finished,Ref,self(),Num,Mod,Func,
- ?mod_result(Status),{Time,RetVal,Opts}}
+ ?mod_result(Status),{Time,RetVal,Opts}},
+ ok
end,
{Time,RetVal,Opts}.
@@ -4329,7 +4329,7 @@ do_format_exception(Reason={Error,Stack}) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% run_test_case_apply(CaseNum, Mod, Func, Args, Name, RunInit,
+%% run_test_case_apply(Mod, Func, Args, Name, RunInit,
%% TimetrapData) ->
%% {{Time,RetVal,Loc,Opts,Comment},DetectedFail,ProcessesBefore,ProcessesAfter} |
%% {{died,Reason,unknown,Comment},DetectedFail,ProcessesBefore,ProcessesAfter}
@@ -4343,9 +4343,9 @@ do_format_exception(Reason={Error,Stack}) ->
%% ProcessesBefore = ProcessesAfter = integer()
%%
-run_test_case_apply(CaseNum, Mod, Func, Args, Name, RunInit,
+run_test_case_apply(Mod, Func, Args, Name, RunInit,
TimetrapData) ->
- test_server:run_test_case_apply({CaseNum,Mod,Func,Args,Name,RunInit,
+ test_server:run_test_case_apply({Mod,Func,Args,Name,RunInit,
TimetrapData}).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -5276,7 +5276,8 @@ check_cross([]) ->
%% This per application analysis writes the file cover.html in the
%% application's run.<timestamp> directory.
stop_cover(#cover{}=CoverInfo, TestDir) ->
- cover_analyse(CoverInfo, TestDir);
+ cover_analyse(CoverInfo, TestDir),
+ ok;
stop_cover(_CoverInfo, _TestDir) ->
%% Cover is probably controlled by the framework
ok.
@@ -5315,7 +5316,7 @@ cover_analyse(CoverInfo, TestDir) ->
[?cross_coverlog_name]),
io:fwrite(CoverLog, "<p>CoverFile: <code>~tp</code>\n", [CoverFile]),
- write_cross_cover_info(TestDir,Cross),
+ ok = write_cross_cover_info(TestDir,Cross),
case length(cover:imported_modules()) of
Imps when Imps > 0 ->
@@ -5329,7 +5330,7 @@ cover_analyse(CoverInfo, TestDir) ->
io:fwrite(CoverLog, "<p>Excluded module(s): <code>~tp</code>\n", [Excluded]),
Coverage = test_server:cover_analyse(TestDir, CoverInfo),
- write_binary_file(filename:join(TestDir,?raw_coverlog_name),
+ ok = write_binary_file(filename:join(TestDir,?raw_coverlog_name),
term_to_binary(Coverage)),
case lists:filter(fun({_M,{_,_,_}}) -> false;
@@ -5344,8 +5345,8 @@ cover_analyse(CoverInfo, TestDir) ->
end,
TotPercent = write_cover_result_table(CoverLog, Coverage),
- write_binary_file(filename:join(TestDir, ?cover_total),
- term_to_binary(TotPercent)).
+ ok = write_binary_file(filename:join(TestDir, ?cover_total),
+ term_to_binary(TotPercent)).
%% Cover analysis - accumulated over multiple tests
%% This can be executed on any node after all tests are finished.
@@ -5395,7 +5396,7 @@ write_cross_cover_info(Dir,Cross) ->
write_cross_cover_logs([{Tag,Coverage}|T],TagDirMods) ->
case lists:keyfind(Tag,1,TagDirMods) of
{_,Dir,Mods} when Mods=/=[] ->
- write_binary_file(filename:join(Dir,?raw_cross_coverlog_name),
+ ok = write_binary_file(filename:join(Dir,?raw_cross_coverlog_name),
term_to_binary(Coverage)),
CoverLogName = filename:join(Dir,?cross_coverlog_name),
{ok,CoverLog} = open_html_file(CoverLogName),
diff --git a/lib/common_test/src/test_server_gl.erl b/lib/common_test/src/test_server_gl.erl
index 333c8fc06e..7d6fe64b92 100644
--- a/lib/common_test/src/test_server_gl.erl
+++ b/lib/common_test/src/test_server_gl.erl
@@ -185,7 +185,7 @@ handle_info({capture,Cap0}, St) ->
end,
{noreply,St#st{capture=Cap}};
handle_info({io_request,From,ReplyAs,Req}=IoReq, St) ->
- try io_req(Req, From, St) of
+ _ = try io_req(Req, From, St) of
passthrough ->
group_leader() ! IoReq;
{EscapeHtml,Data} ->
@@ -197,7 +197,8 @@ handle_info({io_request,From,ReplyAs,Req}=IoReq, St) ->
#st{capture=none} ->
ok;
#st{capture=CapturePid} ->
- CapturePid ! {captured,Data}
+ CapturePid ! {captured,Data},
+ ok
end,
case EscapeHtml andalso St#st.escape_chars of
true ->
diff --git a/lib/common_test/src/test_server_io.erl b/lib/common_test/src/test_server_io.erl
index 8c5c0aef35..3d5238052b 100644
--- a/lib/common_test/src/test_server_io.erl
+++ b/lib/common_test/src/test_server_io.erl
@@ -215,7 +215,7 @@ handle_call({set_fd,Tag,Fd}, _From, #st{fds=Fds0,tags=Tags0,
true ->
%% Fd ready, print anything buffered for associated Tag
lists:filtermap(fun({T,From,Str}) when T == Tag ->
- output(From, Tag, Str, St1),
+ _ = output(From, Tag, Str, St1),
false;
(_) ->
true
@@ -274,14 +274,15 @@ handle_call(reset_state, _From, #st{fds=Fds,tags=Tags,gls=Gls,
end
end, Tags),
GlList = gb_sets:to_list(Gls),
- [test_server_gl:stop(GL) || GL <- GlList],
+ _ = [test_server_gl:stop(GL) || GL <- GlList],
timer:sleep(100),
case lists:filter(fun(GlPid) -> is_process_alive(GlPid) end, GlList) of
[] ->
ok;
_ ->
timer:sleep(2000),
- [exit(GL, kill) || GL <- GlList]
+ [exit(GL, kill) || GL <- GlList],
+ ok
end,
Empty = gb_trees:empty(),
{ok,Shared} = test_server_gl:start_link(),
@@ -304,7 +305,7 @@ handle_call({stop,FdTags}, From, #st{fds=Fds0,tags=Tags0,
none ->
{Fds,Tags};
{value,Fd} ->
- file:close(Fd),
+ _ = file:close(Fd),
{gb_trees:delete(Tag, Fds),
lists:delete(Tag, Tags)}
end
@@ -333,7 +334,7 @@ handle_info({'EXIT',_Pid,Reason}, _St) ->
handle_info(stop_group_leaders, #st{gls=Gls}=St) ->
%% Stop the remaining group leaders.
GlPids = gb_sets:to_list(Gls),
- [test_server_gl:stop(GL) || GL <- GlPids],
+ _ = [test_server_gl:stop(GL) || GL <- GlPids],
timer:sleep(100),
Wait =
case lists:filter(fun(GlPid) -> is_process_alive(GlPid) end, GlPids) of
@@ -344,7 +345,7 @@ handle_info(stop_group_leaders, #st{gls=Gls}=St) ->
{noreply,St};
handle_info(kill_group_leaders, #st{gls=Gls,stopping=From,
pending_ops=Ops}=St) ->
- [exit(GL, kill) || GL <- gb_sets:to_list(Gls)],
+ _ = [exit(GL, kill) || GL <- gb_sets:to_list(Gls)],
if From /= undefined ->
gen_server:reply(From, ok);
true -> % reply has been sent already
@@ -434,7 +435,7 @@ do_print_buffered(Q0, St) ->
eot ->
Q;
{Tag,Str} ->
- do_output(Tag, Str, undefined, St),
+ _ = do_output(Tag, Str, undefined, St),
do_print_buffered(Q, St)
end.
@@ -448,5 +449,5 @@ gc(#st{gls=Gls0}) ->
InUse = ordsets:from_list(InUse0),
Gls = gb_sets:to_list(Gls0),
NotUsed = ordsets:subtract(Gls, InUse),
- [test_server_gl:stop(Pid) || Pid <- NotUsed],
+ _ = [test_server_gl:stop(Pid) || Pid <- NotUsed],
ok.
diff --git a/lib/common_test/src/test_server_node.erl b/lib/common_test/src/test_server_node.erl
index c64399e485..0b406c54cc 100644
--- a/lib/common_test/src/test_server_node.erl
+++ b/lib/common_test/src/test_server_node.erl
@@ -198,9 +198,9 @@ trc_loop(Sock,Patterns,Type) ->
gen_tcp:close(Sock)
end.
add_nodes(Nodes,Patterns,_Type) ->
- ttb:tracer(Nodes,[{file,{local, test_server}},
- {handler, {{?MODULE,handle_debug},initial}}]),
- ttb:p(all,[call,timestamp]),
+ {ok, _} = ttb:tracer(Nodes,[{file,{local, test_server}},
+ {handler, {{?MODULE,handle_debug},initial}}]),
+ {ok, _} = ttb:p(all,[call,timestamp]),
lists:foreach(fun({TP,M,F,A,Pat}) -> ttb:TP(M,F,A,Pat);
({CTP,M,F,A}) -> ttb:CTP(M,F,A)
end,
@@ -360,8 +360,8 @@ start_node_peer(SlaveName, OptList, From, TI) ->
-spec wait_for_node_started_fun(_, _, _, _, _) -> fun(() -> no_return()).
wait_for_node_started_fun(LSock, Tmo, Cleanup, TI, Self) ->
fun() ->
- wait_for_node_started(LSock,Tmo,undefined,
- Cleanup,TI,Self),
+ {{ok, _}, _} = wait_for_node_started(LSock,Tmo,undefined,
+ Cleanup,TI,Self),
receive after infinity -> ok end
end.
@@ -432,7 +432,7 @@ wait_for_node_started(LSock,Timeout,Client,Cleanup,TI,CtrlPid) ->
client=Client});
false -> ok
end,
- gen_tcp:controlling_process(Sock,CtrlPid),
+ ok = gen_tcp:controlling_process(Sock,CtrlPid),
test_server_ctrl:node_started(Nodename),
{{ok,Nodename},W}
end;
diff --git a/lib/common_test/src/test_server_sup.erl b/lib/common_test/src/test_server_sup.erl
index fa2bb33c2d..6922e01fcc 100644
--- a/lib/common_test/src/test_server_sup.erl
+++ b/lib/common_test/src/test_server_sup.erl
@@ -755,7 +755,7 @@ framework_call(FW,_Func,_Args,DefaultReturn)
DefaultReturn;
framework_call(Callback,Func,Args,DefaultReturn) ->
Mod = list_to_atom(Callback),
- case code:is_loaded(Mod) of
+ _ = case code:is_loaded(Mod) of
false -> code:load_file(Mod);
_ -> ok
end,
@@ -851,7 +851,8 @@ util_start() ->
spawn_link(fun() ->
register(?MODULE, self()),
util_loop(#util_state{starter=Starter})
- end);
+ end),
+ ok;
_Pid ->
ok
end.
diff --git a/lib/common_test/src/vts.erl b/lib/common_test/src/vts.erl
index e1c16fbda4..f1c5051164 100644
--- a/lib/common_test/src/vts.erl
+++ b/lib/common_test/src/vts.erl
@@ -64,7 +64,7 @@
%%%-----------------------------------------------------------------
%%% User API
start() ->
- ct_webtool:start(),
+ {ok, _} = ct_webtool:start(),
ct_webtool:start_tools([],"app=vts").
init_data(ConfigFiles,EvHandlers,LogDir,LogOpts,Tests) ->
@@ -169,7 +169,7 @@ loop(State) ->
NewState = State#state{config=Config,event_handler=EvHandlers,
current_log_dir=LogDir,
logopts=LogOpts,tests=Tests},
- ct_install(NewState),
+ _ = ct_install(NewState),
return(From,ok),
loop(NewState);
{start_page,From} ->
@@ -192,12 +192,12 @@ loop(State) ->
loop(State);
{{add_config_file,Input},From} ->
{Return,State1} = add_config_file1(Input,State),
- ct_install(State1),
+ _ = ct_install(State1),
return(From,Return),
loop(State1);
{{remove_config_file,Input},From} ->
{Return,State1} = remove_config_file1(Input,State),
- ct_install(State1),
+ _ = ct_install(State1),
return(From,Return),
loop(State1);
{run_frame,From} ->
@@ -233,7 +233,7 @@ loop(State) ->
return(From,result_summary_frame1(State)),
loop(State);
stop_reload_results ->
- file:set_cwd(State#state.start_dir),
+ ok = file:set_cwd(State#state.start_dir),
loop(State#state{reload_results=false});
{no_result_log_frame,From} ->
return(From,no_result_log_frame1()),
@@ -277,8 +277,8 @@ call(Msg) ->
end.
return({To,Ref},Result) ->
- To ! {Ref, Result}.
-
+ To ! {Ref, Result},
+ ok.
run_test1(State=#state{tests=Tests,current_log_dir=LogDir,
logopts=LogOpts}) ->
@@ -311,7 +311,6 @@ run_test1(State=#state{tests=Tests,current_log_dir=LogDir,
ct_install(#state{config=Config,event_handler=EvHandlers,
current_log_dir=LogDir}) ->
ct_run:install([{config,Config},{event_handler,EvHandlers}],LogDir).
-
%%%-----------------------------------------------------------------
%%% HTML
start_page1() ->
@@ -549,7 +548,7 @@ case_select(Dir,Suite,Case,N) ->
end,
case MakeResult of
ok ->
- code:add_pathz(Dir),
+ true = code:add_pathz(Dir),
case catch apply(Suite,all,[]) of
{'EXIT',Reason} ->
io:format("\n~p\n",[Reason]),
@@ -755,7 +754,7 @@ report1(tests_start,{TestName,_N},State) ->
end,
State#state{testruns=TestRuns};
report1(tests_done,{_Ok,_Fail,_Skip},State) ->
- timer:send_after(5000, self(),stop_reload_results),
+ {ok, _} = timer:send_after(5000, self(),stop_reload_results),
State#state{running=State#state.running-1,reload_results=true};
report1(tc_start,{_Suite,_Case},State) ->
State;
diff --git a/lib/common_test/test/Makefile b/lib/common_test/test/Makefile
index 1532b6c1f7..b1eddfedd7 100644
--- a/lib/common_test/test/Makefile
+++ b/lib/common_test/test/Makefile
@@ -69,7 +69,8 @@ MODULES= \
erl2html2_SUITE \
test_server_SUITE \
test_server_test_lib \
- ct_release_test_SUITE
+ ct_release_test_SUITE \
+ ct_log_SUITE
ERL_FILES= $(MODULES:%=%.erl)
HRL_FILES= test_server_test_lib.hrl
diff --git a/lib/common_test/test/ct_log_SUITE.erl b/lib/common_test/test/ct_log_SUITE.erl
new file mode 100644
index 0000000000..9bdd44cbdf
--- /dev/null
+++ b/lib/common_test/test/ct_log_SUITE.erl
@@ -0,0 +1,328 @@
+%%
+%% %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%
+%%
+
+%%%-------------------------------------------------------------------
+%%% File: ct_log_SUITE
+%%%
+%%% Description: Test that ct:log, ct:pal and io:format print to
+%%% the test case log file as expected, with or without special HTML
+%%% characters being escaped.
+%%%
+%%%-------------------------------------------------------------------
+-module(ct_log_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
+%%--------------------------------------------------------------------
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_testcase(_TestCase, Config) ->
+ Config.
+
+end_per_testcase(_TestCase, _Config) ->
+ ok.
+
+suite() -> [{ct_hooks,[ts_install_cth]}].
+
+all() ->
+ [{group,print_and_verify}].
+
+groups() ->
+ [{print_and_verify,[sequence],[print,verify]}].
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% TEST CASES
+%%--------------------------------------------------------------------
+
+%%%-----------------------------------------------------------------
+%%%
+print(Config) ->
+ TcLogFile = proplists:get_value(tc_logfile, Config),
+ Pid = self(),
+ String = atom_to_list(?MODULE),
+
+ %% START mark
+ io:format("LOGGING START~n"),
+
+ %% io:format
+ io:format("1. Printing nothing~n", []),
+ io:format("2. Printing a string: ~s~n", [String]),
+ io:format("3. Printing a string: ~p~n", [String]),
+ io:format("4. Printing a tuple: ~w~n", [{module,?MODULE}]),
+ io:format("5. Printing a pid: ~w~n", [Pid]),
+ io:format("6. Printing HTML: <pre>~s</pre>~n", [String]),
+
+ %% --- API ---
+ %% pal(Format) ->
+ %% = ct:pal(default, 50, Format, []).
+ %% pal(X1, X2) -> ok
+ %% X1 = Category | Importance | Format
+ %% X2 = Format | FormatArgs
+ %% pal(X1, X2, X3) -> ok
+ %% X1 = Category | Importance
+ %% X2 = Importance | Format
+ %% X3 = Format | FormatArgs
+ %% pal(Category, Importance, Format, FormatArgs) -> ok
+ %% ------
+ ct:pal("1. Printing nothing"),
+ ct:pal("2. Printing nothing", []),
+ ct:pal("3. Printing a string: ~s", [String]),
+ ct:pal("4. Printing a string: ~p", [String]),
+ ct:pal("5. Printing a tuple: ~w", [{module,?MODULE}]),
+ ct:pal("6. Printing a pid: ~w", [Pid]),
+ ct:pal("7. Printing HTML: <pre>~s</pre>", [String]),
+ ct:pal(ct_internal, "8. Printing with category"),
+ ct:pal(ct_internal, "9. Printing with ~s", ["category"]),
+ ct:pal(50, "10. Printing with importance"),
+ ct:pal(50, "11. Printing with ~s", ["importance"]),
+ ct:pal(ct_internal, 50, "12. Printing with ~s", ["category and importance"]),
+
+ %% --- API ---
+ %% log(Format) -> ok
+ %% = ct:log(default, 50, Format, [], []).
+ %% log(X1, X2) -> ok
+ %% X1 = Category | Importance | Format
+ %% X2 = Format | FormatArgs
+ %% log(X1, X2, X3) -> ok
+ %% X1 = Category | Importance
+ %% X2 = Importance | Format
+ %% X3 = Format | FormatArgs | Opts
+ %% log(X1, X2, X3, X4) -> ok
+ %% X1 = Category | Importance
+ %% X2 = Importance | Format
+ %% X3 = Format | FormatArgs
+ %% X4 = FormatArgs | Opts
+ %% log(Category, Importance, Format, FormatArgs, Opts) -> ok
+ %% ------
+ ct:log("1. Printing nothing"),
+ ct:log("2. Printing nothing", []),
+ ct:log("3. Printing a string: ~s", [String]),
+ ct:log("4. Printing a string: ~p", [String]),
+ ct:log("5. Printing a tuple: ~w", [{module,?MODULE}]),
+ ct:log("6. Printing a pid: ~w", [Pid]),
+ ct:log("7. Printing HTML: <pre>~s</pre>", [String]),
+ ct:log("8. Printing a pid escaped: ~w", [Pid], [esc_chars]),
+ ct:log("9. Printing a string escaped: ~p", [String], [esc_chars]),
+ ct:log("10. Printing HTML escaped: <pre>~s</pre>", [String], [esc_chars]),
+ ct:log("11. Printing a string, no css: ~s", [String], [no_css]),
+ ct:log("12. Printing a pid escaped, no css: ~w", [Pid],
+ [esc_chars, no_css]),
+ ct:log(ct_internal, "13. Printing with category"),
+ ct:log(ct_internal, "14. Printing with ~s", ["category"]),
+ ct:log(ct_internal, "15. Printing with ~s, no_css", ["category"],
+ [no_css]),
+ ct:log(50, "16. Printing with importance"),
+ ct:log(50, "17. Printing with ~s", ["importance"]),
+ ct:log(50, "18. Printing with ~s, no_css", ["importance"], [no_css]),
+ ct:log(ct_internal, 50, "19. Printing with category and importance"),
+ ct:log(ct_internal, 50, "20. Printing with ~s", ["category and importance"]),
+ ct:log(ct_internal, 50, "21. Printing a pid escaped with ~s, no_css: ~w",
+ ["category and importance",Pid], [esc_chars,no_css]),
+
+ %% END mark
+ ct:log("LOGGING END", [], [no_css]),
+ {save_config,[{the_logfile,TcLogFile},{the_pid,Pid},{the_string,String}]}.
+
+
+verify(Config) ->
+ {print,SavedCfg} = proplists:get_value(saved_config, 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;",
+ String = proplists:get_value(the_string, SavedCfg),
+ ct:log("Read from prev testcase: ~p & ~p", [TcLogFile,Pid]),
+ {ok,Dev} = file:open(TcLogFile, [read]),
+ ok = read_until(Dev, "LOGGING START\n"),
+
+ %% io:format
+ match_line(Dev, "1. Printing nothing", []),
+ read_nl(Dev),
+ match_line(Dev, "2. Printing a string: ~s", [String]),
+ read_nl(Dev),
+ match_line(Dev, "3. Printing a string: ~p", [String]),
+ read_nl(Dev),
+ match_line(Dev, "4. Printing a tuple: ~w", [{module,?MODULE}]),
+ read_nl(Dev),
+ match_line(Dev, "5. Printing a pid: ~s", [EscPid]),
+ read_nl(Dev),
+ match_line(Dev, "6. Printing HTML: &lt;pre&gt;~s&lt;/pre&gt;", [String]),
+ read_nl(Dev),
+ %% ct:pal
+ read_header(Dev),
+ match_line(Dev, "1. Printing nothing", []),
+ read_footer(Dev),
+ read_header(Dev),
+ match_line(Dev, "2. Printing nothing", []),
+ read_footer(Dev),
+ read_header(Dev),
+ match_line(Dev, "3. Printing a string: ~s", [String]),
+ read_footer(Dev),
+ read_header(Dev),
+ match_line(Dev, "4. Printing a string: ~p", [String]),
+ read_footer(Dev),
+ read_header(Dev),
+ match_line(Dev, "5. Printing a tuple: ~w", [{module,?MODULE}]),
+ read_footer(Dev),
+ read_header(Dev),
+ match_line(Dev, "6. Printing a pid: ~s", [EscPid]),
+ read_footer(Dev),
+ read_header(Dev),
+ match_line(Dev, "7. Printing HTML: &lt;pre&gt;~s&lt;/pre&gt;", [String]),
+ read_footer(Dev),
+ read_header(Dev, "\"ct_internal\""),
+ match_line(Dev, "8. Printing with category", []),
+ read_footer(Dev),
+ read_header(Dev, "\"ct_internal\""),
+ match_line(Dev, "9. Printing with ~s", ["category"]),
+ read_footer(Dev),
+ read_header(Dev),
+ match_line(Dev, "10. Printing with importance", []),
+ read_footer(Dev),
+ read_header(Dev),
+ match_line(Dev, "11. Printing with ~s", ["importance"]),
+ read_footer(Dev),
+ read_header(Dev, "\"ct_internal\""),
+ match_line(Dev, "12. Printing with ~s", ["category and importance"]),
+ read_footer(Dev),
+ %% ct:log
+ read_header(Dev),
+ match_line(Dev, "1. Printing nothing", []),
+ read_footer(Dev),
+ read_header(Dev),
+ match_line(Dev, "2. Printing nothing", []),
+ read_footer(Dev),
+ read_header(Dev),
+ match_line(Dev, "3. Printing a string: ~s", [String]),
+ read_footer(Dev),
+ read_header(Dev),
+ match_line(Dev, "4. Printing a string: ~p", [String]),
+ read_footer(Dev),
+ read_header(Dev),
+ match_line(Dev, "5. Printing a tuple: ~w", [{module,?MODULE}]),
+ read_footer(Dev),
+ read_header(Dev),
+ match_line(Dev, "6. Printing a pid: ~w", [Pid]),
+ read_footer(Dev),
+ read_header(Dev),
+ match_line(Dev, "7. Printing HTML: <pre>~s</pre>", [String]),
+ read_footer(Dev),
+ read_header(Dev),
+ match_line(Dev, "8. Printing a pid escaped: ~s", [EscPid]),
+ read_footer(Dev),
+ read_header(Dev),
+ match_line(Dev, "9. Printing a string escaped: ~p", [String]),
+ read_footer(Dev),
+ read_header(Dev),
+ match_line(Dev, "10. Printing HTML escaped: &lt;pre&gt;~s&lt;/pre&gt;",
+ [String]),
+ read_footer(Dev),
+ match_line(Dev, "11. Printing a string, no css: ~s", [String]),
+ match_line(Dev, "12. Printing a pid escaped, no css: ~s", [EscPid]),
+ read_header(Dev, "\"ct_internal\""),
+ match_line(Dev, "13. Printing with category", []),
+ read_footer(Dev),
+ read_header(Dev, "\"ct_internal\""),
+ match_line(Dev, "14. Printing with ~s", ["category"]),
+ read_footer(Dev),
+ match_line(Dev, "15. Printing with ~s, no_css", ["category"]),
+ read_header(Dev),
+ match_line(Dev, "16. Printing with importance", []),
+ read_footer(Dev),
+ read_header(Dev),
+ match_line(Dev, "17. Printing with ~s", ["importance"]),
+ read_footer(Dev),
+ match_line(Dev, "18. Printing with ~s, no_css", ["importance"]),
+ read_header(Dev, "\"ct_internal\""),
+ match_line(Dev, "19. Printing with category and importance", []),
+ read_footer(Dev),
+ read_header(Dev, "\"ct_internal\""),
+ match_line(Dev, "20. Printing with ~s", ["category and importance"]),
+ read_footer(Dev),
+ match_line(Dev, "21. Printing a pid escaped with ~s, no_css: ~s",
+ ["category and importance",EscPid]),
+
+ file:close(Dev),
+ ok.
+
+%%%-----------------------------------------------------------------
+%%% HELP FUNCTIONS
+%%%-----------------------------------------------------------------
+
+read_until(Dev, Pat) ->
+ case file:read_line(Dev) of
+ {ok,Pat} ->
+ file:read_line(Dev), % \n
+ ok;
+ eof ->
+ file:close(Dev),
+ {error,{not_found,Pat}};
+ _ ->
+ read_until(Dev, Pat)
+ end.
+
+match_line(Dev, Format, Args) ->
+ Pat = lists:flatten(io_lib:format(Format, Args)),
+ Line = element(2, file:read_line(Dev)),
+ case re:run(Line, Pat) of
+ {match,_} ->
+ ok;
+ nomatch ->
+ ct:pal("ERROR! No match for ~p.\nLine = ~p", [Pat,Line]),
+ file:close(Dev),
+ ct:fail({mismatch,Pat,Line})
+ end.
+
+read_header(Dev) ->
+ read_header(Dev, "\"default\"").
+
+read_header(Dev, Cat) ->
+ file:read_line(Dev), % \n
+ "</pre>\n" = element(2, file:read_line(Dev)),
+ {match,_} =
+ re:run(element(2, file:read_line(Dev)), "<div class="++Cat++"><pre><b>"
+ "\\*\\*\\* User \\d{4}-\\d{2}-\\d{2} "
+ "\\d{2}:\\d{2}:\\d{2}.\\d{1,} \\*\\*\\*</b>").
+
+read_footer(Dev) ->
+ "</pre></div>\n" = element(2, file:read_line(Dev)),
+ "<pre>\n" = element(2, file:read_line(Dev)).
+
+read_nl(Dev) ->
+ file:read_line(Dev).
+
+
diff --git a/lib/common_test/test/ct_repeat_testrun_SUITE.erl b/lib/common_test/test/ct_repeat_testrun_SUITE.erl
index 632597c214..f8b6a379f6 100644
--- a/lib/common_test/test/ct_repeat_testrun_SUITE.erl
+++ b/lib/common_test/test/ct_repeat_testrun_SUITE.erl
@@ -66,25 +66,47 @@
%% there will be clashes with logging processes etc).
%%--------------------------------------------------------------------
init_per_suite(Config0) ->
- Config = ct_test_support:init_per_suite(Config0),
- DataDir = ?config(data_dir, Config),
- Suite1 = filename:join([DataDir,"a_test","r1_SUITE"]),
- Suite2 = filename:join([DataDir,"b_test","r2_SUITE"]),
- Opts0 = ct_test_support:get_opts(Config),
- Opts1 = Opts0 ++ [{suite,Suite1},{testcase,tc2},{label,timing1}],
- Opts2 = Opts0 ++ [{suite,Suite2},{testcase,tc2},{label,timing2}],
-
- %% Make sure both suites are compiled
- {1,0,{0,0}} = ct_test_support:run(ct,run_test,[Opts1],Config),
- {1,0,{0,0}} = ct_test_support:run(ct,run_test,[Opts2],Config),
-
- %% Time the shortest testcase to use for offset
- {_T0,{1,0,{0,0}}} = timer:tc(ct_test_support,run,[ct,run_test,[Opts1],Config]),
-
- %% -2 is to ensure we hit inside the target test case and not after
-% T = round(T0/1000000)-2,
- T=0,
- [{offset,T}|Config].
+ TTInfo = {_T,{_Scaled,ScaleVal}} = ct:get_timetrap_info(),
+ ct:pal("Timetrap info = ~w", [TTInfo]),
+ if ScaleVal > 1 ->
+ {skip,"Skip on systems running e.g. cover or debug!"};
+ ScaleVal =< 1 ->
+ Config = ct_test_support:init_per_suite(Config0),
+ DataDir = ?config(data_dir, Config),
+ Suite1 = filename:join([DataDir,"a_test","r1_SUITE"]),
+ Suite2 = filename:join([DataDir,"b_test","r2_SUITE"]),
+ Opts0 = ct_test_support:get_opts(Config),
+ Opts1 = Opts0 ++ [{suite,Suite1},{testcase,tc2},{label,timing1}],
+ Opts2 = Opts0 ++ [{suite,Suite2},{testcase,tc2},{label,timing2}],
+
+ %% Make sure both suites are compiled
+ {1,0,{0,0}} = ct_test_support:run(ct,run_test,[Opts1],Config),
+ {1,0,{0,0}} = ct_test_support:run(ct,run_test,[Opts2],Config),
+
+ %% Check if file i/o is too slow for correct measurements
+ Opts3 = Opts0 ++ [{suite,Suite1},{testcase,tc1},{label,timing3}],
+ {T,_} =
+ timer:tc(
+ fun() ->
+ {1,0,{0,0}} = ct_test_support:run(ct,run_test,
+ [Opts3],Config),
+ {1,0,{0,0}} = ct_test_support:run(ct,run_test,
+ [Opts3],Config)
+ end),
+ %% The time to compare with here must match the timeout value
+ %% in the test suite. Accept 30% logging overhead (26 sec total).
+ if T > 26000000 ->
+ ct:pal("Timing test took ~w sec (< 27 sec expected). "
+ "Skipping the suite!",
+ [trunc(T/1000000)]),
+ ct_test_support:end_per_suite(Config),
+ {skip,"File I/O too slow for this suite"};
+ true ->
+ ct:pal("Timing test took ~w sec. Proceeding...",
+ [trunc(T/1000000)]),
+ [{offset,0}|Config]
+ end
+ end.
end_per_suite(Config) ->
ct_test_support:end_per_suite(Config).
diff --git a/lib/compiler/doc/src/compile.xml b/lib/compiler/doc/src/compile.xml
index 954750fcdd..61e214294e 100644
--- a/lib/compiler/doc/src/compile.xml
+++ b/lib/compiler/doc/src/compile.xml
@@ -40,6 +40,19 @@
<funcs>
<func>
+ <name>env_compiler_options()</name>
+ <fsummary>
+ Compiler options defined via the environment variable
+ <c>ERL_COMPILER_OPTIONS</c>
+ </fsummary>
+ <desc>
+ <p>Return compiler options given via the environment variable
+ <c>ERL_COMPILER_OPTIONS</c>. If the value is a list, it is
+ returned as is. If it is not a list, it is put into a list.
+ </p>
+ </desc>
+ </func>
+ <func>
<name>file(File)</name>
<fsummary>Compiles a file.</fsummary>
<desc>
@@ -768,6 +781,9 @@ module.beam: module.erl \
if you do not want the environment variable to be consulted,
for example, if you are calling the compiler recursively from
inside a parse transform.</p>
+
+ <p>The list can be retrieved with
+ <seealso marker="#env_compiler_options/0">env_compiler_options/0</seealso>.</p>
</section>
<section>
diff --git a/lib/compiler/src/beam_block.erl b/lib/compiler/src/beam_block.erl
index a8cfdffdf3..85d332c56e 100644
--- a/lib/compiler/src/beam_block.erl
+++ b/lib/compiler/src/beam_block.erl
@@ -262,12 +262,17 @@ opt_move_1(R, [{set,[D],[R],move}|Is0], Acc) ->
{yes,Is} -> opt_move_rev(D, Acc, Is);
no -> not_possible
end;
-opt_move_1({x,_}, [{set,_,_,{alloc,_,_}}|_], _) ->
- %% The optimization is not possible. If the X register is not
- %% killed by allocation, the optimization would not be safe.
- %% If the X register is killed, it means that there cannot
- %% follow a 'move' instruction with this X register as the
- %% source.
+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
diff --git a/lib/compiler/src/beam_validator.erl b/lib/compiler/src/beam_validator.erl
index 13aa31b7c9..4c0cb6780a 100644
--- a/lib/compiler/src/beam_validator.erl
+++ b/lib/compiler/src/beam_validator.erl
@@ -658,8 +658,10 @@ valfun_4({test,is_map,{f,Lbl},[Src]}, Vst0) ->
case Src of
{Tag,_} when Tag =:= x; Tag =:= y ->
set_type_reg(map, Src, Vst);
+ {literal,Map} when is_map(Map) ->
+ Vst;
_ ->
- Vst
+ kill_state(Vst)
end;
valfun_4({test,_Op,{f,Lbl},Src}, Vst) ->
validate_src(Src, Vst),
diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl
index 149086152a..82ff8a95f3 100644
--- a/lib/compiler/src/compile.erl
+++ b/lib/compiler/src/compile.erl
@@ -26,6 +26,7 @@
-export([forms/1,forms/2,noenv_forms/2]).
-export([output_generated/1,noenv_output_generated/1]).
-export([options/0]).
+-export([env_compiler_options/0]).
%% Erlc interface.
-export([compile/3,compile_beam/3,compile_asm/3,compile_core/3]).
@@ -131,6 +132,14 @@ noenv_output_generated(Opts) ->
end, Passes).
%%
+%% Retrieve ERL_COMPILER_OPTIONS as a list of terms
+%%
+
+-spec env_compiler_options() -> [term()].
+
+env_compiler_options() -> env_default_opts().
+
+%%
%% Local functions
%%
diff --git a/lib/compiler/src/rec_env.erl b/lib/compiler/src/rec_env.erl
index 936c5f6106..cdc513e57c 100644
--- a/lib/compiler/src/rec_env.erl
+++ b/lib/compiler/src/rec_env.erl
@@ -22,8 +22,7 @@
%% @doc Abstract environments, supporting self-referential bindings and
%% automatic new-key generation.
-%% The current implementation is based on Erlang standard library
-%% dictionaries.
+%% The current implementation is based on Erlang standard library maps.
%%% -define(DEBUG, true).
@@ -62,7 +61,7 @@ test_0(Type, N) ->
io:fwrite("\ncalls: ~w.\n", [get(new_key_calls)]),
io:fwrite("\nretries: ~w.\n", [get(new_key_retries)]),
io:fwrite("\nmax: ~w.\n", [get(new_key_max)]),
- dict:to_list(element(1,Env)).
+ maps:to_list(element(1,Env)).
test_1(integer = Type, N, Env) when is_integer(N), N > 0 ->
Key = new_key(Env),
@@ -80,14 +79,13 @@ test_1(_,0, Env) ->
%%
%% environment() = [Mapping]
%%
-%% Mapping = {map, Dict} | {rec, Dict, Dict}
-%% Dict = dict:dictionary()
+%% Mapping = {map, map()} | {rec, map(), map()}
%%
-%% An empty environment is a list containing a single `{map, Dict}'
+%% An empty environment is a list containing a single `{map, map()}'
%% element - empty lists are not valid environments. To find a key in an
%% environment, it is searched for in each mapping in the list, in
%% order, until it the key is found in some mapping, or the end of the
-%% list is reached. In a 'rec' mapping, we keep the original dictionary
+%% list is reached. In a 'rec' mapping, we keep the original map
%% together with a version where entries may have been deleted - this
%% makes it possible to garbage collect the entire 'rec' mapping when
%% all its entries are unused (for example, by being shadowed by later
@@ -97,7 +95,7 @@ test_1(_,0, Env) ->
%% =====================================================================
%% @type environment(). An abstract environment.
--type mapping() :: {'map', dict:dict()} | {'rec', dict:dict(), dict:dict()}.
+-type mapping() :: {'map', map()} | {'rec', map(), map()}.
-type environment() :: [mapping(),...].
%% =====================================================================
@@ -108,7 +106,7 @@ test_1(_,0, Env) ->
-spec empty() -> environment().
empty() ->
- [{map, dict:new()}].
+ [{map, #{}}].
%% =====================================================================
@@ -119,14 +117,14 @@ empty() ->
-spec is_empty(environment()) -> boolean().
-is_empty([{map, Dict} | Es]) ->
- N = dict:size(Dict),
+is_empty([{map, Map} | Es]) ->
+ N = map_size(Map),
if N =/= 0 -> false;
Es =:= [] -> true;
true -> is_empty(Es)
end;
-is_empty([{rec, Dict, _} | Es]) ->
- N = dict:size(Dict),
+is_empty([{rec, Map, _} | Es]) ->
+ N = map_size(Map),
if N =/= 0 -> false;
Es =:= [] -> true;
true -> is_empty(Es)
@@ -146,12 +144,12 @@ is_empty([{rec, Dict, _} | Es]) ->
size(Env) ->
env_size(Env).
-env_size([{map, Dict}]) ->
- dict:size(Dict);
-env_size([{map, Dict} | Env]) ->
- dict:size(Dict) + env_size(Env);
-env_size([{rec, Dict, _Dict0} | Env]) ->
- dict:size(Dict) + env_size(Env).
+env_size([{map, Map}]) ->
+ map_size(Map);
+env_size([{map, Map} | Env]) ->
+ map_size(Map) + env_size(Env);
+env_size([{rec, Map, _Map0} | Env]) ->
+ map_size(Map) + env_size(Env).
%% =====================================================================
@@ -165,8 +163,8 @@ env_size([{rec, Dict, _Dict0} | Env]) ->
-spec is_defined(term(), environment()) -> boolean().
-is_defined(Key, [{map, Dict} | Env]) ->
- case dict:is_key(Key, Dict) of
+is_defined(Key, [{map, Map} | Env]) ->
+ case maps:is_key(Key, Map) of
true ->
true;
false when Env =:= [] ->
@@ -174,8 +172,8 @@ is_defined(Key, [{map, Dict} | Env]) ->
false ->
is_defined(Key, Env)
end;
-is_defined(Key, [{rec, Dict, _Dict0} | Env]) ->
- dict:is_key(Key, Dict) orelse is_defined(Key, Env).
+is_defined(Key, [{rec, Map, _Map0} | Env]) ->
+ maps:is_key(Key, Map) orelse is_defined(Key, Env).
%% =====================================================================
@@ -188,12 +186,12 @@ is_defined(Key, [{rec, Dict, _Dict0} | Env]) ->
keys(Env) ->
lists:sort(keys(Env, [])).
-keys([{map, Dict}], S) ->
- dict:fetch_keys(Dict) ++ S;
-keys([{map, Dict} | Env], S) ->
- keys(Env, dict:fetch_keys(Dict) ++ S);
-keys([{rec, Dict, _Dict0} | Env], S) ->
- keys(Env, dict:fetch_keys(Dict) ++ S).
+keys([{map, Map}], S) ->
+ maps:keys(Map) ++ S;
+keys([{map, Map} | Env], S) ->
+ keys(Env, maps:keys(Map) ++ S);
+keys([{rec, Map, _Map0} | Env], S) ->
+ keys(Env, maps:keys(Map) ++ S).
%% =====================================================================
@@ -212,12 +210,12 @@ keys([{rec, Dict, _Dict0} | Env], S) ->
to_list(Env) ->
lists:sort(to_list(Env, [])).
-to_list([{map, Dict}], S) ->
- dict:to_list(Dict) ++ S;
-to_list([{map, Dict} | Env], S) ->
- to_list(Env, dict:to_list(Dict) ++ S);
-to_list([{rec, Dict, _Dict0} | Env], S) ->
- to_list(Env, dict:to_list(Dict) ++ S).
+to_list([{map, Map}], S) ->
+ maps:to_list(Map) ++ S;
+to_list([{map, Map} | Env], S) ->
+ to_list(Env, maps:to_list(Map) ++ S);
+to_list([{rec, Map, _Map0} | Env], S) ->
+ to_list(Env, maps:to_list(Map) ++ S).
%% =====================================================================
@@ -236,12 +234,12 @@ to_list([{rec, Dict, _Dict0} | Env], S) ->
-spec bind(term(), term(), environment()) -> environment().
-bind(Key, Value, [{map, Dict}]) ->
- [{map, dict:store(Key, Value, Dict)}];
-bind(Key, Value, [{map, Dict} | Env]) ->
- [{map, dict:store(Key, Value, Dict)} | delete_any(Key, Env)];
+bind(Key, Value, [{map, Map}]) ->
+ [{map, maps:put(Key, Value, Map)}];
+bind(Key, Value, [{map, Map} | Env]) ->
+ [{map, maps:put(Key, Value, Map)} | delete_any(Key, Env)];
bind(Key, Value, Env) ->
- [{map, dict:store(Key, Value, dict:new())} | delete_any(Key, Env)].
+ [{map, maps:put(Key, Value, #{})} | delete_any(Key, Env)].
%% =====================================================================
@@ -259,17 +257,17 @@ bind(Key, Value, Env) ->
-spec bind_list([term()], [term()], environment()) -> environment().
-bind_list(Ks, Vs, [{map, Dict}]) ->
- [{map, store_list(Ks, Vs, Dict)}];
-bind_list(Ks, Vs, [{map, Dict} | Env]) ->
- [{map, store_list(Ks, Vs, Dict)} | delete_list(Ks, Env)];
+bind_list(Ks, Vs, [{map, Map}]) ->
+ [{map, store_list(Ks, Vs, Map)}];
+bind_list(Ks, Vs, [{map, Map} | Env]) ->
+ [{map, store_list(Ks, Vs, Map)} | delete_list(Ks, Env)];
bind_list(Ks, Vs, Env) ->
- [{map, store_list(Ks, Vs, dict:new())} | delete_list(Ks, Env)].
+ [{map, store_list(Ks, Vs, #{})} | delete_list(Ks, Env)].
-store_list([K | Ks], [V | Vs], Dict) ->
- store_list(Ks, Vs, dict:store(K, V, Dict));
-store_list([], _, Dict) ->
- Dict.
+store_list([K | Ks], [V | Vs], Map) ->
+ store_list(Ks, Vs, maps:put(K, V, Map));
+store_list([], _, Map) ->
+ Map.
delete_list([K | Ks], Env) ->
delete_list(Ks, delete_any(K, Env));
@@ -298,48 +296,40 @@ delete_any(Key, Env) ->
-spec delete(term(), environment()) -> environment().
-delete(Key, [{map, Dict} = E | Env]) ->
- case dict:is_key(Key, Dict) of
- true ->
- [{map, dict:erase(Key, Dict)} | Env];
- false ->
+delete(Key, [{map, Map} = E | Env]) ->
+ case maps:take(Key, Map) of
+ {_, Map1} ->
+ [{map, Map1} | Env];
+ error ->
delete_1(Key, Env, E)
end;
-delete(Key, [{rec, Dict, Dict0} = E | Env]) ->
- case dict:is_key(Key, Dict) of
- true ->
- %% The Dict0 component must be preserved as it is until all
- %% keys in Dict have been deleted.
- Dict1 = dict:erase(Key, Dict),
- case dict:size(Dict1) of
- 0 ->
- Env; % the whole {rec,...} is now garbage
- _ ->
- [{rec, Dict1, Dict0} | Env]
- end;
- false ->
+delete(Key, [{rec, Map, Map0} = E | Env]) ->
+ case maps:take(Key, Map) of
+ {_, Map1} when map_size(Map1) =:= 0 ->
+ Env; % the whole {rec,...} is now garbage
+ %% The Map0 component must be preserved as it is until all
+ %% keys in Map have been deleted.
+ {_, Map1} ->
+ [{rec, Map1, Map0} | Env];
+ error ->
[E | delete(Key, Env)]
end.
%% This is just like above, except we pass on the preceding 'map'
%% mapping in the list to enable merging when removing 'rec' mappings.
-delete_1(Key, [{rec, Dict, Dict0} = E | Env], E1) ->
- case dict:is_key(Key, Dict) of
- true ->
- Dict1 = dict:erase(Key, Dict),
- case dict:size(Dict1) of
- 0 ->
- concat(E1, Env);
- _ ->
- [E1, {rec, Dict1, Dict0} | Env]
- end;
- false ->
+delete_1(Key, [{rec, Map, Map0} = E | Env], E1) ->
+ case maps:take(Key, Map) of
+ {_, Map1} when map_size(Map1) =:= 0 ->
+ concat(E1, Env);
+ {_, Map1} ->
+ [E1, {rec, Map1, Map0} | Env];
+ error ->
[E1, E | delete(Key, Env)]
end.
-concat({map, D1}, [{map, D2} | Env]) ->
- [dict:merge(fun (_K, V1, _V2) -> V1 end, D1, D2) | Env];
+concat({map, M1}, [{map, M2} | Env]) ->
+ [maps:merge(M2, M1) | Env];
concat(E1, Env) ->
[E1 | Env].
@@ -392,15 +382,15 @@ bind_recursive([], [], _, Env) ->
Env;
bind_recursive(Ks, Vs, F, Env) ->
F1 = fun (V) ->
- fun (Dict) -> F(V, [{rec, Dict, Dict} | Env]) end
+ fun (Map) -> F(V, [{rec, Map, Map} | Env]) end
end,
- Dict = bind_recursive_1(Ks, Vs, F1, dict:new()),
- [{rec, Dict, Dict} | Env].
+ Map = bind_recursive_1(Ks, Vs, F1, #{}),
+ [{rec, Map, Map} | Env].
-bind_recursive_1([K | Ks], [V | Vs], F, Dict) ->
- bind_recursive_1(Ks, Vs, F, dict:store(K, F(V), Dict));
-bind_recursive_1([], [], _, Dict) ->
- Dict.
+bind_recursive_1([K | Ks], [V | Vs], F, Map) ->
+ bind_recursive_1(Ks, Vs, F, maps:put(K, F(V), Map));
+bind_recursive_1([], [], _, Map) ->
+ Map.
%% =====================================================================
@@ -416,8 +406,8 @@ bind_recursive_1([], [], _, Dict) ->
-spec lookup(term(), environment()) -> 'error' | {'ok', term()}.
-lookup(Key, [{map, Dict} | Env]) ->
- case dict:find(Key, Dict) of
+lookup(Key, [{map, Map} | Env]) ->
+ case maps:find(Key, Map) of
{ok, _}=Value ->
Value;
error when Env =:= [] ->
@@ -425,10 +415,10 @@ lookup(Key, [{map, Dict} | Env]) ->
error ->
lookup(Key, Env)
end;
-lookup(Key, [{rec, Dict, Dict0} | Env]) ->
- case dict:find(Key, Dict) of
+lookup(Key, [{rec, Map, Map0} | Env]) ->
+ case maps:find(Key, Map) of
{ok, F} ->
- {ok, F(Dict0)};
+ {ok, F(Map0)};
error ->
lookup(Key, Env)
end.
diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl
index dbc27db377..e0de50f3ae 100644
--- a/lib/compiler/src/sys_core_fold.erl
+++ b/lib/compiler/src/sys_core_fold.erl
@@ -786,7 +786,7 @@ fold_lit_args(Call, Module, Name, Args0) ->
Val ->
case cerl:is_literal_term(Val) of
true ->
- cerl:abstract(Val);
+ cerl:ann_abstract(cerl:get_ann(Call), Val);
false ->
%% Successful evaluation, but it was not possible
%% to express the computed value as a literal.
@@ -2176,24 +2176,22 @@ opt_not_in_let_1(V, Call, Body) ->
#c_call{module=#c_literal{val=erlang},
name=#c_literal{val='not'},
args=[#c_var{name=V}]} ->
- opt_not_in_let_2(Body);
+ opt_not_in_let_2(Body, Call);
_ ->
no
end.
-opt_not_in_let_2(#c_case{clauses=Cs0}=Case) ->
+opt_not_in_let_2(#c_case{clauses=Cs0}=Case, NotCall) ->
Vars = make_vars([], 1),
- Body = #c_call{module=#c_literal{val=erlang},
- name=#c_literal{val='not'},
- args=Vars},
+ Body = NotCall#c_call{args=Vars},
Cs = [begin
Let = #c_let{vars=Vars,arg=B,body=Body},
C#c_clause{body=opt_not_in_let(Let)}
end || #c_clause{body=B}=C <- Cs0],
{yes,Case#c_case{clauses=Cs}};
-opt_not_in_let_2(#c_call{}=Call0) ->
+opt_not_in_let_2(#c_call{}=Call0, _NotCall) ->
invert_call(Call0);
-opt_not_in_let_2(_) -> no.
+opt_not_in_let_2(_, _) -> no.
invert_call(#c_call{module=#c_literal{val=erlang},
name=#c_literal{val=Name0},
diff --git a/lib/compiler/src/v3_codegen.erl b/lib/compiler/src/v3_codegen.erl
index f5f3c73793..4df1aadd0a 100644
--- a/lib/compiler/src/v3_codegen.erl
+++ b/lib/compiler/src/v3_codegen.erl
@@ -1551,12 +1551,10 @@ set_cg([{var,R}], {binary,Segs}, Le, Vdb, Bef, #cg{bfail=Bfail}=St) ->
%% 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,
- #cg{bfail=Bfail}=St) ->
- Fail = {f,Bfail},
- {Sis,Int0} = maybe_adjust_stack(Bef, Le#l.i, Le#l.i+1, Vdb, 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),
@@ -1570,21 +1568,16 @@ set_cg([{var,R}], {map,Op,Map,[{map_pair,{var,_}=K,V}]}, Le, Vdb, Bef,
Aft = Aft0#sr{reg=put_reg(R, Aft0#sr.reg)},
Target = fetch_reg(R, Aft#sr.reg),
- I = case Op of
- assoc -> put_map_assoc;
- exact -> put_map_exact
- end,
- {Sis++[Line]++[{I,Fail,SrcReg,Target,Live,{list,List}}],Aft,St};
+ {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,
- #cg{bfail=Bfail}=St) ->
+%% 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],
- Fail = {f,Bfail},
- {Sis,Int0} = maybe_adjust_stack(Bef, Le#l.i, Le#l.i+1, Vdb, St),
+ {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),
@@ -1599,11 +1592,10 @@ set_cg([{var,R}], {map,Op,Map,Es}, Le, Vdb, Bef,
Aft = Aft0#sr{reg=put_reg(R, Aft0#sr.reg)},
Target = fetch_reg(R, Aft#sr.reg),
- I = case Op of
- assoc -> put_map_assoc;
- exact -> put_map_exact
- end,
- {Sis++[Line]++[{I,Fail,SrcReg,Target,Live,{list,List}}],Aft,St};
+ {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)},
@@ -1616,6 +1608,34 @@ set_cg([{var,R}], Con, Le, Vdb, Bef, St) ->
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.
%%%
diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl
index a3b0236134..d71411de80 100644
--- a/lib/compiler/src/v3_core.erl
+++ b/lib/compiler/src/v3_core.erl
@@ -868,12 +868,16 @@ try_exception(Ecs0, St0) ->
{Evs,St1} = new_vars(3, St0), % Tag, Value, Info
{Ecs1,Ceps,St2} = clauses(Ecs0, St1),
[_,Value,Info] = Evs,
- Ec = #iclause{anno=#a{anno=[compiler_generated]},
+ LA = case Ecs1 of
+ [] -> [];
+ [C|_] -> get_lineno_anno(C)
+ end,
+ Ec = #iclause{anno=#a{anno=[compiler_generated|LA]},
pats=[c_tuple(Evs)],guard=[#c_literal{val=true}],
body=[#iprimop{anno=#a{}, %Must have an #a{}
name=#c_literal{val=raise},
args=[Info,Value]}]},
- Hs = [#icase{anno=#a{},args=[c_tuple(Evs)],clauses=Ecs1,fc=Ec}],
+ Hs = [#icase{anno=#a{anno=LA},args=[c_tuple(Evs)],clauses=Ecs1,fc=Ec}],
{Evs,Ceps++Hs,St2}.
try_after(As, St0) ->
@@ -2098,7 +2102,8 @@ upattern(#c_var{name=V}=Var, Ks, St0) ->
true ->
{N,St1} = new_var_name(St0),
New = #c_var{name=N},
- Test = #icall{anno=#a{us=add_element(N, [V])},
+ LA = get_lineno_anno(Var),
+ Test = #icall{anno=#a{anno=LA,us=add_element(N, [V])},
module=#c_literal{val=erlang},
name=#c_literal{val='=:='},
args=[New,Var]},
diff --git a/lib/compiler/test/beam_block_SUITE.erl b/lib/compiler/test/beam_block_SUITE.erl
index d343e26737..4bcb252833 100644
--- a/lib/compiler/test/beam_block_SUITE.erl
+++ b/lib/compiler/test/beam_block_SUITE.erl
@@ -21,7 +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,
- get_map_elements/1,otp_7345/1]).
+ get_map_elements/1,otp_7345/1,move_opt_across_gc_bif/1]).
%% The only test for the following functions is that
%% the code compiles and is accepted by beam_validator.
@@ -36,7 +36,8 @@ all() ->
groups() ->
[{p,[parallel],
[get_map_elements,
- otp_7345
+ otp_7345,
+ move_opt_across_gc_bif
]}].
init_per_suite(Config) ->
@@ -118,6 +119,22 @@ otp_7345(ObjRef, _RdEnv, Args) ->
10},
id(LlUnitdataReq).
+
+%% Doing move optimizations across GC bifs are in general not safe.
+move_opt_across_gc_bif(_Config) ->
+ [0,true,1] = positive(speaking),
+ ok.
+
+positive(speaking) ->
+ try
+ Positive = 0,
+ [+Positive, case Positive of _ -> true end, paris([], Positive)]
+ after
+ mailing
+ end.
+
+paris([], P) -> P + 1.
+
%%%
%%% The only test of the following code is that it compiles.
%%%
diff --git a/lib/compiler/test/compile_SUITE.erl b/lib/compiler/test/compile_SUITE.erl
index a15efc2a00..b0148f7103 100644
--- a/lib/compiler/test/compile_SUITE.erl
+++ b/lib/compiler/test/compile_SUITE.erl
@@ -34,7 +34,7 @@
cover/1, env/1, core/1,
core_roundtrip/1, asm/1,
sys_pre_attributes/1, dialyzer/1,
- warnings/1, pre_load_check/1
+ warnings/1, pre_load_check/1, env_compiler_options/1
]).
suite() -> [{ct_hooks,[ts_install_cth]}].
@@ -50,7 +50,8 @@ all() ->
other_output, encrypted_abstr,
strict_record,
cover, env, core, core_roundtrip, asm,
- sys_pre_attributes, dialyzer, warnings, pre_load_check].
+ sys_pre_attributes, dialyzer, warnings, pre_load_check,
+ env_compiler_options].
groups() ->
[].
@@ -1092,6 +1093,23 @@ compiler_modules() ->
FN = filename,
[list_to_atom(FN:rootname(FN:basename(M), ".beam")) || M <- Ms].
+%% Test that ERL_COMPILER_OPTIONS are correctly retrieved
+%% by env_compiler_options/0
+
+env_compiler_options(_Config) ->
+ Cases = [
+ {"bin_opt_info", [bin_opt_info]},
+ {"'S'", ['S']},
+ {"{source, \"test.erl\"}", [{source, "test.erl"}]},
+ {"[{d,macro_one,1},{d,macro_two}]", [{d, macro_one, 1}, {d, macro_two}]},
+ {"[warn_export_all, warn_export_vars]", [warn_export_all, warn_export_vars]}
+ ],
+ F = fun({Env, Expected}) ->
+ true = os:putenv("ERL_COMPILER_OPTIONS", Env),
+ Expected = compile:env_compiler_options()
+ end,
+ lists:foreach(F, Cases).
+
%%%
%%% Utilities.
%%%
diff --git a/lib/compiler/test/core_fold_SUITE.erl b/lib/compiler/test/core_fold_SUITE.erl
index 442b2d424c..376d2c8e9a 100644
--- a/lib/compiler/test/core_fold_SUITE.erl
+++ b/lib/compiler/test/core_fold_SUITE.erl
@@ -25,7 +25,8 @@
eq/1,nested_call_in_case/1,guard_try_catch/1,coverage/1,
unused_multiple_values_error/1,unused_multiple_values/1,
multiple_aliases/1,redundant_boolean_clauses/1,
- mixed_matching_clauses/1,unnecessary_building/1]).
+ mixed_matching_clauses/1,unnecessary_building/1,
+ no_no_file/1]).
-export([foo/0,foo/1,foo/2,foo/3]).
@@ -43,7 +44,8 @@ groups() ->
eq,nested_call_in_case,guard_try_catch,coverage,
unused_multiple_values_error,unused_multiple_values,
multiple_aliases,redundant_boolean_clauses,
- mixed_matching_clauses,unnecessary_building]}].
+ mixed_matching_clauses,unnecessary_building,
+ no_no_file]}].
init_per_suite(Config) ->
@@ -454,4 +456,47 @@ do_unnecessary_building_2({a,_,_}=T) ->
[_,_] = [T,none],
x}.
+%% This test tests that v3_core has provided annotations and that
+%% sys_core_fold retains them, so that warnings produced by
+%% sys_core_fold will have proper filenames and line numbers. Thus, no
+%% "no_file" warnings.
+no_no_file(_Config) ->
+ {'EXIT',{{case_clause,0},_}} = (catch source(true, any)),
+ surgery = (tim(#{reduction => any}))(),
+
+ false = soul(#{[] => true}),
+ {'EXIT',{{case_clause,true},_}} = (catch soul(#{[] => false})),
+
+ ok = experiment(),
+ ok.
+
+source(true, Activities) ->
+ case 0 of
+ Activities when [] ->
+ Activities
+ end.
+
+tim(#{reduction := Emergency}) ->
+ try
+ fun() -> surgery end
+ catch
+ _ when [] ->
+ planet
+ end.
+
+soul(#{[] := Properly}) ->
+ not case true of
+ Properly -> true;
+ Properly -> 0
+ end.
+
+experiment() ->
+ case kingdom of
+ _ ->
+ +case "map" of
+ _ -> 0.0
+ end
+ end,
+ ok.
+
id(I) -> I.
diff --git a/lib/compiler/test/map_SUITE.erl b/lib/compiler/test/map_SUITE.erl
index c3c4862794..36e82c1459 100644
--- a/lib/compiler/test/map_SUITE.erl
+++ b/lib/compiler/test/map_SUITE.erl
@@ -1287,6 +1287,7 @@ t_guard_update(Config) when is_list(Config) ->
first = map_guard_update(#{}, #{x=>first}),
second = map_guard_update(#{y=>old}, #{x=>second,y=>old}),
third = map_guard_update(#{x=>old,y=>old}, #{x=>third,y=>old}),
+ bad_map_guard_update(),
ok.
t_guard_update_large(Config) when is_list(Config) ->
@@ -1353,6 +1354,29 @@ map_guard_update(M1, M2) when M1#{x=>second} =:= M2 -> second;
map_guard_update(M1, M2) when M1#{x:=third} =:= M2 -> third;
map_guard_update(_, _) -> error.
+bad_map_guard_update() ->
+ do_bad_map_guard_update(fun burns/1),
+ do_bad_map_guard_update(fun turns/1),
+ ok.
+
+do_bad_map_guard_update(Fun) ->
+ do_bad_map_guard_update_1(Fun, #{}),
+ do_bad_map_guard_update_1(Fun, #{true=>1}),
+ ok.
+
+do_bad_map_guard_update_1(Fun, Value) ->
+ %% Note: The business with the seemingly redundant fun
+ %% disables inlining, which would otherwise change the
+ %% EXIT reason.
+ {'EXIT',{function_clause,_}} = (catch Fun(Value)),
+ ok.
+
+burns(Richmond) when not (Richmond#{true := 0}); [Richmond] ->
+ specification.
+
+turns(Richmond) when not (Richmond#{true => 0}); [Richmond] ->
+ specification.
+
t_guard_receive(Config) when is_list(Config) ->
M0 = #{ id => 0 },
Pid = spawn_link(fun() -> guard_receive_loop() end),
diff --git a/lib/compiler/test/misc_SUITE.erl b/lib/compiler/test/misc_SUITE.erl
index f05fe6c943..f543f0d4de 100644
--- a/lib/compiler/test/misc_SUITE.erl
+++ b/lib/compiler/test/misc_SUITE.erl
@@ -256,12 +256,15 @@ silly_coverage(Config) when is_list(Config) ->
{jump,{f,42}}]}],99},
expect_error(fun() -> beam_clean:module(CleanInput, []) end),
- %% beam_peep
+ %% 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.
PeepInput = {?MODULE,[{foo,0}],[],
[{function,foo,0,2,
[{label,1},
{func_info,{atom,?MODULE},{atom,foo},0},
- {label,2}|non_proper_list]}],99},
+ {label,2},{select,op,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
diff --git a/lib/debugger/src/dbg_debugged.erl b/lib/debugger/src/dbg_debugged.erl
index 5b1469a10e..e142af4ae0 100644
--- a/lib/debugger/src/dbg_debugged.erl
+++ b/lib/debugger/src/dbg_debugged.erl
@@ -70,7 +70,10 @@ msg_loop(Meta, Mref, SaveStacktrace) ->
%% Meta is evaluating a receive, must be done within context
%% of real (=this) process
{sys, Meta, {'receive',Msg}} ->
- receive Msg -> Meta ! {self(), rec_acked} end,
+ receive Msg ->
+ Meta ! {self(), rec_acked},
+ ok
+ end,
msg_loop(Meta, Mref, SaveStacktrace);
%% Meta needs something evaluated within context of real process
diff --git a/lib/debugger/src/dbg_icmd.erl b/lib/debugger/src/dbg_icmd.erl
index 1b274e20ae..57a3719a50 100644
--- a/lib/debugger/src/dbg_icmd.erl
+++ b/lib/debugger/src/dbg_icmd.erl
@@ -171,10 +171,10 @@ handle_cmd(Bs, Status, Ieval) ->
%% User control of process execution and settings
%%====================================================================
-step(Meta) -> Meta ! {user, {cmd, step}}.
-next(Meta) -> Meta ! {user, {cmd, next}}.
-continue(Meta) -> Meta ! {user, {cmd, continue}}.
-finish(Meta) -> Meta ! {user, {cmd, finish}}.
+step(Meta) -> Meta ! {user, {cmd, step}}, ok.
+next(Meta) -> Meta ! {user, {cmd, next}}, ok.
+continue(Meta) -> Meta ! {user, {cmd, continue}}, ok.
+finish(Meta) -> Meta ! {user, {cmd, finish}}, ok.
skip(Meta) -> Meta ! {user, {cmd, skip}}.
timeout(Meta) -> Meta ! {user, timeout}.
diff --git a/lib/debugger/src/dbg_iserver.erl b/lib/debugger/src/dbg_iserver.erl
index 0ad303d8d9..3561454685 100644
--- a/lib/debugger/src/dbg_iserver.erl
+++ b/lib/debugger/src/dbg_iserver.erl
@@ -72,17 +72,17 @@ cast(Int, Request) ->
gen_server:cast(Int, Request).
safe_call(Request) ->
- ensure_started(),
+ {ok, _} = ensure_started(),
call(Request).
safe_cast(Request) ->
- ensure_started(),
+ {ok, _} = ensure_started(),
cast(Request).
ensure_started() ->
case whereis(?MODULE) of
undefined -> start();
- _Pid -> ignore
+ Pid -> {ok, Pid}
end.
%%--Module database---------------------------------------------------
@@ -402,8 +402,10 @@ handle_cast({set_status, Meta, Status, Info}, State) ->
send_all(subscriber, {new_status, Proc#proc.pid, Status, Info}, State),
if
Status =:= break ->
- auto_attach(break, State#state.auto, Proc);
- true -> ignore
+ _ = auto_attach(break, State#state.auto, Proc),
+ ok;
+ true ->
+ ok
end,
Proc2 = Proc#proc{status=Status, info=Info},
{noreply, State#state{procs=lists:keyreplace(Meta, #proc.meta,
@@ -470,7 +472,7 @@ handle_info({'EXIT',Who,Why}, State) ->
[self(),AttPid,Pid,Why,ExitInfo]);
undefined ->
%% Otherwise, auto attach if necessary
- auto_attach(exit, State#state.auto, Pid),
+ _ = auto_attach(exit, State#state.auto, Pid),
Who
end,
send_all(subscriber, {new_status,Pid,exit,Why}, State),
@@ -583,7 +585,8 @@ send_all(Pids, Msg) ->
lists:foreach(fun(Pid) -> send(Pid, Msg) end, Pids).
send(Pid, Msg) ->
- Pid ! {int, Msg}.
+ Pid ! {int, Msg},
+ ok.
get_proc({Type, Pid}, Procs) ->
Index = case Type of
diff --git a/lib/debugger/src/dbg_wx_break_win.erl b/lib/debugger/src/dbg_wx_break_win.erl
index cd1e81456f..770681510d 100644
--- a/lib/debugger/src/dbg_wx_break_win.erl
+++ b/lib/debugger/src/dbg_wx_break_win.erl
@@ -65,18 +65,18 @@ create_win(Parent, Pos, function, Mod, _Line) ->
{choices, IntStrs}]),
Expand = [{border, 5}, {flag,?wxLEFT bor ?wxRIGHT bor ?wxEXPAND}],
- wxSizer:add(MainS, Label, [{border,5},
+ _ = wxSizer:add(MainS, Label, [{border,5},
{flag,?wxTOP bor ?wxLEFT bor ?wxRIGHT}]),
- wxSizer:add(MainS, Text, Expand),
+ _ = wxSizer:add(MainS, Text, Expand),
FunLabel = wxStaticText:new(Win, ?wxID_ANY, "Function:"),
LB = wxListBox:new(Win, ?wxID_ANY, [{size,{-1, 100}},{style,?wxLB_MULTIPLE}]),
- wxSizer:add(MainS, FunLabel, Expand),
- wxSizer:add(MainS, LB, [{proportion,1}|Expand]),
+ _ = wxSizer:add(MainS, FunLabel, Expand),
+ _ = wxSizer:add(MainS, LB, [{proportion,1}|Expand]),
wxSizer:setMinSize(MainS, 300, 400),
OK = wxDialog:createStdDialogButtonSizer(Win, ?wxOK bor ?wxCANCEL),
- wxSizer:add(MainS, OK, [{border,5},{flag,?wxALL}]),
+ _ = wxSizer:add(MainS, OK, [{border,5},{flag,?wxALL}]),
wxDialog:setSizer(Win,MainS),
- wxSizer:fit(MainS, Win),
+ _ = wxSizer:fit(MainS, Win),
wxSizer:setSizeHints(MainS,Win),
wxComboBox:setFocus(Text),
wxDialog:connect(Win, command_button_clicked),
@@ -110,11 +110,11 @@ create_win(Parent, Pos, Type, Mod, Line) ->
IntStrs = [atom_to_list(M) || M <- Int],
ModT = wxComboBox:new(Win, ?wxID_ANY, [{choices,IntStrs}]),
ModSz = create_label_of_control(Win, "Module:", ModT, Mod),
- wxSizer:add(MainS,ModSz,[{flag, ?wxEXPAND}]),
+ _ = wxSizer:add(MainS,ModSz,[{flag, ?wxEXPAND}]),
%% Create rest of text input fields
Add = fun({IType, Label, Def}) ->
{Sz, Text} = create_sizer_with_text(Win, Label, Def),
- wxSizer:add(MainS, Sz, [{flag, ?wxEXPAND}]),
+ _ = wxSizer:add(MainS, Sz, [{flag, ?wxEXPAND}]),
{Text, IType}
end,
Inputs = case Type of
@@ -129,15 +129,15 @@ create_win(Parent, Pos, Type, Mod, Line) ->
Entries = wx:map(Add, Inputs),
%% Create and add radio box
{TriggerBox,Trigger} = create_trigger_box(Win),
- wxSizer:add(MainS, TriggerBox, [{border,5},{flag,?wxALL bor ?wxEXPAND}]),
+ _ = wxSizer:add(MainS, TriggerBox, [{border,5},{flag,?wxALL bor ?wxEXPAND}]),
- wxSizer:addStretchSpacer(MainS),
+ _ = wxSizer:addStretchSpacer(MainS),
%% Put it together
OK = wxDialog:createStdDialogButtonSizer(Win, ?wxOK bor ?wxCANCEL),
- wxSizer:add(MainS, OK, [{border,5},{flag,?wxALL}]),
+ _ = wxSizer:add(MainS, OK, [{border,5},{flag,?wxALL}]),
wxSizer:setMinSize(MainS, 300, -1),
wxDialog:setSizer(Win,MainS),
- wxSizer:fit(MainS, Win),
+ _ = wxSizer:fit(MainS, Win),
wxSizer:setSizeHints(MainS,Win),
wxComboBox:setFocus(ModT),
wxDialog:connect(Win, command_button_clicked),
@@ -243,8 +243,8 @@ create_label_of_control(Parent, Label, Control, Def) ->
Text = wxStaticText:new(Parent, ?wxID_ANY, Label),
Border = {border, 5},
Flag = ?wxRIGHT bor ?wxLEFT bor ?wxALIGN_CENTRE_VERTICAL,
- wxSizer:add(Sizer, Text, [{proportion,1}, {flag,Flag}, Border]),
- wxSizer:add(Sizer, Control, [{proportion,3}, {flag,Flag bor ?wxEXPAND}, Border]),
+ _ = wxSizer:add(Sizer, Text, [{proportion,1}, {flag,Flag}, Border]),
+ _ = wxSizer:add(Sizer, Control, [{proportion,3}, {flag,Flag bor ?wxEXPAND}, Border]),
wxControl:setLabel(Control, dbg_wx_win:to_string(Def)),
Sizer.
@@ -252,11 +252,11 @@ create_trigger_box(Win) ->
SBox = wxStaticBox:new(Win, ?wxID_ANY, "Trigger Action:"),
SBS = wxStaticBoxSizer:new(SBox, ?wxVERTICAL),
Ebtn = wxRadioButton:new(Win, ?wxID_ANY, "Enable"),
- wxSizer:add(SBS,Ebtn),
+ _ = wxSizer:add(SBS,Ebtn),
Dibtn = wxRadioButton:new(Win, ?wxID_ANY, "Disable"),
- wxSizer:add(SBS,Dibtn),
+ _ = wxSizer:add(SBS,Dibtn),
Debtn = wxRadioButton:new(Win, ?wxID_ANY, "Delete"),
- wxSizer:add(SBS,Debtn),
+ _ = wxSizer:add(SBS,Debtn),
wxRadioButton:setValue(Ebtn, true),
{SBS, [{Ebtn,enable},{Dibtn,disable},{Debtn,delete}]}.
diff --git a/lib/debugger/src/dbg_wx_code.erl b/lib/debugger/src/dbg_wx_code.erl
index f8fc331a81..473963500a 100644
--- a/lib/debugger/src/dbg_wx_code.erl
+++ b/lib/debugger/src/dbg_wx_code.erl
@@ -127,20 +127,22 @@ load_code(Ed, Code) ->
%%io:format("~p ~p ~p~n", [Lines, Sz, LW]),
?stc:setMarginWidth(Ed, 0, LW+5),
?stc:setReadOnly(Ed, true),
- Ed.
+ ok.
unload_code(Ed) ->
?stc:setReadOnly(Ed, false),
?stc:setTextRaw(Ed, <<0:8>>),
?stc:setReadOnly(Ed, true),
- Ed.
+ ok.
add_break_to_code(Ed, Line, active) ->
?stc:markerDelete(Ed, Line-1, 1),
- ?stc:markerAdd(Ed, Line-1, 0);
+ ?stc:markerAdd(Ed, Line-1, 0),
+ ok;
add_break_to_code(Ed, Line, inactive) ->
?stc:markerDelete(Ed, Line-1, 0),
- ?stc:markerAdd(Ed, Line-1, 1).
+ ?stc:markerAdd(Ed, Line-1, 1),
+ ok.
del_break_from_code(Ed,Line) ->
?stc:markerDelete(Ed, Line-1, 0),
diff --git a/lib/debugger/src/dbg_wx_filedialog_win.erl b/lib/debugger/src/dbg_wx_filedialog_win.erl
index 2103536a04..f7b031dc28 100644
--- a/lib/debugger/src/dbg_wx_filedialog_win.erl
+++ b/lib/debugger/src/dbg_wx_filedialog_win.erl
@@ -118,9 +118,9 @@ init([Parent, Id, Options0]) ->
wxTextCtrl:connect(Dir, char, [{callback, IsTab}]),
Top = wxBoxSizer:new(?wxHORIZONTAL),
- wxSizer:add(Top, Back, [{border, 2},{flag,?wxALL bor ?wxEXPAND}]),
- wxSizer:add(Top, Forw, [{border, 2},{flag,?wxALL bor ?wxEXPAND}]),
- wxSizer:add(Top, Up, [{border, 2},{flag,?wxALL bor ?wxEXPAND}]),
+ _ = wxSizer:add(Top, Back, [{border, 2},{flag,?wxALL bor ?wxEXPAND}]),
+ _ = wxSizer:add(Top, Forw, [{border, 2},{flag,?wxALL bor ?wxEXPAND}]),
+ _ = wxSizer:add(Top, Up, [{border, 2},{flag,?wxALL bor ?wxEXPAND}]),
%% List Ctrl
{Art, IconMap} = create_icons(ExtraIcons),
@@ -154,13 +154,13 @@ init([Parent, Id, Options0]) ->
%% OK done
Box = wxBoxSizer:new(?wxVERTICAL),
- wxSizer:add(Box, Top, [{border, 2}, {flag,?wxALL bor ?wxEXPAND}]),
- wxSizer:add(Box, Dir, [{border, 2}, {flag,?wxALL bor ?wxEXPAND}]),
- wxSizer:add(Box, LC, [{border, 2}, {flag,?wxALL bor ?wxEXPAND}, {proportion, 1}]),
- wxSizer:add(Box, Bott, [{border, 2}, {flag,?wxALL bor ?wxEXPAND}]),
+ _ = wxSizer:add(Box, Top, [{border, 2}, {flag,?wxALL bor ?wxEXPAND}]),
+ _ = wxSizer:add(Box, Dir, [{border, 2}, {flag,?wxALL bor ?wxEXPAND}]),
+ _ = wxSizer:add(Box, LC, [{border, 2}, {flag,?wxALL bor ?wxEXPAND}, {proportion, 1}]),
+ _ = wxSizer:add(Box, Bott, [{border, 2}, {flag,?wxALL bor ?wxEXPAND}]),
wxWindow:setSizer(Dlg, Box),
- wxSizer:fit(Box, Dlg),
+ _ = wxSizer:fit(Box, Dlg),
wxSizer:setSizeHints(Box,Dlg),
State = #state{win=Dlg,
back=Back, forward=Forw, up=Up,
diff --git a/lib/debugger/src/dbg_wx_mon.erl b/lib/debugger/src/dbg_wx_mon.erl
index 345367a911..a32a6894b8 100644
--- a/lib/debugger/src/dbg_wx_mon.erl
+++ b/lib/debugger/src/dbg_wx_mon.erl
@@ -135,7 +135,7 @@ init2(CallingPid, Mode, SFile, GS) ->
%% Start other necessary stuff
dbg_wx_win:init(),
- dbg_wx_winman:start(), % Debugger window manager
+ _ = dbg_wx_winman:start(), % Debugger window manager
%% Create monitor window
Title = "Monitor",
@@ -339,7 +339,7 @@ gui_cmd('Delete All Modules', State) ->
lists:foreach(fun(Mod) -> int:nn(Mod) end, int:interpreted()),
State;
gui_cmd({module, Mod, What}, State) ->
- case What of
+ _ = case What of
delete -> int:nn(Mod);
view ->
Window = dbg_wx_mon_win:get_window(State#state.win),
diff --git a/lib/debugger/src/dbg_wx_mon_win.erl b/lib/debugger/src/dbg_wx_mon_win.erl
index 2e48210f55..9737c9e67f 100644
--- a/lib/debugger/src/dbg_wx_mon_win.erl
+++ b/lib/debugger/src/dbg_wx_mon_win.erl
@@ -107,31 +107,31 @@ create_win_batch(Title, Menus) ->
Hlb = 200,
Listbox = wxListBox:new(Panel, ?wxID_ANY, [{size,{?Wf,Hlb}},
{style,?wxLB_SINGLE}]),
- wxSizer:add(LeftSz,Listbox,[{proportion,1},{border,3},{flag,?wxEXPAND}]),
+ _ = wxSizer:add(LeftSz,Listbox,[{proportion,1},{border,3},{flag,?wxEXPAND}]),
wxListBox:connect(Listbox, command_listbox_doubleclicked),
wxListBox:connect(Listbox, right_down),
SBox = wxStaticBox:new(Panel, ?wxID_ANY, "Auto Attach:"),
SBS = wxStaticBoxSizer:new(SBox, ?wxVERTICAL),
Fbtn = wxCheckBox:new(Panel, ?autoId, "First Call"),
- wxSizer:add(SBS,Fbtn),
+ _ = wxSizer:add(SBS,Fbtn),
Bbtn = wxCheckBox:new(Panel, ?autoId, "On Break"),
- wxSizer:add(SBS,Bbtn),
+ _ = wxSizer:add(SBS,Bbtn),
Ebtn = wxCheckBox:new(Panel, ?autoId, "On Exit"),
- wxSizer:add(SBS,Ebtn),
+ _ = wxSizer:add(SBS,Ebtn),
wxFrame:connect(Panel, command_checkbox_clicked),
- wxSizer:add(LeftSz,SBS, [{flag,?wxEXPAND}]),
+ _ = wxSizer:add(LeftSz,SBS, [{flag,?wxEXPAND}]),
SLabel = wxStaticText:new(Panel, ?wxID_ANY, "Stack Trace:\n On (with tail)"),
- wxSizer:add(LeftSz,SLabel),
+ _ = wxSizer:add(LeftSz,SLabel),
BLabel = wxStaticText:new(Panel, ?wxID_ANY, "Back Trace Size:\n 50000"),
- wxSizer:add(LeftSz,BLabel),
+ _ = wxSizer:add(LeftSz,BLabel),
StringsBox = wxStaticBox:new(Panel, ?wxID_ANY, "Strings:"),
StringsBS = wxStaticBoxSizer:new(StringsBox, ?wxVERTICAL),
Stringsbtn = wxCheckBox:new(Panel, ?stringsId, ?STRTEXT),
- wxSizer:add(StringsBS,Stringsbtn),
- wxSizer:add(LeftSz,StringsBS, [{flag,?wxEXPAND}]),
+ _ = wxSizer:add(StringsBS,Stringsbtn),
+ _ = wxSizer:add(LeftSz,StringsBS, [{flag,?wxEXPAND}]),
%% Create list_crtl / grid
Grid = wxListCtrl:new(Panel, [{winid, ?GRID},
@@ -169,12 +169,12 @@ create_win_batch(Title, Menus) ->
wxWindow:setFocus(Grid),
%% Put it in the window
- wxSizer:add(MainSz, LeftSz, [{border, 3}, {flag,?wxALL bor ?wxEXPAND}]),
- wxSizer:add(MainSz, Grid, [{border, 3}, {flag,?wxALL bor ?wxEXPAND},
+ _ = wxSizer:add(MainSz, LeftSz, [{border, 3}, {flag,?wxALL bor ?wxEXPAND}]),
+ _ = wxSizer:add(MainSz, Grid, [{border, 3}, {flag,?wxALL bor ?wxEXPAND},
{proportion, 1}]),
wxWindow:setSizer(Panel,MainSz),
- wxSizer:fit(MainSz, Win),
+ _ = wxSizer:fit(MainSz, Win),
wxSizer:setSizeHints(MainSz,Win),
IconFile = dbg_wx_win:find_icon("erlang_bug.png"),
diff --git a/lib/debugger/src/dbg_wx_src_view.erl b/lib/debugger/src/dbg_wx_src_view.erl
index 571c6b01bb..207c407fbc 100644
--- a/lib/debugger/src/dbg_wx_src_view.erl
+++ b/lib/debugger/src/dbg_wx_src_view.erl
@@ -56,7 +56,7 @@ code_area(Parent, Sizer) ->
end,
[SetStyle(Style) || Style <- Styles],
?stc:setKeyWords(Ed, 0, keyWords()),
- wxSizer:add(Sizer, Ed, [{proportion,1}, {flag, ?wxEXPAND}]),
+ _ = wxSizer:add(Sizer, Ed, [{proportion,1}, {flag, ?wxEXPAND}]),
Ed.
diff --git a/lib/debugger/src/dbg_wx_trace.erl b/lib/debugger/src/dbg_wx_trace.erl
index f9c60f9b72..6af19af33b 100644
--- a/lib/debugger/src/dbg_wx_trace.erl
+++ b/lib/debugger/src/dbg_wx_trace.erl
@@ -321,7 +321,7 @@ gui_cmd('Kill', State) ->
exit(State#state.pid, kill),
State;
gui_cmd('Messages', State) ->
- case int:meta(State#state.meta, messages) of
+ _ = case int:meta(State#state.meta, messages) of
[] ->
dbg_wx_trace_win:eval_output(State#state.win,"< No Messages!\n", bold);
Messages ->
diff --git a/lib/debugger/src/dbg_wx_trace_win.erl b/lib/debugger/src/dbg_wx_trace_win.erl
index 51687ad4e9..972a917728 100644
--- a/lib/debugger/src/dbg_wx_trace_win.erl
+++ b/lib/debugger/src/dbg_wx_trace_win.erl
@@ -123,7 +123,8 @@
%% GS = term()
%%--------------------------------------------------------------------
init() ->
- dbg_wx_win:init().
+ _ = dbg_wx_win:init(),
+ ok.
stop(#winInfo{window=Win}) ->
(catch wxFrame:destroy(Win)),
@@ -149,29 +150,29 @@ create_win(Parent, Title, Windows, Menus) ->
Sizer = wxBoxSizer:new(?wxVERTICAL),
Code = code_area(Panel),
- wxSizer:add(Sizer, Code#sub.win,
+ _ = wxSizer:add(Sizer, Code#sub.win,
[{proportion,1}, {border, 2},
{flag, ?wxEXPAND bor ?wxDOWN}]),
wxSizer:setVirtualSizeHints(Sizer, Code#sub.win),
ExpandWithBorder = [{border, 3},{flag,?wxEXPAND bor ?wxALL}],
Search = search_area(Panel),
- wxSizer:add(Sizer, Search#sub.win, ExpandWithBorder),
+ _ = wxSizer:add(Sizer, Search#sub.win, ExpandWithBorder),
Bs = button_area(Panel),
- wxSizer:add(Sizer, Bs#sub.win, ExpandWithBorder),
+ _ = wxSizer:add(Sizer, Bs#sub.win, ExpandWithBorder),
InfoArea = wxBoxSizer:new(?wxHORIZONTAL),
wxSizer:setMinSize(InfoArea, {100, ?EVAL_H}),
Eval = eval_area(Panel),
- wxSizer:add(InfoArea, Eval#sub.win, [{proportion,1},{flag,?wxEXPAND}]),
+ _ = wxSizer:add(InfoArea, Eval#sub.win, [{proportion,1},{flag,?wxEXPAND}]),
Bind = bind_area(Panel),
- wxSizer:add(InfoArea, Bind#sub.win,
+ _ = wxSizer:add(InfoArea, Bind#sub.win,
[{proportion,1},{border, 2},
{flag,?wxEXPAND bor ?wxLEFT}]),
- wxSizer:add(Sizer, InfoArea, ExpandWithBorder),
+ _ = wxSizer:add(Sizer, InfoArea, ExpandWithBorder),
Trace = trace_area(Panel),
- wxSizer:add(Sizer, Trace#sub.win, ExpandWithBorder),
+ _ = wxSizer:add(Sizer, Trace#sub.win, ExpandWithBorder),
SB = wxFrame:createStatusBar(Win,[]),
%% Note id and lastId to get the event when it dragged is complete
@@ -192,7 +193,7 @@ create_win(Parent, Title, Windows, Menus) ->
Wi = show_windows(enable_windows(Wi0,Windows)),
wxWindow:setSizer(Panel, Sizer),
- wxSizer:fit(Sizer, Win),
+ _ = wxSizer:fit(Sizer, Win),
wxSizer:setSizeHints(Sizer,Win),
IconFile = dbg_wx_win:find_icon("erlang_bug.png"),
@@ -230,11 +231,11 @@ get_window(WinInfo) ->
%%--------------------------------------------------------------------
configure(Wi=#winInfo{window=Win,m_szr={Panel,Sizer}}) ->
wx:batch(fun() ->
- show_windows(Wi),
+ _ = show_windows(Wi),
wxSizer:layout(Sizer),
%%wxWindow:setSizerAndFit(Panel,Sizer),
wxWindow:setSizer(Panel, Sizer),
- wxSizer:fit(Sizer, Win),
+ _ = wxSizer:fit(Sizer, Win),
wxSizer:setSizeHints(Sizer,Win),
Wi
end).
@@ -242,10 +243,10 @@ configure(Wi=#winInfo{window=Win,m_szr={Panel,Sizer}}) ->
configure(Wi0=#winInfo{window=Win,m_szr={Panel,Sizer}}, Windows) ->
wx:batch(fun() ->
Wi = enable_windows(Wi0, Windows),
- show_windows(Wi),
+ _ = show_windows(Wi),
wxSizer:layout(Sizer),
wxWindow:setSizer(Panel, Sizer),
- wxSizer:fit(Sizer, Win),
+ _ = wxSizer:fit(Sizer, Win),
wxSizer:setSizeHints(Sizer,Win),
Wi
end).
@@ -348,7 +349,7 @@ add_break(WinInfo, Menu, {{Mod,Line},[Status|_Options]}=Break) ->
case WinInfo#winInfo.editor of
{Mod, Editor} ->
dbg_wx_code:add_break_to_code(Editor, Line, Status);
- _ -> ignore
+ _ -> ok
end,
add_break_to_menu(WinInfo, Menu, Break).
@@ -372,7 +373,7 @@ update_break(WinInfo, {{Mod,Line},[Status|_Options]}=Break) ->
case WinInfo#winInfo.editor of
{Mod, Editor} ->
dbg_wx_code:add_break_to_code(Editor, Line, Status);
- _ -> ignore
+ _ -> ok
end,
update_break_in_menu(WinInfo, Break).
@@ -929,7 +930,7 @@ button_area(Parent) ->
B=wxButton:new(Parent, Button,
[{label,dbg_wx_win:to_string(Name)}]),
Id = wxWindow:getId(B),
- wxSizer:add(Sz,B, []),
+ _ = wxSizer:add(Sz,B, []),
wxButton:connect(B, command_button_clicked, [{id,Id}])
end, buttons()),
#sub{name='Button Area', win=Sz}.
@@ -938,22 +939,22 @@ button_area(Parent) ->
search_area(Parent) ->
HSz = wxBoxSizer:new(?wxHORIZONTAL),
- wxSizer:add(HSz, wxStaticText:new(Parent, ?wxID_ANY, "Find:"),
+ _ = wxSizer:add(HSz, wxStaticText:new(Parent, ?wxID_ANY, "Find:"),
[{flag,?wxALIGN_CENTER_VERTICAL}]),
TC1 = wxTextCtrl:new(Parent, ?SEARCH_ENTRY, [{style, ?wxTE_PROCESS_ENTER}]),
- wxSizer:add(HSz, TC1, [{proportion,3}, {flag, ?wxEXPAND}]),
+ _ = wxSizer:add(HSz, TC1, [{proportion,3}, {flag, ?wxEXPAND}]),
Nbtn = wxRadioButton:new(Parent, ?wxID_ANY, "Next"),
wxRadioButton:setValue(Nbtn, true),
- wxSizer:add(HSz,Nbtn,[{flag,?wxALIGN_CENTER_VERTICAL}]),
+ _ = wxSizer:add(HSz,Nbtn,[{flag,?wxALIGN_CENTER_VERTICAL}]),
Pbtn = wxRadioButton:new(Parent, ?wxID_ANY, "Previous"),
- wxSizer:add(HSz,Pbtn,[{flag,?wxALIGN_CENTER_VERTICAL}]),
+ _ = wxSizer:add(HSz,Pbtn,[{flag,?wxALIGN_CENTER_VERTICAL}]),
Cbtn = wxCheckBox:new(Parent, ?wxID_ANY, "Match Case"),
- wxSizer:add(HSz,Cbtn,[{flag,?wxALIGN_CENTER_VERTICAL}]),
- wxSizer:add(HSz, 15,15, [{proportion,1}, {flag, ?wxEXPAND}]),
- wxSizer:add(HSz, wxStaticText:new(Parent, ?wxID_ANY, "Goto Line:"),
+ _ = wxSizer:add(HSz,Cbtn,[{flag,?wxALIGN_CENTER_VERTICAL}]),
+ _ = wxSizer:add(HSz, 15,15, [{proportion,1}, {flag, ?wxEXPAND}]),
+ _ = wxSizer:add(HSz, wxStaticText:new(Parent, ?wxID_ANY, "Goto Line:"),
[{flag,?wxALIGN_CENTER_VERTICAL}]),
TC2 = wxTextCtrl:new(Parent, ?GOTO_ENTRY, [{style, ?wxTE_PROCESS_ENTER}]),
- wxSizer:add(HSz, TC2, [{proportion,0}, {flag, ?wxEXPAND}]),
+ _ = wxSizer:add(HSz, TC2, [{proportion,0}, {flag, ?wxEXPAND}]),
wxTextCtrl:connect(TC1, command_text_updated),
wxTextCtrl:connect(TC1, command_text_enter),
wxTextCtrl:connect(TC1, kill_focus),
@@ -969,14 +970,14 @@ eval_area(Parent) ->
VSz = wxBoxSizer:new(?wxVERTICAL),
HSz = wxBoxSizer:new(?wxHORIZONTAL),
- wxSizer:add(HSz, wxStaticText:new(Parent, ?wxID_ANY, "Evaluator:"),
+ _ = wxSizer:add(HSz, wxStaticText:new(Parent, ?wxID_ANY, "Evaluator:"),
[{flag,?wxALIGN_CENTER_VERTICAL}]),
TC = wxTextCtrl:new(Parent, ?EVAL_ENTRY, [{style, ?wxTE_PROCESS_ENTER}]),
- wxSizer:add(HSz, TC, [{proportion,1}, {flag, ?wxEXPAND}]),
- wxSizer:add(VSz, HSz, [{flag, ?wxEXPAND}]),
+ _ = wxSizer:add(HSz, TC, [{proportion,1}, {flag, ?wxEXPAND}]),
+ _ = wxSizer:add(VSz, HSz, [{flag, ?wxEXPAND}]),
TL = wxTextCtrl:new(Parent, ?EVAL_LOG, [{style, ?wxTE_DONTWRAP bor
?wxTE_MULTILINE bor ?wxTE_READONLY}]),
- wxSizer:add(VSz, TL, [{proportion,5}, {flag, ?wxEXPAND}]),
+ _ = wxSizer:add(VSz, TL, [{proportion,5}, {flag, ?wxEXPAND}]),
wxTextCtrl:connect(TC, command_text_enter),
#sub{name='Evaluator Area', win=VSz, in=TC, out=TL}.
diff --git a/lib/debugger/src/dbg_wx_win.erl b/lib/debugger/src/dbg_wx_win.erl
index 1ff8818bbe..25ffc5054c 100644
--- a/lib/debugger/src/dbg_wx_win.erl
+++ b/lib/debugger/src/dbg_wx_win.erl
@@ -43,7 +43,8 @@
%% GS = term()
%%--------------------------------------------------------------------
init() ->
- wx:new().
+ _ = wx:new(),
+ ok.
%%--------------------------------------------------------------------
%% create_menus(MenuBar, [Menu])
@@ -80,12 +81,12 @@ create_menus(_MB,[], _Win,Id) ->
Id.
create_menu_item(Menu, [separator|Is], Win, Id,Connect) ->
- wxMenu:appendSeparator(Menu),
+ _ = wxMenu:appendSeparator(Menu),
create_menu_item(Menu,Is,Win,Id+1,Connect);
create_menu_item(Menu, [{Name, _N, cascade, Items}|Is], Win, Id0,Connect) ->
Sub = wxMenu:new([]),
Id = create_menu_item(Sub, Items, Win, Id0, false),
- wxMenu:append(Menu, ?wxID_ANY, menu_name(Name,ignore), Sub),
+ _ = wxMenu:append(Menu, ?wxID_ANY, menu_name(Name,ignore), Sub),
%% Simulate GS sub checkBox/RadioBox behaviour
Self = self(),
Butts = [{MI,get(MI)} || {MI,_,_} <- Items],
@@ -99,8 +100,8 @@ create_menu_item(Menu, [{Name, _N, cascade, Items}|Is], Win, Id0,Connect) ->
Enabled = lists:foldl(IsChecked, [], Butts),
Self ! Ev#wx{userData={Name, Enabled}}
end,
- wxMenu:connect(Win, command_menu_selected,
- [{id,Id0},{lastId, Id-1},{callback,Filter}]),
+ _ = wxMenu:connect(Win, command_menu_selected,
+ [{id,Id0},{lastId, Id-1},{callback,Filter}]),
create_menu_item(Menu, Is, Win, Id, Connect);
create_menu_item(Menu, [{Name,Pos}|Is], Win, Id, Connect) ->
MenuId = case lists:member(Name, ['Debugger']) of
@@ -168,7 +169,7 @@ add_break(Win, MenuName, Point) ->
Delete = wxMenu:appendRadioItem(Trigger, ?wxID_ANY,"Delete"),
Add(Delete, {break,Point,{trigger,delete}}),
- wxMenu:append(Sub, ?wxID_ANY, "Trigger Action", Trigger),
+ _ = wxMenu:append(Sub, ?wxID_ANY, "Trigger Action", Trigger),
MenuBtn = wxMenu:append(Menu,?wxID_ANY, Label, Sub),
#break{mb={Menu,MenuBtn},
diff --git a/lib/debugger/src/dbg_wx_winman.erl b/lib/debugger/src/dbg_wx_winman.erl
index efa58ae325..ca858fa4bb 100644
--- a/lib/debugger/src/dbg_wx_winman.erl
+++ b/lib/debugger/src/dbg_wx_winman.erl
@@ -100,11 +100,11 @@ update_windows_menu(Win, [MonInfo|Infos]) ->
OldItems = wxMenu:getMenuItems(Menu),
[wxMenu:delete(Menu, Item) || Item <- OldItems],
menuitem(Win, Menu,MonInfo, 700),
- wxMenu:appendSeparator(Menu),
+ _ = wxMenu:appendSeparator(Menu),
wx:foldl(fun(Info,Acc) -> menuitem(Win,Menu,Info,Acc) end, 701, Infos).
menuitem(Window, Menu, {Title, Win}, Id) ->
- wxMenu:append(Menu, Id, Title),
+ _ = wxMenu:append(Menu, Id, Title),
wxWindow:connect(Window, command_menu_selected,
[{id,Id},{userData,{dbg_ui_winman,Win}}]),
Id+1.
diff --git a/lib/debugger/src/i.erl b/lib/debugger/src/i.erl
index 4ed5265bdf..2da3e77618 100644
--- a/lib/debugger/src/i.erl
+++ b/lib/debugger/src/i.erl
@@ -108,7 +108,7 @@ ib(Module,Function,Arity) ->
ib(Module,Function,Arity,Cond) ->
Breaks1 = int:all_breaks(Module),
- int:break_in(Module,Function,Arity),
+ ok = int:break_in(Module,Function,Arity),
Breaks2 = int:all_breaks(Module),
lists:foreach(fun({Mod,Line}) -> int:test_at_break(Mod,Line,Cond) end,
Breaks2--Breaks1).
diff --git a/lib/debugger/src/int.erl b/lib/debugger/src/int.erl
index 3906c22afd..e5bade9abe 100644
--- a/lib/debugger/src/int.erl
+++ b/lib/debugger/src/int.erl
@@ -352,10 +352,10 @@ start() -> dbg_iserver:start().
stop() ->
lists:foreach(
fun(Mod) ->
- everywhere(distributed,
- fun() ->
+ _ = everywhere(distributed,
+ fun() ->
erts_debug:breakpoint({Mod,'_','_'}, false)
- end)
+ end)
end,
interpreted()),
dbg_iserver:stop().
@@ -524,21 +524,21 @@ check(Mod) when is_atom(Mod) -> catch check_module(Mod);
check(File) when is_list(File) -> catch check_file(File).
load({Mod, Src, Beam, BeamBin, Exp, Abst}, Dist) ->
- everywhere(Dist,
- fun() ->
+ _ = everywhere(Dist,
+ fun() ->
code:purge(Mod),
erts_debug:breakpoint({Mod,'_','_'}, false),
{module,Mod} = code:load_binary(Mod, Beam, BeamBin)
- end),
+ end),
case erl_prim_loader:get_file(filename:absname(Src)) of
{ok, SrcBin, _} ->
MD5 = code:module_md5(BeamBin),
Bin = term_to_binary({interpreter_module,Exp,Abst,SrcBin,MD5}),
{module, Mod} = dbg_iserver:safe_call({load, Mod, Src, Bin}),
- everywhere(Dist,
- fun() ->
+ _ = everywhere(Dist,
+ fun() ->
true = erts_debug:breakpoint({Mod,'_','_'}, true) > 0
- end),
+ end),
{module, Mod};
error ->
error
@@ -738,9 +738,9 @@ del_mod(AbsMod, Dist) ->
list_to_atom(filename:basename(AbsMod,".erl"))
end,
dbg_iserver:safe_cast({delete, Mod}),
- everywhere(Dist,
- fun() ->
+ _ = everywhere(Dist,
+ fun() ->
erts_debug:breakpoint({Mod,'_','_'}, false),
erlang:yield()
- end),
+ end),
ok.
diff --git a/lib/dialyzer/src/dialyzer_contracts.erl b/lib/dialyzer/src/dialyzer_contracts.erl
index d1ffa07706..272ad10e90 100644
--- a/lib/dialyzer/src/dialyzer_contracts.erl
+++ b/lib/dialyzer/src/dialyzer_contracts.erl
@@ -591,10 +591,13 @@ remove_uses([{Var, Use}|ToRemove], Constrs0) ->
remove_uses(_Var, _Use, []) -> [];
remove_uses(Var, Use, [Constr|Constrs]) ->
{V, Form} = Constr,
- case erl_types:t_var_name(V) =:= Var of
- true -> [{V, remove_use(Form, Use)}|Constrs];
- false -> [Constr|remove_uses(Var, Use, Constrs)]
- end.
+ NewConstr = case erl_types:t_var_name(V) =:= Var of
+ true ->
+ {V, remove_use(Form, Use)};
+ false ->
+ Constr
+ end,
+ [NewConstr|remove_uses(Var, Use, Constrs)].
remove_use({var, L, V}, V) -> {var, L, '_'};
remove_use(T, V) when is_tuple(T) ->
diff --git a/lib/dialyzer/src/dialyzer_dataflow.erl b/lib/dialyzer/src/dialyzer_dataflow.erl
index 5ab0c39c04..3349b12932 100644
--- a/lib/dialyzer/src/dialyzer_dataflow.erl
+++ b/lib/dialyzer/src/dialyzer_dataflow.erl
@@ -430,17 +430,35 @@ handle_apply(Tree, Map, State) ->
handle_apply_or_call(FunInfoList, Args, ArgTypes, Map, Tree, State) ->
None = t_none(),
+ %% Call-site analysis may be inaccurate and consider more funs than those that
+ %% are actually possible. If all of them are incorrect, then warnings can be
+ %% emitted. If at least one fun is ok, however, then no warning is emitted,
+ %% just in case the bad ones are not really possible. The last argument is
+ %% used for this, with the following encoding:
+ %% Initial value: {none, []}
+ %% First fun checked: {one, <List of warns>}
+ %% More funs checked: {many, <List of warns>}
+ %% A '{one, []}' can only become '{many, []}'.
+ %% If at any point an fun does not add warnings, then the list is also
+ %% replaced with an empty list.
handle_apply_or_call(FunInfoList, Args, ArgTypes, Map, Tree, State,
- [None || _ <- ArgTypes], None, false).
+ [None || _ <- ArgTypes], None, false, {none, []}).
handle_apply_or_call([{local, external}|Left], Args, ArgTypes, Map, Tree, State,
- _AccArgTypes, _AccRet, _HadExternal) ->
+ _AccArgTypes, _AccRet, _HadExternal, Warns) ->
+ {HowMany, _} = Warns,
+ NewHowMany =
+ case HowMany of
+ none -> one;
+ _ -> many
+ end,
+ NewWarns = {NewHowMany, []},
handle_apply_or_call(Left, Args, ArgTypes, Map, Tree, State,
- ArgTypes, t_any(), true);
+ ArgTypes, t_any(), true, NewWarns);
handle_apply_or_call([{TypeOfApply, {Fun, Sig, Contr, LocalRet}}|Left],
Args, ArgTypes, Map, Tree,
#state{opaques = Opaques} = State,
- AccArgTypes, AccRet, HadExternal) ->
+ AccArgTypes, AccRet, HadExternal, Warns) ->
Any = t_any(),
AnyArgs = [Any || _ <- Args],
GenSig = {AnyArgs, fun(_) -> t_any() end},
@@ -586,16 +604,32 @@ handle_apply_or_call([{TypeOfApply, {Fun, Sig, Contr, LocalRet}}|Left],
end,
NewAccRet = t_sup(AccRet, TotalRet),
?debug("NewAccRet: ~s\n", [t_to_string(NewAccRet)]),
+ {NewWarnings, State4} = state__remove_added_warnings(State, State3),
+ {HowMany, OldWarnings} = Warns,
+ NewWarns =
+ case HowMany of
+ none -> {one, NewWarnings};
+ _ ->
+ case OldWarnings =:= [] of
+ true -> {many, []};
+ false ->
+ case NewWarnings =:= [] of
+ true -> {many, []};
+ false -> {many, NewWarnings ++ OldWarnings}
+ end
+ end
+ end,
handle_apply_or_call(Left, Args, ArgTypes, Map, Tree,
- State3, NewAccArgTypes, NewAccRet, HadExternal);
+ State4, NewAccArgTypes, NewAccRet, HadExternal, NewWarns);
handle_apply_or_call([], Args, _ArgTypes, Map, _Tree, State,
- AccArgTypes, AccRet, HadExternal) ->
+ AccArgTypes, AccRet, HadExternal, {_, Warnings}) ->
+ State1 = state__add_warnings(Warnings, State),
case HadExternal of
false ->
NewMap = enter_type_lists(Args, AccArgTypes, Map),
- {State, NewMap, AccRet};
+ {State1, NewMap, AccRet};
true ->
- {had_external, State}
+ {had_external, State1}
end.
apply_fail_reason(FailedSig, FailedBif, FailedContract) ->
@@ -3038,6 +3072,14 @@ state__add_warning(#state{warnings = Warnings, warning_mode = true} = State,
end
end.
+state__remove_added_warnings(OldState, NewState) ->
+ #state{warnings = OldWarnings} = OldState,
+ #state{warnings = NewWarnings} = NewState,
+ {NewWarnings -- OldWarnings, NewState#state{warnings = OldWarnings}}.
+
+state__add_warnings(Warns, #state{warnings = Warnings} = State) ->
+ State#state{warnings = Warns ++ Warnings}.
+
-spec state__set_curr_fun(curr_fun(), state()) -> state().
state__set_curr_fun(undefined, State) ->
diff --git a/lib/dialyzer/test/small_SUITE_data/results/higher_order_discrepancy b/lib/dialyzer/test/small_SUITE_data/results/higher_order_discrepancy
index 7ce440a60d..11b9ecade6 100644
--- a/lib/dialyzer/test/small_SUITE_data/results/higher_order_discrepancy
+++ b/lib/dialyzer/test/small_SUITE_data/results/higher_order_discrepancy
@@ -1,4 +1,3 @@
-higher_order_discrepancy.erl:11: The call higher_order_discrepancy:g('foo') will never return since it differs in the 1st argument from the success typing arguments: ('bar')
-higher_order_discrepancy.erl:14: Function g/1 has no local return
-higher_order_discrepancy.erl:14: The pattern 'bar' can never match the type 'foo'
+higher_order_discrepancy.erl:19: Function g/1 has no local return
+higher_order_discrepancy.erl:19: The pattern 'bar' can never match the type 'foo'
diff --git a/lib/dialyzer/test/small_SUITE_data/src/higher_order_discrepancy.erl b/lib/dialyzer/test/small_SUITE_data/src/higher_order_discrepancy.erl
index ff5ee6bac4..f9547d4929 100644
--- a/lib/dialyzer/test/small_SUITE_data/src/higher_order_discrepancy.erl
+++ b/lib/dialyzer/test/small_SUITE_data/src/higher_order_discrepancy.erl
@@ -1,3 +1,8 @@
+%% With the patch introduced to avoid false warnings in
+%% user_SUITE_data/src/wpc_hlines.erl we can unfortunately no longer precisely
+%% catch problems like this one... The refinement procedure is still enough to
+%% keep some of the details, nevertheless.
+
-module(higher_order_discrepancy).
-export([test/1]).
diff --git a/lib/dialyzer/test/small_SUITE_data/src/loopy.erl b/lib/dialyzer/test/small_SUITE_data/src/loopy.erl
new file mode 100644
index 0000000000..28125ec3d9
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/loopy.erl
@@ -0,0 +1,17 @@
+%% ERL-157, OTP-13653.
+%% Would cause Dialyzer to go into an infinite loop.
+
+-module(loopy).
+
+-export([loop/1]).
+
+
+-spec loop(Args) -> ok when
+ Args :: [{Module, Args}],
+ Module :: module(),
+ Args :: any().
+loop([{Module, Args} | Rest]) ->
+ Module:init(Args),
+ loop(Rest);
+loop([]) ->
+ ok.
diff --git a/lib/dialyzer/test/user_SUITE_data/results/wpc_hlines b/lib/dialyzer/test/user_SUITE_data/results/wpc_hlines
new file mode 100644
index 0000000000..d6e3f29ab9
--- /dev/null
+++ b/lib/dialyzer/test/user_SUITE_data/results/wpc_hlines
@@ -0,0 +1,3 @@
+
+wpc_hlines.erl:22: Function bad/1 has no local return
+wpc_hlines.erl:22: The pattern 'false' can never match the type 'true'
diff --git a/lib/dialyzer/test/user_SUITE_data/src/wpc_hlines.erl b/lib/dialyzer/test/user_SUITE_data/src/wpc_hlines.erl
new file mode 100644
index 0000000000..8c205a8247
--- /dev/null
+++ b/lib/dialyzer/test/user_SUITE_data/src/wpc_hlines.erl
@@ -0,0 +1,22 @@
+%% Bug reported by Dan Gudmundsson, test shrunk down by Magnus LÃ¥ng.
+
+%% The problem is that dialyzer_dep generates edges from the fun
+%% application to both of the functions, and then during the warning pass
+%% dialyzer_dataflow:handle_apply_or_call generates warnings for any such
+%% edge that won't return.
+
+%% Since dialyzer_dep is currently supposed to overapproximate rather than
+%% underapproximate, the fix was to modify handle_apply_or_call to not generate
+%% warnings if some of the possible funs can succeed.
+
+-module(wpc_hlines).
+
+-export([do_export/0]).
+
+do_export() ->
+ {Proj, _} = % The culprit seems to be putting the funs in a tuple
+ {fun good/1, fun bad/1},
+ Proj(true).
+
+good(_) -> ok.
+bad(false) -> ok.
diff --git a/lib/edoc/priv/edoc.dtd b/lib/edoc/priv/edoc.dtd
index 4278a9e643..89058f5d85 100644
--- a/lib/edoc/priv/edoc.dtd
+++ b/lib/edoc/priv/edoc.dtd
@@ -103,7 +103,7 @@
<!ATTLIST type name CDATA #IMPLIED>
<!ELEMENT union (typevar | atom | integer | float | nil | list | tuple |
- fun | record | abstype)+>
+ fun | record | map | abstype)+>
<!ELEMENT typevar EMPTY>
<!ATTLIST typevar name CDATA #REQUIRED>
@@ -129,6 +129,10 @@
<!ELEMENT field (atom, type)>
+<!ELEMENT map (map_field)*>
+
+<!ELEMENT map_field (type, type)>
+
<!ELEMENT abstype (erlangName, type*)>
<!ATTLIST abstype
href CDATA #IMPLIED>
diff --git a/lib/edoc/src/edoc_layout.erl b/lib/edoc/src/edoc_layout.erl
index f723cd8373..e86d090b13 100644
--- a/lib/edoc/src/edoc_layout.erl
+++ b/lib/edoc/src/edoc_layout.erl
@@ -898,8 +898,20 @@ t_map(Es) ->
Fs = get_elem(map_field, Es),
["#{"] ++ seq(fun t_map_field/1, Fs, ["}"]).
-t_map_field(#xmlElement{content = [K,V]}) ->
- t_utype_elem(K) ++ [" => "] ++ t_utype_elem(V).
+t_map_field(#xmlElement{content = [K,V]}=E) ->
+ KElem = t_utype_elem(K),
+ VElem = t_utype_elem(V),
+ AT = get_attrval(assoc_type, E),
+ IsAny = fun(["any","()"]) -> true; (_) -> false end,
+ case AT =:= "assoc" andalso IsAny(KElem) andalso IsAny(VElem) of
+ true -> "...";
+ false ->
+ AS = case AT of
+ "assoc" -> " => ";
+ "exact" -> " := "
+ end,
+ KElem ++ [AS] ++ VElem
+ end.
t_record(E, Es) ->
Name = ["#"] ++ t_type(get_elem(atom, Es)),
@@ -1133,8 +1145,12 @@ ot_tuple(Es) ->
ot_map(Es) ->
{type,0,map,[ot_map_field(E) || E <- get_elem(map_field,Es)]}.
-ot_map_field(#xmlElement{content=[K,V]}) ->
- {type,0,map_field_assoc,ot_utype_elem(K), ot_utype_elem(V)}.
+ot_map_field(#xmlElement{content=[K,V]}=E) ->
+ A = case get_attrval(assoc_type, E) of
+ "assoc" -> map_field_assoc;
+ "exact" -> map_field_exact
+ end,
+ {type,0,A,[ot_utype_elem(K), ot_utype_elem(V)]}.
ot_fun(Es) ->
Range = ot_utype(get_elem(type, Es)),
diff --git a/lib/edoc/src/edoc_parser.yrl b/lib/edoc/src/edoc_parser.yrl
index 835e7ccaa6..983e2f8496 100644
--- a/lib/edoc/src/edoc_parser.yrl
+++ b/lib/edoc/src/edoc_parser.yrl
@@ -36,8 +36,8 @@ Terminals
atom float integer var an_var string start_spec start_typedef start_throws
start_ref
-'(' ')' ',' '.' '=>' '->' '{' '}' '[' ']' '|' '+' ':' '::' '=' '/' '//' '*'
-'#' 'where' '<<' '>>' '..' '...'.
+'(' ')' ',' '.' '=>' ':=' '->' '{' '}' '[' ']' '|' '+' ':' '::' '=' '/' '//'
+'*' '#' 'where' '<<' '>>' '..' '...'.
Rootsymbol start.
@@ -76,7 +76,15 @@ utype_map_fields -> '$empty' : [].
utype_map_fields -> utype_map_field : ['$1'].
utype_map_fields -> utype_map_fields ',' utype_map_field : ['$3' | '$1'].
-utype_map_field -> utype '=>' utype : #t_map_field{ k_type = '$1', v_type = '$3'}.
+utype_map_field -> utype '=>' utype : #t_map_field{assoc_type = assoc,
+ k_type = '$1',
+ v_type = '$3'}.
+utype_map_field -> utype ':=' utype : #t_map_field{assoc_type = exact,
+ k_type = '$1',
+ v_type = '$3'}.
+utype_map_field -> '...' : #t_map_field{assoc_type = assoc,
+ k_type = any(),
+ v_type = any()}.
utype_tuple -> '{' utypes '}' : lists:reverse('$2').
@@ -346,6 +354,9 @@ all_vars([#t_var{} | As]) ->
all_vars(As) ->
As =:= [].
+any() ->
+ #t_type{name = #t_name{name = any}, args = []}.
+
%% ---------------------------------------------------------------------
%% @doc EDoc type specification parsing. Parses the content of
diff --git a/lib/edoc/src/edoc_run.erl b/lib/edoc/src/edoc_run.erl
index 9a569d0879..261a649c70 100644
--- a/lib/edoc/src/edoc_run.erl
+++ b/lib/edoc/src/edoc_run.erl
@@ -44,6 +44,8 @@
-import(edoc_report, [report/2, error/1]).
+-type args() :: [string()].
+
%% @spec application([string()]) -> none()
%%
@@ -58,6 +60,7 @@
%% automatically terminated when the call has completed, signalling
%% success or failure to the operating system.
+-spec application(args()) -> no_return().
application(Args) ->
F = fun () ->
case parse_args(Args) of
@@ -81,6 +84,7 @@ application(Args) ->
%% automatically terminated when the call has completed, signalling
%% success or failure to the operating system.
+-spec files(args()) -> no_return().
files(Args) ->
F = fun () ->
case parse_args(Args) of
@@ -93,6 +97,7 @@ files(Args) ->
run(F).
%% @hidden Not official yet
+-spec toc(args()) -> no_return().
toc(Args) ->
F = fun () ->
case parse_args(Args) of
@@ -126,6 +131,7 @@ toc(Args) ->
%% automatically terminated when the call has completed, signalling
%% success or failure to the operating system.
+-spec file(args()) -> no_return().
file(Args) ->
F = fun () ->
case parse_args(Args) of
@@ -137,8 +143,7 @@ file(Args) ->
end,
run(F).
--spec invalid_args(string(), list()) -> no_return().
-
+-spec invalid_args(string(), args()) -> no_return().
invalid_args(Where, Args) ->
report("invalid arguments to ~ts: ~w.", [Where, Args]),
shutdown_error().
@@ -169,10 +174,12 @@ wait_init() ->
%% When and if a function init:stop/1 becomes generally available, we
%% can use that instead of delay-and-pray when there is an error.
+-spec shutdown_ok() -> no_return().
shutdown_ok() ->
%% shut down emulator nicely, signalling "normal termination"
init:stop().
+-spec shutdown_error() -> no_return().
shutdown_error() ->
%% delay 1 second to allow I/O to finish
receive after 1000 -> ok end,
diff --git a/lib/edoc/src/edoc_scanner.erl b/lib/edoc/src/edoc_scanner.erl
index 36423d63f8..f1d5e1d4b9 100644
--- a/lib/edoc/src/edoc_scanner.erl
+++ b/lib/edoc/src/edoc_scanner.erl
@@ -146,6 +146,8 @@ scan1([$>,$>|Cs], Toks, Pos) ->
scan1(Cs, [{'>>',Pos}|Toks], Pos);
scan1([$-,$>|Cs], Toks, Pos) ->
scan1(Cs, [{'->',Pos}|Toks], Pos);
+scan1([$:,$=|Cs], Toks, Pos) ->
+ scan1(Cs, [{':=',Pos}|Toks], Pos);
scan1([$:,$:|Cs], Toks, Pos) ->
scan1(Cs, [{'::',Pos}|Toks], Pos);
scan1([$/,$/|Cs], Toks, Pos) ->
diff --git a/lib/edoc/src/edoc_specs.erl b/lib/edoc/src/edoc_specs.erl
index faee8adf7b..c15dfd328f 100644
--- a/lib/edoc/src/edoc_specs.erl
+++ b/lib/edoc/src/edoc_specs.erl
@@ -369,11 +369,11 @@ d2e({type,_,map,any}, _Prec) ->
d2e({type,_,map,Es}, _Prec) ->
#t_map{types = d2e(Es) };
d2e({type,_,map_field_assoc,[K,V]}, Prec) ->
- T = #t_map_field{k_type = d2e(K), v_type=d2e(V) },
+ T = #t_map_field{assoc_type = assoc, k_type = d2e(K), v_type=d2e(V) },
{P,_R} = erl_parse:type_preop_prec('#'),
maybe_paren(P, Prec, T);
-d2e({type,_,map_field_exact,K,V}, Prec) ->
- T = #t_map_field{k_type = d2e(K), v_type=d2e(V) },
+d2e({type,_,map_field_exact,[K,V]}, Prec) ->
+ T = #t_map_field{assoc_type = exact, k_type = d2e(K), v_type=d2e(V) },
{P,_R} = erl_parse:type_preop_prec('#'),
maybe_paren(P, Prec, T);
d2e({type,_,tuple,Ts0}, _Prec) ->
diff --git a/lib/edoc/src/edoc_types.erl b/lib/edoc/src/edoc_types.erl
index 65fba61a72..5bb68e79fb 100644
--- a/lib/edoc/src/edoc_types.erl
+++ b/lib/edoc/src/edoc_types.erl
@@ -89,8 +89,8 @@ to_xml(#t_fun{args = As, range = T}, Env) ->
wrap_utype(T, Env)]};
to_xml(#t_map{ types = Ts}, Env) ->
{map, map(fun to_xml/2, Ts, Env)};
-to_xml(#t_map_field{ k_type=K, v_type=V}, Env) ->
- {map_field, [wrap_utype(K,Env), wrap_utype(V, Env)]};
+to_xml(#t_map_field{assoc_type = AT, k_type=K, v_type=V}, Env) ->
+ {map_field, [{assoc_type, AT}], [wrap_utype(K,Env), wrap_utype(V, Env)]};
to_xml(#t_tuple{types = Ts}, Env) ->
{tuple, map(fun wrap_utype/2, Ts, Env)};
to_xml(#t_list{type = T}, Env) ->
diff --git a/lib/edoc/src/edoc_types.hrl b/lib/edoc/src/edoc_types.hrl
index 7fec10d936..3e5e91484f 100644
--- a/lib/edoc/src/edoc_types.hrl
+++ b/lib/edoc/src/edoc_types.hrl
@@ -157,5 +157,5 @@
-record(t_paren, {a=[], type}). % parentheses
-record(t_map, {a=[], types=[]}).
--record(t_map_field, {a=[], k_type, v_type}).
+-record(t_map_field, {a=[], assoc_type, k_type, v_type}).
diff --git a/lib/eldap/test/eldap_basic_SUITE.erl b/lib/eldap/test/eldap_basic_SUITE.erl
index d52a7c83f7..ac3447cfe6 100644
--- a/lib/eldap/test/eldap_basic_SUITE.erl
+++ b/lib/eldap/test/eldap_basic_SUITE.erl
@@ -32,7 +32,7 @@
-define(manageDsaIT, {control,"2.16.840.1.113730.3.4.2",false,asn1_NOVALUE}).
suite() ->
- [{timetrap,{seconds,40}}].
+ [{timetrap,{seconds,360}}].
all() ->
[app,
diff --git a/lib/erl_docgen/src/docgen_otp_specs.erl b/lib/erl_docgen/src/docgen_otp_specs.erl
index e154323f07..5bc3be7a8d 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-2015. All Rights Reserved.
+%% 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.
@@ -389,10 +389,10 @@ t_type([#xmlElement{name = list, content = Es}]) ->
t_list(Es);
t_type([#xmlElement{name = nonempty_list, content = Es}]) ->
t_nonempty_list(Es);
-t_type([#xmlElement{name = tuple, content = Es}]) ->
- t_tuple(Es);
t_type([#xmlElement{name = map, content = Es}]) ->
t_map(Es);
+t_type([#xmlElement{name = tuple, content = Es}]) ->
+ t_tuple(Es);
t_type([#xmlElement{name = 'fun', content = Es}]) ->
["fun("] ++ t_fun(Es) ++ [")"];
t_type([E = #xmlElement{name = record, content = Es}]) ->
@@ -435,16 +435,28 @@ t_nonempty_list(Es) ->
t_tuple(Es) ->
["{"] ++ seq(fun t_utype_elem/1, Es, ["}"]).
+t_fun(Es) ->
+ ["("] ++ seq(fun t_utype_elem/1, get_content(argtypes, Es),
+ [") -> "] ++ t_utype(get_elem(type, Es))).
+
t_map(Es) ->
Fs = get_elem(map_field, Es),
["#{"] ++ seq(fun t_map_field/1, Fs, ["}"]).
-t_map_field(#xmlElement{content = [K,V]}) ->
- [t_utype_elem(K) ++ " => " ++ t_utype_elem(V)].
-
-t_fun(Es) ->
- ["("] ++ seq(fun t_utype_elem/1, get_content(argtypes, Es),
- [") -> "] ++ t_utype(get_elem(type, Es))).
+t_map_field(#xmlElement{content = [K,V]}=E) ->
+ KElem = t_utype_elem(K),
+ VElem = t_utype_elem(V),
+ AT = get_attrval(assoc_type, E),
+ IsAny = fun(["any","()"]) -> true; (_) -> false end,
+ case AT =:= "assoc" andalso IsAny(KElem) andalso IsAny(VElem) of
+ true -> "...";
+ false ->
+ AS = case AT of
+ "assoc" -> " => ";
+ "exact" -> " := "
+ end,
+ KElem ++ [AS] ++ VElem
+ end.
t_record(E, Es) ->
Name = ["#"] ++ t_type(get_elem(atom, Es)),
@@ -618,8 +630,12 @@ ot_tuple(Es) ->
ot_map(Es) ->
{type,0,map,[ot_map_field(E) || E <- get_elem(map_field,Es)]}.
-ot_map_field(#xmlElement{content=[K,V]}) ->
- {type,0,map_field_assoc,[ot_utype_elem(K),ot_utype_elem(V)]}.
+ot_map_field(#xmlElement{content=[K,V]}=E) ->
+ A = case get_attrval(assoc_type, E) of
+ "assoc" -> map_field_assoc;
+ "exact" -> map_field_exact
+ end,
+ {type,0,A,[ot_utype_elem(K), ot_utype_elem(V)]}.
ot_fun(Es) ->
Range = ot_utype(get_elem(type, Es)),
diff --git a/lib/erl_interface/src/misc/ei_portio.h b/lib/erl_interface/src/misc/ei_portio.h
index a14fdbd7d1..fbb61b0ccf 100644
--- a/lib/erl_interface/src/misc/ei_portio.h
+++ b/lib/erl_interface/src/misc/ei_portio.h
@@ -21,6 +21,12 @@
*/
#ifndef _EI_PORTIO_H
#define _EI_PORTIO_H
+#if !defined(__WIN32__) || !defined(VXWORKS)
+#ifdef HAVE_WRITEV
+/* Declaration of struct iovec *iov should be visible in this scope. */
+#include <sys/uio.h>
+#endif
+#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);
@@ -29,8 +35,7 @@ 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);
+int ei_writev_fill_t(int fd, const struct iovec *iov, int iovcnt, unsigned ms);
#endif
#endif /* _EI_PORTIO_H */
diff --git a/lib/inets/src/ftp/ftp.erl b/lib/inets/src/ftp/ftp.erl
index c2ca511795..bbf25f8e90 100644
--- a/lib/inets/src/ftp/ftp.erl
+++ b/lib/inets/src/ftp/ftp.erl
@@ -106,8 +106,8 @@
-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), 'n/a').
+-define(DBG(F,A), io:format(F,A)).
%%%=========================================================================
%%% API - CLIENT FUNCTIONS
@@ -1383,12 +1383,18 @@ 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),
@@ -1769,12 +1775,12 @@ handle_ctrl_result({pos_compl, _Lines},
{LSock, Caller}}} = State) ->
handle_caller(State#state{caller = Caller, dsock = {lsock, LSock}});
-handle_ctrl_result({Status, Lines},
+handle_ctrl_result({Status, _Lines},
#state{mode = active,
caller = {setup_data_connection, {LSock, _}}}
= State) ->
- close_connection(LSock),
- ctrl_result_response(Status, State, {error, Lines});
+ close_connection({tcp,LSock}),
+ ctrl_result_response(Status, State, {error, Status});
%% Data connection setup passive mode
handle_ctrl_result({pos_compl, Lines},
@@ -1965,7 +1971,7 @@ handle_ctrl_result(_, #state{caller = {handle_dir_data_third_phase, DirData},
{noreply, State#state{client = undefined, caller = undefined}};
handle_ctrl_result({Status, _}, #state{caller = cd} = State) ->
- ctrl_result_response(Status, State, {error, epath});
+ ctrl_result_response(Status, State, {error, Status});
handle_ctrl_result(Status={epath, _}, #state{caller = {dir,_}} = State) ->
ctrl_result_response(Status, State, {error, epath});
@@ -1980,11 +1986,11 @@ handle_ctrl_result({pos_interm, _}, #state{caller = {rename, NewFile}}
handle_ctrl_result({Status, _},
#state{caller = {rename, _}} = State) ->
- ctrl_result_response(Status, State, {error, epath});
+ ctrl_result_response(Status, State, {error, Status});
handle_ctrl_result({Status, _},
#state{caller = rename_second_phase} = State) ->
- ctrl_result_response(Status, State, {error, epath});
+ ctrl_result_response(Status, State, {error, Status});
%%--------------------------------------------------------------------------
%% File handling - recv_bin
@@ -2095,7 +2101,7 @@ handle_ctrl_result({pos_prel, _}, #state{caller = {transfer_data, Bin}}
%% Default
handle_ctrl_result({Status, Lines}, #state{client = From} = State)
when From =/= undefined ->
- ctrl_result_response(Status, State, {error, Lines}).
+ ctrl_result_response(Status, State, {error, Status}).
%%--------------------------------------------------------------------------
%% Help functions to handle_ctrl_result
@@ -2113,7 +2119,6 @@ ctrl_result_response(Status, #state{client = From} = State, _)
(Status =:= epnospc) orelse
(Status =:= efnamena) orelse
(Status =:= econn) ->
-%Status == etnospc; Status == epnospc; Status == econn ->
gen_server:reply(From, {error, Status}),
%% {stop, normal, {error, Status}, State#state{client = undefined}};
{stop, normal, State#state{client = undefined}};
@@ -2378,6 +2383,7 @@ 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}) -> gen_tcp:close(Socket);
close_connection({tcp, Socket}) -> gen_tcp:close(Socket);
close_connection({ssl, Socket}) -> ssl:close(Socket).
diff --git a/lib/inets/src/ftp/ftp_response.erl b/lib/inets/src/ftp/ftp_response.erl
index 32db2dfe66..7533bc4550 100644
--- a/lib/inets/src/ftp/ftp_response.erl
+++ b/lib/inets/src/ftp/ftp_response.erl
@@ -194,5 +194,6 @@ interpret_status(?TRANS_NEG_COMPL,_,_) -> trans_neg_compl;
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/test/ftp_SUITE.erl b/lib/inets/test/ftp_SUITE.erl
index 08295d4e3c..a8d39e3fe7 100644
--- a/lib/inets/test/ftp_SUITE.erl
+++ b/lib/inets/test/ftp_SUITE.erl
@@ -50,12 +50,17 @@
%%--------------------------------------------------------------------
%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
+suite() ->
+ [{timetrap,{seconds,20}}].
+
all() ->
[
{group, ftp_passive},
{group, ftp_active},
{group, ftps_passive},
- {group, ftps_active}
+ {group, ftps_active},
+ error_ehost,
+ clean_shutdown
].
groups() ->
@@ -92,14 +97,13 @@ ftp_tests()->
recv_chunk,
type,
quote,
- ip_v6_disabled,
+ error_elogin,
progress_report_send,
progress_report_recv,
not_owner,
unexpected_call,
unexpected_cast,
- unexpected_bang,
- clean_shutdown
+ unexpected_bang
].
%%--------------------------------------------------------------------
@@ -190,35 +194,31 @@ init_per_group(_Group, Config) -> Config.
end_per_group(_Group, Config) -> Config.
%%--------------------------------------------------------------------
-
-init_per_testcase(Case, Config) when (Case =:= progress_report_send) orelse
- (Case =:= progress_report_recv) ->
- common_init_per_testcase(Case, [{progress, {?MODULE, progress, #progress{}}} | Config]);
-
-init_per_testcase(Case, Config) ->
- common_init_per_testcase(Case, Config).
-
-common_init_per_testcase(Case, Config0) ->
- Group = proplists:get_value(name,proplists:get_value(tc_group_properties,Config0)),
- try ?MODULE:Case(doc) of
- Msg -> ct:comment(Msg)
- catch
- _:_-> ok
- end,
+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}],
- ExtraOpts = [verbose],
+ 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_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;
+ 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)) ),
@@ -229,6 +229,9 @@ common_init_per_testcase(Case, Config0) ->
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;
@@ -286,7 +289,8 @@ cd(Config0) ->
{ok, PWD} = ftp:pwd(Pid),
ExpectedPWD = id2ftp_result(Dir, Config),
PWD = ExpectedPWD,
- {error, epath} = ftp:cd(Pid, ?BAD_DIR).
+ {error, epath} = ftp:cd(Pid, ?BAD_DIR),
+ ok.
%%-------------------------------------------------------------------------
lcd() ->
@@ -359,8 +363,11 @@ rename(Config0) ->
id2ftp(NewFile,Config)),
true = (chk_file(NewFile,Contents,Config)
- and chk_no_file([OldFile],Config)).
-
+ and chk_no_file([OldFile],Config)),
+ {error,epath} = ftp:rename(Pid,
+ id2ftp("non_existing_file",Config),
+ id2ftp(NewFile,Config)),
+ ok.
%%-------------------------------------------------------------------------
send() ->
@@ -372,14 +379,16 @@ send(Config0) ->
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),
+ 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),
- chk_file(File, Contents, Config).
+ {error,epath} = ftp:send(Pid, "non_existing_file"),
+ ok.
%%-------------------------------------------------------------------------
send_3() ->
@@ -395,8 +404,10 @@ send_3(Config0) ->
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),
- chk_file([Dir,RemoteFile], Contents, Config).
+ {error,epath} = ftp:send(Pid, "non_existing_file", RemoteFile),
+ ok.
%%-------------------------------------------------------------------------
send_bin() ->
@@ -408,24 +419,33 @@ send_bin(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).
+ 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) ->
- Contents = <<"ftp_SUITE test ...">>,
+ 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, Contents),
- ok = ftp:send_chunk(Pid, Contents),
+ ok = ftp:send_chunk(Pid, Contents1),
+ ok = ftp:send_chunk(Pid, Contents2),
ok = ftp:send_chunk_end(Pid),
- chk_file(File, <<Contents/binary,Contents/binary>>, Config).
+ 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() ->
@@ -436,7 +456,9 @@ delete(Config0) ->
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).
+ chk_no_file([File], Config),
+ {error,epath} = ftp:delete(Pid, id2ftp(File,Config)),
+ ok.
%%-------------------------------------------------------------------------
mkdir() ->
@@ -446,7 +468,9 @@ mkdir(Config0) ->
Config = set_state([reset], Config0),
Pid = proplists:get_value(ftp, Config),
ok = ftp:mkdir(Pid, id2ftp(NewDir,Config)),
- chk_dir([NewDir], Config).
+ chk_dir([NewDir], Config),
+ {error,epath} = ftp:mkdir(Pid, id2ftp(NewDir,Config)),
+ ok.
%%-------------------------------------------------------------------------
rmdir() ->
@@ -456,7 +480,9 @@ rmdir(Config0) ->
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).
+ chk_no_dir([Dir], Config),
+ {error,epath} = ftp:rmdir(Pid, id2ftp(Dir,Config)),
+ ok.
%%-------------------------------------------------------------------------
append() ->
@@ -469,7 +495,9 @@ append(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).
+ chk_file(DstFile, <<Contents/binary,Contents/binary>>, Config),
+ {error,epath} = ftp:append(Pid, id2ftp("non_existing_file",Config), id2ftp(DstFile,Config)),
+ ok.
%%-------------------------------------------------------------------------
append_bin() ->
@@ -511,7 +539,9 @@ recv(Config0) ->
ok = ftp:cd(Pid, id2ftp(SrcDir,Config)),
ok = ftp:lcd(Pid, id2ftp("",Config)),
ok = ftp:recv(Pid, File),
- chk_file(File, Contents, Config).
+ chk_file(File, Contents, Config),
+ {error,epath} = ftp:recv(Pid, "non_existing_file"),
+ ok.
%%-------------------------------------------------------------------------
recv_3() ->
@@ -535,7 +565,9 @@ recv_bin(Config0) ->
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).
+ find_diff(Received, Contents),
+ {error,epath} = ftp:recv_bin(Pid, id2ftp("non_existing_file",Config)),
+ ok.
%%-------------------------------------------------------------------------
recv_chunk() ->
@@ -581,6 +613,154 @@ quote(Config) ->
%% = 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 -----------------------------------------------
%%--------------------------------------------------------------------
@@ -674,112 +854,7 @@ chk_no_dir(PathList, Config) ->
ct:fail("Unexpected error for ~p: ~p",[Path,Error])
end.
-%%-------------------------------------------------------------------------
-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),
- OtherPid = spawn_link(?MODULE, not_owner, [Pid, self()]),
-
- 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) ->
- PrivDir = proplists:get_value(priv_dir, Config),
- LogFile = filename:join([PrivDir,"ticket_6035.log"]),
- Host = proplists:get_value(ftpd_host,Config),
- try
- Pid = spawn(?MODULE, open_wait_6035, [Host, self()]),
- error_logger:logfile({open, LogFile}),
- true = kill_ftp_proc_6035(Pid, LogFile),
- error_logger:logfile(close)
- catch
- throw:{error, not_found} ->
- {skip, "No available FTP servers"}
- end.
-
%%--------------------------------------------------------------------
-%% Internal functions
-%%--------------------------------------------------------------------
-
find_executable(Config) ->
FTPservers = case proplists:get_value(ftpservers,Config) of
undefined -> ?default_ftp_servers;
@@ -893,12 +968,6 @@ rm(F, Pfx) ->
ok
end.
-not_owner(FtpPid, Pid) ->
- {error, not_connection_owner} = ftp:pwd(FtpPid),
- ftp:close(FtpPid),
- ct:sleep(100),
- Pid ! {self(), ok}.
-
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)).
@@ -912,96 +981,75 @@ is_expected_ftpInName(Id, File, Conf) -> File = (proplists:get_value(id2ftp,Conf
is_expected_ftpOutName(Id, File, Conf) -> File = (proplists:get_value(id2ftp_result,Conf))(Id).
-progress(#progress{} = Progress , _File, {file_size, Total}) ->
+%%%----------------------------------------------------------------
+%%% 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,
- Progress#progress{total = Total};
+ P#progress{total = Total};
-progress(#progress{total = Total, current = Current}
- = Progress, _File, {transfer_size, 0}) ->
+progress(#progress{current = Current} = P, _File, {transfer_size, 0} = M) ->
+ ct:pal("Progress: ~p",[M]),
progress_report_receiver ! finish,
- case Total of
- unknown ->
- ok;
- Current ->
- ok;
- _ ->
- ct:fail({error, {progress, {total, Total},
- {current, Current}}})
- end,
- Progress;
-progress(#progress{current = Current} = Progress, _File,
- {transfer_size, Size}) ->
+ 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,
- Progress#progress{current = Current + Size}.
+ 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(Pid, N) ->
+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
+ start -> ok
end,
- progress_report_receiver_loop(Pid, N-1).
-
-progress_report_receiver_loop(Pid, N) ->
- receive
- update ->
- progress_report_receiver_loop(Pid, N);
- finish when N =:= 0 ->
- Pid ! {self(), ok};
- finish ->
- Pid ! {self(), ok},
- receive
- start ->
- ok
- end,
- progress_report_receiver_loop(Pid, N-1)
- end.
-
-kill_ftp_proc_6035(Pid, LogFile) ->
+ progress_report_receiver_loop(Parent, N-1).
+
+
+progress_report_receiver_loop(Parent, N) ->
+ ct:pal("progress_report expect update | finish. N = ~p",[N]),
receive
- open ->
- exit(Pid, shutdown),
- kill_ftp_proc_6035(Pid, LogFile);
- {open_failed, Reason} ->
- exit({skip, {failed_openening_server_connection, Reason}})
- after
- 5000 ->
- is_error_report_6035(LogFile)
+ 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.
-open_wait_6035({_Tag, FtpServer}, From) ->
- case ftp:open(FtpServer, [{timeout, timer:seconds(15)}]) of
- {ok, Pid} ->
- _LoginResult = ftp:user(Pid,"anonymous","kldjf"),
- From ! open,
- receive
- dummy ->
- ok
- after
- 10000 ->
- ok
- end,
- ok;
- {error, Reason} ->
- From ! {open_failed, {Reason, FtpServer}},
- ok
- end.
+%%%----------------------------------------------------------------
+%%% Help functions for bug OTP-6035
is_error_report_6035(LogFile) ->
- Res =
- case file:read_file(LogFile) of
- {ok, Bin} ->
- Txt = binary_to_list(Bin),
- read_log_6035(Txt);
- _ ->
- false
- end,
- %% file:delete(LogFile),
- Res.
-
-read_log_6035("=ERROR REPORT===="++_Rest) ->
- true;
-read_log_6035([_|T]) ->
- read_log_6035(T);
-read_log_6035([]) ->
- false.
+ case file:read_file(LogFile) of
+ {ok, Bin} ->
+ nomatch =/= binary:match(Bin, <<"=ERROR REPORT====">>);
+ _ ->
+ false
+ end.
+
diff --git a/lib/inets/test/ftp_format_SUITE.erl b/lib/inets/test/ftp_format_SUITE.erl
index 2c17e2657c..a33b31f46f 100644
--- a/lib/inets/test/ftp_format_SUITE.erl
+++ b/lib/inets/test/ftp_format_SUITE.erl
@@ -253,7 +253,7 @@ ftp_other_status_codes(Config) when is_list(Config) ->
{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"),
- {perm_neg_compl, _ } = ftp_response:interpret("530 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"),
diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl
index 42772923e4..932567ec55 100644
--- a/lib/inets/test/httpc_SUITE.erl
+++ b/lib/inets/test/httpc_SUITE.erl
@@ -2080,7 +2080,7 @@ run_clients(NumClients, ServerPort, SeqNumServer) ->
end
end),
MRef = erlang:monitor(process, Pid),
- timer:sleep(10 + random:uniform(1334)),
+ timer:sleep(10 + rand:uniform(1334)),
{Id, Pid, MRef}
end,
lists:seq(1, NumClients)).
@@ -2169,7 +2169,7 @@ slowly_send_response(CSock, Answer) ->
[length(Answer), Answer])),
lists:foreach(
fun(Char) ->
- timer:sleep(random:uniform(500)),
+ timer:sleep(rand:uniform(500)),
gen_tcp:send(CSock, <<Char>>)
end,
Response).
@@ -2189,9 +2189,8 @@ parse_connection_type(Request) ->
set_random_seed() ->
Unique = erlang:unique_integer(),
-
A = erlang:phash2([make_ref(), self(), Unique]),
- random:seed(A, A, A).
+ rand:seed(exsplus, {A, A, A}).
otp_8739(doc) ->
diff --git a/lib/kernel/doc/src/gen_tcp.xml b/lib/kernel/doc/src/gen_tcp.xml
index 8bd94892ad..88135ea43d 100644
--- a/lib/kernel/doc/src/gen_tcp.xml
+++ b/lib/kernel/doc/src/gen_tcp.xml
@@ -153,17 +153,17 @@ do_recv(Sock, Bs) ->
<c><anno>Address</anno></c> can be a hostname or an IP address.</p>
<p>The following options are available:</p>
<taglist>
- <tag><c>{ip, ip_address()}</c></tag>
+ <tag><c>{ip, Address}</c></tag>
<item><p>If the host has many network interfaces, this option
specifies which one to use.</p></item>
- <tag><c>{ifaddr, ip_address()}</c></tag>
- <item><p>Same as <c>{ip, ip_address()}</c>. If the host has many
+ <tag><c>{ifaddr, Address}</c></tag>
+ <item><p>Same as <c>{ip, Address}</c>. If the host has many
network interfaces, this option specifies which one to use.</p>
</item>
<tag><c>{fd, integer() >= 0}</c></tag>
<item><p>If a socket has somehow been connected without using
<c>gen_tcp</c>, use this option to pass the file descriptor
- for it. If <c>{ip, ip_address()}</c> and/or
+ for it. If <c>{ip, Address}</c> and/or
<c>{port, port_number()}</c> is combined with this option, the
<c>fd</c> is bound to the specified interface and port before
connecting. If these options are not specified, it is assumed that
@@ -172,6 +172,15 @@ do_recv(Sock, Bs) ->
<item><p>Sets up the socket for IPv4.</p></item>
<tag><c>inet6</c></tag>
<item><p>Sets up the socket for IPv6.</p></item>
+ <tag><c>local</c></tag>
+ <item>
+ <p>
+ Sets up a Unix Domain Socket. See
+ <seealso marker="inet#type-local_address">
+ <c>inet:local_address()</c>
+ </seealso>
+ </p>
+ </item>
<tag><c>{port, Port}</c></tag>
<item><p>Specifies which local port number to use.</p></item>
<tag><c>{tcp_module, module()}</c></tag>
@@ -246,7 +255,7 @@ do_recv(Sock, Bs) ->
<item><p><c>B</c> is an integer &gt;= <c>0</c>. The backlog value
defines the maximum length that the queue of pending connections
can grow to. Defaults to <c>5</c>.</p></item>
- <tag><c>{ip, ip_address()}</c></tag>
+ <tag><c>{ip, Address}</c></tag>
<item><p>If the host has many network interfaces, this option
specifies which one to listen on.</p></item>
<tag><c>{port, Port}</c></tag>
@@ -255,8 +264,8 @@ do_recv(Sock, Bs) ->
<item><p>If a socket has somehow been connected without using
<c>gen_tcp</c>, use this option to pass the file
descriptor for it.</p></item>
- <tag><c>{ifaddr, ip_address()}</c></tag>
- <item><p>Same as <c>{ip, ip_address()}</c>. If the host has many
+ <tag><c>{ifaddr, Address}</c></tag>
+ <item><p>Same as <c>{ip, Address}</c>. If the host has many
network interfaces, this option specifies which one to use.</p>
</item>
<tag><c>inet6</c></tag>
diff --git a/lib/kernel/doc/src/gen_udp.xml b/lib/kernel/doc/src/gen_udp.xml
index 3db291600d..3f88a0272d 100644
--- a/lib/kernel/doc/src/gen_udp.xml
+++ b/lib/kernel/doc/src/gen_udp.xml
@@ -85,11 +85,11 @@
<item><p>Received <c>Packet</c> is delivered as a list.</p></item>
<tag><c>binary</c></tag>
<item><p>Received <c>Packet</c> is delivered as a binary.</p></item>
- <tag><c>{ip, ip_address()}</c></tag>
+ <tag><c>{ip, Address}</c></tag>
<item><p>If the host has many network interfaces, this option
specifies which one to use.</p></item>
- <tag><c>{ifaddr, ip_address()}</c></tag>
- <item><p>Same as <c>{ip, ip_address()}</c>. If the host has many
+ <tag><c>{ifaddr, Address}</c></tag>
+ <item><p>Same as <c>{ip, Address}</c>. If the host has many
network interfaces, this option specifies which one to
use.</p></item>
<tag><c>{fd, integer() >= 0}</c></tag>
@@ -104,6 +104,15 @@
<item><p>Sets up the socket for IPv6.</p></item>
<tag><c>inet</c></tag>
<item><p>Sets up the socket for IPv4.</p></item>
+ <tag><c>local</c></tag>
+ <item>
+ <p>
+ Sets up a Unix Domain Socket. See
+ <seealso marker="inet#type-local_address">
+ <c>inet:local_address()</c>
+ </seealso>
+ </p>
+ </item>
<tag><c>{udp_module, module()}</c></tag>
<item><p>Overrides which callback module is used. Defaults to
<c>inet_udp</c> for IPv4 and <c>inet6_udp</c> for IPv6.</p></item>
@@ -176,8 +185,10 @@
<name name="send" arity="4"/>
<fsummary>Send a packet.</fsummary>
<desc>
- <p>Sends a packet to the specified address and port. Argument
- <c><anno>Address</anno></c> can be a hostname or an IP address.</p>
+ <p>
+ Sends a packet to the specified address and port. Argument
+ <c><anno>Address</anno></c> can be a hostname or a socket address.
+ </p>
</desc>
</func>
</funcs>
diff --git a/lib/kernel/doc/src/heart.xml b/lib/kernel/doc/src/heart.xml
index c587e39345..864f8facac 100644
--- a/lib/kernel/doc/src/heart.xml
+++ b/lib/kernel/doc/src/heart.xml
@@ -83,6 +83,17 @@
<c><![CDATA[SIGKILL]]></c>:</p>
<pre>
% <input>erl -heart -env HEART_KILL_SIGNAL SIGABRT ...</input></pre>
+ <p> If heart should <b>not</b> kill the Erlang runtime system, this can be indicated
+ using the environment variable <c><![CDATA[HEART_NO_KILL=TRUE]]></c>.
+ This can be useful if the command executed by heart takes care of this,
+ for example as part of a specific cleanup sequence.
+ If unset, or not set to <c><![CDATA[TRUE]]></c>, the default behaviour
+ will be to kill as described above.
+ </p>
+
+ <pre>
+% <input>erl -heart -env HEART_NO_KILL 1 ...</input></pre>
+
<p>Furthermore, <c><![CDATA[ERL_CRASH_DUMP_SECONDS]]></c> has the
following behavior on <c>heart</c>:</p>
<taglist>
diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml
index 5ff167bcb3..c0dce2f50c 100644
--- a/lib/kernel/doc/src/inet.xml
+++ b/lib/kernel/doc/src/inet.xml
@@ -118,6 +118,59 @@ fe80::204:acff:fe17:bf38
<name name="port_number"/>
</datatype>
<datatype>
+ <name name="local_address"/>
+ <desc>
+ <p>
+ This address family only works on Unix-like systems.
+ </p>
+ <p>
+ <c><anno>File</anno></c> is normally a file pathname
+ in a local filesystem. It is limited in length by the
+ operating system, traditionally to 108 bytes.
+ </p>
+ <p>
+ A <c>binary()</c> is passed as is to the operating system,
+ but a <c>string()</c> is encoded according to the
+ <seealso marker="file#native_name_encoding/0">
+ system filename encoding mode.
+ </seealso>
+ </p>
+ <p>
+ Other addresses are possible, for example Linux implements
+ "Abstract Addresses". See the documentation for
+ Unix Domain Sockets on your system,
+ normally <c>unix</c> in manual section 7.
+ </p>
+ <p>
+ In most API functions where you can use
+ this address family the port number must be <c>0</c>.
+ </p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="socket_address"/>
+ </datatype>
+ <datatype>
+ <name name="returned_non_ip_address"/>
+ <desc>
+ <p>
+ Addresses besides
+ <seealso marker="#type-ip_address">
+ <c>ip_address()</c>
+ </seealso>
+ ones that are returned from socket API functions.
+ See in particular
+ <seealso marker="#type-local_address">
+ <c>local_address()</c>.
+ </seealso>
+ The <c>unspec</c> family corresponds to AF_UNSPEC and can
+ occur if the other side has no socket address.
+ The <c>undefined</c> family can only occur in the unlikely
+ event of an address family that the VM does not recognize.
+ </p>
+ </desc>
+ </datatype>
+ <datatype>
<name name="posix"/>
<desc>
<p>An atom that is named from the POSIX error codes used in Unix,
diff --git a/lib/kernel/src/Makefile b/lib/kernel/src/Makefile
index 8bf02afec9..2b72f78dcf 100644
--- a/lib/kernel/src/Makefile
+++ b/lib/kernel/src/Makefile
@@ -104,6 +104,8 @@ MODULES = \
inet_sctp \
kernel \
kernel_config \
+ local_udp \
+ local_tcp \
net \
net_adm \
net_kernel \
@@ -244,6 +246,8 @@ $(EBIN)/inet_tcp.beam: inet_int.hrl
$(EBIN)/inet_udp_dist.beam: ../include/net_address.hrl ../include/dist.hrl ../include/dist_util.hrl
$(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)/net_kernel.beam: ../include/net_address.hrl
$(EBIN)/os.beam: ../include/file.hrl
$(EBIN)/ram_file.beam: ../include/file.hrl
diff --git a/lib/kernel/src/gen_sctp.erl b/lib/kernel/src/gen_sctp.erl
index d00ed828a7..b133e6fed4 100644
--- a/lib/kernel/src/gen_sctp.erl
+++ b/lib/kernel/src/gen_sctp.erl
@@ -124,8 +124,8 @@ open() ->
SockType :: seqpacket | stream,
Socket :: sctp_socket().
-open(Opts) when is_list(Opts) ->
- Mod = mod(Opts, undefined),
+open(Opts0) when is_list(Opts0) ->
+ {Mod, Opts} = inet:sctp_module(Opts0),
case Mod:open(Opts) of
{error,badarg} ->
erlang:error(badarg, [Opts]);
@@ -445,32 +445,3 @@ controlling_process(S, Pid) when is_port(S), is_pid(Pid) ->
inet:udp_controlling_process(S, Pid);
controlling_process(S, Pid) ->
erlang:error(badarg, [S,Pid]).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Utilites
-%%
-
-%% Get the SCTP module, but IPv6 address overrides default IPv4
-mod(Address) ->
- case inet_db:sctp_module() of
- inet_sctp when tuple_size(Address) =:= 8 ->
- inet6_sctp;
- Mod ->
- Mod
- end.
-
-%% Get the SCTP module, but option sctp_module|inet|inet6 overrides
-mod([{sctp_module,Mod}|_], _Address) ->
- Mod;
-mod([inet|_], _Address) ->
- inet_sctp;
-mod([inet6|_], _Address) ->
- inet6_sctp;
-mod([{ip, Address}|Opts], _) ->
- mod(Opts, Address);
-mod([{ifaddr, Address}|Opts], _) ->
- mod(Opts, Address);
-mod([_|Opts], Address) ->
- mod(Opts, Address);
-mod([], Address) ->
- mod(Address).
diff --git a/lib/kernel/src/gen_tcp.erl b/lib/kernel/src/gen_tcp.erl
index 1f0d44b8e1..1a21541b7c 100644
--- a/lib/kernel/src/gen_tcp.erl
+++ b/lib/kernel/src/gen_tcp.erl
@@ -96,17 +96,17 @@
tos |
ipv6_v6only.
-type connect_option() ::
- {ip, inet:ip_address()} |
+ {ip, inet:socket_address()} |
{fd, Fd :: non_neg_integer()} |
- {ifaddr, inet:ip_address()} |
+ {ifaddr, inet:socket_address()} |
inet:address_family() |
{port, inet:port_number()} |
{tcp_module, module()} |
option().
-type listen_option() ::
- {ip, inet:ip_address()} |
+ {ip, inet:socket_address()} |
{fd, Fd :: non_neg_integer()} |
- {ifaddr, inet:ip_address()} |
+ {ifaddr, inet:socket_address()} |
inet:address_family() |
{port, inet:port_number()} |
{backlog, B :: non_neg_integer()} |
@@ -122,7 +122,7 @@
%%
-spec connect(Address, Port, Options) -> {ok, Socket} | {error, Reason} when
- Address :: inet:ip_address() | inet:hostname(),
+ Address :: inet:socket_address() | inet:hostname(),
Port :: inet:port_number(),
Options :: [connect_option()],
Socket :: socket(),
@@ -133,7 +133,7 @@ connect(Address, Port, Opts) ->
-spec connect(Address, Port, Options, Timeout) ->
{ok, Socket} | {error, Reason} when
- Address :: inet:ip_address() | inet:hostname(),
+ Address :: inet:socket_address() | inet:hostname(),
Port :: inet:port_number(),
Options :: [connect_option()],
Timeout :: timeout(),
@@ -151,8 +151,8 @@ connect(Address, Port, Opts, Time) ->
Error -> Error
end.
-connect1(Address,Port,Opts,Timer) ->
- Mod = mod(Opts, Address),
+connect1(Address, Port, Opts0, Timer) ->
+ {Mod, Opts} = inet:tcp_module(Opts0, Address),
case Mod:getaddrs(Address,Timer) of
{ok,IPs} ->
case Mod:getserv(Port) of
@@ -185,8 +185,8 @@ try_connect([], _Port, _Opts, _Timer, _Mod, Err) ->
ListenSocket :: socket(),
Reason :: system_limit | inet:posix().
-listen(Port, Opts) ->
- Mod = mod(Opts, undefined),
+listen(Port, Opts0) ->
+ {Mod, Opts} = inet:tcp_module(Opts0),
case Mod:getserv(Port) of
{ok,TP} ->
Mod:listen(TP, Opts);
@@ -335,32 +335,6 @@ controlling_process(S, NewOwner) ->
%%
%% Create a port/socket from a file descriptor
%%
-fdopen(Fd, Opts) ->
- Mod = mod(Opts, undefined),
+fdopen(Fd, Opts0) ->
+ {Mod, Opts} = inet:tcp_module(Opts0),
Mod:fdopen(Fd, Opts).
-
-%% Get the tcp_module, but IPv6 address overrides default IPv4
-mod(Address) ->
- case inet_db:tcp_module() of
- inet_tcp when tuple_size(Address) =:= 8 ->
- inet6_tcp;
- Mod ->
- Mod
- end.
-
-%% Get the tcp_module, but option tcp_module|inet|inet6 overrides
-mod([{tcp_module,Mod}|_], _Address) ->
- Mod;
-mod([inet|_], _Address) ->
- inet_tcp;
-mod([inet6|_], _Address) ->
- inet6_tcp;
-mod([{ip, Address}|Opts], _) ->
- mod(Opts, Address);
-mod([{ifaddr, Address}|Opts], _) ->
- mod(Opts, Address);
-mod([_|Opts], Address) ->
- mod(Opts, Address);
-mod([], Address) ->
- mod(Address).
-
diff --git a/lib/kernel/src/gen_udp.erl b/lib/kernel/src/gen_udp.erl
index 5e85c61dd9..98d2f0bcfb 100644
--- a/lib/kernel/src/gen_udp.erl
+++ b/lib/kernel/src/gen_udp.erl
@@ -92,18 +92,18 @@ open(Port) ->
-spec open(Port, Opts) -> {ok, Socket} | {error, Reason} when
Port :: inet:port_number(),
Opts :: [Option],
- Option :: {ip, inet:ip_address()}
+ Option :: {ip, inet:socket_address()}
| {fd, non_neg_integer()}
- | {ifaddr, inet:ip_address()}
+ | {ifaddr, inet:socket_address()}
| inet:address_family()
| {port, inet:port_number()}
| option(),
Socket :: socket(),
Reason :: inet:posix().
-open(Port, Opts) ->
- Mod = mod(Opts, undefined),
- {ok,UP} = Mod:getserv(Port),
+open(Port, Opts0) ->
+ {Mod, Opts} = inet:udp_module(Opts0),
+ {ok, UP} = Mod:getserv(Port),
Mod:open(UP, Opts).
-spec close(Socket) -> ok when
@@ -114,7 +114,7 @@ close(S) ->
-spec send(Socket, Address, Port, Packet) -> ok | {error, Reason} when
Socket :: socket(),
- Address :: inet:ip_address() | inet:hostname(),
+ Address :: inet:socket_address() | inet:hostname(),
Port :: inet:port_number(),
Packet :: iodata(),
Reason :: not_owner | inet:posix().
@@ -148,7 +148,7 @@ send(S, Packet) when is_port(S) ->
{ok, {Address, Port, Packet}} | {error, Reason} when
Socket :: socket(),
Length :: non_neg_integer(),
- Address :: inet:ip_address(),
+ Address :: inet:ip_address() | inet:returned_non_ip_address(),
Port :: inet:port_number(),
Packet :: string() | binary(),
Reason :: not_owner | inet:posix().
@@ -166,7 +166,7 @@ recv(S,Len) when is_port(S), is_integer(Len) ->
Socket :: socket(),
Length :: non_neg_integer(),
Timeout :: timeout(),
- Address :: inet:ip_address(),
+ Address :: inet:ip_address() | inet:returned_non_ip_address(),
Port :: inet:port_number(),
Packet :: string() | binary(),
Reason :: not_owner | inet:posix().
@@ -203,32 +203,6 @@ controlling_process(S, NewOwner) ->
%%
%% Create a port/socket from a file descriptor
%%
-fdopen(Fd, Opts) ->
- Mod = mod(Opts, undefined),
+fdopen(Fd, Opts0) ->
+ {Mod,Opts} = inet:udp_module(Opts0),
Mod:fdopen(Fd, Opts).
-
-
-%% Get the udp_module, but IPv6 address overrides default IPv4
-mod(Address) ->
- case inet_db:udp_module() of
- inet_udp when tuple_size(Address) =:= 8 ->
- inet6_udp;
- Mod ->
- Mod
- end.
-
-%% Get the udp_module, but option udp_module|inet|inet6 overrides
-mod([{udp_module,Mod}|_], _Address) ->
- Mod;
-mod([inet|_], _Address) ->
- inet_udp;
-mod([inet6|_], _Address) ->
- inet6_udp;
-mod([{ip, Address}|Opts], _) ->
- mod(Opts, Address);
-mod([{ifaddr, Address}|Opts], _) ->
- mod(Opts, Address);
-mod([_|Opts], Address) ->
- mod(Opts, Address);
-mod([], Address) ->
- mod(Address).
diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl
index 713a9cf725..9fc685e728 100644
--- a/lib/kernel/src/inet.erl
+++ b/lib/kernel/src/inet.erl
@@ -37,6 +37,7 @@
parse_ipv6strict_address/1, parse_address/1, parse_strict_address/1, ntoa/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]).
-export([i/0, i/1, i/2]).
@@ -72,9 +73,9 @@
-export([start_timer/1, timeout/1, timeout/2, stop_timer/1]).
-export_type([address_family/0, hostent/0, hostname/0, ip4_address/0,
- ip6_address/0, ip_address/0, posix/0, socket/0,
- port_number/0]).
-
+ ip6_address/0, ip_address/0, port_number/0,
+ local_address/0, socket_address/0, returned_non_ip_address/0,
+ posix/0, socket/0, stat_option/0]).
%% imports
-import(lists, [append/1, duplicate/2, filter/2, foldl/3]).
@@ -97,6 +98,11 @@
0..65535,0..65535,0..65535,0..65535}.
-type ip_address() :: ip4_address() | ip6_address().
-type port_number() :: 0..65535.
+-type local_address() :: {local, File :: binary() | string()}.
+-type returned_non_ip_address() ::
+ {local, binary()} |
+ {unspec, <<>>} |
+ {undefined, any()}.
-type posix() :: exbadport | exbadseq | file:posix().
-type socket() :: port().
@@ -133,9 +139,11 @@
'running' | 'multicast' | 'loopback']} |
{'hwaddr', ether_address()}.
--type address_family() :: 'inet' | 'inet6'.
+-type address_family() :: 'inet' | 'inet6' | 'local'.
-type socket_protocol() :: 'tcp' | 'udp' | 'sctp'.
-type socket_type() :: 'stream' | 'dgram' | 'seqpacket'.
+-type socket_address() ::
+ ip_address() | 'any' | 'loopback' | local_address().
-type stat_option() ::
'recv_cnt' | 'recv_max' | 'recv_avg' | 'recv_oct' | 'recv_dvi' |
'send_cnt' | 'send_max' | 'send_avg' | 'send_oct' | 'send_pend'.
@@ -160,26 +168,33 @@ close(Socket) ->
end.
--spec peername(Socket) -> {ok, {Address, Port}} | {error, posix()} when
- Socket :: socket(),
- Address :: ip_address(),
- Port :: non_neg_integer().
+-spec peername(Socket :: socket()) ->
+ {ok,
+ {ip_address(), port_number()} |
+ returned_non_ip_address()} |
+ {error, posix()}.
peername(Socket) ->
prim_inet:peername(Socket).
--spec setpeername(Socket :: socket(), Address :: {ip_address(), port_number()}) ->
- 'ok' | {'error', any()}.
+-spec setpeername(
+ Socket :: socket(),
+ Address ::
+ {ip_address() | 'any' | 'loopback',
+ port_number()} |
+ socket_address()) ->
+ 'ok' | {'error', any()}.
setpeername(Socket, {IP,Port}) ->
prim_inet:setpeername(Socket, {IP,Port});
setpeername(Socket, undefined) ->
prim_inet:setpeername(Socket, undefined).
--spec peernames(Socket) -> {ok, [{Address, Port}]} | {error, posix()} when
- Socket :: socket(),
- Address :: ip_address(),
- Port :: non_neg_integer().
+-spec peernames(Socket :: socket()) ->
+ {ok,
+ [{ip_address(), port_number()} |
+ returned_non_ip_address()]} |
+ {error, posix()}.
peernames(Socket) ->
prim_inet:peernames(Socket).
@@ -195,15 +210,21 @@ peernames(Socket, Assoc) ->
prim_inet:peernames(Socket, Assoc).
--spec sockname(Socket) -> {ok, {Address, Port}} | {error, posix()} when
- Socket :: socket(),
- Address :: ip_address(),
- Port :: non_neg_integer().
+-spec sockname(Socket :: socket()) ->
+ {ok,
+ {ip_address(), port_number()} |
+ returned_non_ip_address()} |
+ {error, posix()}.
sockname(Socket) ->
prim_inet:sockname(Socket).
--spec setsockname(Socket :: socket(), Address :: {ip_address(), port_number()}) ->
+-spec setsockname(
+ Socket :: socket(),
+ Address ::
+ {ip_address() | 'any' | 'loopback',
+ port_number()} |
+ socket_address()) ->
'ok' | {'error', any()}.
setsockname(Socket, {IP,Port}) ->
@@ -211,10 +232,11 @@ setsockname(Socket, {IP,Port}) ->
setsockname(Socket, undefined) ->
prim_inet:setsockname(Socket, undefined).
--spec socknames(Socket) -> {ok, [{Address, Port}]} | {error, posix()} when
- Socket :: socket(),
- Address :: ip_address(),
- Port :: non_neg_integer().
+-spec socknames(Socket :: socket()) ->
+ {ok,
+ [{ip_address(), port_number()} |
+ returned_non_ip_address()]} |
+ {error, posix()}.
socknames(Socket) ->
prim_inet:socknames(Socket).
@@ -681,7 +703,7 @@ connect_options() ->
low_msgq_watermark, send_timeout, send_timeout_close, delay_send, raw,
show_econnreset].
-connect_options(Opts, Family) ->
+connect_options(Opts, Mod) ->
BaseOpts =
case application:get_env(kernel, inet_default_connect_options) of
{ok,List} when is_list(List) ->
@@ -698,7 +720,7 @@ connect_options(Opts, Family) ->
{ok, R} ->
{ok, R#connect_opts {
opts = lists:reverse(R#connect_opts.opts),
- ifaddr = translate_ip(R#connect_opts.ifaddr, Family)
+ ifaddr = Mod:translate_ip(R#connect_opts.ifaddr)
}};
Error -> Error
end.
@@ -713,9 +735,6 @@ con_opt([Opt | Opts], #connect_opts{} = R, As) ->
{fd,Fd} -> con_opt(Opts, R#connect_opts { fd = Fd }, As);
binary -> con_add(mode, binary, R, Opts, As);
list -> con_add(mode, list, R, Opts, As);
- {tcp_module,_} -> con_opt(Opts, R, As);
- inet -> con_opt(Opts, R, As);
- inet6 -> con_opt(Opts, R, As);
{netns,NS} ->
BinNS = filename2binary(NS),
case prim_inet:is_sockopt_val(netns, BinNS) of
@@ -752,7 +771,7 @@ listen_options() ->
low_msgq_watermark, send_timeout, send_timeout_close, delay_send,
packet_size, raw, show_econnreset].
-listen_options(Opts, Family) ->
+listen_options(Opts, Mod) ->
BaseOpts =
case application:get_env(kernel, inet_default_listen_options) of
{ok,List} when is_list(List) ->
@@ -769,7 +788,7 @@ listen_options(Opts, Family) ->
{ok, R} ->
{ok, R#listen_opts {
opts = lists:reverse(R#listen_opts.opts),
- ifaddr = translate_ip(R#listen_opts.ifaddr, Family)
+ ifaddr = Mod:translate_ip(R#listen_opts.ifaddr)
}};
Error -> Error
end.
@@ -785,9 +804,6 @@ list_opt([Opt | Opts], #listen_opts{} = R, As) ->
{backlog,BL} -> list_opt(Opts, R#listen_opts { backlog = BL }, As);
binary -> list_add(mode, binary, R, Opts, As);
list -> list_add(mode, list, R, Opts, As);
- {tcp_module,_} -> list_opt(Opts, R, As);
- inet -> list_opt(Opts, R, As);
- inet6 -> list_opt(Opts, R, As);
{netns,NS} ->
BinNS = filename2binary(NS),
case prim_inet:is_sockopt_val(netns, BinNS) of
@@ -812,6 +828,19 @@ list_add(Name, Val, #listen_opts{} = R, Opts, As) ->
Error -> Error
end.
+tcp_module(Opts) ->
+ tcp_module_1(Opts, undefined).
+
+tcp_module(Opts, Addr) ->
+ Address = {undefined,Addr},
+ %% Address has to be a 2-tuple but the first element is ignored
+ tcp_module_1(Opts, Address).
+
+tcp_module_1(Opts, Address) ->
+ mod(
+ Opts, tcp_module, Address,
+ #{inet => inet_tcp, inet6 => inet6_tcp, local => local_tcp}).
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Available options for udp:open
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -823,12 +852,12 @@ udp_options() ->
high_msgq_watermark, low_msgq_watermark].
-udp_options(Opts, Family) ->
+udp_options(Opts, Mod) ->
case udp_opt(Opts, #udp_opts { }, udp_options()) of
{ok, R} ->
{ok, R#udp_opts {
opts = lists:reverse(R#udp_opts.opts),
- ifaddr = translate_ip(R#udp_opts.ifaddr, Family)
+ ifaddr = Mod:translate_ip(R#udp_opts.ifaddr)
}};
Error -> Error
end.
@@ -843,9 +872,6 @@ udp_opt([Opt | Opts], #udp_opts{} = R, As) ->
{fd,Fd} -> udp_opt(Opts, R#udp_opts { fd = Fd }, As);
binary -> udp_add(mode, binary, R, Opts, As);
list -> udp_add(mode, list, R, Opts, As);
- {udp_module,_} -> udp_opt(Opts, R, As);
- inet -> udp_opt(Opts, R, As);
- inet6 -> udp_opt(Opts, R, As);
{netns,NS} ->
BinNS = filename2binary(NS),
case prim_inet:is_sockopt_val(netns, BinNS) of
@@ -870,6 +896,11 @@ udp_add(Name, Val, #udp_opts{} = R, Opts, As) ->
Error -> Error
end.
+udp_module(Opts) ->
+ mod(
+ Opts, udp_module, undefined,
+ #{inet => inet_udp, inet6 => inet6_udp, local => local_udp}).
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Available options for sctp:open
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -926,9 +957,6 @@ sctp_opt([Opt|Opts], Mod, #sctp_opts{} = R, As) ->
sctp_opt(Opts, Mod, R#sctp_opts{type=Type}, As);
binary -> sctp_opt (Opts, Mod, R, As, mode, binary);
list -> sctp_opt (Opts, Mod, R, As, mode, list);
- {sctp_module,_} -> sctp_opt (Opts, Mod, R, As); % Done with
- inet -> sctp_opt (Opts, Mod, R, As); % Done with
- inet6 -> sctp_opt (Opts, Mod, R, As); % Done with
{netns,NS} ->
BinNS = filename2binary(NS),
case prim_inet:is_sockopt_val(netns, BinNS) of
@@ -970,6 +998,11 @@ sctp_opt_ifaddr(Opts, Mod, #sctp_opts{ifaddr=IfAddr}=R, As, Addr) ->
_ -> [IP,IfAddr]
end}, As).
+sctp_module(Opts) ->
+ mod(
+ Opts, sctp_module, undefined,
+ #{inet => inet_sctp, inet6 => inet6_sctp}).
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Util to check and insert option in option list
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1028,6 +1061,53 @@ translate_ip(any, inet6) -> {0,0,0,0,0,0,0,0};
translate_ip(loopback, inet6) -> {0,0,0,0,0,0,0,1};
translate_ip(IP, _) -> IP.
+mod(Opts, Tag, Address, Map) ->
+ mod(Opts, Tag, Address, Map, undefined, []).
+%%
+mod([{Tag, M}|Opts], Tag, Address, Map, Mod, Acc) ->
+ mod(Opts, Tag, Address, Map, Mod, Acc, M);
+mod([{T, _} = Opt|Opts], Tag, _Address, Map, Mod, Acc)
+ when T =:= ip; T =:= ifaddr->
+ mod(Opts, Tag, Opt, Map, Mod, [Opt|Acc]);
+mod([Family|Opts], Tag, Address, Map, Mod, Acc) when is_atom(Family) ->
+ case Map of
+ #{Family := M} ->
+ mod(Opts, Tag, Address, Map, Mod, Acc, M);
+ #{} ->
+ mod(Opts, Tag, Address, Map, Mod, [Family|Acc])
+ end;
+mod([Opt|Opts], Tag, Address, Map, Mod, Acc) ->
+ mod(Opts, Tag, Address, Map, Mod, [Opt|Acc]);
+mod([], Tag, Address, Map, undefined, Acc) ->
+ {case Address of
+ {_, {local, _}} ->
+ case Map of
+ #{local := Mod} ->
+ Mod;
+ #{} ->
+ inet_db:Tag()
+ end;
+ {_, IP} when tuple_size(IP) =:= 8 ->
+ #{inet := IPv4Mod} = Map,
+ %% Get the mod, but IPv6 address overrides default IPv4
+ case inet_db:Tag() of
+ IPv4Mod ->
+ #{inet6 := IPv6Mod} = Map,
+ IPv6Mod;
+ Mod ->
+ Mod
+ end;
+ _ ->
+ inet_db:Tag()
+ end, lists:reverse(Acc)};
+mod([], _Tag, _Address, _Map, Mod, Acc) ->
+ {Mod, lists:reverse(Acc)}.
+%%
+mod(Opts, Tag, Address, Map, undefined, Acc, M) ->
+ mod(Opts, Tag, Address, Map, M, Acc);
+mod(Opts, Tag, Address, Map, Mod, Acc, _M) ->
+ mod(Opts, Tag, Address, Map, Mod, Acc).
+
getaddrs_tm({A,B,C,D} = IP, Fam, _) ->
%% Only "syntactic" validation and check of family.
@@ -1235,7 +1315,17 @@ gethostbyaddr_tm_native(Addr, Timer, Opts) ->
end.
-spec open(Fd_or_OpenOpts :: integer() | list(),
- Addr :: ip_address(),
+ Addr ::
+ socket_address() |
+ {ip_address() | 'any' | 'loopback', % Unofficial
+ port_number()} |
+ {inet, % Unofficial
+ {ip4_address() | 'any' | 'loopback',
+ port_number()}} |
+ {inet6, % Unofficial
+ {ip6_address() | 'any' | 'loopback',
+ port_number()}} |
+ undefined, % Internal - no bind()
Port :: port_number(),
Opts :: [socket_setopt()],
Protocol :: socket_protocol(),
@@ -1255,11 +1345,16 @@ open(FdO, Addr, Port, Opts, Protocol, Family, Type, Module)
{ok,S} ->
case prim_inet:setopts(S, Opts) of
ok ->
- case if is_list(Addr) ->
- bindx(S, Addr, Port);
- true ->
- prim_inet:bind(S, Addr, Port)
- end of
+ case
+ case Addr of
+ undefined ->
+ {ok, undefined};
+ _ when is_list(Addr) ->
+ bindx(S, Addr, Port);
+ _ ->
+ prim_inet:bind(S, Addr, Port)
+ end
+ of
{ok, _} ->
inet_db:register_socket(S, Module),
{ok,S};
diff --git a/lib/kernel/src/inet6_sctp.erl b/lib/kernel/src/inet6_sctp.erl
index cc98bc0ccb..a5503f6f54 100644
--- a/lib/kernel/src/inet6_sctp.erl
+++ b/lib/kernel/src/inet6_sctp.erl
@@ -1,8 +1,8 @@
%%
%% %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
@@ -14,13 +14,12 @@
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
-%%
+%%
%% %CopyrightEnd%
%%
%% SCTP protocol contribution by Leonid Timochouk and Serge Aleynikov.
%% See also: $ERL_TOP/lib/kernel/AUTHORS
%%
-%%
-module(inet6_sctp).
%% This module provides functions for communicating with
@@ -31,6 +30,7 @@
-include("inet_sctp.hrl").
-include("inet_int.hrl").
+-define(PROTO, sctp).
-define(FAMILY, inet6).
-export([getserv/1,getaddr/1,getaddr/2,translate_ip/1]).
-export([open/1,close/1,listen/2,peeloff/2,connect/5]).
@@ -39,25 +39,19 @@
getserv(Port) when is_integer(Port) -> {ok, Port};
-getserv(Name) when is_atom(Name) ->
- inet:getservbyname(Name, sctp);
-getserv(_) ->
- {error,einval}.
-
-getaddr(Address) ->
- inet:getaddr(Address, ?FAMILY).
-getaddr(Address, Timer) ->
- inet:getaddr_tm(Address, ?FAMILY, Timer).
+getserv(Name) when is_atom(Name) -> inet:getservbyname(Name, ?PROTO);
+getserv(_) -> {error,einval}.
-translate_ip(IP) ->
- inet:translate_ip(IP, ?FAMILY).
+getaddr(Address) -> inet:getaddr(Address, ?FAMILY).
+getaddr(Address, Timer) -> inet:getaddr_tm(Address, ?FAMILY, Timer).
+translate_ip(IP) -> inet:translate_ip(IP, ?FAMILY).
open(Opts) ->
case inet:sctp_options(Opts, ?MODULE) of
{ok,#sctp_opts{fd=Fd,ifaddr=Addr,port=Port,type=Type,opts=SOs}} ->
- inet:open(Fd, Addr, Port, SOs, sctp, ?FAMILY, Type, ?MODULE);
+ inet:open(Fd, Addr, Port, SOs, ?PROTO, ?FAMILY, Type, ?MODULE);
Error -> Error
end.
diff --git a/lib/kernel/src/inet6_tcp.erl b/lib/kernel/src/inet6_tcp.erl
index 3dfe5dfc86..a0d5d3df70 100644
--- a/lib/kernel/src/inet6_tcp.erl
+++ b/lib/kernel/src/inet6_tcp.erl
@@ -25,13 +25,18 @@
-export([controlling_process/2]).
-export([fdopen/2]).
--export([family/0, mask/2, parse_address/1]).
+-export([family/0, mask/2, parse_address/1]). % inet_tcp_dist
-export([getserv/1, getaddr/1, getaddr/2, getaddrs/1, getaddrs/2]).
+-export([translate_ip/1]).
-include("inet_int.hrl").
+-define(FAMILY, inet6).
+-define(PROTO, tcp).
+-define(TYPE, stream).
+
%% my address family
-family() -> inet6.
+family() -> ?FAMILY.
%% Apply netmask on address
mask({M1,M2,M3,M4,M5,M6,M7,M8}, {IP1,IP2,IP3,IP4,IP5,IP6,IP7,IP8}) ->
@@ -50,15 +55,18 @@ parse_address(Host) ->
%% inet_tcp port lookup
getserv(Port) when is_integer(Port) -> {ok, Port};
-getserv(Name) when is_atom(Name) -> inet:getservbyname(Name,tcp).
+getserv(Name) when is_atom(Name) -> inet:getservbyname(Name, ?PROTO).
%% inet_tcp address lookup
-getaddr(Address) -> inet:getaddr(Address, inet6).
-getaddr(Address,Timer) -> inet:getaddr_tm(Address, inet6, Timer).
+getaddr(Address) -> inet:getaddr(Address, ?FAMILY).
+getaddr(Address, Timer) -> inet:getaddr_tm(Address, ?FAMILY, Timer).
%% inet_tcp address lookup
-getaddrs(Address) -> inet:getaddrs(Address, inet6).
-getaddrs(Address,Timer) -> inet:getaddrs_tm(Address,inet6,Timer).
+getaddrs(Address) -> inet:getaddrs(Address, ?FAMILY).
+getaddrs(Address, Timer) -> inet:getaddrs_tm(Address, ?FAMILY, Timer).
+
+%% inet_udp special this side addresses
+translate_ip(IP) -> inet:translate_ip(IP, ?FAMILY).
%%
%% Send data on a socket
@@ -73,11 +81,6 @@ recv(Socket, Length) -> prim_inet:recv(Socket, Length).
recv(Socket, Length, Timeout) -> prim_inet:recv(Socket, Length, Timeout).
unrecv(Socket, Data) -> prim_inet:unrecv(Socket, Data).
-%%
-%% Close a socket (async)
-%%
-close(Socket) ->
- inet:tcp_close(Socket).
%%
%% Shutdown one end of a socket
@@ -86,6 +89,12 @@ shutdown(Socket, How) ->
prim_inet:shutdown(Socket, How).
%%
+%% Close a socket (async)
+%%
+close(Socket) ->
+ inet:tcp_close(Socket).
+
+%%
%% Set controlling process
%% FIXME: move messages to new owner!!!
%%
@@ -100,24 +109,28 @@ connect(Address, Port, Opts) ->
connect(Address, Port, Opts, infinity) ->
do_connect(Address, Port, Opts, infinity);
-connect(Address, Port, Opts, Timeout) when is_integer(Timeout),
- Timeout >= 0 ->
+connect(Address, Port, Opts, Timeout)
+ when is_integer(Timeout), Timeout >= 0 ->
do_connect(Address, Port, Opts, Timeout).
-do_connect(Addr = {A,B,C,D,E,F,G,H}, Port, Opts, Time) when
- ?ip6(A,B,C,D,E,F,G,H), ?port(Port) ->
- case inet:connect_options(Opts, inet6) of
+do_connect(Addr = {A,B,C,D,E,F,G,H}, Port, Opts, Time)
+ when ?ip6(A,B,C,D,E,F,G,H), ?port(Port) ->
+ case inet:connect_options(Opts, ?MODULE) of
{error, Reason} -> exit(Reason);
- {ok, #connect_opts{fd=Fd,
- ifaddr=BAddr={Ab,Bb,Cb,Db,Eb,Fb,Gb,Hb},
- port=BPort,
- opts=SockOpts}}
+ {ok,
+ #connect_opts{
+ fd = Fd,
+ ifaddr = BAddr = {Ab,Bb,Cb,Db,Eb,Fb,Gb,Hb},
+ port = BPort,
+ opts = SockOpts}}
when ?ip6(Ab,Bb,Cb,Db,Eb,Fb,Gb,Hb), ?port(BPort) ->
- case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet6,stream,?MODULE) of
+ case inet:open(
+ Fd, BAddr, BPort, SockOpts,
+ ?PROTO, ?FAMILY, ?TYPE, ?MODULE) of
{ok, S} ->
case prim_inet:connect(S, Addr, Port, Time) of
- ok -> {ok,S};
- Error -> prim_inet:close(S), Error
+ ok -> {ok,S};
+ Error -> prim_inet:close(S), Error
end;
Error -> Error
end;
@@ -128,14 +141,18 @@ do_connect(Addr = {A,B,C,D,E,F,G,H}, Port, Opts, Time) when
%% Listen
%%
listen(Port, Opts) ->
- case inet:listen_options([{port,Port} | Opts], inet6) of
+ case inet:listen_options([{port,Port} | Opts], ?MODULE) of
{error, Reason} -> exit(Reason);
- {ok, #listen_opts{fd=Fd,
- ifaddr=BAddr={A,B,C,D,E,F,G,H},
- port=BPort,
- opts=SockOpts}=R}
+ {ok,
+ #listen_opts{
+ fd = Fd,
+ ifaddr = BAddr = {A,B,C,D,E,F,G,H},
+ port = BPort,
+ opts = SockOpts} = R}
when ?ip6(A,B,C,D,E,F,G,H), ?port(BPort) ->
- case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet6,stream,?MODULE) of
+ case inet:open(
+ Fd, BAddr, BPort, SockOpts,
+ ?PROTO, ?FAMILY, ?TYPE, ?MODULE) of
{ok, S} ->
case prim_inet:listen(S, R#listen_opts.backlog) of
ok -> {ok, S};
@@ -156,18 +173,17 @@ accept(L) ->
{ok,S};
Error -> Error
end.
-
-accept(L,Timeout) ->
- case prim_inet:accept(L,Timeout) of
+
+accept(L, Timeout) ->
+ case prim_inet:accept(L, Timeout) of
{ok, S} ->
inet_db:register_socket(S, ?MODULE),
{ok,S};
Error -> Error
end.
-
+
%%
%% Create a port/socket from a file descriptor
%%
fdopen(Fd, Opts) ->
- inet:fdopen(Fd, Opts, tcp, inet6, stream, ?MODULE).
-
+ inet:fdopen(Fd, Opts, ?PROTO, ?FAMILY, ?TYPE, ?MODULE).
diff --git a/lib/kernel/src/inet6_udp.erl b/lib/kernel/src/inet6_udp.erl
index eb6945f60a..71db0357cd 100644
--- a/lib/kernel/src/inet6_udp.erl
+++ b/lib/kernel/src/inet6_udp.erl
@@ -24,29 +24,44 @@
-export([controlling_process/2]).
-export([fdopen/2]).
--export([getserv/1, getaddr/1, getaddr/2]).
+-export([getserv/1, getaddr/1, getaddr/2, translate_ip/1]).
-include("inet_int.hrl").
+-define(FAMILY, inet6).
+-define(PROTO, udp).
+-define(TYPE, dgram).
+
+
%% inet_udp port lookup
getserv(Port) when is_integer(Port) -> {ok, Port};
-getserv(Name) when is_atom(Name) -> inet:getservbyname(Name,udp).
+getserv(Name) when is_atom(Name) -> inet:getservbyname(Name, ?PROTO).
%% inet_udp address lookup
-getaddr(Address) -> inet:getaddr(Address, inet6).
-getaddr(Address,Timer) -> inet:getaddr(Address, inet6, Timer).
+getaddr(Address) -> inet:getaddr(Address, ?FAMILY).
+getaddr(Address, Timer) -> inet:getaddr(Address, ?FAMILY, Timer).
+
+%% inet_udp special this side addresses
+translate_ip(IP) -> inet:translate_ip(IP, ?FAMILY).
+-spec open(_) -> {ok, inet:socket()} | {error, atom()}.
open(Port) -> open(Port, []).
+-spec open(_, _) -> {ok, inet:socket()} | {error, atom()}.
open(Port, Opts) ->
- case inet:udp_options([{port,Port} | Opts], inet6) of
+ case inet:udp_options(
+ [{port,Port} | Opts],
+ ?MODULE) of
{error, Reason} -> exit(Reason);
- {ok, #udp_opts{fd=Fd,
- ifaddr=BAddr={A,B,C,D,E,F,G,H},
- port=BPort,
- opts=SockOpts}}
+ {ok,
+ #udp_opts{
+ fd = Fd,
+ ifaddr = BAddr = {A,B,C,D,E,F,G,H},
+ port = BPort,
+ opts = SockOpts}}
when ?ip6(A,B,C,D,E,F,G,H), ?port(BPort) ->
- inet:open(Fd,BAddr,BPort,SockOpts,udp,inet6,dgram,?MODULE);
+ inet:open(
+ Fd, BAddr, BPort, SockOpts, ?PROTO, ?FAMILY, ?TYPE, ?MODULE);
{ok, _} -> exit(badarg)
end.
@@ -61,12 +76,13 @@ connect(S, Addr = {A,B,C,D,E,F,G,H}, P)
when ?ip6(A,B,C,D,E,F,G,H), ?port(P) ->
prim_inet:connect(S, Addr, P).
-recv(S,Len) ->
+recv(S, Len) ->
prim_inet:recvfrom(S, Len).
-recv(S,Len,Time) ->
+recv(S, Len, Time) ->
prim_inet:recvfrom(S, Len, Time).
+-spec close(inet:socket()) -> ok.
close(S) ->
inet:udp_close(S).
@@ -85,4 +101,4 @@ controlling_process(Socket, NewOwner) ->
%% Create a port/socket from a file descriptor
%%
fdopen(Fd, Opts) ->
- inet:fdopen(Fd, Opts, udp, inet6, dgram, ?MODULE).
+ inet:fdopen(Fd, Opts, ?PROTO, ?FAMILY, ?TYPE, ?MODULE).
diff --git a/lib/kernel/src/inet_int.hrl b/lib/kernel/src/inet_int.hrl
index 65d78b66c9..c8a8962e78 100644
--- a/lib/kernel/src/inet_int.hrl
+++ b/lib/kernel/src/inet_int.hrl
@@ -25,10 +25,13 @@
%%
%% family codes to open
+-define(INET_AF_UNSPEC, 0).
-define(INET_AF_INET, 1).
-define(INET_AF_INET6, 2).
-define(INET_AF_ANY, 3). % Fake for ANY in any address family
-define(INET_AF_LOOPBACK, 4). % Fake for LOOPBACK in any address family
+-define(INET_AF_LOCAL, 5). % For Unix Domain address family
+-define(INET_AF_UNDEFINED, 6). % For any unknown address family
%% type codes to open and gettype - INET_REQ_GETTYPE
-define(INET_TYPE_STREAM, 1).
@@ -378,7 +381,7 @@
{
ifaddr = any, %% bind to interface address
port = 0, %% bind to port (default is dynamic port)
- fd = -1, %% fd >= 0 => already bound
+ fd = -1, %% fd >= 0 => already bound
opts = [] %% [{active,true}] added in inet:connect_options
}).
diff --git a/lib/kernel/src/inet_sctp.erl b/lib/kernel/src/inet_sctp.erl
index 60677cb7de..8569cacb29 100644
--- a/lib/kernel/src/inet_sctp.erl
+++ b/lib/kernel/src/inet_sctp.erl
@@ -30,6 +30,7 @@
-include("inet_sctp.hrl").
-include("inet_int.hrl").
+-define(PROTO, sctp).
-define(FAMILY, inet).
-export([getserv/1,getaddr/1,getaddr/2,translate_ip/1]).
-export([open/1,close/1,listen/2,peeloff/2,connect/5]).
@@ -38,25 +39,19 @@
getserv(Port) when is_integer(Port) -> {ok, Port};
-getserv(Name) when is_atom(Name) ->
- inet:getservbyname(Name, sctp);
-getserv(_) ->
- {error,einval}.
+getserv(Name) when is_atom(Name) -> inet:getservbyname(Name, ?PROTO);
+getserv(_) -> {error,einval}.
-getaddr(Address) ->
- inet:getaddr(Address, ?FAMILY).
-getaddr(Address, Timer) ->
- inet:getaddr_tm(Address, ?FAMILY, Timer).
-
-translate_ip(IP) ->
- inet:translate_ip(IP, ?FAMILY).
+getaddr(Address) -> inet:getaddr(Address, ?FAMILY).
+getaddr(Address, Timer) -> inet:getaddr_tm(Address, ?FAMILY, Timer).
+translate_ip(IP) -> inet:translate_ip(IP, ?FAMILY).
open(Opts) ->
case inet:sctp_options(Opts, ?MODULE) of
{ok,#sctp_opts{fd=Fd,ifaddr=Addr,port=Port,type=Type,opts=SOs}} ->
- inet:open(Fd, Addr, Port, SOs, sctp, ?FAMILY, Type, ?MODULE);
+ inet:open(Fd, Addr, Port, SOs, ?PROTO, ?FAMILY, Type, ?MODULE);
Error -> Error
end.
diff --git a/lib/kernel/src/inet_tcp.erl b/lib/kernel/src/inet_tcp.erl
index ee885af3b0..dac6b3119d 100644
--- a/lib/kernel/src/inet_tcp.erl
+++ b/lib/kernel/src/inet_tcp.erl
@@ -27,13 +27,18 @@
-export([controlling_process/2]).
-export([fdopen/2]).
--export([family/0, mask/2, parse_address/1]).
+-export([family/0, mask/2, parse_address/1]). % inet_tcp_dist
-export([getserv/1, getaddr/1, getaddr/2, getaddrs/1, getaddrs/2]).
+-export([translate_ip/1]).
-include("inet_int.hrl").
+-define(FAMILY, inet).
+-define(PROTO, tcp).
+-define(TYPE, stream).
+
%% my address family
-family() -> inet.
+family() -> ?FAMILY.
%% Apply netmask on address
mask({M1,M2,M3,M4}, {IP1,IP2,IP3,IP4}) ->
@@ -48,16 +53,19 @@ parse_address(Host) ->
%% inet_tcp port lookup
getserv(Port) when is_integer(Port) -> {ok, Port};
-getserv(Name) when is_atom(Name) -> inet:getservbyname(Name,tcp).
+getserv(Name) when is_atom(Name) -> inet:getservbyname(Name, ?PROTO).
%% inet_tcp address lookup
-getaddr(Address) -> inet:getaddr(Address, inet).
-getaddr(Address,Timer) -> inet:getaddr_tm(Address, inet, Timer).
+getaddr(Address) -> inet:getaddr(Address, ?FAMILY).
+getaddr(Address, Timer) -> inet:getaddr_tm(Address, ?FAMILY, Timer).
%% inet_tcp address lookup
-getaddrs(Address) -> inet:getaddrs(Address, inet).
-getaddrs(Address,Timer) -> inet:getaddrs_tm(Address,inet,Timer).
-
+getaddrs(Address) -> inet:getaddrs(Address, ?FAMILY).
+getaddrs(Address, Timer) -> inet:getaddrs_tm(Address, ?FAMILY, Timer).
+
+%% inet_udp special this side addresses
+translate_ip(IP) -> inet:translate_ip(IP, ?FAMILY).
+
%%
%% Send data on a socket
%%
@@ -77,7 +85,7 @@ unrecv(Socket, Data) -> prim_inet:unrecv(Socket, Data).
%%
shutdown(Socket, How) ->
prim_inet:shutdown(Socket, How).
-
+
%%
%% Close a socket (async)
%%
@@ -88,7 +96,7 @@ close(Socket) ->
%% Set controlling process
%%
controlling_process(Socket, NewOwner) ->
- inet:tcp_controlling_process(Socket, NewOwner).
+ inet:tcp_controlling_process(Socket, NewOwner).
%%
%% Connect
@@ -98,23 +106,28 @@ connect(Address, Port, Opts) ->
connect(Address, Port, Opts, infinity) ->
do_connect(Address, Port, Opts, infinity);
-connect(Address, Port, Opts, Timeout) when is_integer(Timeout),
- Timeout >= 0 ->
+connect(Address, Port, Opts, Timeout)
+ when is_integer(Timeout), Timeout >= 0 ->
do_connect(Address, Port, Opts, Timeout).
-do_connect({A,B,C,D}, Port, Opts, Time) when ?ip(A,B,C,D), ?port(Port) ->
- case inet:connect_options(Opts, inet) of
+do_connect(Addr = {A,B,C,D}, Port, Opts, Time)
+ when ?ip(A,B,C,D), ?port(Port) ->
+ case inet:connect_options(Opts, ?MODULE) of
{error, Reason} -> exit(Reason);
- {ok, #connect_opts{fd=Fd,
- ifaddr=BAddr={Ab,Bb,Cb,Db},
- port=BPort,
- opts=SockOpts}}
+ {ok,
+ #connect_opts{
+ fd = Fd,
+ ifaddr = BAddr = {Ab,Bb,Cb,Db},
+ port = BPort,
+ opts = SockOpts}}
when ?ip(Ab,Bb,Cb,Db), ?port(BPort) ->
- case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet,stream,?MODULE) of
+ case inet:open(
+ Fd, BAddr, BPort, SockOpts,
+ ?PROTO, ?FAMILY, ?TYPE, ?MODULE) of
{ok, S} ->
- case prim_inet:connect(S, {A,B,C,D}, Port, Time) of
- ok -> {ok,S};
- Error -> prim_inet:close(S), Error
+ case prim_inet:connect(S, Addr, Port, Time) of
+ ok -> {ok,S};
+ Error -> prim_inet:close(S), Error
end;
Error -> Error
end;
@@ -125,14 +138,18 @@ do_connect({A,B,C,D}, Port, Opts, Time) when ?ip(A,B,C,D), ?port(Port) ->
%% Listen
%%
listen(Port, Opts) ->
- case inet:listen_options([{port,Port} | Opts], inet) of
- {error,Reason} -> exit(Reason);
- {ok, #listen_opts{fd=Fd,
- ifaddr=BAddr={A,B,C,D},
- port=BPort,
- opts=SockOpts}=R}
+ case inet:listen_options([{port,Port} | Opts], ?MODULE) of
+ {error, Reason} -> exit(Reason);
+ {ok,
+ #listen_opts{
+ fd = Fd,
+ ifaddr = BAddr = {A,B,C,D},
+ port = BPort,
+ opts = SockOpts} = R}
when ?ip(A,B,C,D), ?port(BPort) ->
- case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet,stream,?MODULE) of
+ case inet:open(
+ Fd, BAddr, BPort, SockOpts,
+ ?PROTO, ?FAMILY, ?TYPE, ?MODULE) of
{ok, S} ->
case prim_inet:listen(S, R#listen_opts.backlog) of
ok -> {ok, S};
@@ -146,23 +163,24 @@ listen(Port, Opts) ->
%%
%% Accept
%%
-accept(L) ->
+accept(L) ->
case prim_inet:accept(L) of
{ok, S} ->
inet_db:register_socket(S, ?MODULE),
{ok,S};
Error -> Error
end.
-
-accept(L,Timeout) ->
- case prim_inet:accept(L,Timeout) of
+
+accept(L, Timeout) ->
+ case prim_inet:accept(L, Timeout) of
{ok, S} ->
inet_db:register_socket(S, ?MODULE),
{ok,S};
Error -> Error
end.
+
%%
%% Create a port/socket from a file descriptor
%%
fdopen(Fd, Opts) ->
- inet:fdopen(Fd, Opts, tcp, inet, stream, ?MODULE).
+ inet:fdopen(Fd, Opts, ?PROTO, ?FAMILY, ?TYPE, ?MODULE).
diff --git a/lib/kernel/src/inet_udp.erl b/lib/kernel/src/inet_udp.erl
index 7e8d9cdb72..8a8aa8ecca 100644
--- a/lib/kernel/src/inet_udp.erl
+++ b/lib/kernel/src/inet_udp.erl
@@ -24,21 +24,26 @@
-export([controlling_process/2]).
-export([fdopen/2]).
--export([getserv/1, getaddr/1, getaddr/2]).
+-export([getserv/1, getaddr/1, getaddr/2, translate_ip/1]).
-include("inet_int.hrl").
+-define(FAMILY, inet).
+-define(PROTO, udp).
+-define(TYPE, dgram).
-define(RECBUF, (8*1024)).
-
%% inet_udp port lookup
getserv(Port) when is_integer(Port) -> {ok, Port};
-getserv(Name) when is_atom(Name) -> inet:getservbyname(Name,udp).
+getserv(Name) when is_atom(Name) -> inet:getservbyname(Name, ?PROTO).
%% inet_udp address lookup
-getaddr(Address) -> inet:getaddr(Address, inet).
-getaddr(Address,Timer) -> inet:getaddr_tm(Address, inet, Timer).
+getaddr(Address) -> inet:getaddr(Address, ?FAMILY).
+getaddr(Address, Timer) -> inet:getaddr(Address, ?FAMILY, Timer).
+
+%% inet_udp special this side addresses
+translate_ip(IP) -> inet:translate_ip(IP, ?FAMILY).
-spec open(_) -> {ok, inet:socket()} | {error, atom()}.
open(Port) -> open(Port, []).
@@ -47,33 +52,38 @@ open(Port) -> open(Port, []).
open(Port, Opts) ->
case inet:udp_options(
[{port,Port}, {recbuf, ?RECBUF} | Opts],
- inet) of
+ ?MODULE) of
{error, Reason} -> exit(Reason);
- {ok, #udp_opts{fd=Fd,
- ifaddr=BAddr={A,B,C,D},
- port=BPort,
- opts=SockOpts}} when ?ip(A,B,C,D), ?port(BPort) ->
- inet:open(Fd,BAddr,BPort,SockOpts,udp,inet,dgram,?MODULE);
+ {ok,
+ #udp_opts{
+ fd = Fd,
+ ifaddr = BAddr = {A,B,C,D},
+ port = BPort,
+ opts = SockOpts}}
+ when ?ip(A,B,C,D), ?port(BPort) ->
+ inet:open(
+ Fd, BAddr, BPort, SockOpts, ?PROTO, ?FAMILY, ?TYPE, ?MODULE);
{ok, _} -> exit(badarg)
end.
-send(S,{A,B,C,D},P,Data) when ?ip(A,B,C,D), ?port(P) ->
- prim_inet:sendto(S, {A,B,C,D}, P, Data).
+send(S, {A,B,C,D} = Addr, P, Data)
+ when ?ip(A,B,C,D), ?port(P) ->
+ prim_inet:sendto(S, Addr, P, Data).
send(S, Data) ->
prim_inet:sendto(S, {0,0,0,0}, 0, Data).
-connect(S, {A,B,C,D}, P) when ?ip(A,B,C,D), ?port(P) ->
- prim_inet:connect(S, {A,B,C,D}, P).
+connect(S, Addr = {A,B,C,D}, P)
+ when ?ip(A,B,C,D), ?port(P) ->
+ prim_inet:connect(S, Addr, P).
-recv(S,Len) ->
+recv(S, Len) ->
prim_inet:recvfrom(S, Len).
-recv(S,Len,Time) ->
+recv(S, Len, Time) ->
prim_inet:recvfrom(S, Len, Time).
-spec close(inet:socket()) -> ok.
-
close(S) ->
inet:udp_close(S).
@@ -92,9 +102,9 @@ controlling_process(Socket, NewOwner) ->
%% Create a port/socket from a file descriptor
%%
fdopen(Fd, Opts) ->
- inet:fdopen(Fd,
- optuniquify([{recbuf, ?RECBUF} | Opts]),
- udp, inet, dgram, ?MODULE).
+ inet:fdopen(
+ Fd, optuniquify([{recbuf, ?RECBUF} | Opts]),
+ ?PROTO, ?FAMILY, ?TYPE, ?MODULE).
%% Remove all duplicate options from an option list.
diff --git a/lib/kernel/src/kernel.app.src b/lib/kernel/src/kernel.app.src
index 1acd6803b2..56d1699656 100644
--- a/lib/kernel/src/kernel.app.src
+++ b/lib/kernel/src/kernel.app.src
@@ -55,6 +55,8 @@
inet_tcp_dist,
kernel,
kernel_config,
+ local_tcp,
+ local_udp,
net,
net_adm,
net_kernel,
diff --git a/lib/kernel/src/local_tcp.erl b/lib/kernel/src/local_tcp.erl
new file mode 100644
index 0000000000..e3c67dfbb7
--- /dev/null
+++ b/lib/kernel/src/local_tcp.erl
@@ -0,0 +1,178 @@
+%%
+%% %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(local_tcp).
+
+%% Socket server for TCP/IP
+
+-export([connect/3, connect/4, listen/2, accept/1, accept/2, close/1]).
+-export([send/2, send/3, recv/2, recv/3, unrecv/2]).
+-export([shutdown/2]).
+-export([controlling_process/2]).
+-export([fdopen/2]).
+
+-export([getserv/1, getaddr/1, getaddr/2, getaddrs/1, getaddrs/2]).
+-export([translate_ip/1]).
+
+-include("inet_int.hrl").
+
+-define(FAMILY, local).
+-define(PROTO, tcp).
+-define(TYPE, stream).
+
+%% port lookup
+getserv(0) -> {ok, 0}.
+
+%% no address lookup
+getaddr({?FAMILY, _} = Address) -> {ok, Address}.
+getaddr({?FAMILY, _} = Address, _Timer) -> {ok, Address}.
+
+%% no address lookup
+getaddrs({?FAMILY, _} = Address) -> {ok, [Address]}.
+getaddrs({?FAMILY, _} = Address, _Timer) -> {ok, [Address]}.
+
+%% special this side addresses
+translate_ip(IP) -> IP.
+
+%%
+%% Send data on a socket
+%%
+send(Socket, Packet, Opts) -> prim_inet:send(Socket, Packet, Opts).
+send(Socket, Packet) -> prim_inet:send(Socket, Packet, []).
+
+%%
+%% Receive data from a socket (inactive only)
+%%
+recv(Socket, Length) -> prim_inet:recv(Socket, Length).
+recv(Socket, Length, Timeout) -> prim_inet:recv(Socket, Length, Timeout).
+
+unrecv(Socket, Data) -> prim_inet:unrecv(Socket, Data).
+
+%%
+%% Shutdown one end of a socket
+%%
+shutdown(Socket, How) ->
+ prim_inet:shutdown(Socket, How).
+
+%%
+%% Close a socket (async)
+%%
+close(Socket) ->
+ inet:tcp_close(Socket).
+
+%%
+%% Set controlling process
+%% FIXME: move messages to new owner!!!
+%%
+controlling_process(Socket, NewOwner) ->
+ inet:tcp_controlling_process(Socket, NewOwner).
+
+%%
+%% Connect
+%%
+connect(Address, Port, Opts) ->
+ do_connect(Address, Port, Opts, infinity).
+%%
+connect(Address, Port, Opts, infinity) ->
+ do_connect(Address, Port, Opts, infinity);
+connect(Address, Port, Opts, Timeout)
+ when is_integer(Timeout), Timeout >= 0 ->
+ do_connect(Address, Port, Opts, Timeout).
+
+do_connect(Addr = {?FAMILY, _}, 0, Opts, Time) ->
+ case inet:connect_options(Opts, ?MODULE) of
+ {error, Reason} -> exit(Reason);
+ {ok,
+ #connect_opts{
+ fd = Fd,
+ ifaddr = BAddr,
+ port = 0,
+ opts = SockOpts}}
+ when tuple_size(BAddr) =:= 2, element(1, BAddr) =:= ?FAMILY;
+ BAddr =:= any ->
+ case inet:open(
+ Fd,
+ case BAddr of
+ any ->
+ undefined;
+ _ ->
+ BAddr
+ end,
+ 0, SockOpts, ?PROTO, ?FAMILY, ?TYPE, ?MODULE) of
+ {ok, S} ->
+ case prim_inet:connect(S, Addr, 0, Time) of
+ ok -> {ok,S};
+ Error -> prim_inet:close(S), Error
+ end;
+ Error -> Error
+ end;
+ {ok, _} -> exit(badarg)
+ end.
+
+%%
+%% Listen
+%%
+listen(0, Opts) ->
+ case inet:listen_options([{port,0} | Opts], ?MODULE) of
+ {error, Reason} -> exit(Reason);
+ {ok,
+ #listen_opts{
+ fd = Fd,
+ ifaddr = BAddr,
+ port = 0,
+ opts = SockOpts} = R}
+ when tuple_size(BAddr) =:= 2, element(1, BAddr) =:= ?FAMILY;
+ BAddr =:= any ->
+ case inet:open(
+ Fd, BAddr, 0, SockOpts,
+ ?PROTO, ?FAMILY, ?TYPE, ?MODULE) of
+ {ok, S} ->
+ case prim_inet:listen(S, R#listen_opts.backlog) of
+ ok -> {ok, S};
+ Error -> prim_inet:close(S), Error
+ end;
+ Error -> Error
+ end;
+ {ok, _} -> exit(badarg)
+ end.
+
+%%
+%% Accept
+%%
+accept(L) ->
+ case prim_inet:accept(L) of
+ {ok, S} ->
+ inet_db:register_socket(S, ?MODULE),
+ {ok,S};
+ Error -> Error
+ end.
+%%
+accept(L, Timeout) ->
+ case prim_inet:accept(L, Timeout) of
+ {ok, S} ->
+ inet_db:register_socket(S, ?MODULE),
+ {ok,S};
+ Error -> Error
+ end.
+
+%%
+%% Create a port/socket from a file descriptor
+%%
+fdopen(Fd, Opts) ->
+ inet:fdopen(Fd, Opts, ?PROTO, ?FAMILY, ?TYPE, ?MODULE).
diff --git a/lib/kernel/src/local_udp.erl b/lib/kernel/src/local_udp.erl
new file mode 100644
index 0000000000..481a8c4910
--- /dev/null
+++ b/lib/kernel/src/local_udp.erl
@@ -0,0 +1,106 @@
+%%
+%% %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(local_udp).
+
+-export([open/1, open/2, close/1]).
+-export([send/2, send/4, recv/2, recv/3, connect/3]).
+-export([controlling_process/2]).
+-export([fdopen/2]).
+
+-export([getserv/1, getaddr/1, getaddr/2, translate_ip/1]).
+
+-include("inet_int.hrl").
+
+-define(FAMILY, local).
+-define(PROTO, udp).
+-define(TYPE, dgram).
+
+
+%% port lookup
+getserv(0) -> {ok, 0}.
+
+%% no address lookup
+getaddr({?FAMILY, _} = Address) -> {ok, Address}.
+getaddr({?FAMILY, _} = Address, _Timer) -> {ok, Address}.
+
+%% special this side addresses
+translate_ip(IP) -> IP.
+
+open(0) -> open(0, []).
+%%
+open(0, Opts) ->
+ case inet:udp_options(
+ [{port,0} | Opts],
+ ?MODULE) of
+ {error, Reason} -> exit(Reason);
+ {ok,
+ #udp_opts{
+ fd = Fd,
+ ifaddr = BAddr,
+ port = 0,
+ opts = SockOpts}}
+ when tuple_size(BAddr) =:= 2, element(1, BAddr) =:= ?FAMILY;
+ BAddr =:= any ->
+ inet:open(
+ Fd,
+ case BAddr of
+ any ->
+ undefined;
+ _ ->
+ BAddr
+ end,
+ 0, SockOpts, ?PROTO, ?FAMILY, ?TYPE, ?MODULE);
+ {ok, _} -> exit(badarg)
+ end.
+
+send(S, Addr = {?FAMILY,_}, 0, Data) ->
+ prim_inet:sendto(S, Addr, 0, Data).
+%%
+send(S, Data) ->
+ prim_inet:sendto(S, {?FAMILY,<<>>}, 0, Data).
+
+connect(S, Addr = {?FAMILY,_}, 0) ->
+ prim_inet:connect(S, Addr, 0).
+
+recv(S, Len) ->
+ prim_inet:recvfrom(S, Len).
+%%
+recv(S, Len, Time) ->
+ prim_inet:recvfrom(S, Len, Time).
+
+close(S) ->
+ inet:udp_close(S).
+
+%%
+%% Set controlling process:
+%% 1) First sync socket into a known state
+%% 2) Move all messages onto the new owners message queue
+%% 3) Commit the owner
+%% 4) Wait for ack of new Owner (since socket does some link and unlink)
+%%
+
+controlling_process(Socket, NewOwner) ->
+ inet:udp_controlling_process(Socket, NewOwner).
+
+%%
+%% Create a port/socket from a file descriptor
+%%
+fdopen(Fd, Opts) ->
+ inet:fdopen(Fd, Opts, ?PROTO, ?FAMILY, ?TYPE, ?MODULE).
diff --git a/lib/kernel/test/heart_SUITE.erl b/lib/kernel/test/heart_SUITE.erl
index 548b27db97..e63ed34973 100644
--- a/lib/kernel/test/heart_SUITE.erl
+++ b/lib/kernel/test/heart_SUITE.erl
@@ -29,11 +29,11 @@
set_cmd/1, clear_cmd/1, get_cmd/1,
callback_api/1,
options_api/1,
- dont_drop/1, kill_pid/1]).
+ dont_drop/1, kill_pid/1, heart_no_kill/1]).
-export([init_per_testcase/2, end_per_testcase/2]).
--export([start_heart_stress/1, mangle/1, suicide_by_heart/0]).
+-export([start_heart_stress/1, mangle/1, suicide_by_heart/0, non_suicide_by_heart/0]).
-define(DEFAULT_TIMEOUT_SECS, 120).
@@ -491,6 +491,30 @@ do_kill_pid(_Config) ->
false
end.
+
+heart_no_kill(suite) ->
+ [];
+heart_no_kill(doc) ->
+ ["Tests that heart doesn't kill the old erlang node when ",
+ "HEART_NO_KILL is set."];
+heart_no_kill(Config) when is_list(Config) ->
+ ok = do_no_kill(Config).
+
+do_no_kill(_Config) ->
+ Name = heart_test,
+ {ok,Node} = start_node_run(Name,[],non_suicide_by_heart,[]),
+ io:format("Node is ~p~n", [Node]),
+ ok = wait_for_node(Node,15),
+ io:format("wait_for_node is ~p~n", [ok]),
+ erlang:monitor_node(Node, true),
+ receive {nodedown,Node} -> false
+ after 30000 ->
+ io:format("Node didn't die..\n"),
+ rpc:call(Node,init,stop,[]),
+ io:format("done init:stop..\n"),
+ ok
+ end.
+
wait_for_node(_,0) ->
false;
wait_for_node(Node,N) ->
@@ -609,6 +633,18 @@ suicide_by_heart() ->
sallad
end.
+non_suicide_by_heart() ->
+ P = open_port({spawn,"heart -ht 11 -pid "++os:getpid()},[exit_status, {env, {"HEART_NO_KILL", "TRUE"}}, {packet,2}]),
+ receive X -> X end,
+ %% Just hang and wait for heart to timeout
+ receive
+ {P,{exit_status,_}} ->
+ ok
+ after
+ 20000 ->
+ exit(timeout)
+ end.
+
%% generate a module from binary
generate(Module, Attributes, FunStrings) ->
diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl
index c93b10fa1c..f60c13d2e3 100644
--- a/lib/kernel/test/inet_SUITE.erl
+++ b/lib/kernel/test/inet_SUITE.erl
@@ -139,11 +139,13 @@ t_gethostbyaddr(Config) when is_list(Config) ->
ok;
_ ->
io:format("alias list: ~p", [HEnt#hostent.h_aliases]),
- io:format("check alias list: ~p", [[Aliases,[Rname]]]),
+ io:format(
+ "check alias list: ~p", [[Aliases,tl(Aliases),[Rname]]]),
io:format("name: ~p", [HEnt#hostent.h_name]),
io:format("check name: ~p", [[Name,FullName]]),
- check_elems([{HEnt#hostent.h_name,[Name,FullName]},
- {HEnt#hostent.h_aliases,[[],Aliases,[Rname]]}])
+ check_elems(
+ [{HEnt#hostent.h_name,[Name,FullName]},
+ {HEnt#hostent.h_aliases,[[],Aliases,tl(Aliases),[Rname]]}])
end,
{_DName, _DFullName, DIPStr, DIP, _, _, _} = ct:get_config(test_dummy_host),
@@ -171,8 +173,9 @@ t_gethostbyaddr_v6(Config) when is_list(Config) ->
h_length = 16,
h_addr_list = [IP6]},
HEnt6_ = HEnt6,
- check_elems([{HEnt6#hostent.h_name,[Name6,FullName6]},
- {HEnt6#hostent.h_aliases,[[],Aliases6]}]),
+ check_elems(
+ [{HEnt6#hostent.h_name,[Name6,FullName6]},
+ {HEnt6#hostent.h_aliases,[[],Aliases6,tl(Aliases6)]}]),
{_DName6, _DFullName6, DIPStr6, DIP6, _} =
ct:get_config(test_dummy_ipv6_host),
@@ -195,14 +198,14 @@ t_gethostbyname(Config) when is_list(Config) ->
HEnt_ = HEnt,
check_elems([{HEnt#hostent.h_name,[Name,FullName]},
- {HEnt#hostent.h_aliases,[[],Aliases]}]),
+ {HEnt#hostent.h_aliases,[[],Aliases,tl(Aliases)]}]),
{ok,HEntF} = inet:gethostbyname(FullName),
HEntF_ = HEntF#hostent{h_name = FullName,
h_addrtype = inet,
h_length = 4,
h_addr_list = [IP]},
HEntF_ = HEntF,
- check_elems([{HEnt#hostent.h_aliases,[[],Aliases]}]),
+ check_elems([{HEnt#hostent.h_aliases,[[],Aliases,tl(Aliases)]}]),
%%
FullNameU = toupper(FullName),
{ok,HEntU} = inet:gethostbyname(FullNameU),
@@ -237,7 +240,7 @@ t_gethostbyname_v6(Config) when is_list(Config) ->
h_length = 16} = HEnt,
check_elems(
[{HEnt#hostent.h_name,[Name,FullName]},
- {HEnt#hostent.h_aliases,[[],Aliases]}]);
+ {HEnt#hostent.h_aliases,[[],Aliases,tl(Aliases)]}]);
[IP46] -> % IPv4 compatible address
{ok,HEnt4} = inet:gethostbyname(Name, inet),
#hostent{h_addrtype = inet,
@@ -257,7 +260,7 @@ t_gethostbyname_v6(Config) when is_list(Config) ->
h_addrtype = inet6,
h_length = 16} = HEntF,
check_elems(
- [{HEnt#hostent.h_aliases,[[],Aliases]}]);
+ [{HEnt#hostent.h_aliases,[[],Aliases,tl(Aliases)]}]);
[IP46F] -> % IPv4 compatible address
{ok,HEnt4F} = inet:gethostbyname(FullName, inet),
#hostent{h_addrtype = inet,
@@ -363,7 +366,7 @@ ipv4_to_ipv6(Config) when is_list(Config) ->
h_addr_list = [IP_46]},
HEnt_ = HEnt,
check_elems([{HEnt#hostent.h_name,[IP_46_Str,IPStr]},
- {HEnt#hostent.h_aliases,[[],Aliases]}]);
+ {HEnt#hostent.h_aliases,[[],Aliases,tl(Aliases)]}]);
{_,IP4to6Res} -> ok
end,
ok.
@@ -1002,12 +1005,12 @@ getifaddrs(Config) when is_list (Config) ->
[check_addr(Addr) || Addr <- Addrs],
ok.
-check_addr(Addr)
+check_addr({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) ->
+check_addr({addr,Addr}) ->
io:format("Addr: ~p.~n", [Addr]),
Ping = "ping",
Pong = "pong",
@@ -1021,74 +1024,82 @@ check_addr(Addr) ->
ok = gen_tcp:close(S1),
{ok,Pong} = gen_tcp:recv(S2, length(Pong)),
ok = gen_tcp:close(S2),
- ok = gen_tcp:close(L),
- ok.
+ ok = gen_tcp:close(L).
-record(ifopts, {name,flags,addrs=[],hwaddr}).
ifaddrs([]) -> [];
ifaddrs([{If,Opts}|IOs]) ->
- #ifopts{flags=Flags} = Ifopts =
- check_ifopts(Opts, #ifopts{name=If}),
- case Flags =/= undefined andalso lists:member(up, Flags) of
- true ->
- Ifopts#ifopts.addrs;
- false ->
- []
- end++ifaddrs(IOs).
+ #ifopts{flags=F} = Ifopts = check_ifopts(Opts, #ifopts{name=If}),
+ case F of
+ {flags,Flags} ->
+ case lists:member(up, Flags) of
+ true ->
+ Ifopts#ifopts.addrs;
+ false ->
+ []
+ end ++ ifaddrs(IOs);
+ undefined ->
+ ifaddrs(IOs)
+ end.
-check_ifopts([], #ifopts{name=If,flags=Flags,addrs=Raddrs}=Ifopts) ->
+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...
- if is_list(Flags) -> ok;
- true ->
- ct:fail({flags_undefined,If})
- end,
+ {flags,Flags} = F,
case lists:member(broadcast, Flags) of
true ->
[case A of
- {_,_,_} -> A;
- {T,_} when tuple_size(T) =:= 8 -> A;
- _ ->
- ct:fail({broaddr_missing,If,A})
+ {{addr,_},{netmask,_},{broadaddr,_}} ->
+ A;
+ {{addr,T},{netmask,_}} when tuple_size(T) =:= 8 ->
+ A
end || A <- Addrs];
false ->
- [case A of {_,_} -> A;
- _ ->
- ct:fail({should_have_netmask,If,A})
- end || A <- Addrs]
+ 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,Flags}|Opts], #ifopts{flags=undefined}=Ifopts) ->
- check_ifopts(Opts, Ifopts#ifopts{flags=Flags});
-check_ifopts([{flags,Fs}|Opts], #ifopts{flags=Flags}=Ifopts) ->
- case Fs of
+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#ifopts{});
+ check_ifopts(Opts, Ifopts);
_ ->
- ct:fail({multiple_flags,Fs,Ifopts})
+ ct:fail({multiple_flags,F,Ifopts})
end;
check_ifopts(
- [{addr,Addr},{netmask,Netmask},{broadaddr,Broadaddr}|Opts],
+ [{addr,_}=A,{netmask,_}=N,{dstaddr,_}=D|Opts],
#ifopts{addrs=Addrs}=Ifopts) ->
- check_ifopts(Opts, Ifopts#ifopts{addrs=[{Addr,Netmask,Broadaddr}|Addrs]});
+ check_ifopts(Opts, Ifopts#ifopts{addrs=[{A,N,D}|Addrs]});
check_ifopts(
- [{addr,Addr},{netmask,Netmask},{dstaddr,_}|Opts],
+ [{addr,_}=A,{netmask,_}=N,{broadaddr,_}=B|Opts],
#ifopts{addrs=Addrs}=Ifopts) ->
- check_ifopts(Opts, Ifopts#ifopts{addrs=[{Addr,Netmask}|Addrs]});
+ check_ifopts(Opts, Ifopts#ifopts{addrs=[{A,N,B}|Addrs]});
check_ifopts(
- [{addr,Addr},{netmask,Netmask}|Opts],
+ [{addr,_}=A,{netmask,_}=N|Opts],
#ifopts{addrs=Addrs}=Ifopts) ->
- check_ifopts(Opts, Ifopts#ifopts{addrs=[{Addr,Netmask}|Addrs]});
-check_ifopts([{addr,Addr}|Opts], #ifopts{addrs=Addrs}=Ifopts) ->
- check_ifopts(Opts, Ifopts#ifopts{addrs=[{Addr}|Addrs]});
-check_ifopts([{hwaddr,Hwaddr}|Opts], #ifopts{hwaddr=undefined}=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=Hwaddr});
-check_ifopts([{hwaddr,HwAddr}|_], #ifopts{}=Ifopts) ->
- ct:fail({multiple_hwaddrs,HwAddr,Ifopts}).
+ check_ifopts(Opts, Ifopts#ifopts{hwaddr=H});
+check_ifopts([{hwaddr,_}=H|_], #ifopts{}=Ifopts) ->
+ ct:fail({multiple_hwaddrs,H,Ifopts}).
%% 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 9662d1fef5..6691ad9c06 100644
--- a/lib/kernel/test/inet_res_SUITE.erl
+++ b/lib/kernel/test/inet_res_SUITE.erl
@@ -42,6 +42,21 @@
-define(RUN_NAMED, "run-named").
+%% This test suite use a script ?RUN_NAMED that tries to start
+%% a temporary local nameserver BIND 8 or 9 that must be installed
+%% on your machine.
+%%
+%% For example, on Ubuntu 14.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:
+%% /ldisk/daily_build/** r,
+%% And yes; the trailing comma must be there...
+
+
+
suite() ->
[{ct_hooks,[ts_install_cth]},
{timetrap,{minutes,1}}].
diff --git a/lib/megaco/src/app/megaco.appup.src b/lib/megaco/src/app/megaco.appup.src
index 93bf1d980c..46da79cfe3 100644
--- a/lib/megaco/src/app/megaco.appup.src
+++ b/lib/megaco/src/app/megaco.appup.src
@@ -192,34 +192,11 @@
{"%VSN%",
[
- {"3.17.3", [{restart_application,megaco}]},
- {"3.17.2", []},
- {"3.17.1", [{restart_application,megaco}]},
- {"3.17.0.3", [{restart_application,megaco}]},
- {"3.17.0.2", []},
- {"3.17.0.1", []},
- {"3.17", []},
- {"3.16.0.3",
- [
- {update, megaco_flex_scanner_handler, {advanced, upgrade_from_pre_3_17},
- soft_purge, soft_purge, []}
- ]
- }
+ {<<"3\\..*">>, [{restart_application, megaco}]}
],
+
[
- {"3.17.3", [{restart_application,megaco}]},
- {"3.17.2", []},
- {"3.17.1", [{restart_application,megaco}]},
- {"3.17.0.3", [{restart_application,megaco}]},
- {"3.17.0.2", []},
- {"3.17.0.1", []},
- {"3.17", []},
- {"3.16.0.3",
- [
- {update, megaco_flex_scanner_handler, {advanced, downgrade_to_pre_3_17},
- soft_purge, soft_purge, []}
- ]
- }
+ {<<"3\\..*">>, [{restart_application, megaco}]}
]
}.
diff --git a/lib/observer/src/crashdump_viewer.erl b/lib/observer/src/crashdump_viewer.erl
index de52e2a995..9268dac180 100644
--- a/lib/observer/src/crashdump_viewer.erl
+++ b/lib/observer/src/crashdump_viewer.erl
@@ -1491,6 +1491,9 @@ get_portinfo(Fd,Port) ->
"Port controls linked-in driver" ->
Str = lists:flatten(["Linked in driver: " | val(Fd)]),
get_portinfo(Fd,Port#port{controls=Str});
+ "Port controls forker process" ->
+ Str = lists:flatten(["Forker process: " | val(Fd)]),
+ get_portinfo(Fd,Port#port{controls=Str});
"Port controls external process" ->
Str = lists:flatten(["External proc: " | val(Fd)]),
get_portinfo(Fd,Port#port{controls=Str});
diff --git a/lib/observer/src/observer_procinfo.erl b/lib/observer/src/observer_procinfo.erl
index fe2aa11450..620979dcc9 100644
--- a/lib/observer/src/observer_procinfo.erl
+++ b/lib/observer/src/observer_procinfo.erl
@@ -317,7 +317,7 @@ fetch_state_info2(Pid, M) ->
of
{status, _, {module, _},
[_PDict, _SysState, _Parent, _Dbg,
- [Header,{data, First},{data, Second}]]} ->
+ [Header,{data, First},{data, Second}|_]]} ->
[{"Behaviour", B}, Header] ++ First ++ Second;
{status, _, {module, _},
[_PDict, _SysState, _Parent, _Dbg,
diff --git a/lib/public_key/doc/src/Makefile b/lib/public_key/doc/src/Makefile
index f3db24afc9..5bdc5d4159 100644
--- a/lib/public_key/doc/src/Makefile
+++ b/lib/public_key/doc/src/Makefile
@@ -38,7 +38,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
# ----------------------------------------------------
XML_APPLICATION_FILES = ref_man.xml
XML_REF3_FILES = public_key.xml
-XML_REF6_FILES =
+XML_REF6_FILES = public_key_app.xml
XML_PART_FILES = part.xml part_notes.xml
XML_CHAPTER_FILES = \
@@ -50,7 +50,7 @@ XML_CHAPTER_FILES = \
BOOK_FILES = book.xml
XML_FILES = $(BOOK_FILES) $(XML_APPLICATION_FILES) $(XML_REF3_FILES) \
- $(XML_PART_FILES) $(XML_CHAPTER_FILES)
+ $(XML_REF6_FILES) $(XML_PART_FILES) $(XML_CHAPTER_FILES)
GIF_FILES = note.gif
@@ -67,9 +67,11 @@ 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:%_app.xml=$(MAN6DIR)/%.6)
HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
@@ -98,10 +100,11 @@ html: gifs $(HTML_REF_MAN_FILE)
clean clean_docs:
rm -rf $(HTMLDIR)/*
rm -f $(MAN3DIR)/*
+ rm -f $(MAN6DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
-man: $(MAN3_FILES)
+man: $(MAN3_FILES) $(MAN6_FILES)
gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
@@ -122,6 +125,8 @@ release_docs_spec: docs
$(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
$(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
$(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man6"
+ $(INSTALL_DATA) $(MAN6DIR)/* "$(RELEASE_PATH)/man/man6"
release_spec:
info:
diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml
index 04daee460f..1aa601dc55 100644
--- a/lib/public_key/doc/src/public_key.xml
+++ b/lib/public_key/doc/src/public_key.xml
@@ -34,40 +34,13 @@
<module>public_key</module>
<modulesummary>API module for public-key infrastructure.</modulesummary>
<description>
- <p>This module provides functions to handle public-key infrastructure. It can
- encode/decode different file formats (PEM, OpenSSH), sign and verify digital signatures,
- and validate certificate paths and certificate revocation lists.
+ <p>Provides functions to handle public-key infrastructure,
+ for details see
+ <seealso marker="public_key_app">public_key(6)</seealso>.
</p>
</description>
<section>
- <title>public_key</title>
-
- <list type="bulleted">
- <item> Public Key requires the Crypto and ASN1 applications,
- the latter as OTP R16 (hopefully the runtime dependency on ASN1 will
- be removed again in the future).</item>
-
- <item>Supports <url href="http://www.ietf.org/rfc/rfc5280.txt">RFC 5280 </url> -
- Internet X.509 Public-Key Infrastructure Certificate and Certificate Revocation List
- (CRL) Profile </item>
- <item>Supports <url href="http://www.ietf.org/rfc/rfc3447.txt"> PKCS-1 </url> -
- RSA Cryptography Standard </item>
- <item>Supports <url href="http://csrc.nist.gov/publications/fips/fips186-3/fips_186-3.pdf"> DSS</url> -
- Digital Signature Standard (DSA - Digital Signature Algorithm)</item>
- <item>Supports
- <url href="http://www.emc.com/emc-plus/rsa-labs/standards-initiatives/pkcs-3-diffie-hellman-key-agreement-standar.htm"> PKCS-3 </url> -
- Diffie-Hellman Key Agreement Standard </item>
- <item>Supports <url href="http://www.ietf.org/rfc/rfc2898.txt"> PKCS-5</url> -
- Password-Based Cryptography Standard </item>
- <item>Supports <url href="http://www.ietf.org/rfc/rfc5208.txt"> PKCS-8</url> -
- Private-Key Information Syntax Standard</item>
- <item>Supports <url href="http://www.ietf.org/rfc/rfc5967.txt"> PKCS-10</url> -
- Certification Request Syntax Standard</item>
- </list>
- </section>
-
- <section>
<title>DATA TYPES</title>
<note><p>All records used in this Reference Manual
diff --git a/lib/public_key/doc/src/public_key_app.xml b/lib/public_key/doc/src/public_key_app.xml
new file mode 100644
index 0000000000..1f87932b6c
--- /dev/null
+++ b/lib/public_key/doc/src/public_key_app.xml
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE appref SYSTEM "appref.dtd">
+
+<appref>
+ <header>
+ <copyright>
+ <year>2016</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>public_key</title>
+ <prepared></prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ <file>public_key_app.sgml</file>
+ </header>
+ <app>public_key</app>
+ <appsummary>Provides functions to handle public-key infrastructure. </appsummary>
+ <description>
+
+ <p> Provides encode/decode of different file formats (PEM, OpenSSH),
+ digital signature and verification functions,
+ validation of certificate paths and certificate revocation lists (CRLs) and
+ other functions for handling of certificates, keys and CRLs.</p>
+
+ <list type="bulleted">
+ <item>Supports <url href="http://www.ietf.org/rfc/rfc5280.txt">RFC 5280 </url> -
+ Internet X.509 Public-Key Infrastructure Certificate and Certificate Revocation List
+ (CRL) Profile. Certificate policies are currently not supported. </item>
+ <item>Supports <url href="http://www.ietf.org/rfc/rfc3447.txt"> PKCS-1 </url> -
+ RSA Cryptography Standard </item>
+ <item>Supports <url href="http://csrc.nist.gov/publications/fips/fips186-3/fips_186-3.pdf"> DSS</url> -
+ Digital Signature Standard (DSA - Digital Signature Algorithm)</item>
+ <item>Supports
+ <url href="http://www.emc.com/emc-plus/rsa-labs/standards-initiatives/pkcs-3-diffie-hellman-key-agreement-standar.htm"> PKCS-3 </url> -
+ Diffie-Hellman Key Agreement Standard </item>
+ <item>Supports <url href="http://www.ietf.org/rfc/rfc2898.txt"> PKCS-5</url> -
+ Password-Based Cryptography Standard </item>
+ <item>Supports <url href="http://www.ietf.org/rfc/rfc5208.txt"> PKCS-8</url> -
+ Private-Key Information Syntax Standard</item>
+ <item>Supports <url href="http://www.ietf.org/rfc/rfc5967.txt"> PKCS-10</url> -
+ Certification Request Syntax Standard</item>
+ </list>
+ </description>
+
+ <section>
+ <title>DEPENDENCIES</title>
+ <p>The <c>public_key</c> application uses the
+ Crypto application to preform cryptographic operations and the
+ ASN-1 application to handle PKIX-ASN-1 specifications, hence
+ these applications must be loaded for the <c>public_key</c> application to work.
+ In an embedded environment this means they must be started with
+ <c>application:start/[1,2]</c> before the <c>public_key</c> application is
+ started.</p>
+ </section>
+
+ <section>
+ <title>ERROR LOGGER AND EVENT HANDLERS</title>
+ <p> The <c>public_key</c> application is a library application
+ and does not use the error logger. The functions will either sucssed
+ or fail with a runtime error.
+ </p>
+ </section>
+
+ <section>
+ <title>SEE ALSO</title>
+ <p><seealso marker="kernel:application">application(3)</seealso></p>
+ </section>
+
+</appref>
diff --git a/lib/public_key/doc/src/ref_man.xml b/lib/public_key/doc/src/ref_man.xml
index 75c5374257..2bd1733dbc 100644
--- a/lib/public_key/doc/src/ref_man.xml
+++ b/lib/public_key/doc/src/ref_man.xml
@@ -36,6 +36,7 @@
from RFC 3280 (X.509 certificates) and parts of the PKCS standard.
</p>
</description>
+ <xi:include href="public_key_app.xml"/>
<xi:include href="public_key.xml"/>
</application>
diff --git a/lib/public_key/src/pubkey_cert.erl b/lib/public_key/src/pubkey_cert.erl
index c5e6ffded5..f45f2c2e9a 100644
--- a/lib/public_key/src/pubkey_cert.erl
+++ b/lib/public_key/src/pubkey_cert.erl
@@ -547,7 +547,9 @@ cert_auth_key_id(#'AuthorityKeyIdentifier'{authorityCertIssuer =
{ok, {SerialNr, decode_general_name(AuthCertIssuer)}}.
decode_general_name([{directoryName, Issuer}]) ->
- normalize_general_name(Issuer).
+ normalize_general_name(Issuer);
+decode_general_name([{_, Issuer}]) ->
+ Issuer.
%% Strip all leading and trailing spaces and make
%% sure there is no double spaces in between.
diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl
index 9c39c36be4..71a77efa2e 100644
--- a/lib/public_key/test/public_key_SUITE.erl
+++ b/lib/public_key/test/public_key_SUITE.erl
@@ -44,7 +44,7 @@ all() ->
encrypt_decrypt,
{group, sign_verify},
pkix, pkix_countryname, pkix_emailaddress, pkix_path_validation,
- pkix_iso_rsa_oid, pkix_iso_dsa_oid, pkix_crl].
+ pkix_iso_rsa_oid, pkix_iso_dsa_oid, pkix_crl, general_name].
groups() ->
[{pem_decode_encode, [], [dsa_pem, rsa_pem, ec_pem, encrypted_pem,
@@ -644,11 +644,10 @@ pkix(Config) when is_list(Config) ->
[{'AttributeTypeAndValue', {2,5,4,3},{printableString," erlang ca "}}]]},
VerifyStr = {rdnSequence,
[[{'AttributeTypeAndValue', {2,5,4,3},{printableString,"erlangca"}}],
- [{'AttributeTypeAndValue', {2,5,4,3},{printableString,"erlang ca"}}]]},
- VerifyStr = public_key:pkix_normalize_name(TestStr),
-
- ok.
-
+ [{'AttributeTypeAndValue', {2,5,4,3},{printableString,"erlang ca"}}]]},
+ VerifyStr = public_key:pkix_normalize_name(TestStr).
+
+
%%--------------------------------------------------------------------
pkix_countryname() ->
[{doc, "Test workaround for certs that code x509countryname as utf8"}].
@@ -805,6 +804,18 @@ pkix_crl(Config) when is_list(Config) ->
reasons = asn1_NOVALUE,
distributionPoint = Point} = public_key:pkix_dist_point(OTPIDPCert).
+general_name() ->
+ [{doc, "Test that decoding of general name filed may have other values"
+ " than {rdnSequence, Seq}"}].
+
+general_name(Config) when is_list(Config) ->
+ DummyRfc822Name = "CN=CNDummy, OU=OUDummy, O=ODummy, C=SE",
+ {ok, {1, DummyRfc822Name}} =
+ pubkey_cert:cert_auth_key_id(
+ #'AuthorityKeyIdentifier'{authorityCertIssuer =
+ [{rfc822Name, DummyRfc822Name}],
+ authorityCertSerialNumber =
+ 1}).
%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
diff --git a/lib/runtime_tools/c_src/dyntrace_lttng.h b/lib/runtime_tools/c_src/dyntrace_lttng.h
index 2a3224e191..5e838892d6 100644
--- a/lib/runtime_tools/c_src/dyntrace_lttng.h
+++ b/lib/runtime_tools/c_src/dyntrace_lttng.h
@@ -19,7 +19,7 @@
*/
#undef TRACEPOINT_PROVIDER
-#define TRACEPOINT_PROVIDER com_ericsson_dyntrace
+#define TRACEPOINT_PROVIDER org_erlang_dyntrace
#if !defined(DYNTRACE_LTTNG_H) || defined(TRACEPOINT_HEADER_MULTI_READ)
#define DYNTRACE_LTTNG_H
@@ -27,22 +27,22 @@
#include <lttng/tracepoint.h>
#define LTTNG1(Name, Arg1) \
- tracepoint(com_ericsson_dyntrace, Name, (Arg1))
+ tracepoint(org_erlang_dyntrace, Name, (Arg1))
#define LTTNG2(Name, Arg1, Arg2) \
- tracepoint(com_ericsson_dyntrace, Name, (Arg1), (Arg2))
+ tracepoint(org_erlang_dyntrace, Name, (Arg1), (Arg2))
#define LTTNG3(Name, Arg1, Arg2, Arg3) \
- tracepoint(com_ericsson_dyntrace, Name, (Arg1), (Arg2), (Arg3))
+ tracepoint(org_erlang_dyntrace, Name, (Arg1), (Arg2), (Arg3))
#define LTTNG4(Name, Arg1, Arg2, Arg3, Arg4) \
- tracepoint(com_ericsson_dyntrace, Name, (Arg1), (Arg2), (Arg3), (Arg4))
+ tracepoint(org_erlang_dyntrace, Name, (Arg1), (Arg2), (Arg3), (Arg4))
#define LTTNG5(Name, Arg1, Arg2, Arg3, Arg4, Arg5) \
- tracepoint(com_ericsson_dyntrace, Name, (Arg1), (Arg2), (Arg3), (Arg4), (Arg5))
+ tracepoint(org_erlang_dyntrace, Name, (Arg1), (Arg2), (Arg3), (Arg4), (Arg5))
#define LTTNG_ENABLED(Name) \
- tracepoint_enabled(com_ericsson_dyntrace, Name)
+ tracepoint_enabled(org_erlang_dyntrace, Name)
#define LTTNG_BUFFER_SZ (256)
#define LTTNG_PROC_BUFFER_SZ (16)
@@ -76,7 +76,7 @@
/* Process scheduling */
TRACEPOINT_EVENT(
- com_ericsson_dyntrace,
+ org_erlang_dyntrace,
process_spawn,
TP_ARGS(
char*, p,
@@ -91,7 +91,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_dyntrace,
+ org_erlang_dyntrace,
process_link,
TP_ARGS(
char*, from,
@@ -106,7 +106,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_dyntrace,
+ org_erlang_dyntrace,
process_exit,
TP_ARGS(
char*, p,
@@ -119,7 +119,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_dyntrace,
+ org_erlang_dyntrace,
process_register,
TP_ARGS(
char*, pid,
@@ -136,7 +136,7 @@ TRACEPOINT_EVENT(
/* Scheduled */
TRACEPOINT_EVENT(
- com_ericsson_dyntrace,
+ org_erlang_dyntrace,
process_scheduled,
TP_ARGS(
char*, p,
@@ -154,7 +154,7 @@ TRACEPOINT_EVENT(
TRACEPOINT_EVENT(
- com_ericsson_dyntrace,
+ org_erlang_dyntrace,
port_open,
TP_ARGS(
char*, pid,
@@ -169,7 +169,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_dyntrace,
+ org_erlang_dyntrace,
port_exit,
TP_ARGS(
char*, port,
@@ -182,7 +182,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_dyntrace,
+ org_erlang_dyntrace,
port_link,
TP_ARGS(
char*, from,
@@ -197,7 +197,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_dyntrace,
+ org_erlang_dyntrace,
port_scheduled,
TP_ARGS(
char*, p,
@@ -214,7 +214,7 @@ TRACEPOINT_EVENT(
/* Call tracing */
TRACEPOINT_EVENT(
- com_ericsson_dyntrace,
+ org_erlang_dyntrace,
function_call,
TP_ARGS(
char*, pid,
@@ -229,7 +229,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_dyntrace,
+ org_erlang_dyntrace,
function_return,
TP_ARGS(
char*, pid,
@@ -244,7 +244,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_dyntrace,
+ org_erlang_dyntrace,
function_exception,
TP_ARGS(
char*, pid,
@@ -261,7 +261,7 @@ TRACEPOINT_EVENT(
/* Process messages */
TRACEPOINT_EVENT(
- com_ericsson_dyntrace,
+ org_erlang_dyntrace,
message_send,
TP_ARGS(
char*, sender,
@@ -276,7 +276,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_dyntrace,
+ org_erlang_dyntrace,
message_receive,
TP_ARGS(
char*, receiver,
@@ -291,7 +291,7 @@ TRACEPOINT_EVENT(
/* Process Memory */
TRACEPOINT_EVENT(
- com_ericsson_dyntrace,
+ org_erlang_dyntrace,
gc_minor_start,
TP_ARGS(
char*, p,
@@ -308,7 +308,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_dyntrace,
+ org_erlang_dyntrace,
gc_minor_end,
TP_ARGS(
char*, p,
@@ -325,7 +325,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_dyntrace,
+ org_erlang_dyntrace,
gc_major_start,
TP_ARGS(
char*, p,
@@ -342,7 +342,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_dyntrace,
+ org_erlang_dyntrace,
gc_major_end,
TP_ARGS(
char*, p,
diff --git a/lib/runtime_tools/doc/src/LTTng.xml b/lib/runtime_tools/doc/src/LTTng.xml
index 9b490a27a0..82a4c79379 100644
--- a/lib/runtime_tools/doc/src/LTTng.xml
+++ b/lib/runtime_tools/doc/src/LTTng.xml
@@ -66,7 +66,7 @@ $ make </code>
<section>
<title>Dyntrace Tracepoints</title>
- <p>All tracepoints are in the domain of <c>com_ericsson_dyntrace</c></p>
+ <p>All tracepoints are in the domain of <c>org_erlang_dyntrace</c></p>
<p>All Erlang types are the string equivalent in LTTng.</p>
<p><em>process_spawn</em></p>
@@ -310,7 +310,7 @@ $ make </code>
<section>
<title>BEAM Tracepoints</title>
- <p>All tracepoints are in the domain of <c>com_ericsson_otp</c></p>
+ <p>All tracepoints are in the domain of <c>org_erlang_otp</c></p>
<p>All Erlang types are the string equivalent in LTTng.</p>
<p><em>scheduler_poll</em></p>
@@ -550,8 +550,8 @@ Eshell V8.0 (abort with ^G)
<p>Enable the process_register LTTng tracepoint for Erlang.</p>
- <pre>$ lttng enable-event -u com_ericsson_dyntrace:process_register
-UST event com_ericsson_dyntrace:process_register created in channel channel0</pre>
+ <pre>$ lttng enable-event -u org_erlang_dyntrace:process_register
+UST event org_erlang_dyntrace:process_register created in channel channel0</pre>
<p>Enable process tracing for new processes and use <c>dyntrace</c> as tracer backend.</p>
@@ -573,23 +573,23 @@ Tracing started for session erlang-demo</pre>
<pre>$ lttng stop
Tracing stopped for session erlang-demo
$ lttng view
-[17:20:42.561168759] (+?.?????????) elxd1168lx9 com_ericsson_dyntrace:process_register: \
+[17:20:42.561168759] (+?.?????????) elxd1168lx9 org_erlang_dyntrace:process_register: \
{ cpu_id = 5 }, { pid = "&lt;0.66.0&gt;", name = "sasl_sup", type = "register" }
-[17:20:42.561215519] (+0.000046760) elxd1168lx9 com_ericsson_dyntrace:process_register: \
+[17:20:42.561215519] (+0.000046760) elxd1168lx9 org_erlang_dyntrace:process_register: \
{ cpu_id = 5 }, { pid = "&lt;0.67.0&gt;", name = "sasl_safe_sup", type = "register" }
-[17:20:42.562149024] (+0.000933505) elxd1168lx9 com_ericsson_dyntrace:process_register: \
+[17:20:42.562149024] (+0.000933505) elxd1168lx9 org_erlang_dyntrace:process_register: \
{ cpu_id = 5 }, { pid = "&lt;0.68.0&gt;", name = "alarm_handler", type = "register" }
-[17:20:42.571035803] (+0.008886779) elxd1168lx9 com_ericsson_dyntrace:process_register: \
+[17:20:42.571035803] (+0.008886779) elxd1168lx9 org_erlang_dyntrace:process_register: \
{ cpu_id = 5 }, { pid = "&lt;0.69.0&gt;", name = "release_handler", type = "register" }
-[17:20:42.574939868] (+0.003904065) elxd1168lx9 com_ericsson_dyntrace:process_register: \
+[17:20:42.574939868] (+0.003904065) elxd1168lx9 org_erlang_dyntrace:process_register: \
{ cpu_id = 5 }, { pid = "&lt;0.74.0&gt;", name = "os_mon_sup", type = "register" }
-[17:20:42.576818712] (+0.001878844) elxd1168lx9 com_ericsson_dyntrace:process_register: \
+[17:20:42.576818712] (+0.001878844) elxd1168lx9 org_erlang_dyntrace:process_register: \
{ cpu_id = 5 }, { pid = "&lt;0.75.0&gt;", name = "disksup", type = "register" }
-[17:20:42.580032013] (+0.003213301) elxd1168lx9 com_ericsson_dyntrace:process_register: \
+[17:20:42.580032013] (+0.003213301) elxd1168lx9 org_erlang_dyntrace:process_register: \
{ cpu_id = 5 }, { pid = "&lt;0.76.0&gt;", name = "memsup", type = "register" }
-[17:20:42.583046339] (+0.003014326) elxd1168lx9 com_ericsson_dyntrace:process_register: \
+[17:20:42.583046339] (+0.003014326) elxd1168lx9 org_erlang_dyntrace:process_register: \
{ cpu_id = 5 }, { pid = "&lt;0.78.0&gt;", name = "cpu_sup", type = "register" }
-[17:20:42.586206242] (+0.003159903) elxd1168lx9 com_ericsson_dyntrace:process_register: \
+[17:20:42.586206242] (+0.003159903) elxd1168lx9 org_erlang_dyntrace:process_register: \
{ cpu_id = 5 }, { pid = "&lt;0.82.0&gt;", name = "timer_server", type = "register" }</pre>
</section>
</chapter>
diff --git a/lib/runtime_tools/test/dyntrace_lttng_SUITE.erl b/lib/runtime_tools/test/dyntrace_lttng_SUITE.erl
index e6c147b003..a98ac6e99c 100644
--- a/lib/runtime_tools/test/dyntrace_lttng_SUITE.erl
+++ b/lib/runtime_tools/test/dyntrace_lttng_SUITE.erl
@@ -84,25 +84,25 @@ end_per_testcase(Case, _Config) ->
%% tracepoints
%%
-%% com_ericsson_dyntrace:gc_major_end
-%% com_ericsson_dyntrace:gc_major_start
-%% com_ericsson_dyntrace:gc_minor_end
-%% com_ericsson_dyntrace:gc_minor_start
-%% com_ericsson_dyntrace:message_receive
-%% com_ericsson_dyntrace:message_send
-%% -com_ericsson_dyntrace:message_queued
-%% com_ericsson_dyntrace:function_exception
-%% com_ericsson_dyntrace:function_return
-%% com_ericsson_dyntrace:function_call
-%% com_ericsson_dyntrace:port_link
-%% com_ericsson_dyntrace:port_exit
-%% com_ericsson_dyntrace:port_open
-%% com_ericsson_dyntrace:port_scheduled
-%% com_ericsson_dyntrace:process_scheduled
-%% com_ericsson_dyntrace:process_register
-%% com_ericsson_dyntrace:process_exit
-%% com_ericsson_dyntrace:process_link
-%% com_ericsson_dyntrace:process_spawn
+%% org_erlang_dyntrace:gc_major_end
+%% org_erlang_dyntrace:gc_major_start
+%% org_erlang_dyntrace:gc_minor_end
+%% org_erlang_dyntrace:gc_minor_start
+%% org_erlang_dyntrace:message_receive
+%% org_erlang_dyntrace:message_send
+%% -org_erlang_dyntrace:message_queued
+%% org_erlang_dyntrace:function_exception
+%% org_erlang_dyntrace:function_return
+%% org_erlang_dyntrace:function_call
+%% org_erlang_dyntrace:port_link
+%% org_erlang_dyntrace:port_exit
+%% org_erlang_dyntrace:port_open
+%% org_erlang_dyntrace:port_scheduled
+%% org_erlang_dyntrace:process_scheduled
+%% org_erlang_dyntrace:process_register
+%% org_erlang_dyntrace:process_exit
+%% org_erlang_dyntrace:process_link
+%% org_erlang_dyntrace:process_spawn
%%
%% Testcases
%%
@@ -112,7 +112,7 @@ t_lttng_list(_Config) ->
ok.
t_procs(Config) when is_list(Config) ->
- ok = lttng_start_event("com_ericsson_dyntrace:process_*", Config),
+ ok = lttng_start_event("org_erlang_dyntrace:process_*", Config),
_ = erlang:trace(new, true, [{tracer, dyntrace, []},procs]),
Pid = spawn_link(fun() -> waiter() end),
@@ -122,27 +122,27 @@ t_procs(Config) when is_list(Config) ->
_ = erlang:trace(all, false, [procs]),
Res = lttng_stop_and_view(Config),
- ok = check_tracepoint("com_ericsson_dyntrace:process_spawn", Res),
- ok = check_tracepoint("com_ericsson_dyntrace:process_link", Res),
- ok = check_tracepoint("com_ericsson_dyntrace:process_exit", Res),
- ok = check_tracepoint("com_ericsson_dyntrace:process_register", Res),
+ ok = check_tracepoint("org_erlang_dyntrace:process_spawn", Res),
+ ok = check_tracepoint("org_erlang_dyntrace:process_link", Res),
+ ok = check_tracepoint("org_erlang_dyntrace:process_exit", Res),
+ ok = check_tracepoint("org_erlang_dyntrace:process_register", Res),
ok.
t_ports(Config) when is_list(Config) ->
- ok = lttng_start_event("com_ericsson_dyntrace:port_*", Config),
+ ok = lttng_start_event("org_erlang_dyntrace:port_*", Config),
_ = erlang:trace(new, true, [{tracer, dyntrace, []},ports]),
_ = os:cmd("ls"),
_ = erlang:trace(all, false, [{tracer, dyntrace, []},ports]),
Res = lttng_stop_and_view(Config),
- ok = check_tracepoint("com_ericsson_dyntrace:port_open", Res),
- ok = check_tracepoint("com_ericsson_dyntrace:port_link", Res),
- ok = check_tracepoint("com_ericsson_dyntrace:port_exit", Res),
+ ok = check_tracepoint("org_erlang_dyntrace:port_open", Res),
+ ok = check_tracepoint("org_erlang_dyntrace:port_link", Res),
+ ok = check_tracepoint("org_erlang_dyntrace:port_exit", Res),
ok.
t_running_process(Config) when is_list(Config) ->
- ok = lttng_start_event("com_ericsson_dyntrace:process_scheduled", Config),
+ ok = lttng_start_event("org_erlang_dyntrace:process_scheduled", Config),
_ = erlang:trace(new, true, [{tracer, dyntrace, []},running]),
Pid = spawn_link(fun() -> waiter() end),
@@ -152,11 +152,11 @@ t_running_process(Config) when is_list(Config) ->
_ = erlang:trace(all, false, [running]),
Res = lttng_stop_and_view(Config),
- ok = check_tracepoint("com_ericsson_dyntrace:process_scheduled", Res),
+ ok = check_tracepoint("org_erlang_dyntrace:process_scheduled", Res),
ok.
t_running_port(Config) when is_list(Config) ->
- ok = lttng_start_event("com_ericsson_dyntrace:port_scheduled", Config),
+ ok = lttng_start_event("org_erlang_dyntrace:port_scheduled", Config),
_ = erlang:trace(new, true, [{tracer, dyntrace, []},running_ports]),
_ = os:cmd("ls"),
@@ -164,12 +164,12 @@ t_running_port(Config) when is_list(Config) ->
_ = erlang:trace(all, false, [running_ports]),
Res = lttng_stop_and_view(Config),
- ok = check_tracepoint("com_ericsson_dyntrace:port_scheduled", Res),
+ ok = check_tracepoint("org_erlang_dyntrace:port_scheduled", Res),
ok.
t_call(Config) when is_list(Config) ->
- ok = lttng_start_event("com_ericsson_dyntrace:function_*", Config),
+ ok = lttng_start_event("org_erlang_dyntrace:function_*", Config),
_ = erlang:trace(new, true, [{tracer, dyntrace, []}, call]),
_ = erlang:trace_pattern({?MODULE, '_', '_'}, [{'_',[],[{exception_trace}]}], [local]),
@@ -184,13 +184,13 @@ t_call(Config) when is_list(Config) ->
_ = erlang:trace_pattern({?MODULE, '_', '_'}, false, [local]),
_ = erlang:trace(all, false, [call]),
Res = lttng_stop_and_view(Config),
- ok = check_tracepoint("com_ericsson_dyntrace:function_call", Res),
- ok = check_tracepoint("com_ericsson_dyntrace:function_return", Res),
- ok = check_tracepoint("com_ericsson_dyntrace:function_exception", Res),
+ ok = check_tracepoint("org_erlang_dyntrace:function_call", Res),
+ ok = check_tracepoint("org_erlang_dyntrace:function_return", Res),
+ ok = check_tracepoint("org_erlang_dyntrace:function_exception", Res),
ok.
t_send(Config) when is_list(Config) ->
- ok = lttng_start_event("com_ericsson_dyntrace:message_send", Config),
+ ok = lttng_start_event("org_erlang_dyntrace:message_send", Config),
_ = erlang:trace(new, true, [{tracer, dyntrace, []},send]),
Pid = spawn_link(fun() -> waiter() end),
@@ -201,11 +201,11 @@ t_send(Config) when is_list(Config) ->
_ = erlang:trace(all, false, [send]),
Res = lttng_stop_and_view(Config),
- ok = check_tracepoint("com_ericsson_dyntrace:message_send", Res),
+ ok = check_tracepoint("org_erlang_dyntrace:message_send", Res),
ok.
t_call_return_to(Config) when is_list(Config) ->
- ok = lttng_start_event("com_ericsson_dyntrace:function_*", Config),
+ ok = lttng_start_event("org_erlang_dyntrace:function_*", Config),
_ = erlang:trace(new, true, [{tracer, dyntrace, []}, call, return_to]),
_ = erlang:trace_pattern({lists, '_', '_'}, true, [local]),
_ = erlang:trace_pattern({?MODULE, '_', '_'}, true, [local]),
@@ -219,11 +219,11 @@ t_call_return_to(Config) when is_list(Config) ->
_ = erlang:trace_pattern({lists, '_', '_'}, false, [local]),
_ = erlang:trace(all, false, [call,return_to]),
Res = lttng_stop_and_view(Config),
- ok = check_tracepoint("com_ericsson_dyntrace:function_call", Res),
+ ok = check_tracepoint("org_erlang_dyntrace:function_call", Res),
ok.
t_call_silent(Config) when is_list(Config) ->
- ok = lttng_start_event("com_ericsson_dyntrace:function_*", Config),
+ ok = lttng_start_event("org_erlang_dyntrace:function_*", Config),
_ = erlang:trace(new, true, [{tracer, dyntrace, []}, call, silent]),
_ = erlang:trace_pattern({?MODULE, '_', '_'}, [{'_',[],[{exception_trace}]}], [local]),
@@ -238,27 +238,33 @@ t_call_silent(Config) when is_list(Config) ->
_ = erlang:trace_pattern({?MODULE, '_', '_'}, false, [local]),
_ = erlang:trace(all, false, [call]),
Res = lttng_stop_and_view(Config),
- notfound = check_tracepoint("com_ericsson_dyntrace:function_call", Res),
- notfound = check_tracepoint("com_ericsson_dyntrace:function_return", Res),
- notfound = check_tracepoint("com_ericsson_dyntrace:function_exception", Res),
+ notfound = check_tracepoint("org_erlang_dyntrace:function_call", Res),
+ notfound = check_tracepoint("org_erlang_dyntrace:function_return", Res),
+ notfound = check_tracepoint("org_erlang_dyntrace:function_exception", Res),
ok.
t_receive(Config) when is_list(Config) ->
- ok = lttng_start_event("com_ericsson_dyntrace:message_receive", Config),
+ ok = lttng_start_event("org_erlang_dyntrace:message_receive", Config),
_ = erlang:trace(new, true, [{tracer, dyntrace, []},'receive']),
+ timer:sleep(20),
+
+ Pid1 = spawn_link(fun() -> waiter() end),
+ Pid1 ! {self(), ok},
+ ok = receive {Pid1,ok} -> ok end,
+
+ Pid2 = spawn_link(fun() -> waiter() end),
+ Pid2 ! {self(), ok},
+ ok = receive {Pid2,ok} -> ok end,
- Pid = spawn_link(fun() -> waiter() end),
- Pid ! {self(), ok},
- ok = receive {Pid,ok} -> ok end,
timer:sleep(10),
_ = erlang:trace(all, false, ['receive']),
Res = lttng_stop_and_view(Config),
- ok = check_tracepoint("com_ericsson_dyntrace:message_receive", Res),
+ ok = check_tracepoint("org_erlang_dyntrace:message_receive", Res),
ok.
t_garbage_collection(Config) when is_list(Config) ->
- ok = lttng_start_event("com_ericsson_dyntrace:gc_*", Config),
+ ok = lttng_start_event("org_erlang_dyntrace:gc_*", Config),
_ = erlang:trace(new, true, [{tracer, dyntrace, []},garbage_collection]),
Pid = spawn_link(fun() -> gcfier() end),
@@ -267,14 +273,14 @@ t_garbage_collection(Config) when is_list(Config) ->
timer:sleep(10),
_ = erlang:trace(all, false, [garbage_collection]),
Res = lttng_stop_and_view(Config),
- ok = check_tracepoint("com_ericsson_dyntrace:gc_major_start", Res),
- ok = check_tracepoint("com_ericsson_dyntrace:gc_major_end", Res),
- ok = check_tracepoint("com_ericsson_dyntrace:gc_minor_start", Res),
- ok = check_tracepoint("com_ericsson_dyntrace:gc_minor_end", Res),
+ ok = check_tracepoint("org_erlang_dyntrace:gc_major_start", Res),
+ ok = check_tracepoint("org_erlang_dyntrace:gc_major_end", Res),
+ ok = check_tracepoint("org_erlang_dyntrace:gc_minor_start", Res),
+ ok = check_tracepoint("org_erlang_dyntrace:gc_minor_end", Res),
ok.
t_all(Config) when is_list(Config) ->
- ok = lttng_start_event("com_ericsson_dyntrace:*", Config),
+ ok = lttng_start_event("org_erlang_dyntrace:*", Config),
_ = erlang:trace(new, true, [{tracer, dyntrace, []},all]),
Pid1 = spawn_link(fun() -> waiter() end),
@@ -291,21 +297,21 @@ t_all(Config) when is_list(Config) ->
_ = erlang:trace(all, false, [all]),
Res = lttng_stop_and_view(Config),
- ok = check_tracepoint("com_ericsson_dyntrace:process_spawn", Res),
- ok = check_tracepoint("com_ericsson_dyntrace:process_link", Res),
- ok = check_tracepoint("com_ericsson_dyntrace:process_exit", Res),
- ok = check_tracepoint("com_ericsson_dyntrace:process_register", Res),
- ok = check_tracepoint("com_ericsson_dyntrace:port_open", Res),
- ok = check_tracepoint("com_ericsson_dyntrace:port_link", Res),
- ok = check_tracepoint("com_ericsson_dyntrace:port_exit", Res),
- ok = check_tracepoint("com_ericsson_dyntrace:process_scheduled", Res),
- ok = check_tracepoint("com_ericsson_dyntrace:port_scheduled", Res),
- ok = check_tracepoint("com_ericsson_dyntrace:message_send", Res),
- ok = check_tracepoint("com_ericsson_dyntrace:message_receive", Res),
- ok = check_tracepoint("com_ericsson_dyntrace:gc_major_start", Res),
- ok = check_tracepoint("com_ericsson_dyntrace:gc_major_end", Res),
- ok = check_tracepoint("com_ericsson_dyntrace:gc_minor_start", Res),
- ok = check_tracepoint("com_ericsson_dyntrace:gc_minor_end", Res),
+ ok = check_tracepoint("org_erlang_dyntrace:process_spawn", Res),
+ ok = check_tracepoint("org_erlang_dyntrace:process_link", Res),
+ ok = check_tracepoint("org_erlang_dyntrace:process_exit", Res),
+ ok = check_tracepoint("org_erlang_dyntrace:process_register", Res),
+ ok = check_tracepoint("org_erlang_dyntrace:port_open", Res),
+ ok = check_tracepoint("org_erlang_dyntrace:port_link", Res),
+ ok = check_tracepoint("org_erlang_dyntrace:port_exit", Res),
+ ok = check_tracepoint("org_erlang_dyntrace:process_scheduled", Res),
+ ok = check_tracepoint("org_erlang_dyntrace:port_scheduled", Res),
+ ok = check_tracepoint("org_erlang_dyntrace:message_send", Res),
+ ok = check_tracepoint("org_erlang_dyntrace:message_receive", Res),
+ ok = check_tracepoint("org_erlang_dyntrace:gc_major_start", Res),
+ ok = check_tracepoint("org_erlang_dyntrace:gc_major_end", Res),
+ ok = check_tracepoint("org_erlang_dyntrace:gc_minor_start", Res),
+ ok = check_tracepoint("org_erlang_dyntrace:gc_minor_end", Res),
ok.
diff --git a/lib/sasl/test/release_handler_SUITE.erl b/lib/sasl/test/release_handler_SUITE.erl
index 4dcaec03a7..8134e02221 100644
--- a/lib/sasl/test/release_handler_SUITE.erl
+++ b/lib/sasl/test/release_handler_SUITE.erl
@@ -1366,7 +1366,7 @@ upgrade_supervisor(Conf) when is_list(Conf) ->
ASupBeam2 = rpc:call(Node, code, which, [a_sup]),
%% Check that the restart strategy and child spec is updated
- {status, _, {module, _}, [_, _, _, _, [_,_,{data,[{"State",State}]}]]} =
+ {status, _, {module, _}, [_, _, _, _, [_,_,{data,[{"State",State}]}|_]]} =
rpc:call(Node,sys,get_status,[a_sup]),
{state,_,RestartStrategy,[Child],_,_,_,_,_,_,_} = State,
one_for_all = RestartStrategy, % changed from one_for_one
diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml
index bd330e479f..e6c54d27bf 100644
--- a/lib/ssh/doc/src/ssh.xml
+++ b/lib/ssh/doc/src/ssh.xml
@@ -124,10 +124,10 @@
</func>
<func>
- <name>connect(TcpSocket, Options) -> </name>
- <name>connect(TcpSocket, Options, Timeout) -> </name>
<name>connect(Host, Port, Options) -> </name>
- <name>connect(Host, Port, Options, Timeout) ->
+ <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>
@@ -140,7 +140,7 @@
<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 <c>gen_tcp:connect</c> with option <c>{active,false}</c></d>
+ <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>Connects to an SSH server. No channel is started. This is done
@@ -351,8 +351,9 @@
<func>
<name>daemon(Port) -> </name>
<name>daemon(Port, Options) -> </name>
- <name>daemon(HostAddress, Port, Options) -> {ok,
- ssh_daemon_ref()} | {error, atom()}</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>
@@ -361,6 +362,8 @@
<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
@@ -722,12 +725,15 @@
<func>
<name>shell(Host) -> </name>
<name>shell(Host, Option) -> </name>
- <name>shell(Host, Port, Option) -> _</name>
+ <name>shell(Host, Port, Option) -> </name>
+ <name>shell(TcpSocket) -> _</name>
<fsummary>Starts an interactive shell over an 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>
</type>
<desc>
<p>Starts an interactive shell over an SSH server on the
diff --git a/lib/ssh/doc/src/ssh_sftp.xml b/lib/ssh/doc/src/ssh_sftp.xml
index 67531b7d99..eb6f43d417 100644
--- a/lib/ssh/doc/src/ssh_sftp.xml
+++ b/lib/ssh/doc/src/ssh_sftp.xml
@@ -526,10 +526,6 @@
</func>
<func>
- <name>start_channel(TcpSocket) -></name>
- <name>start_channel(TcpSocket, Options) ->
- {ok, Pid, ConnectionRef} | {error, reason()|term()}</name>
-
<name>start_channel(ConnectionRef) -></name>
<name>start_channel(ConnectionRef, Options) ->
{ok, Pid} | {error, reason()|term()}</name>
@@ -537,13 +533,18 @@
<name>start_channel(Host, Options) -></name>
<name>start_channel(Host, Port, Options) ->
{ok, Pid, ConnectionRef} | {error, reason()|term()}</name>
+
+ <name>start_channel(TcpSocket) -></name>
+ <name>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>Port = integer()</v>
<v>TcpSocket = port()</v>
- <d>The socket is supposed to be from <c>gen_tcp:connect</c> with option <c>{active,false}</c></d>
+ <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>Options = [{Option, Value}]</v>
</type>
<desc>
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index 50dfe55798..65f1acc6a6 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -86,29 +86,19 @@ connect(Socket, Options) ->
connect(Socket, Options, Timeout) when is_port(Socket) ->
case handle_options(Options) of
- {error, _Reason} = Error ->
- Error;
+ {error, Error} ->
+ {error, Error};
{_SocketOptions, SshOptions} ->
- case proplists:get_value(transport, Options, {tcp, gen_tcp, tcp_closed}) of
- {tcp,_,_} ->
- %% Is the socket a valid tcp socket?
- case {{ok,[]} =/= inet:getopts(Socket, [delay_send]),
- {ok,[{active,false}]} == inet:getopts(Socket, [active])
- }
- of
- {true, true} ->
- {ok, {Host,_Port}} = inet:sockname(Socket),
- Opts = [{user_pid,self()}, {host,fmt_host(Host)} | SshOptions],
- ssh_connection_handler:start_connection(client, Socket, Opts, Timeout);
- {true, false} ->
- {error, not_passive_mode};
- _ ->
- {error, not_tcp_socket}
- end;
- {L4,_,_} ->
- {error, {unsupported,L4}}
+ case valid_socket_to_use(Socket, Options) of
+ ok ->
+ {ok, {Host,_Port}} = inet:sockname(Socket),
+ Opts = [{user_pid,self()}, {host,fmt_host(Host)} | SshOptions],
+ ssh_connection_handler:start_connection(client, Socket, Opts, Timeout);
+ {error,SockError} ->
+ {error,SockError}
end
end;
+
connect(Host, Port, Options) when is_integer(Port), Port>0 ->
connect(Host, Port, Options, infinity).
@@ -160,7 +150,7 @@ channel_info(ConnectionRef, ChannelId, Options) ->
%%--------------------------------------------------------------------
-spec daemon(integer()) -> {ok, pid()} | {error, term()}.
--spec daemon(integer(), proplists:proplist()) -> {ok, pid()} | {error, term()}.
+-spec daemon(integer()|port(), proplists:proplist()) -> {ok, pid()} | {error, term()}.
-spec daemon(any | inet:ip_address(), integer(), proplists:proplist()) -> {ok, pid()} | {error, term()}.
%% Description: Starts a server listening for SSH connections
@@ -169,28 +159,16 @@ channel_info(ConnectionRef, ChannelId, Options) ->
daemon(Port) ->
daemon(Port, []).
-daemon(Port, Options) ->
- daemon(any, Port, Options).
+daemon(Port, Options) when is_integer(Port) ->
+ daemon(any, Port, Options);
+
+daemon(Socket, Options0) when is_port(Socket) ->
+ Options = daemon_shell_opt(Options0),
+ start_daemon(Socket, Options).
daemon(HostAddr, Port, Options0) ->
- Options1 = case proplists:get_value(shell, Options0) of
- undefined ->
- [{shell, {shell, start, []}} | Options0];
- _ ->
- Options0
- end,
-
- {Host, Inet, Options} = case HostAddr of
- any ->
- {ok, Host0} = inet:gethostname(),
- {Host0, proplists:get_value(inet, Options1, inet), Options1};
- {_,_,_,_} ->
- {HostAddr, inet,
- [{ip, HostAddr} | Options1]};
- {_,_,_,_,_,_,_,_} ->
- {HostAddr, inet6,
- [{ip, HostAddr} | Options1]}
- end,
+ Options1 = daemon_shell_opt(Options0),
+ {Host, Inet, Options} = daemon_host_inet_opt(HostAddr, Options1),
start_daemon(Host, Port, Options, Inet).
%%--------------------------------------------------------------------
@@ -284,19 +262,128 @@ default_algorithms() ->
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
+valid_socket_to_use(Socket, Options) ->
+ case proplists:get_value(transport, Options, {tcp, gen_tcp, tcp_closed}) of
+ {tcp,_,_} ->
+ %% Is this tcp-socket a valid socket?
+ case {is_tcp_socket(Socket),
+ {ok,[{active,false}]} == inet:getopts(Socket, [active])
+ }
+ of
+ {true, true} ->
+ ok;
+ {true, false} ->
+ {error, not_passive_mode};
+ _ ->
+ {error, not_tcp_socket}
+ end;
+ {L4,_,_} ->
+ {error, {unsupported,L4}}
+ end.
+
+is_tcp_socket(Socket) -> {ok,[]} =/= inet:getopts(Socket, [delay_send]).
+
+
+
+daemon_shell_opt(Options) ->
+ case proplists:get_value(shell, Options) of
+ undefined ->
+ [{shell, {shell, start, []}} | Options];
+ _ ->
+ Options
+ end.
+
+daemon_host_inet_opt(HostAddr, Options1) ->
+ case HostAddr of
+ any ->
+ {ok, Host0} = inet:gethostname(),
+ {Host0, proplists:get_value(inet, Options1, inet), Options1};
+ {_,_,_,_} ->
+ {HostAddr, inet,
+ [{ip, HostAddr} | Options1]};
+ {_,_,_,_,_,_,_,_} ->
+ {HostAddr, inet6,
+ [{ip, HostAddr} | Options1]}
+ end.
+
+
+start_daemon(Socket, Options) ->
+ case handle_options(Options) of
+ {error, Error} ->
+ {error, Error};
+ {SocketOptions, SshOptions} ->
+ case valid_socket_to_use(Socket, Options) of
+ ok ->
+ try
+ do_start_daemon(Socket, [{role,server}|SshOptions], SocketOptions)
+ catch
+ throw:bad_fd -> {error,bad_fd};
+ _C:_E -> {error,{cannot_start_daemon,_C,_E}}
+ end;
+ {error,SockError} ->
+ {error,SockError}
+ end
+ end.
+
start_daemon(Host, Port, Options, Inet) ->
case handle_options(Options) of
{error, _Reason} = Error ->
Error;
{SocketOptions, SshOptions}->
try
- do_start_daemon(Host, Port,[{role, server} |SshOptions] , [Inet | SocketOptions])
+ do_start_daemon(Host, Port, [{role,server}|SshOptions] , [Inet|SocketOptions])
catch
throw:bad_fd -> {error,bad_fd};
_C:_E -> {error,{cannot_start_daemon,_C,_E}}
end
end.
+do_start_daemon(Socket, SshOptions, SocketOptions) ->
+ {ok, {IP,Port}} =
+ try {ok,_} = inet:sockname(Socket)
+ catch
+ _:_ -> throw(bad_socket)
+ end,
+ Host = fmt_host(IP),
+ Profile = proplists:get_value(profile, SshOptions, ?DEFAULT_PROFILE),
+ Opts = [{asocket, Socket},
+ {asock_owner,self()},
+ {address, Host},
+ {port, Port},
+ {role, server},
+ {socket_opts, SocketOptions},
+ {ssh_opts, SshOptions}],
+ {_, Callback, _} = proplists:get_value(transport, SshOptions, {tcp, gen_tcp, tcp_closed}),
+ case ssh_system_sup:system_supervisor(Host, Port, Profile) of
+ undefined ->
+ %% It would proably make more sense to call the
+ %% address option host but that is a too big change at the
+ %% monent. The name is a legacy name!
+ try sshd_sup:start_child(Opts) of
+ {error, {already_started, _}} ->
+ {error, eaddrinuse};
+ Result = {ok,_} ->
+ ssh_acceptor:handle_connection(Callback, Host, Port, Opts, Socket),
+ Result;
+ Result = {error, _} ->
+ Result
+ catch
+ exit:{noproc, _} ->
+ {error, ssh_not_started}
+ end;
+ Sup ->
+ AccPid = ssh_system_sup:acceptor_supervisor(Sup),
+ case ssh_acceptor_sup:start_child(AccPid, Opts) of
+ {error, {already_started, _}} ->
+ {error, eaddrinuse};
+ {ok, _} ->
+ ssh_acceptor:handle_connection(Callback, Host, Port, Opts, Socket),
+ {ok, Sup};
+ Other ->
+ Other
+ end
+ end.
+
do_start_daemon(Host0, Port0, SshOptions, SocketOptions) ->
{Host,Port1} =
try
@@ -312,7 +399,7 @@ do_start_daemon(Host0, Port0, SshOptions, SocketOptions) ->
_:_ -> throw(bad_fd)
end,
Profile = proplists:get_value(profile, SshOptions, ?DEFAULT_PROFILE),
- {Port, WaitRequestControl, Opts} =
+ {Port, WaitRequestControl, Opts0} =
case Port1 of
0 -> %% Allocate the socket here to get the port number...
{_, Callback, _} =
@@ -326,17 +413,17 @@ do_start_daemon(Host0, Port0, SshOptions, SocketOptions) ->
_ ->
{Port1, false, []}
end,
+ Opts = [{address, Host},
+ {port, Port},
+ {role, server},
+ {socket_opts, SocketOptions},
+ {ssh_opts, SshOptions} | Opts0],
case ssh_system_sup:system_supervisor(Host, Port, Profile) of
undefined ->
%% It would proably make more sense to call the
%% address option host but that is a too big change at the
%% monent. The name is a legacy name!
- try sshd_sup:start_child([{address, Host},
- {port, Port},
- {role, server},
- {socket_opts, SocketOptions},
- {ssh_opts, SshOptions}
- | Opts]) of
+ try sshd_sup:start_child(Opts) of
{error, {already_started, _}} ->
{error, eaddrinuse};
Result = {ok,_} ->
@@ -350,12 +437,7 @@ do_start_daemon(Host0, Port0, SshOptions, SocketOptions) ->
end;
Sup ->
AccPid = ssh_system_sup:acceptor_supervisor(Sup),
- case ssh_acceptor_sup:start_child(AccPid, [{address, Host},
- {port, Port},
- {role, server},
- {socket_opts, SocketOptions},
- {ssh_opts, SshOptions}
- | Opts]) of
+ case ssh_acceptor_sup:start_child(AccPid, Opts) of
{error, {already_started, _}} ->
{error, eaddrinuse};
{ok, _} ->
diff --git a/lib/ssh/src/ssh_acceptor.erl b/lib/ssh/src/ssh_acceptor.erl
index 90fd951dcd..9f3e60bd62 100644
--- a/lib/ssh/src/ssh_acceptor.erl
+++ b/lib/ssh/src/ssh_acceptor.erl
@@ -27,7 +27,8 @@
%% Internal application API
-export([start_link/5,
number_of_connections/1,
- callback_listen/3]).
+ callback_listen/3,
+ handle_connection/5]).
%% spawn export
-export([acceptor_init/6, acceptor_loop/6]).
diff --git a/lib/ssh/src/ssh_system_sup.erl b/lib/ssh/src/ssh_system_sup.erl
index 5035bc8f80..e97ac7b01a 100644
--- a/lib/ssh/src/ssh_system_sup.erl
+++ b/lib/ssh/src/ssh_system_sup.erl
@@ -131,7 +131,10 @@ init([ServerOpts]) ->
RestartStrategy = one_for_one,
MaxR = 0,
MaxT = 3600,
- Children = child_specs(ServerOpts),
+ Children = case proplists:get_value(asocket,ServerOpts) of
+ undefined -> child_specs(ServerOpts);
+ _ -> []
+ end,
{ok, {{RestartStrategy, MaxR, MaxT}, Children}}.
%%%=========================================================================
diff --git a/lib/ssh/test/ssh_algorithms_SUITE.erl b/lib/ssh/test/ssh_algorithms_SUITE.erl
index ed9e7aacaa..0f68130a05 100644
--- a/lib/ssh/test/ssh_algorithms_SUITE.erl
+++ b/lib/ssh/test/ssh_algorithms_SUITE.erl
@@ -24,6 +24,7 @@
-include_lib("common_test/include/ct.hrl").
-include_lib("ssh/src/ssh_transport.hrl").
+-include("ssh_test_lib.hrl").
%% Note: This directive should only be used in test suites.
-compile(export_all).
@@ -70,32 +71,39 @@ two_way_tags() -> [cipher,mac,compression].
%%--------------------------------------------------------------------
init_per_suite(Config) ->
- ct:log("~n"
- "Environment:~n============~n"
- "os:getenv(\"HOME\") = ~p~n"
- "init:get_argument(home) = ~p~n~n~n"
- "OS ssh:~n=======~n~p~n~n~n"
- "Erl ssh:~n========~n~p~n~n~n"
- "Installed ssh client:~n=====================~n~p~n~n~n"
- "Installed ssh server:~n=====================~n~p~n~n~n"
- "Misc values:~n============~n"
- " -- Default dh group exchange parameters ({min,def,max}): ~p~n"
- " -- dh_default_groups: ~p~n"
- " -- Max num algorithms: ~p~n"
- ,[os:getenv("HOME"),
- init:get_argument(home),
- os:cmd("ssh -V"),
- ssh:default_algorithms(),
- ssh_test_lib:default_algorithms(sshc),
- ssh_test_lib:default_algorithms(sshd),
- {?DEFAULT_DH_GROUP_MIN,?DEFAULT_DH_GROUP_NBITS,?DEFAULT_DH_GROUP_MAX},
- public_key:dh_gex_group_sizes(),
- ?MAX_NUM_ALGORITHMS
- ]),
- 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)].
+ ?CHECK_CRYPTO(
+ begin
+ ct:log("~n"
+ "Environment:~n============~n"
+ "os:getenv(\"HOME\") = ~p~n"
+ "init:get_argument(home) = ~p~n~n~n"
+ "OS ssh:~n=======~n~p~n~n~n"
+ "Erl ssh:~n========~n~p~n~n~n"
+ "crypto:info_lib():~n========~n~p~n~n~n"
+ "Installed ssh client:~n=====================~n~p~n~n~n"
+ "Installed ssh server:~n=====================~n~p~n~n~n"
+ "Misc values:~n============~n"
+ " -- Default dh group exchange parameters ({min,def,max}): ~p~n"
+ " -- dh_default_groups: ~p~n"
+ " -- Max num algorithms: ~p~n"
+ ,[os:getenv("HOME"),
+ init:get_argument(home),
+ os:cmd("ssh -V"),
+ ssh:default_algorithms(),
+ crypto:info_lib(),
+ ssh_test_lib:default_algorithms(sshc),
+ ssh_test_lib:default_algorithms(sshd),
+ {?DEFAULT_DH_GROUP_MIN,?DEFAULT_DH_GROUP_NBITS,?DEFAULT_DH_GROUP_MAX},
+ public_key:dh_gex_group_sizes(),
+ ?MAX_NUM_ALGORITHMS
+ ]),
+ 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)]
+ end
+ ).
+
end_per_suite(_Config) ->
ssh:stop().
diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl
index 4991816850..733414e23a 100644
--- a/lib/ssh/test/ssh_basic_SUITE.erl
+++ b/lib/ssh/test/ssh_basic_SUITE.erl
@@ -25,6 +25,7 @@
-include_lib("common_test/include/ct.hrl").
-include_lib("kernel/include/inet.hrl").
-include_lib("kernel/include/file.hrl").
+-include("ssh_test_lib.hrl").
%% Note: This directive should only be used in test suites.
%%-compile(export_all).
@@ -130,7 +131,7 @@ basic_tests() ->
%%--------------------------------------------------------------------
init_per_suite(Config) ->
- Config.
+ ?CHECK_CRYPTO(Config).
end_per_suite(_Config) ->
ssh:stop().
diff --git a/lib/ssh/test/ssh_connection_SUITE.erl b/lib/ssh/test/ssh_connection_SUITE.erl
index c9a321fbbd..bcf3b01824 100644
--- a/lib/ssh/test/ssh_connection_SUITE.erl
+++ b/lib/ssh/test/ssh_connection_SUITE.erl
@@ -43,11 +43,15 @@ suite() ->
all() ->
[
{group, openssh},
+ small_interrupted_send,
interrupted_send,
start_shell,
start_shell_exec,
start_shell_exec_fun,
start_shell_sock_exec_fun,
+ start_shell_sock_daemon_exec,
+ connect_sock_not_tcp,
+ daemon_sock_not_tcp,
gracefull_invalid_version,
gracefull_invalid_start,
gracefull_invalid_long_start,
@@ -57,13 +61,11 @@ all() ->
max_channels_option
].
groups() ->
- [{openssh, [], payload() ++ ptty()}].
+ [{openssh, [], payload() ++ ptty() ++ sock()}].
payload() ->
[simple_exec,
simple_exec_sock,
- connect_sock_not_tcp,
- connect_sock_not_passive,
small_cat,
big_cat,
send_after_exit].
@@ -73,9 +75,14 @@ ptty() ->
ptty_alloc,
ptty_alloc_pixel].
+sock() ->
+ [connect_sock_not_passive,
+ daemon_sock_not_passive
+ ].
+
%%--------------------------------------------------------------------
init_per_suite(Config) ->
- Config.
+ ?CHECK_CRYPTO(Config).
end_per_suite(Config) ->
Config.
@@ -118,7 +125,7 @@ simple_exec(Config) when is_list(Config) ->
do_simple_exec(ConnectionRef).
-simple_exec_sock(Config) ->
+simple_exec_sock(_Config) ->
{ok, Sock} = gen_tcp:connect("localhost", ?SSH_DEFAULT_PORT, [{active,false}]),
{ok, ConnectionRef} = ssh:connect(Sock, [{silently_accept_hosts, true},
{user_interaction, false}]),
@@ -159,18 +166,30 @@ do_simple_exec(ConnectionRef) ->
end.
%%--------------------------------------------------------------------
-connect_sock_not_tcp(Config) ->
+connect_sock_not_tcp(_Config) ->
{ok,Sock} = gen_udp:open(0, []),
{error, not_tcp_socket} = ssh:connect(Sock, []),
gen_udp:close(Sock).
%%--------------------------------------------------------------------
-connect_sock_not_passive(Config) ->
+daemon_sock_not_tcp(_Config) ->
+ {ok,Sock} = gen_udp:open(0, []),
+ {error, not_tcp_socket} = ssh:daemon(Sock),
+ gen_udp:close(Sock).
+
+%%--------------------------------------------------------------------
+connect_sock_not_passive(_Config) ->
{ok,Sock} = gen_tcp:connect("localhost", ?SSH_DEFAULT_PORT, []),
{error, not_passive_mode} = ssh:connect(Sock, []),
gen_tcp:close(Sock).
%%--------------------------------------------------------------------
+daemon_sock_not_passive(_Config) ->
+ {ok,Sock} = gen_tcp:connect("localhost", ?SSH_DEFAULT_PORT, []),
+ {error, not_passive_mode} = ssh:daemon(Sock),
+ gen_tcp:close(Sock).
+
+%%--------------------------------------------------------------------
small_cat() ->
[{doc, "Use 'cat' to echo small data block back to us."}].
@@ -343,44 +362,96 @@ ptty_alloc_pixel(Config) when is_list(Config) ->
ssh:close(ConnectionRef).
%%--------------------------------------------------------------------
+small_interrupted_send(Config) ->
+ K = 1024,
+ M = K*K,
+ do_interrupted_send(Config, 10*M, 4*K).
interrupted_send(Config) ->
+ M = 1024*1024,
+ do_interrupted_send(Config, 10*M, 4*M).
+
+do_interrupted_send(Config, SendSize, EchoSize) ->
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),
SysDir = proplists:get_value(data_dir, Config),
+ EchoSS_spec = {ssh_echo_server, [EchoSize,[{dbg,true}]]},
{Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir},
{user_dir, UserDir},
{password, "morot"},
- {subsystems, [{"echo_n", {ssh_echo_server, [4000000]}}]}]),
-
+ {subsystems, [{"echo_n",EchoSS_spec}]}]),
+
+ ct:log("connect", []),
ConnectionRef = ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
{user, "foo"},
{password, "morot"},
{user_interaction, false},
{user_dir, UserDir}]),
-
- {ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity),
-
- success = ssh_connection:subsystem(ConnectionRef, ChannelId, "echo_n", infinity),
-
- %% build 10MB binary
- Data = << <<X:32>> || X <- lists:seq(1,2500000)>>,
-
- %% expect remote end to send us 4MB back
- <<ExpectedData:4000000/binary, _/binary>> = Data,
-
- %% pre-adjust receive window so the other end doesn't block
- ssh_connection:adjust_window(ConnectionRef, ChannelId, size(ExpectedData) + 1),
-
- case ssh_connection:send(ConnectionRef, ChannelId, Data, 10000) of
- {error, closed} ->
- ok;
- Msg ->
- ct:fail({expected,{error,closed}, got, Msg})
- end,
- receive_data(ExpectedData, ConnectionRef, ChannelId),
- ssh:close(ConnectionRef),
- ssh:stop_daemon(Pid).
+ ct:log("connected", []),
+
+ %% build big binary
+ Data = << <<X:32>> || X <- lists:seq(1,SendSize div 4)>>,
+
+ %% expect remote end to send us EchoSize back
+ <<ExpectedData:EchoSize/binary, _/binary>> = Data,
+
+ %% Spawn listener. Otherwise we could get a deadlock due to filled buffers
+ Parent = self(),
+ ResultPid = spawn(
+ fun() ->
+ ct:log("open channel",[]),
+ {ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity),
+ ct:log("start subsystem", []),
+ case ssh_connection:subsystem(ConnectionRef, ChannelId, "echo_n", infinity) of
+ success ->
+ Parent ! {self(), channelId, ChannelId},
+
+ Result =
+ try collect_data(ConnectionRef, ChannelId)
+ of
+ ExpectedData ->
+ ok;
+ _ ->
+ {fail,"unexpected result"}
+ catch
+ Class:Exception ->
+ {fail, io_lib:format("Exception ~p:~p",[Class,Exception])}
+ end,
+ Parent ! {self(), Result};
+ Other ->
+ Parent ! {self(), channelId, error, Other}
+ end
+ end),
+
+ receive
+ {ResultPid, channelId, ChannelId} ->
+ %% pre-adjust receive window so the other end doesn't block
+ ct:log("adjust window", []),
+ ssh_connection:adjust_window(ConnectionRef, ChannelId, size(ExpectedData) + 1),
+
+ ct:log("going to send ~p bytes", [size(Data)]),
+ case ssh_connection:send(ConnectionRef, ChannelId, Data, 30000) of
+ {error, closed} ->
+ ct:log("{error,closed} - That's what we expect :)", []),
+ ok;
+ Msg ->
+ ct:log("Got ~p - that's bad, very bad indeed",[Msg]),
+ ct:fail({expected,{error,closed}, got, Msg})
+ end,
+ ct:log("going to check the result (if it is available)", []),
+ receive
+ {ResultPid, Result} ->
+ ct:log("Got result: ~p", [Result]),
+ ssh:close(ConnectionRef),
+ ssh:stop_daemon(Pid),
+ Result
+ end;
+
+ {ResultPid, channelId, error, Other} ->
+ ssh:close(ConnectionRef),
+ ssh:stop_daemon(Pid),
+ {fail, io_lib:format("ssh_connection:subsystem: ~p",[Other])}
+ end.
%%--------------------------------------------------------------------
start_shell() ->
@@ -520,7 +591,44 @@ start_shell_sock_exec_fun(Config) when is_list(Config) ->
ssh:stop_daemon(Pid).
%%--------------------------------------------------------------------
+start_shell_sock_daemon_exec(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),
+ SysDir = proplists:get_value(data_dir, Config),
+
+ {ok,Sl} = gen_tcp:listen(0, [{active,false}]),
+ {ok,{_IP,Port}} = inet:sockname(Sl), % _IP is likely to be {0,0,0,0}. Win don't like...
+
+ spawn_link(fun() ->
+ {ok,Ss} = gen_tcp:connect("localhost", Port, [{active,false}]),
+ {ok, _Pid} = ssh:daemon(Ss, [{system_dir, SysDir},
+ {user_dir, UserDir},
+ {password, "morot"},
+ {exec, fun ssh_exec/1}])
+ end),
+ {ok,Sc} = gen_tcp:accept(Sl),
+ {ok,ConnectionRef} = ssh:connect(Sc, [{silently_accept_hosts, true},
+ {user, "foo"},
+ {password, "morot"},
+ {user_interaction, true},
+ {user_dir, UserDir}]),
+
+ {ok, ChannelId0} = ssh_connection:session_channel(ConnectionRef, infinity),
+
+ success = ssh_connection:exec(ConnectionRef, ChannelId0,
+ "testing", infinity),
+ receive
+ {ssh_cm, ConnectionRef, {data, _ChannelId, 0, <<"testing\r\n">>}} ->
+ ok
+ after 5000 ->
+ ct:fail("Exec Timeout")
+ end,
+
+ ssh:close(ConnectionRef).
+
+%%--------------------------------------------------------------------
gracefull_invalid_version(Config) when is_list(Config) ->
PrivDir = proplists:get_value(priv_dir, Config),
UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth
@@ -801,20 +909,36 @@ big_cat_rx(ConnectionRef, ChannelId, Acc) ->
timeout
end.
-receive_data(ExpectedData, ConnectionRef, ChannelId) ->
- ExpectedData = collect_data(ConnectionRef, ChannelId).
-
collect_data(ConnectionRef, ChannelId) ->
- collect_data(ConnectionRef, ChannelId, []).
+ ct:log("Listener ~p running! ConnectionRef=~p, ChannelId=~p",[self(),ConnectionRef,ChannelId]),
+ collect_data(ConnectionRef, ChannelId, [], 0).
-collect_data(ConnectionRef, ChannelId, Acc) ->
+collect_data(ConnectionRef, ChannelId, Acc, Sum) ->
+ TO = 5000,
receive
- {ssh_cm, ConnectionRef, {data, ChannelId, 0, Data}} ->
- collect_data(ConnectionRef, ChannelId, [Data | Acc]);
+ {ssh_cm, ConnectionRef, {data, ChannelId, 0, Data}} when is_binary(Data) ->
+ ct:log("collect_data: received ~p bytes. total ~p bytes",[size(Data),Sum+size(Data)]),
+ collect_data(ConnectionRef, ChannelId, [Data | Acc], Sum+size(Data));
{ssh_cm, ConnectionRef, {eof, ChannelId}} ->
- iolist_to_binary(lists:reverse(Acc))
- after 5000 ->
- timeout
+ try
+ iolist_to_binary(lists:reverse(Acc))
+ of
+ Bin ->
+ ct:log("collect_data: received eof.~nGot in total ~p bytes",[size(Bin)]),
+ Bin
+ catch
+ C:E ->
+ ct:log("collect_data: received eof.~nAcc is strange...~nException=~p:~p~nAcc=~p",
+ [C,E,Acc]),
+ {error,{C,E}}
+ end;
+ Msg ->
+ ct:log("collect_data: ***** unexpected message *****~n~p",[Msg]),
+ collect_data(ConnectionRef, ChannelId, Acc, Sum)
+
+ after TO ->
+ ct:log("collect_data: ----- Nothing received for ~p seconds -----~n",[]),
+ collect_data(ConnectionRef, ChannelId, Acc, Sum)
end.
%%%-------------------------------------------------------------------
diff --git a/lib/ssh/test/ssh_echo_server.erl b/lib/ssh/test/ssh_echo_server.erl
index ed9bbe1b67..5387d21efd 100644
--- a/lib/ssh/test/ssh_echo_server.erl
+++ b/lib/ssh/test/ssh_echo_server.erl
@@ -26,15 +26,29 @@
-record(state, {
n,
id,
- cm
+ cm,
+ dbg = false
}).
-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 "++Fmt, [?MODULE,?LINE,self()|Args]);
+ false -> ok
+ end).
+
+
init([N]) ->
- ct:pal("Echo server: ~p",[self()]),
- {ok, #state{n = N}}.
+ {ok, #state{n = N}};
+init([N,Opts]) ->
+ State = #state{n = N,
+ dbg = proplists:get_value(dbg,Opts,false)
+ },
+ ?DBG(State, "init([~p])",[N]),
+ {ok, State}.
handle_msg({ssh_channel_up, ChannelId, ConnectionManager}, State) ->
+ ?DBG(State, "ssh_channel_up Cid=~p ConnMngr=~p",[ChannelId,ConnectionManager]),
{ok, State#state{id = ChannelId,
cm = ConnectionManager}}.
@@ -42,32 +56,39 @@ handle_ssh_msg({ssh_cm, CM, {data, ChannelId, 0, Data}}, #state{n = N} = State)
M = N - size(Data),
case M > 0 of
true ->
+ ?DBG(State, "ssh_cm data Cid=~p size(Data)=~p M=~p",[ChannelId,size(Data),M]),
ssh_connection:send(CM, ChannelId, Data),
{ok, State#state{n = M}};
false ->
<<SendData:N/binary, _/binary>> = Data,
+ ?DBG(State, "ssh_cm data Cid=~p size(Data)=~p M=~p size(SendData)=~p~nSend eof",[ChannelId,size(Data),M,size(SendData)]),
ssh_connection:send(CM, ChannelId, SendData),
ssh_connection:send_eof(CM, ChannelId),
{stop, ChannelId, State}
end;
handle_ssh_msg({ssh_cm, _ConnectionManager,
{data, _ChannelId, 1, Data}}, State) ->
+ ?DBG(State, "stderr: ~p",[Data]),
error_logger:format(standard_error, " ~p~n", [binary_to_list(Data)]),
{ok, State};
handle_ssh_msg({ssh_cm, _ConnectionManager, {eof, _ChannelId}}, State) ->
+ ?DBG(State, "{eof ~p}",[_ChannelId]),
{ok, State};
-handle_ssh_msg({ssh_cm, _, {signal, _, _}}, State) ->
+handle_ssh_msg({ssh_cm, _, _Sig={signal, _, _}}, State) ->
%% Ignore signals according to RFC 4254 section 6.9.
+ ?DBG(State, "~p",[_Sig]),
{ok, State};
-handle_ssh_msg({ssh_cm, _, {exit_signal, ChannelId, _, _Error, _}},
- State) ->
+handle_ssh_msg({ssh_cm, _, _Sig={exit_signal, ChannelId, _, _Error, _}}, State) ->
+ ?DBG(State, "~p",[_Sig]),
{stop, ChannelId, State};
-handle_ssh_msg({ssh_cm, _, {exit_status, ChannelId, _Status}}, State) ->
+handle_ssh_msg({ssh_cm, _, _Sig={exit_status, ChannelId, _Status}}, State) ->
+ ?DBG(State, "~p",[_Sig]),
{stop, ChannelId, State}.
terminate(_Reason, _State) ->
+ ?DBG(_State, "terminate ~p",[_Reason]),
ok.
diff --git a/lib/ssh/test/ssh_options_SUITE.erl b/lib/ssh/test/ssh_options_SUITE.erl
index d1e3d6cb0e..61883c0647 100644
--- a/lib/ssh/test/ssh_options_SUITE.erl
+++ b/lib/ssh/test/ssh_options_SUITE.erl
@@ -27,7 +27,7 @@
-include_lib("common_test/include/ct.hrl").
-include_lib("kernel/include/file.hrl").
-
+-include("ssh_test_lib.hrl").
%%% Test cases
-export([connectfun_disconnectfun_client/1,
@@ -126,7 +126,7 @@ groups() ->
%%--------------------------------------------------------------------
init_per_suite(Config) ->
- Config.
+ ?CHECK_CRYPTO(Config).
end_per_suite(_Config) ->
ssh:stop().
diff --git a/lib/ssh/test/ssh_protocol_SUITE.erl b/lib/ssh/test/ssh_protocol_SUITE.erl
index 41faf951e1..4fac1f718a 100644
--- a/lib/ssh/test/ssh_protocol_SUITE.erl
+++ b/lib/ssh/test/ssh_protocol_SUITE.erl
@@ -26,6 +26,7 @@
-include_lib("ssh/src/ssh.hrl"). % ?UINT32, ?BYTE, #ssh{} ...
-include_lib("ssh/src/ssh_transport.hrl").
-include_lib("ssh/src/ssh_auth.hrl").
+-include("ssh_test_lib.hrl").
%% Note: This directive should only be used in test suites.
-compile(export_all).
@@ -87,7 +88,7 @@ groups() ->
init_per_suite(Config) ->
- start_std_daemon( setup_dirs( start_apps(Config))).
+ ?CHECK_CRYPTO(start_std_daemon( setup_dirs( start_apps(Config)))).
end_per_suite(Config) ->
stop_apps(Config).
diff --git a/lib/ssh/test/ssh_renegotiate_SUITE.erl b/lib/ssh/test/ssh_renegotiate_SUITE.erl
index 300816276a..b10ec3707f 100644
--- a/lib/ssh/test/ssh_renegotiate_SUITE.erl
+++ b/lib/ssh/test/ssh_renegotiate_SUITE.erl
@@ -21,6 +21,7 @@
-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).
@@ -45,7 +46,7 @@ tests() -> [rekey, rekey_limit, renegotiate1, renegotiate2].
%%--------------------------------------------------------------------
init_per_suite(Config) ->
- Config.
+ ?CHECK_CRYPTO(Config).
end_per_suite(_Config) ->
ssh:stop().
diff --git a/lib/ssh/test/ssh_sftp_SUITE.erl b/lib/ssh/test/ssh_sftp_SUITE.erl
index 4d40b4647c..19ad81e7da 100644
--- a/lib/ssh/test/ssh_sftp_SUITE.erl
+++ b/lib/ssh/test/ssh_sftp_SUITE.erl
@@ -26,7 +26,7 @@
-include_lib("common_test/include/ct.hrl").
-include_lib("kernel/include/file.hrl").
-
+-include("ssh_test_lib.hrl").
% Default timetrap timeout
-define(default_timeout, ?t:minutes(1)).
@@ -45,10 +45,13 @@ all() ->
init_per_suite(Config) ->
- ct:log("file:native_name_encoding() = ~p,~nio:getopts() = ~p",
- [file:native_name_encoding(),io:getopts()]),
- ssh:start(),
- Config.
+ ?CHECK_CRYPTO(
+ begin
+ ct:log("file:native_name_encoding() = ~p,~nio:getopts() = ~p",
+ [file:native_name_encoding(),io:getopts()]),
+ ssh:start(),
+ Config
+ end).
end_per_suite(_onfig) ->
ssh:stop().
@@ -673,6 +676,7 @@ start_channel_sock(Config) ->
%% Test that the socket is closed when the Connection closes
ok = ssh:close(Conn),
+ timer:sleep(400), %% Until the stop sequence is fixed
{error,einval} = inet:getopts(Sock, [active]),
ok.
diff --git a/lib/ssh/test/ssh_sftpd_SUITE.erl b/lib/ssh/test/ssh_sftpd_SUITE.erl
index 4a69fd36b3..52a26110c4 100644
--- a/lib/ssh/test/ssh_sftpd_SUITE.erl
+++ b/lib/ssh/test/ssh_sftpd_SUITE.erl
@@ -28,6 +28,7 @@
-include_lib("kernel/include/file.hrl").
-include("ssh_xfer.hrl").
-include("ssh.hrl").
+-include("ssh_test_lib.hrl").
-define(USER, "Alladin").
-define(PASSWD, "Sesame").
@@ -72,14 +73,17 @@ groups() ->
%%--------------------------------------------------------------------
init_per_suite(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- PrivDir = proplists:get_value(priv_dir, Config),
- ssh_test_lib:setup_dsa(DataDir, PrivDir),
- %% to make sure we don't use public-key-auth
- %% this should be tested by other test suites
- UserDir = filename:join(proplists:get_value(priv_dir, Config), nopubkey),
- file:make_dir(UserDir),
- Config.
+ ?CHECK_CRYPTO(
+ begin
+ DataDir = proplists:get_value(data_dir, Config),
+ PrivDir = proplists:get_value(priv_dir, Config),
+ ssh_test_lib:setup_dsa(DataDir, PrivDir),
+ %% to make sure we don't use public-key-auth
+ %% this should be tested by other test suites
+ UserDir = filename:join(proplists:get_value(priv_dir, Config), nopubkey),
+ file:make_dir(UserDir),
+ Config
+ end).
end_per_suite(Config) ->
SysDir = proplists:get_value(priv_dir, Config),
diff --git a/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl b/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl
index 75b5090c2b..56a33d6349 100644
--- a/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl
+++ b/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl
@@ -26,6 +26,7 @@
-include_lib("common_test/include/ct.hrl").
-include_lib("kernel/include/file.hrl").
+-include("ssh_test_lib.hrl").
-define(USER, "Alladin").
-define(PASSWD, "Sesame").
@@ -53,17 +54,20 @@ groups() ->
%%--------------------------------------------------------------------
init_per_suite(Config) ->
- catch ssh:stop(),
- DataDir = proplists:get_value(data_dir, Config),
- PrivDir = proplists:get_value(priv_dir, Config),
- FileAlt = filename:join(DataDir, "ssh_sftpd_file_alt.erl"),
- c:c(FileAlt),
- FileName = filename:join(DataDir, "test.txt"),
- {ok, FileInfo} = file:read_file_info(FileName),
- ok = file:write_file_info(FileName,
- FileInfo#file_info{mode = 8#400}),
- ssh_test_lib:setup_dsa(DataDir, PrivDir),
- Config.
+ ?CHECK_CRYPTO(
+ begin
+ catch ssh:stop(),
+ DataDir = proplists:get_value(data_dir, Config),
+ PrivDir = proplists:get_value(priv_dir, Config),
+ FileAlt = filename:join(DataDir, "ssh_sftpd_file_alt.erl"),
+ c:c(FileAlt),
+ FileName = filename:join(DataDir, "test.txt"),
+ {ok, FileInfo} = file:read_file_info(FileName),
+ ok = file:write_file_info(FileName,
+ FileInfo#file_info{mode = 8#400}),
+ ssh_test_lib:setup_dsa(DataDir, PrivDir),
+ Config
+ end).
end_per_suite(Config) ->
UserDir = filename:join(proplists:get_value(priv_dir, Config), nopubkey),
diff --git a/lib/ssh/test/ssh_sup_SUITE.erl b/lib/ssh/test/ssh_sup_SUITE.erl
index 574564f6e9..ff53e1c4c6 100644
--- a/lib/ssh/test/ssh_sup_SUITE.erl
+++ b/lib/ssh/test/ssh_sup_SUITE.erl
@@ -53,11 +53,14 @@ end_per_group(_GroupName, Config) ->
Config.
init_per_suite(Config) ->
- Port = ssh_test_lib:inet_port(node()),
- 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),
- [{userdir, UserDir},{port, Port}, {host, "localhost"}, {host_ip, any} | Config].
+ ?CHECK_CRYPTO(
+ begin
+ Port = ssh_test_lib:inet_port(node()),
+ 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),
+ [{userdir, UserDir},{port, Port}, {host, "localhost"}, {host_ip, any} | Config]
+ end).
end_per_suite(_) ->
ok.
diff --git a/lib/ssh/test/ssh_test_lib.hrl b/lib/ssh/test/ssh_test_lib.hrl
index 7cb7edeaa8..54c93b7e87 100644
--- a/lib/ssh/test/ssh_test_lib.hrl
+++ b/lib/ssh/test/ssh_test_lib.hrl
@@ -1,4 +1,14 @@
%%-------------------------------------------------------------------------
+%% Check for usable crypt
+%%-------------------------------------------------------------------------
+-define(CHECK_CRYPTO(Available),
+ try crypto:start()
+ of _ -> Available
+ catch _:_ -> {skip, "Can't start crypto"}
+ end
+ ).
+
+%%-------------------------------------------------------------------------
%% Help macro
%%-------------------------------------------------------------------------
-define(wait_match(Pattern, FunctionCall, Bind, Timeout, Ntries),
diff --git a/lib/ssh/test/ssh_to_openssh_SUITE.erl b/lib/ssh/test/ssh_to_openssh_SUITE.erl
index f96a2cc62b..a914938c41 100644
--- a/lib/ssh/test/ssh_to_openssh_SUITE.erl
+++ b/lib/ssh/test/ssh_to_openssh_SUITE.erl
@@ -22,6 +22,7 @@
-module(ssh_to_openssh_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).
@@ -62,12 +63,14 @@ groups() ->
].
init_per_suite(Config) ->
- case gen_tcp:connect("localhost", 22, []) of
- {error,econnrefused} ->
- {skip,"No openssh deamon"};
- _ ->
- ssh_test_lib:openssh_sanity_check(Config)
- end.
+ ?CHECK_CRYPTO(
+ case gen_tcp:connect("localhost", 22, []) of
+ {error,econnrefused} ->
+ {skip,"No openssh deamon"};
+ _ ->
+ ssh_test_lib:openssh_sanity_check(Config)
+ end
+ ).
end_per_suite(_Config) ->
ok.
diff --git a/lib/ssh/test/ssh_upgrade_SUITE.erl b/lib/ssh/test/ssh_upgrade_SUITE.erl
index 9d9b2b78fb..b5b27c369a 100644
--- a/lib/ssh/test/ssh_upgrade_SUITE.erl
+++ b/lib/ssh/test/ssh_upgrade_SUITE.erl
@@ -23,6 +23,7 @@
-compile(export_all).
-include_lib("common_test/include/ct.hrl").
+-include("ssh_test_lib.hrl").
-record(state, {
config,
@@ -48,13 +49,15 @@ all() ->
].
init_per_suite(Config0) ->
- case ct_release_test:init(Config0) of
- {skip, Reason} ->
- {skip, Reason};
- Config ->
- ssh:start(),
- Config
- end.
+ ?CHECK_CRYPTO(
+ case ct_release_test:init(Config0) of
+ {skip, Reason} ->
+ {skip, Reason};
+ Config ->
+ ssh:start(),
+ Config
+ end
+ ).
end_per_suite(Config) ->
ct_release_test:cleanup(Config),
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
index 33ece8f769..bed82cdb91 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -423,7 +423,7 @@ fun(srp, Username :: string(), UserState :: term()) ->
<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
mitigation strategy to interoperate with legacy software.
- Defaults to <c>one_n_minus_one</c></p>.
+ Defaults to <c>one_n_minus_one</c>.</p>
<p><c>one_n_minus_one</c> - Perform 1/n-1 BEAST mitigation.</p>
@@ -706,6 +706,12 @@ fun(srp, Username :: string(), UserState :: term()) ->
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>
@@ -895,6 +901,23 @@ 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>
+ <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>
+ </desc>
+ </func>
+
+ <func>
<name>listen(Port, Options) ->
{ok, ListenSocket} | {error, Reason}</name>
<fsummary>Creates an SSL listen socket.</fsummary>
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index 33d5c1c6d6..d2aeb3258f 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -34,7 +34,8 @@
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
+ 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,
@@ -469,6 +470,32 @@ setopts(#sslsocket{}, Options) ->
{error, {options,{not_a_proplist, Options}}}.
%%---------------------------------------------------------------
+-spec getstat(Socket) ->
+ {ok, OptionValues} | {error, inet:posix()} when
+ Socket :: #sslsocket{},
+ OptionValues :: [{inet:stat_option(), integer()}].
+%%
+%% Description: Get all statistic options for a socket.
+%%--------------------------------------------------------------------
+getstat(Socket) ->
+ getstat(Socket, inet:stats()).
+
+%%---------------------------------------------------------------
+-spec getstat(Socket, Options) ->
+ {ok, OptionValues} | {error, inet:posix()} when
+ Socket :: #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) ->
+ ssl_socket:getstat(Transport, Listen, Options);
+
+getstat(#sslsocket{pid = Pid, fd = {Transport, Socket, _, _}}, Options) when is_pid(Pid), is_list(Options) ->
+ ssl_socket:getstat(Transport, Socket, Options).
+
+%%---------------------------------------------------------------
-spec shutdown(#sslsocket{}, read | write | read_write) -> ok | {error, reason()}.
%%
%% Description: Same as gen_tcp:shutdown/2
@@ -732,7 +759,8 @@ handle_options(Opts0, Role) ->
false, Role)),
client, Role),
crl_check = handle_option(crl_check, Opts, false),
- crl_cache = handle_option(crl_cache, Opts, {ssl_crl_cache, {internal, []}})
+ crl_cache = handle_option(crl_cache, Opts, {ssl_crl_cache, {internal, []}}),
+ v2_hello_compatible = handle_option(v2_hello_compatible, Opts, false)
},
CbInfo = proplists:get_value(cb_info, Opts, {gen_tcp, tcp, tcp_closed, tcp_error}),
@@ -747,7 +775,7 @@ handle_options(Opts0, Role) ->
alpn_preferred_protocols, next_protocols_advertised,
client_preferred_next_protocols, log_alert,
server_name_indication, honor_cipher_order, padding_check, crl_check, crl_cache,
- fallback, signature_algs, beast_mitigation],
+ fallback, signature_algs, beast_mitigation, v2_hello_compatible],
SockOpts = lists:foldl(fun(Key, PropList) ->
proplists:delete(Key, PropList)
@@ -991,6 +1019,8 @@ 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(Opt, Value) ->
throw({error, {options, {Opt, Value}}}).
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index b45c5c8fc6..90e0810241 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -465,6 +465,14 @@ certify(internal, #certificate{asn1_certificates = []},
Connection:next_record(State0#state{client_certificate_requested = false}),
Connection:next_event(certify, Record, State);
+certify(internal, #certificate{},
+ #state{role = server,
+ negotiated_version = Version,
+ ssl_options = #ssl_options{verify = verify_none}} =
+ State, Connection) ->
+ Alert = ?ALERT_REC(?FATAL,?UNEXPECTED_MESSAGE, unrequested_certificate),
+ Connection:handle_own_alert(Alert, Version, certify, State);
+
certify(internal, #certificate{} = Cert,
#state{negotiated_version = Version,
role = Role,
diff --git a/lib/ssl/src/ssl_crl.erl b/lib/ssl/src/ssl_crl.erl
index faf5007b16..d9f21e04ac 100644
--- a/lib/ssl/src/ssl_crl.erl
+++ b/lib/ssl/src/ssl_crl.erl
@@ -39,13 +39,12 @@ trusted_cert_and_path(CRL, {SerialNumber, Issuer},{Db, DbRef} = DbHandle) ->
end;
trusted_cert_and_path(CRL, issuer_not_found, {Db, DbRef} = DbHandle) ->
- try find_issuer(CRL, DbHandle) of
- OtpCert ->
+ case find_issuer(CRL, DbHandle) of
+ {ok, OtpCert} ->
{ok, Root, Chain} = ssl_certificate:certificate_chain(OtpCert, Db, DbRef),
- {ok, Root, lists:reverse(Chain)}
- catch
- throw:_ ->
- {error, issuer_not_found}
+ {ok, Root, lists:reverse(Chain)};
+ {error, issuer_not_found} ->
+ {ok, unknown_crl_ca, []}
end.
find_issuer(CRL, {Db,_}) ->
@@ -61,11 +60,10 @@ find_issuer(CRL, {Db,_}) ->
issuer_not_found ->
{error, issuer_not_found}
catch
- {ok, IssuerCert} ->
- IssuerCert
+ {ok, _} = Result ->
+ Result
end.
-
verify_crl_issuer(CRL, ErlCertCandidate, Issuer, NotIssuer) ->
TBSCert = ErlCertCandidate#'OTPCertificate'.tbsCertificate,
case public_key:pkix_normalize_name(TBSCert#'OTPTBSCertificate'.subject) of
diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl
index dddcbdeeda..c19c1787ff 100644
--- a/lib/ssl/src/ssl_internal.hrl
+++ b/lib/ssl/src/ssl_internal.hrl
@@ -139,7 +139,8 @@
fallback = false :: boolean(),
crl_check :: boolean() | peer | best_effort,
crl_cache,
- signature_algs
+ signature_algs,
+ v2_hello_compatible :: boolean()
}).
-record(socket_options,
diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl
index 60b4fbe995..c7dcbaabe9 100644
--- a/lib/ssl/src/ssl_manager.erl
+++ b/lib/ssl/src/ssl_manager.erl
@@ -67,6 +67,7 @@
-define(CLEAN_SESSION_DB, 60000).
-define(CLEAN_CERT_DB, 500).
-define(DEFAULT_MAX_SESSION_CACHE, 1000).
+-define(LOAD_MITIGATION, 10).
%%====================================================================
%% API
@@ -196,10 +197,12 @@ register_session(Port, Session) ->
%%--------------------------------------------------------------------
-spec invalidate_session(host(), inet:port_number(), #session{}) -> ok.
invalidate_session(Host, Port, Session) ->
+ load_mitigation(),
cast({invalidate_session, Host, Port, Session}).
-spec invalidate_session(inet:port_number(), #session{}) -> ok.
invalidate_session(Port, Session) ->
+ load_mitigation(),
cast({invalidate_session, Port, Session}).
-spec invalidate_pem(File::binary()) -> ok.
@@ -719,3 +722,11 @@ invalidate_session_cache(undefined, CacheCb, Cache) ->
start_session_validator(Cache, CacheCb, {invalidate_before, erlang:monotonic_time()}, undefined);
invalidate_session_cache(Pid, _CacheCb, _Cache) ->
Pid.
+
+load_mitigation() ->
+ MSec = rand:uniform(?LOAD_MITIGATION),
+ receive
+ after
+ MSec ->
+ continue
+ end.
diff --git a/lib/ssl/src/ssl_socket.erl b/lib/ssl/src/ssl_socket.erl
index 95a70a4602..b2aea2ba9c 100644
--- a/lib/ssl/src/ssl_socket.erl
+++ b/lib/ssl/src/ssl_socket.erl
@@ -24,7 +24,7 @@
-include("ssl_internal.hrl").
-include("ssl_api.hrl").
--export([socket/5, setopts/3, getopts/3, peername/2, sockname/2, port/2]).
+-export([socket/5, setopts/3, getopts/3, getstat/3, peername/2, sockname/2, port/2]).
-export([emulated_options/0, internal_inet_values/0, default_inet_values/0,
init/1, start_link/3, terminate/2, inherit_tracker/3, get_emulated_opts/1,
set_emulated_opts/2, get_all_opts/1, handle_call/3, handle_cast/2,
@@ -74,6 +74,11 @@ getopts(gen_tcp, Socket, Options) ->
getopts(Transport, Socket, Options) ->
Transport:getopts(Socket, Options).
+getstat(gen_tcp, Socket, Options) ->
+ inet:getstat(Socket, Options);
+getstat(Transport, Socket, Options) ->
+ Transport:getstat(Socket, Options).
+
peername(gen_tcp, Socket) ->
inet:peername(Socket);
peername(Transport, Socket) ->
diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl
index 56e516bce2..eaf2dd002d 100644
--- a/lib/ssl/src/tls_connection.erl
+++ b/lib/ssl/src/tls_connection.erl
@@ -399,9 +399,10 @@ handle_common_event(internal, #alert{} = Alert, StateName,
handle_common_event(internal, #ssl_tls{type = ?HANDSHAKE, fragment = Data},
StateName, #state{protocol_buffers =
#protocol_buffers{tls_handshake_buffer = Buf0} = Buffers,
- negotiated_version = Version} = State0) ->
- try
- {Packets, Buf} = tls_handshake:get_tls_handshake(Version,Data,Buf0),
+ negotiated_version = Version,
+ ssl_options = Options} = State0) ->
+ try
+ {Packets, Buf} = tls_handshake:get_tls_handshake(Version,Data,Buf0, Options),
State =
State0#state{protocol_buffers =
Buffers#protocol_buffers{tls_handshake_buffer = Buf}},
diff --git a/lib/ssl/src/tls_handshake.erl b/lib/ssl/src/tls_handshake.erl
index 871eb970eb..397f963ad5 100644
--- a/lib/ssl/src/tls_handshake.erl
+++ b/lib/ssl/src/tls_handshake.erl
@@ -33,7 +33,7 @@
-include_lib("public_key/include/public_key.hrl").
-export([client_hello/8, hello/4,
- get_tls_handshake/3, encode_handshake/2, decode_handshake/3]).
+ get_tls_handshake/4, encode_handshake/2, decode_handshake/4]).
-type tls_handshake() :: #client_hello{} | ssl_handshake:ssl_handshake().
@@ -133,17 +133,17 @@ encode_handshake(Package, Version) ->
[MsgType, ?uint24(Len), Bin].
%%--------------------------------------------------------------------
--spec get_tls_handshake(tls_record:tls_version(), binary(), binary() | iolist()) ->
+-spec get_tls_handshake(tls_record:tls_version(), binary(), binary() | iolist(), #ssl_options{}) ->
{[tls_handshake()], binary()}.
%%
%% Description: Given buffered and new data from ssl_record, collects
%% and returns it as a list of handshake messages, also returns leftover
%% data.
%%--------------------------------------------------------------------
-get_tls_handshake(Version, Data, <<>>) ->
- get_tls_handshake_aux(Version, Data, []);
-get_tls_handshake(Version, Data, Buffer) ->
- get_tls_handshake_aux(Version, list_to_binary([Buffer, Data]), []).
+get_tls_handshake(Version, Data, <<>>, Options) ->
+ get_tls_handshake_aux(Version, Data, Options, []);
+get_tls_handshake(Version, Data, Buffer, Options) ->
+ get_tls_handshake_aux(Version, list_to_binary([Buffer, Data]), Options, []).
%%--------------------------------------------------------------------
%%% Internal functions
@@ -184,24 +184,24 @@ handle_client_hello(Version, #client_hello{session_id = SugesstedId,
end.
get_tls_handshake_aux(Version, <<?BYTE(Type), ?UINT24(Length),
- Body:Length/binary,Rest/binary>>, Acc) ->
+ Body:Length/binary,Rest/binary>>, #ssl_options{v2_hello_compatible = V2Hello} = Opts, Acc) ->
Raw = <<?BYTE(Type), ?UINT24(Length), Body/binary>>,
- Handshake = decode_handshake(Version, Type, Body),
- get_tls_handshake_aux(Version, Rest, [{Handshake,Raw} | Acc]);
-get_tls_handshake_aux(_Version, Data, Acc) ->
+ Handshake = decode_handshake(Version, Type, Body, V2Hello),
+ get_tls_handshake_aux(Version, Rest, Opts, [{Handshake,Raw} | Acc]);
+get_tls_handshake_aux(_Version, Data, _, Acc) ->
{lists:reverse(Acc), Data}.
-decode_handshake(_, ?HELLO_REQUEST, <<>>) ->
+decode_handshake(_, ?HELLO_REQUEST, <<>>, _) ->
#hello_request{};
%% Client hello v2.
%% 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_handshake(_Version, ?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor),
- ?UINT16(CSLength), ?UINT16(0),
- ?UINT16(CDLength),
- CipherSuites:CSLength/binary,
- ChallengeData:CDLength/binary>>) ->
+ ?UINT16(CSLength), ?UINT16(0),
+ ?UINT16(CDLength),
+ CipherSuites:CSLength/binary,
+ ChallengeData:CDLength/binary>>, true) ->
#client_hello{client_version = {Major, Minor},
random = ssl_v2:client_random(ChallengeData, CDLength),
session_id = 0,
@@ -209,12 +209,18 @@ decode_handshake(_Version, ?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor),
compression_methods = [?NULL],
extensions = #hello_extensions{}
};
+decode_handshake(_Version, ?CLIENT_HELLO, <<?BYTE(_), ?BYTE(_),
+ ?UINT16(CSLength), ?UINT16(0),
+ ?UINT16(CDLength),
+ _CipherSuites:CSLength/binary,
+ _ChallengeData:CDLength/binary>>, false) ->
+ throw(?ALERT_REC(?FATAL, ?PROTOCOL_VERSION, ssl_v2_client_hello_no_supported));
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>>) ->
-
+ ?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{
@@ -226,7 +232,7 @@ decode_handshake(_Version, ?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:3
extensions = DecodedExtensions
};
-decode_handshake(Version, Tag, Msg) ->
+decode_handshake(Version, Tag, Msg, _) ->
ssl_handshake:decode_handshake(Version, Tag, Msg).
enc_handshake(#hello_request{}, _Version) ->
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index 99f7c9b780..93b6ae66dc 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -150,6 +150,7 @@ api_tests() ->
sockname,
versions,
controlling_process,
+ getstat,
close_with_timeout,
hibernate,
hibernate_right_away,
@@ -691,6 +692,75 @@ controlling_process(Config) when is_list(Config) ->
ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
+getstat() ->
+ [{doc,"Test API function getstat/2"}].
+
+getstat(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server1 =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result, []}},
+ {options, [{active, false} | ServerOpts]}]),
+ Port1 = ssl_test_lib:inet_port(Server1),
+ Server2 =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result, []}},
+ {options, [{active, false} | ServerOpts]}]),
+ Port2 = ssl_test_lib:inet_port(Server2),
+ {ok, ActiveC} = rpc:call(ClientNode, ssl, connect,
+ [Hostname,Port1,[{active, once}|ClientOpts]]),
+ {ok, PassiveC} = rpc:call(ClientNode, ssl, connect,
+ [Hostname,Port2,[{active, false}|ClientOpts]]),
+
+ ct:log("Testcase ~p, Client ~p Servers ~p, ~p ~n",
+ [self(), self(), Server1, Server2]),
+
+ %% We only check that the values are non-zero initially
+ %% (due to the handshake), and that sending more changes the values.
+
+ %% Passive socket.
+
+ {ok, InitialStats} = ssl:getstat(PassiveC),
+ ct:pal("InitialStats ~p~n", [InitialStats]),
+ [true] = lists:usort([0 =/= proplists:get_value(Name, InitialStats)
+ || Name <- [recv_cnt, recv_oct, recv_avg, recv_max, send_cnt, send_oct, send_avg, send_max]]),
+
+ ok = ssl:send(PassiveC, "Hello world"),
+ wait_for_send(PassiveC),
+ {ok, SStats} = ssl:getstat(PassiveC, [send_cnt, send_oct]),
+ ct:pal("SStats ~p~n", [SStats]),
+ [true] = lists:usort([proplists:get_value(Name, SStats) =/= proplists:get_value(Name, InitialStats)
+ || Name <- [send_cnt, send_oct]]),
+
+ %% Active socket.
+
+ {ok, InitialAStats} = ssl:getstat(ActiveC),
+ ct:pal("InitialAStats ~p~n", [InitialAStats]),
+ [true] = lists:usort([0 =/= proplists:get_value(Name, InitialAStats)
+ || Name <- [recv_cnt, recv_oct, recv_avg, recv_max, send_cnt, send_oct, send_avg, send_max]]),
+
+ _ = receive
+ {ssl, ActiveC, _} ->
+ ok
+ after
+ ?SLEEP ->
+ exit(timeout)
+ end,
+
+ ok = ssl:send(ActiveC, "Hello world"),
+ wait_for_send(ActiveC),
+ {ok, ASStats} = ssl:getstat(ActiveC, [send_cnt, send_oct]),
+ ct:pal("ASStats ~p~n", [ASStats]),
+ [true] = lists:usort([proplists:get_value(Name, ASStats) =/= proplists:get_value(Name, InitialAStats)
+ || Name <- [send_cnt, send_oct]]),
+
+ ok.
+
+%%--------------------------------------------------------------------
controller_dies() ->
[{doc,"Test that the socket is closed after controlling process dies"}].
controller_dies(Config) when is_list(Config) ->
@@ -3059,7 +3129,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),
+ ServerHello = tls_handshake:decode_handshake({RecMajor, RecMinor}, 2, HelloBin, false),
case ServerHello of
#server_hello{server_version = {3,0}, cipher_suite = <<0,57>>} ->
ok;
@@ -4592,4 +4662,6 @@ first_rsa_suite([{rsa, _, _, _} = Suite| _]) ->
first_rsa_suite([_ | Rest]) ->
first_rsa_suite(Rest).
-
+wait_for_send(Socket) ->
+ %% Make sure TLS process processed send message event
+ _ = ssl:connection_information(Socket).
diff --git a/lib/ssl/test/ssl_handshake_SUITE.erl b/lib/ssl/test/ssl_handshake_SUITE.erl
index 26e83413c1..a671e3e307 100644
--- a/lib/ssl/test/ssl_handshake_SUITE.erl
+++ b/lib/ssl/test/ssl_handshake_SUITE.erl
@@ -99,7 +99,8 @@ decode_hello_handshake(_Config) ->
16#70, 16#64, 16#79, 16#2f, 16#32>>,
Version = {3, 0},
- {Records, _Buffer} = tls_handshake:get_tls_handshake(Version, HelloPacket, <<>>),
+ {Records, _Buffer} = tls_handshake:get_tls_handshake(Version, HelloPacket, <<>>,
+ #ssl_options{v2_hello_compatible = false}),
{Hello, _Data} = hd(Records),
#renegotiation_info{renegotiated_connection = <<0>>}
diff --git a/lib/ssl/test/ssl_npn_hello_SUITE.erl b/lib/ssl/test/ssl_npn_hello_SUITE.erl
index 533501e788..00eb9fee4f 100644
--- a/lib/ssl/test/ssl_npn_hello_SUITE.erl
+++ b/lib/ssl/test/ssl_npn_hello_SUITE.erl
@@ -57,7 +57,7 @@ encode_and_decode_client_hello_test(Config) ->
HandShakeData = create_client_handshake(undefined),
Version = ssl_test_lib:protocol_version(Config),
{[{DecodedHandshakeMessage, _Raw}], _} =
- tls_handshake:get_tls_handshake(Version, list_to_binary(HandShakeData), <<>>),
+ tls_handshake:get_tls_handshake(Version, list_to_binary(HandShakeData), <<>>, #ssl_options{}),
NextProtocolNegotiation = (DecodedHandshakeMessage#client_hello.extensions)#hello_extensions.next_protocol_negotiation,
NextProtocolNegotiation = undefined.
%%--------------------------------------------------------------------
@@ -65,7 +65,7 @@ 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), <<>>),
+ 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 = <<>>}.
%%--------------------------------------------------------------------
@@ -73,7 +73,7 @@ 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), <<>>),
+ tls_handshake:get_tls_handshake(Version, list_to_binary(HandShakeData), <<>>, #ssl_options{}),
NextProtocolNegotiation = (DecodedHandshakeMessage#server_hello.extensions)#hello_extensions.next_protocol_negotiation,
NextProtocolNegotiation = undefined.
%%--------------------------------------------------------------------
@@ -81,7 +81,7 @@ 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), <<>>),
+ 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">>}.
diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl
index 9df31a3381..d9a4657a79 100644
--- a/lib/ssl/test/ssl_to_openssl_SUITE.erl
+++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl
@@ -131,6 +131,13 @@ end_per_suite(_Config) ->
ssl:stop(),
application:stop(crypto).
+init_per_group(basic, Config) ->
+ 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 ->
@@ -296,15 +303,18 @@ basic_erlang_server_openssl_client() ->
basic_erlang_server_openssl_client(Config) when is_list(Config) ->
process_flag(trap_exit, true),
ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
+ V2Compat = proplists:get_value(v2_hello_compatible, Config),
{_, ServerNode, _} = 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, ServerOpts}]),
+ {mfa, {?MODULE, erlang_ssl_receive, [Data]}},
+ {options,[{v2_hello_compatible, V2Compat} | ServerOpts]}]),
+
Port = ssl_test_lib:inet_port(Server),
Exe = "openssl",
@@ -318,8 +328,8 @@ basic_erlang_server_openssl_client(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),
- ok.
+ process_flag(trap_exit, false).
+
%%--------------------------------------------------------------------
erlang_client_openssl_server() ->
[{doc,"Test erlang client with openssl server"}].
diff --git a/lib/stdlib/src/supervisor.erl b/lib/stdlib/src/supervisor.erl
index a594c66fa7..c81e72689c 100644
--- a/lib/stdlib/src/supervisor.erl
+++ b/lib/stdlib/src/supervisor.erl
@@ -30,7 +30,7 @@
%% Internal exports
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
- terminate/2, code_change/3]).
+ terminate/2, code_change/3, format_status/2]).
-export([try_again_restart/2]).
%% For release_handler only
@@ -264,8 +264,13 @@ cast(Supervisor, Req) ->
get_callback_module(Pid) ->
{status, _Pid, {module, _Mod},
[_PDict, _SysState, _Parent, _Dbg, Misc]} = sys:get_status(Pid),
- [_Header, _Data, {data, [{"State", State}]}] = Misc,
- State#state.module.
+ case lists:keyfind(supervisor, 1, Misc) of
+ {supervisor, [{"Callback", Mod}]} ->
+ Mod;
+ _ ->
+ [_Header, _Data, {data, [{"State", State}]} | _] = Misc,
+ State#state.module
+ end.
%%% ---------------------------------------------------
%%%
@@ -1450,3 +1455,9 @@ report_progress(Child, SupName) ->
Progress = [{supervisor, SupName},
{started, extract_child(Child)}],
error_logger:info_report(progress, Progress).
+
+format_status(terminate, [_PDict, State]) ->
+ State;
+format_status(_, [_PDict, State]) ->
+ [{data, [{"State", State}]},
+ {supervisor, [{"Callback", State#state.module}]}].
diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl
index 8c1c625676..40764a943d 100644
--- a/lib/stdlib/test/ets_SUITE.erl
+++ b/lib/stdlib/test/ets_SUITE.erl
@@ -215,7 +215,7 @@ memory_check_summary(_Config) ->
receive {get_failed_memchecks, FailedMemchecks} -> ok end,
io:format("Failed memchecks: ~p\n",[FailedMemchecks]),
NoFailedMemchecks = length(FailedMemchecks),
- if NoFailedMemchecks > 3 ->
+ if NoFailedMemchecks > 300 ->
ct:fail("Too many failed (~p) memchecks", [NoFailedMemchecks]);
true ->
ok
@@ -604,9 +604,9 @@ memory(Config) when is_list(Config) ->
memory_do(Opts) ->
L = [T1,T2,T3,T4] = fill_sets_int(1000,Opts),
XR1 = case mem_mode(T1) of
- {normal,_} -> {13836,13046,13046,13052}; %{13862,13072,13072,13078};
- {compressed,4} -> {11041,10251,10251,10252}; %{11067,10277,10277,10278};
- {compressed,8} -> {10050,9260,9260,9260} %{10076,9286,9286,9286}
+ {normal,_} -> {13836,13560,13560,13566}; %{13836,13046,13046,13052}
+ {compressed,4} -> {11041,10865,10865,10866}; %{11041,10251,10251,10252}
+ {compressed,8} -> {10050,9774,9774,9774} % {10050,9260,9260,9260}
end,
XRes1 = adjust_xmem(L, XR1),
Res1 = {?S(T1),?S(T2),?S(T3),?S(T4)},
@@ -620,9 +620,9 @@ memory_do(Opts) ->
end,
L),
XR2 = case mem_mode(T1) of
- {normal,_} -> {13826,13037,13028,13034}; %{13852,13063,13054,13060};
- {compressed,4} -> {11031,10242,10233,10234}; %{11057,10268,10259,10260};
- {compressed,8} -> {10040,9251,9242,9242} %10066,9277,9268,9268}
+ {normal,_} -> {13826,13551,13542,13548}; %{13826,13037,13028,13034};
+ {compressed,4} -> {11031,10856,10747,10748}; %{11031,10242,10233,10234};
+ {compressed,8} -> {10040,9765,9756,9756} %{10040,9251,9242,9242}
end,
XRes2 = adjust_xmem(L, XR2),
Res2 = {?S(T1),?S(T2),?S(T3),?S(T4)},
@@ -636,9 +636,9 @@ memory_do(Opts) ->
end,
L),
XR3 = case mem_mode(T1) of
- {normal,_} -> {13816,13028,13010,13016}; %{13842,13054,13036,13042};
- {compressed,4} -> {11021,10233,10215,10216}; %{11047,10259,10241,10242};
- {compressed,8} -> {10030,9242,9224,9224} %{10056,9268,9250,9250}
+ {normal,_} -> {13816,13542,13524,13530}; %{13816,13028,13010,13016}
+ {compressed,4} -> {11021,10747,10729,10730}; %{11021,10233,10215,10216}
+ {compressed,8} -> {10030,9756,9738,9738} %{10030,9242,9224,9224}
end,
XRes3 = adjust_xmem(L, XR3),
Res3 = {?S(T1),?S(T2),?S(T3),?S(T4)},
@@ -5350,12 +5350,12 @@ verify_table_load(T) ->
Stats = ets:info(T,stats),
{Buckets,AvgLen,StdDev,ExpSD,_MinLen,_MaxLen,_} = Stats,
ok = if
- AvgLen > 7 ->
+ AvgLen > 2 ->
io:format("Table overloaded: Stats=~p\n~p\n",
[Stats, ets:info(T)]),
false;
- Buckets>256, AvgLen < 6 ->
+ Buckets>256, AvgLen < 0.5 ->
io:format("Table underloaded: Stats=~p\n~p\n",
[Stats, ets:info(T)]),
false;
diff --git a/lib/stdlib/test/id_transform_SUITE.erl b/lib/stdlib/test/id_transform_SUITE.erl
index 54f452825f..3d4ae1a189 100644
--- a/lib/stdlib/test/id_transform_SUITE.erl
+++ b/lib/stdlib/test/id_transform_SUITE.erl
@@ -61,13 +61,8 @@ id_transform(Config) when is_list(Config) ->
"erl_id_trans.erl"]),
{ok,erl_id_trans,Bin} = compile:file(File,[binary]),
{module,erl_id_trans} = code:load_binary(erl_id_trans, File, Bin),
- case test_server:purify_is_running() of
- false ->
- ct:timetrap({hours,1}),
- run_in_test_suite();
- true ->
- {skip,"Valgrind (too slow)"}
- end.
+ ct:timetrap({hours,1}),
+ run_in_test_suite().
run_in_test_suite() ->
SuperDir = filename:dirname(filename:dirname(code:which(?MODULE))),
diff --git a/lib/stdlib/test/supervisor_SUITE.erl b/lib/stdlib/test/supervisor_SUITE.erl
index 3f1aa0e7a3..cd2c6b0cbb 100644
--- a/lib/stdlib/test/supervisor_SUITE.erl
+++ b/lib/stdlib/test/supervisor_SUITE.erl
@@ -66,7 +66,7 @@
%% Misc tests
-export([child_unlink/1, tree/1, count_children/1,
- count_restarting_children/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,
@@ -91,7 +91,7 @@ all() ->
{group, normal_termination},
{group, shutdown_termination},
{group, abnormal_termination}, child_unlink, tree,
- count_children, count_restarting_children,
+ count_children, 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,
@@ -1507,6 +1507,14 @@ count_restarting_children(Config) when is_list(Config) ->
[1,0,0,0] = get_child_counts(SupPid).
%%-------------------------------------------------------------------------
+%% Test get_callback_module
+get_callback_module(Config) when is_list(Config) ->
+ Child = {child, {supervisor_1, start_child, []}, temporary, 1000,
+ worker, []},
+ {ok, SupPid} = start_link({ok, {{simple_one_for_one, 2, 3600}, [Child]}}),
+ supervisor_SUITE = supervisor:get_callback_module(SupPid).
+
+%%-------------------------------------------------------------------------
%% Temporary children shall not be restarted so they should not save
%% start parameters, as it potentially can take up a huge amount of
%% memory for no purpose.
diff --git a/lib/wx/src/wxe_master.erl b/lib/wx/src/wxe_master.erl
index 06be0367f8..e17a3327ac 100644
--- a/lib/wx/src/wxe_master.erl
+++ b/lib/wx/src/wxe_master.erl
@@ -185,10 +185,10 @@ handle_cast(_Msg, State) ->
%% Description: Handling all non call/cast messages
%%--------------------------------------------------------------------
handle_info({wxe_driver, error, Msg}, State) ->
- error_logger:format("WX ERROR: ~s~n", [Msg]),
+ error_logger:error_report([{wx, error}, {message, lists:flatten(Msg)}]),
{noreply, State};
handle_info({wxe_driver, internal_error, Msg}, State) ->
- error_logger:format("WX INTERNAL ERROR: ~s~n", [Msg]),
+ error_logger:error_report([{wx, internal_error}, {message, lists:flatten(Msg)}]),
{noreply, State};
handle_info({wxe_driver, debug, Msg}, State) ->
io:format("WX DBG: ~s~n", [Msg]),
diff --git a/lib/wx/src/wxe_util.erl b/lib/wx/src/wxe_util.erl
index 3eaf6aebed..bbcd9a65ea 100644
--- a/lib/wx/src/wxe_util.erl
+++ b/lib/wx/src/wxe_util.erl
@@ -82,9 +82,11 @@ rec(Op) ->
{'_wxe_error_', Op, Error} ->
[{_,MF}] = ets:lookup(wx_debug_info,Op),
erlang:error({Error, MF});
- {'_wxe_error_', Old, Error} ->
- [{_,MF}] = ets:lookup(wx_debug_info,Old),
- erlang:exit({Error, MF})
+ {'_wxe_error_', Old, Error} ->
+ [{_,{M,F,A}}] = ets:lookup(wx_debug_info,Old),
+ Msg = io_lib:format("~p in ~w:~w/~w", [Error, M, F, A]),
+ wxe_master ! {wxe_driver, error, Msg},
+ rec(Op)
end.
construct(Op, Args) ->
diff --git a/lib/wx/test/wx_basic_SUITE.erl b/lib/wx/test/wx_basic_SUITE.erl
index f89f25274a..6a2528780e 100644
--- a/lib/wx/test/wx_basic_SUITE.erl
+++ b/lib/wx/test/wx_basic_SUITE.erl
@@ -192,7 +192,9 @@ wx_api(Config) ->
?m(ok,wxButton:setLabel(Temp, "Testing")),
?m(ok,wxButton:destroy(Temp)),
?m({'EXIT',_},wxButton:getLabel(Temp)),
-
+ ?m(ok,wxButton:setLabel(Temp, "Testing")), %% Should generate an error report
+ ?m({'EXIT',_},wxButton:getLabel(Temp)),
+
case wx_test_lib:user_available(Config) of
true ->
%% Hmm popup doesn't return until mouse is pressed.
diff --git a/otp_build b/otp_build
index 1b79b0b0fe..28a229b101 100755
--- a/otp_build
+++ b/otp_build
@@ -1393,9 +1393,6 @@ case "$1" in
TYPE=opt
fi;
FLAVOR=$1
- if [ $FLAVOR = opt ]; then
- FLAVOR=plain
- fi
do_boot;;
update_primary)
case $version_controller in