aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--HOWTO/INSTALL-CROSS.md6
-rw-r--r--aclocal.m46
-rw-r--r--bootstrap/lib/compiler/ebin/beam_asm.beambin11676 -> 11672 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/cerl.beambin32276 -> 32024 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/compiler.app6
-rw-r--r--bootstrap/lib/compiler/ebin/sys_core_fold.beambin50164 -> 50332 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/v3_core.beambin53120 -> 53216 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/disk_log_server.beambin6604 -> 6668 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/global.beambin32672 -> 32688 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/hipe_unified_loader.beambin13516 -> 13516 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/kernel.app3
-rw-r--r--bootstrap/lib/kernel/ebin/os.beambin5448 -> 5716 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/epp.beambin28428 -> 28428 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_compile.beambin7312 -> 7324 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_lint.beambin89576 -> 89540 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_parse.beambin74708 -> 75044 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/gen_event.beambin18264 -> 18320 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/gen_fsm.beambin15628 -> 15652 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/gen_server.beambin17404 -> 17416 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/otp_internal.beambin10436 -> 10156 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/stdlib.app5
-rw-r--r--bootstrap/lib/stdlib/ebin/sys.beambin7556 -> 8372 bytes
-rw-r--r--erts/aclocal.m46
-rw-r--r--erts/configure.in4
-rw-r--r--erts/doc/src/erlang.xml2
-rw-r--r--erts/doc/src/escript.xml9
-rw-r--r--erts/emulator/Makefile.in2
-rw-r--r--erts/emulator/beam/erl_map.c16
-rw-r--r--erts/emulator/beam/erl_message.c6
-rw-r--r--erts/emulator/beam/erl_port_task.c2
-rw-r--r--erts/emulator/beam/io.c6
-rw-r--r--erts/emulator/drivers/common/inet_drv.c593
-rw-r--r--erts/emulator/sys/common/erl_check_io.c3
-rw-r--r--erts/emulator/sys/ose/beam.lmconf (renamed from erts/emulator/sys/ose/default.lmconf)3
-rw-r--r--erts/emulator/sys/ose/erl_main.c2
-rw-r--r--erts/emulator/sys/ose/erl_poll.c8
-rw-r--r--erts/emulator/sys/ose/sys.c353
-rw-r--r--erts/epmd/src/Makefile.in2
-rw-r--r--erts/epmd/src/epmd.c16
-rw-r--r--erts/epmd/src/epmd_int.h6
-rw-r--r--erts/epmd/src/epmd_srv.c46
-rw-r--r--erts/etc/common/Makefile.in2
-rw-r--r--erts/etc/common/to_erl_common.c3
-rw-r--r--erts/etc/ose/etc.lmconf20
-rw-r--r--erts/etc/ose/run_erl_main.c2
-rw-r--r--erts/include/internal/ethr_mutex.h2
-rw-r--r--erts/include/internal/ethread.h18
-rw-r--r--lib/compiler/src/sys_core_fold.erl43
-rw-r--r--lib/compiler/src/v3_codegen.erl4
-rw-r--r--lib/compiler/src/v3_core.erl34
-rw-r--r--lib/compiler/src/v3_kernel.erl3
-rw-r--r--lib/compiler/src/v3_life.erl3
-rw-r--r--lib/compiler/test/core_fold_SUITE.erl14
-rw-r--r--lib/compiler/test/map_SUITE.erl36
-rw-r--r--lib/compiler/test/warnings_SUITE.erl43
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/invalid_spec_22
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/invalid_spec_2/scala_data.erl5
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/invalid_spec_2/scala_user.erl8
-rw-r--r--lib/eldap/src/Makefile2
-rw-r--r--lib/eldap/test/eldap_misc_SUITE.erl51
-rw-r--r--lib/erl_interface/aclocal.m46
-rw-r--r--lib/hipe/cerl/erl_types.erl3
-rw-r--r--lib/hipe/rtl/hipe_icode2rtl.erl2
-rw-r--r--lib/hipe/rtl/hipe_tagscheme.erl16
-rw-r--r--lib/inets/test/inets_sup_SUITE.erl15
-rw-r--r--lib/kernel/src/inet_config.erl3
-rw-r--r--lib/kernel/src/os.erl2
-rw-r--r--lib/kernel/test/gen_tcp_misc_SUITE.erl18
-rw-r--r--lib/megaco/aclocal.m46
-rw-r--r--lib/odbc/aclocal.m46
-rw-r--r--lib/ose/doc/src/ose_intro.xml4
-rw-r--r--lib/public_key/src/pubkey_cert.erl17
-rw-r--r--lib/public_key/src/pubkey_crl.erl36
-rw-r--r--lib/sasl/src/systools_make.erl2
-rw-r--r--lib/sasl/test/systools_SUITE.erl34
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_duplicate_modules/lib/app1-1.0/ebin/app1.app7
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_duplicate_modules/lib/app1-1.0/src/myapp.erl2
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_duplicate_modules/lib/app2-1.0/ebin/app2.app7
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_duplicate_modules/lib/app2-1.0/src/myapp.erl2
-rw-r--r--lib/snmp/test/Makefile4
-rw-r--r--lib/snmp/test/modules.mk3
-rw-r--r--lib/snmp/test/snmp_agent_test.erl300
-rw-r--r--lib/snmp/test/snmp_agent_test_lib.erl22
-rw-r--r--lib/snmp/test/snmp_manager_test.erl337
-rw-r--r--lib/snmp/test/snmp_test_mgr.erl3
-rw-r--r--lib/snmp/test/snmp_test_mgr_counter_server.erl152
-rw-r--r--lib/ssh/doc/src/ssh.xml17
-rw-r--r--lib/ssh/src/ssh.erl12
-rw-r--r--lib/ssh/src/ssh_acceptor.erl5
-rw-r--r--lib/ssh/src/ssh_connection_handler.erl14
-rw-r--r--lib/ssl/src/dtls_connection.erl724
-rw-r--r--lib/ssl/src/dtls_connection.hrl21
-rw-r--r--lib/ssl/src/dtls_connection_sup.erl12
-rw-r--r--lib/ssl/src/dtls_handshake.erl402
-rw-r--r--lib/ssl/src/dtls_handshake.hrl4
-rw-r--r--lib/ssl/src/dtls_record.erl57
-rw-r--r--lib/ssl/src/dtls_record.hrl13
-rw-r--r--lib/ssl/src/dtls_v1.erl4
-rw-r--r--lib/ssl/src/ssl.erl29
-rw-r--r--lib/ssl/src/ssl_alert.erl18
-rw-r--r--lib/ssl/src/ssl_alert.hrl16
-rw-r--r--lib/ssl/src/ssl_api.hrl33
-rw-r--r--lib/ssl/src/ssl_cipher.erl27
-rw-r--r--lib/ssl/src/ssl_cipher.hrl12
-rw-r--r--lib/ssl/src/ssl_connection.erl1
-rw-r--r--lib/ssl/src/ssl_connection.hrl8
-rw-r--r--lib/ssl/src/ssl_handshake.erl50
-rw-r--r--lib/ssl/src/ssl_handshake.hrl16
-rw-r--r--lib/ssl/src/ssl_internal.hrl4
-rw-r--r--lib/ssl/src/ssl_record.erl19
-rw-r--r--lib/ssl/src/ssl_record.hrl4
-rw-r--r--lib/ssl/src/ssl_v3.erl4
-rw-r--r--lib/ssl/src/tls_handshake.erl16
-rw-r--r--lib/ssl/src/tls_handshake.hrl4
-rw-r--r--lib/ssl/src/tls_record.erl7
-rw-r--r--lib/ssl/src/tls_v1.erl4
-rw-r--r--lib/ssl/test/Makefile1
-rw-r--r--lib/ssl/test/make_certs.erl310
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl6
-rw-r--r--lib/ssl/test/ssl_crl_SUITE.erl530
-rw-r--r--lib/ssl/test/ssl_test_lib.erl154
-rw-r--r--lib/stdlib/doc/src/zip.xml13
-rw-r--r--lib/stdlib/src/escript.erl5
-rw-r--r--lib/stdlib/src/otp_internal.erl25
-rw-r--r--lib/stdlib/src/slave.erl23
-rw-r--r--lib/stdlib/src/zip.erl37
-rw-r--r--lib/stdlib/test/erl_lint_SUITE.erl18
-rw-r--r--lib/test_server/src/test_server.erl10
-rw-r--r--lib/wx/aclocal.m46
-rw-r--r--make/ose_lm.mk.in4
-rw-r--r--system/doc/design_principles/spec_proc.xml16
-rw-r--r--system/doc/reference_manual/modules.xml19
-rw-r--r--xcomp/erl-xcomp-powerpc-ose5.conf10
-rw-r--r--xcomp/erl-xcomp-vars.sh2
134 files changed, 3801 insertions, 1360 deletions
diff --git a/HOWTO/INSTALL-CROSS.md b/HOWTO/INSTALL-CROSS.md
index cb9d12e753..10f463c06d 100644
--- a/HOWTO/INSTALL-CROSS.md
+++ b/HOWTO/INSTALL-CROSS.md
@@ -537,7 +537,11 @@ When a variable has been set, no warning will be issued.
* `erl_xcomp_ose_LM_LCF` - OSE load module linker configuration file
-* `erl_xcomp_ose_LM_CONF` - OSE load module default configuration file
+* `erl_xcomp_ose_BEAM_LM_CONF` - Beam OSE load module configuration file
+
+* `erl_xcomp_ose_EPMD_LM_CONF` - EPMD OSE load module configuration file
+
+* `erl_xcomp_ose_RUN_ERL_LM_CONF` - run_erl_lm OSE load module configuration file
Copyright and License
---------------------
diff --git a/aclocal.m4 b/aclocal.m4
index c51c26794a..2b47f7c4bc 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -83,8 +83,10 @@ AC_ARG_VAR(erl_xcomp_ose_LM_POST_LINK, [OSE postlink tool (only used when cross
AC_ARG_VAR(erl_xcomp_ose_LM_SET_CONF, [Sets the configuration for an OSE load module (only used when cross compiling for OSE)])
AC_ARG_VAR(erl_xcomp_ose_LM_ELF_SIZE, [Prints the section size information for an OSE load module (only used when cross compiling for OSE)])
AC_ARG_VAR(erl_xcomp_ose_LM_LCF, [OSE load module linker configuration file (only used when cross compiling for OSE)])
-AC_ARG_VAR(erl_xcomp_ose_LM_CONF, [OSE load module default configuration file (only used when cross compiling for OSE)])
-AC_ARG_VAR(erl_xcomp_ose_CONFD, [OSE OSE confd source file])
+AC_ARG_VAR(erl_xcomp_ose_BEAM_LM_CONF, [BEAM OSE load module default configuration file (only used when cross compiling for OSE)])
+AC_ARG_VAR(erl_xcomp_ose_EPMD_LM_CONF, [EPMD OSE load module default configuration file (only used when cross compiling for OSE)])
+AC_ARG_VAR(erl_xcomp_ose_RUN_ERL_LM_CONF, [run_erl_lm OSE load module default configuration file (only used when cross compiling for OSE)])
+AC_ARG_VAR(erl_xcomp_ose_CONFD, [OSE confd source file])
AC_ARG_VAR(erl_xcomp_ose_CRT0_LM, [OSE crt0 lm source file])
])
diff --git a/bootstrap/lib/compiler/ebin/beam_asm.beam b/bootstrap/lib/compiler/ebin/beam_asm.beam
index a3b9f3df8a..42ff7e9c1f 100644
--- a/bootstrap/lib/compiler/ebin/beam_asm.beam
+++ b/bootstrap/lib/compiler/ebin/beam_asm.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/cerl.beam b/bootstrap/lib/compiler/ebin/cerl.beam
index d5e97e4f68..ff6f0ea0fd 100644
--- a/bootstrap/lib/compiler/ebin/cerl.beam
+++ b/bootstrap/lib/compiler/ebin/cerl.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/compiler.app b/bootstrap/lib/compiler/ebin/compiler.app
index 83554a68a5..f415965277 100644
--- a/bootstrap/lib/compiler/ebin/compiler.app
+++ b/bootstrap/lib/compiler/ebin/compiler.app
@@ -18,7 +18,7 @@
{application, compiler,
[{description, "ERTS CXC 138 10"},
- {vsn, "4.9.4"},
+ {vsn, "5.0"},
{modules, [
beam_a,
beam_asm,
@@ -67,4 +67,6 @@
]},
{registered, []},
{applications, [kernel, stdlib]},
- {env, []}]}.
+ {env, []},
+ {runtime_dependencies, ["stdlib-2.0","kernel-3.0","hipe-3.10.3","erts-6.0",
+ "crypto-3.3"]}]}.
diff --git a/bootstrap/lib/compiler/ebin/sys_core_fold.beam b/bootstrap/lib/compiler/ebin/sys_core_fold.beam
index 9bdab52015..39be60c555 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_core.beam b/bootstrap/lib/compiler/ebin/v3_core.beam
index b876bd9970..6b322b8da0 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/kernel/ebin/disk_log_server.beam b/bootstrap/lib/kernel/ebin/disk_log_server.beam
index ec9422d41b..8c1622c7d8 100644
--- a/bootstrap/lib/kernel/ebin/disk_log_server.beam
+++ b/bootstrap/lib/kernel/ebin/disk_log_server.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/global.beam b/bootstrap/lib/kernel/ebin/global.beam
index 1629089858..d25be3994c 100644
--- a/bootstrap/lib/kernel/ebin/global.beam
+++ b/bootstrap/lib/kernel/ebin/global.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam b/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam
index d24c06f112..46263fae7b 100644
--- a/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam
+++ b/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/kernel.app b/bootstrap/lib/kernel/ebin/kernel.app
index f491239a45..1fd4edd044 100644
--- a/bootstrap/lib/kernel/ebin/kernel.app
+++ b/bootstrap/lib/kernel/ebin/kernel.app
@@ -114,6 +114,7 @@
pg2]},
{applications, []},
{env, [{error_logger, tty}]},
- {mod, {kernel, []}}
+ {mod, {kernel, []}},
+ {runtime_dependencies, ["erts-6.0", "stdlib-2.0", "sasl-2.4"]}
]
}.
diff --git a/bootstrap/lib/kernel/ebin/os.beam b/bootstrap/lib/kernel/ebin/os.beam
index b8b01b31ab..b1b92ca36b 100644
--- a/bootstrap/lib/kernel/ebin/os.beam
+++ b/bootstrap/lib/kernel/ebin/os.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/epp.beam b/bootstrap/lib/stdlib/ebin/epp.beam
index ab22f9971b..7013e29466 100644
--- a/bootstrap/lib/stdlib/ebin/epp.beam
+++ b/bootstrap/lib/stdlib/ebin/epp.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_compile.beam b/bootstrap/lib/stdlib/ebin/erl_compile.beam
index 88da2b246f..e650afbf6d 100644
--- a/bootstrap/lib/stdlib/ebin/erl_compile.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_compile.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_lint.beam b/bootstrap/lib/stdlib/ebin/erl_lint.beam
index 9660509270..50b3e3c9d3 100644
--- a/bootstrap/lib/stdlib/ebin/erl_lint.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_lint.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_parse.beam b/bootstrap/lib/stdlib/ebin/erl_parse.beam
index c1c114dd3c..3d36ee85b7 100644
--- a/bootstrap/lib/stdlib/ebin/erl_parse.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_parse.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/gen_event.beam b/bootstrap/lib/stdlib/ebin/gen_event.beam
index 46f1512a24..d45e508d22 100644
--- a/bootstrap/lib/stdlib/ebin/gen_event.beam
+++ b/bootstrap/lib/stdlib/ebin/gen_event.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/gen_fsm.beam b/bootstrap/lib/stdlib/ebin/gen_fsm.beam
index d6719e68d9..bf5bbb7839 100644
--- a/bootstrap/lib/stdlib/ebin/gen_fsm.beam
+++ b/bootstrap/lib/stdlib/ebin/gen_fsm.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/gen_server.beam b/bootstrap/lib/stdlib/ebin/gen_server.beam
index 806c4d58d7..fe95ca0826 100644
--- a/bootstrap/lib/stdlib/ebin/gen_server.beam
+++ b/bootstrap/lib/stdlib/ebin/gen_server.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/otp_internal.beam b/bootstrap/lib/stdlib/ebin/otp_internal.beam
index 1146ef9ab8..defe4fa5a0 100644
--- a/bootstrap/lib/stdlib/ebin/otp_internal.beam
+++ b/bootstrap/lib/stdlib/ebin/otp_internal.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/stdlib.app b/bootstrap/lib/stdlib/ebin/stdlib.app
index 31c7222100..1d255fb2c8 100644
--- a/bootstrap/lib/stdlib/ebin/stdlib.app
+++ b/bootstrap/lib/stdlib/ebin/stdlib.app
@@ -102,5 +102,8 @@
{registered,[timer_server,rsh_starter,take_over_monitor,pool_master,
dets]},
{applications, [kernel]},
- {env, []}]}.
+ {env, []},
+ {runtime_dependencies, ["sasl-2.4","kernel-3.0","erts-6.0","crypto-3.3",
+ "compiler-5.0"]}
+]}.
diff --git a/bootstrap/lib/stdlib/ebin/sys.beam b/bootstrap/lib/stdlib/ebin/sys.beam
index 2aed63dc88..1413b822f2 100644
--- a/bootstrap/lib/stdlib/ebin/sys.beam
+++ b/bootstrap/lib/stdlib/ebin/sys.beam
Binary files differ
diff --git a/erts/aclocal.m4 b/erts/aclocal.m4
index c51c26794a..2b47f7c4bc 100644
--- a/erts/aclocal.m4
+++ b/erts/aclocal.m4
@@ -83,8 +83,10 @@ AC_ARG_VAR(erl_xcomp_ose_LM_POST_LINK, [OSE postlink tool (only used when cross
AC_ARG_VAR(erl_xcomp_ose_LM_SET_CONF, [Sets the configuration for an OSE load module (only used when cross compiling for OSE)])
AC_ARG_VAR(erl_xcomp_ose_LM_ELF_SIZE, [Prints the section size information for an OSE load module (only used when cross compiling for OSE)])
AC_ARG_VAR(erl_xcomp_ose_LM_LCF, [OSE load module linker configuration file (only used when cross compiling for OSE)])
-AC_ARG_VAR(erl_xcomp_ose_LM_CONF, [OSE load module default configuration file (only used when cross compiling for OSE)])
-AC_ARG_VAR(erl_xcomp_ose_CONFD, [OSE OSE confd source file])
+AC_ARG_VAR(erl_xcomp_ose_BEAM_LM_CONF, [BEAM OSE load module default configuration file (only used when cross compiling for OSE)])
+AC_ARG_VAR(erl_xcomp_ose_EPMD_LM_CONF, [EPMD OSE load module default configuration file (only used when cross compiling for OSE)])
+AC_ARG_VAR(erl_xcomp_ose_RUN_ERL_LM_CONF, [run_erl_lm OSE load module default configuration file (only used when cross compiling for OSE)])
+AC_ARG_VAR(erl_xcomp_ose_CONFD, [OSE confd source file])
AC_ARG_VAR(erl_xcomp_ose_CRT0_LM, [OSE crt0 lm source file])
])
diff --git a/erts/configure.in b/erts/configure.in
index 208c294106..9ebb56e3bc 100644
--- a/erts/configure.in
+++ b/erts/configure.in
@@ -1042,6 +1042,8 @@ AC_CHECK_LIB(dl, dlopen)
AC_CHECK_LIB(inet, main)
AC_CHECK_LIB(util, openpty)
+AC_CHECK_LIB(systemd-daemon, sd_listen_fds)
+
dnl Try to find a thread library.
dnl
dnl ETHR_LIB_NAME, ETHR_LIBS, ETHR_X_LIBS, ETHR_THR_LIB_BASE and ETHR_DEFS
@@ -1677,6 +1679,8 @@ AC_CHECK_MEMBERS([struct ifreq.ifr_enaddr], [], [],
#endif
])
+AC_CHECK_HEADERS(systemd/sd-daemon.h)
+
dnl ----------------------------------------------------------------------
dnl Check the availability for libdlpi
dnl ----------------------------------------------------------------------
diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml
index b06d5aeb12..7aaded200c 100644
--- a/erts/doc/src/erlang.xml
+++ b/erts/doc/src/erlang.xml
@@ -887,7 +887,7 @@
<fsummary>Print a term on standard output</fsummary>
<desc>
<p>Prints a text representation of <c><anno>Term</anno></c> on the standard
- output.</p>
+ output. On OSE the term is printed to the ramlog.</p>
<warning>
<p>This BIF is intended for debugging only.</p>
</warning>
diff --git a/erts/doc/src/escript.xml b/erts/doc/src/escript.xml
index 1abbdb2180..9159d68f60 100644
--- a/erts/doc/src/escript.xml
+++ b/erts/doc/src/escript.xml
@@ -236,8 +236,13 @@ factorial 5 = 120
<v>EmuArgs = string() | 'undefined'</v>
<v>Body = {source, SourceCode}
| {beam, BeamCode}
- | {archive, ZipArchive}</v>
- <v>SourceCode = BeamCode = ZipArchive = binary()</v>
+ | {archive, ZipArchive}
+ | {archive, ZipFiles, ZipOptions}</v>
+ <v>SourceCode = BeamCode = file:filename() | binary()</v>
+ <v>ZipArchive = <seealso marker="stdlib:zip#type-filename">zip:filename()</seealso> | binary()</v>
+ <v>ZipFiles = [ZipFile]</v>
+ <v>ZipFile = file:filename() | {file:filename(), binary()} | {file:filename(), binary(), file:file_info()}</v>
+ <v>ZipOptions = [<seealso marker="stdlib:zip#type-create_option">zip:create_option()</seealso>]</v>
</type>
<desc>
<p>The <marker id="create_2"></marker> <c>create/2</c>
diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in
index 58e77ed1fa..58639c7190 100644
--- a/erts/emulator/Makefile.in
+++ b/erts/emulator/Makefile.in
@@ -1035,7 +1035,7 @@ else
ifeq ($(findstring ose,$(TARGET)),ose)
$(BINDIR)/$(EMULATOR_EXECUTABLE): $(INIT_OBJS) $(OBJS) $(DEPLIBS) $(LCF)
$(call build-ose-load-module, $@, $(INIT_OBJS) $(OBJS), $(STATIC_NIF_LIBS) \
- $(STATIC_DRIVER_LIBS) $(LIBS), $(LMCONF))
+ $(STATIC_DRIVER_LIBS) $(LIBS), $(BEAM_LMCONF))
else
$(BINDIR)/$(EMULATOR_EXECUTABLE): $(INIT_OBJS) $(OBJS) $(DEPLIBS)
diff --git a/erts/emulator/beam/erl_map.c b/erts/emulator/beam/erl_map.c
index 2fff7f9390..fdd2d0c0f6 100644
--- a/erts/emulator/beam/erl_map.c
+++ b/erts/emulator/beam/erl_map.c
@@ -647,22 +647,24 @@ int erts_maps_remove(Process *p, Eterm key, Eterm map, Eterm *res) {
*mhp++ = tup;
if (is_immed(key)) {
- while(n--) {
+ while (1) {
if (*ks == key) {
goto found_key;
- } else {
+ } else if (--n) {
*mhp++ = *vs++;
*thp++ = *ks++;
- }
+ } else
+ break;
}
} else {
- while(n--) {
+ while(1) {
if (EQ(*ks, key)) {
goto found_key;
- } else {
+ } else if (--n) {
*mhp++ = *vs++;
*thp++ = *ks++;
- }
+ } else
+ break;
}
}
@@ -676,7 +678,7 @@ int erts_maps_remove(Process *p, Eterm key, Eterm map, Eterm *res) {
found_key:
/* Copy rest of keys and values */
- if (n) {
+ if (--n) {
sys_memcpy(mhp, vs+1, n*sizeof(Eterm));
sys_memcpy(thp, ks+1, n*sizeof(Eterm));
}
diff --git a/erts/emulator/beam/erl_message.c b/erts/emulator/beam/erl_message.c
index 6a9030fd99..0eb8117980 100644
--- a/erts/emulator/beam/erl_message.c
+++ b/erts/emulator/beam/erl_message.c
@@ -896,8 +896,10 @@ erts_send_message(Process* sender,
#ifdef USE_VM_PROBES
*sender_name = *receiver_name = '\0';
if (DTRACE_ENABLED(message_send)) {
- erts_snprintf(sender_name, sizeof(DTRACE_CHARBUF_NAME(sender_name)), "%T", sender->common.id);
- erts_snprintf(receiver_name, sizeof(DTRACE_CHARBUF_NAME(receiver_name)), "%T", receiver->common.id);
+ erts_snprintf(sender_name, sizeof(DTRACE_CHARBUF_NAME(sender_name)),
+ "%T", sender->common.id);
+ erts_snprintf(receiver_name, sizeof(DTRACE_CHARBUF_NAME(receiver_name)),
+ "%T", receiver->common.id);
}
#endif
if (SEQ_TRACE_TOKEN(sender) != NIL && !(flags & ERTS_SND_FLG_NO_SEQ_TRACE)) {
diff --git a/erts/emulator/beam/erl_port_task.c b/erts/emulator/beam/erl_port_task.c
index 4e107b722d..31d9a1e26e 100644
--- a/erts/emulator/beam/erl_port_task.c
+++ b/erts/emulator/beam/erl_port_task.c
@@ -2037,7 +2037,7 @@ begin_port_cleanup(Port *pp, ErtsPortTask **execqp, int *processing_busy_q_p)
erts_snprintf(port_str, sizeof(DTRACE_CHARBUF_NAME(port_str)), "%T", pp->common.id);
while (plp2 != NULL) {
- erts_snprintf(pid_str, sizeof(DTRACE_CHARBUF_NAME(pid_str)), "%T", plp2->pid);
+ erts_snprintf(pid_str, sizeof(DTRACE_CHARBUF_NAME(pid_str)), "%T", plp2->pid);
DTRACE2(process_port_unblocked, pid_str, port_str);
}
}
diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c
index 999d2fb2f7..edf4a28784 100644
--- a/erts/emulator/beam/io.c
+++ b/erts/emulator/beam/io.c
@@ -914,8 +914,8 @@ int erts_port_handle_xports(Port *prt)
(iov)->iov_base = (ptr); \
(iov)->iov_len = (len); \
if (sizeof((iov)->iov_len) < sizeof(len) \
- /* Check if (len) overflowed (iov)->iov_len */ \
- && ((len) >> (sizeof((iov)->iov_len)*CHAR_BIT)) != 0) { \
+ /* Check if (len) overflowed (iov)->iov_len */ \
+ && (iov)->iov_len != (len)) { \
goto L_overflow; \
} \
*(bv)++ = (bin); \
@@ -4727,7 +4727,7 @@ erts_port_resume_procs(Port *prt)
erts_snprintf(port_str, sizeof(DTRACE_CHARBUF_NAME(port_str)), "%T", prt->common.id);
while (plp2 != NULL) {
- erts_snprintf(pid_str, sizeof(DTRACE_CHARBUF_NAME(pid_str)), "%T", plp2->pid);
+ erts_snprintf(pid_str, sizeof(DTRACE_CHARBUF_NAME(pid_str)), "%T", plp2->pid);
DTRACE2(process_port_unblocked, pid_str, port_str);
}
}
diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c
index 357a4b7bcb..e33594b026 100644
--- a/erts/emulator/drivers/common/inet_drv.c
+++ b/erts/emulator/drivers/common/inet_drv.c
@@ -93,6 +93,10 @@ typedef unsigned long long llu_t;
#define INT16_MAX (32767)
#endif
+#ifdef __OSE__
+#include "inet.h"
+#endif
+
#ifdef __WIN32__
#define STRNCASECMP strncasecmp
@@ -121,10 +125,6 @@ typedef unsigned long long llu_t;
#undef WANT_NONBLOCKING
#include "sys.h"
-#ifdef __OSE__
-#include "inet.h"
-#endif
-
#undef EWOULDBLOCK
#undef ETIMEDOUT
@@ -200,6 +200,7 @@ typedef unsigned long long llu_t;
#define HAVE_MULTICAST_SUPPORT
+#define HAVE_UDP
#define ERRNO_BLOCK WSAEWOULDBLOCK
@@ -294,29 +295,55 @@ static unsigned long zero_value = 0;
static unsigned long one_value = 1;
#elif defined (__OSE__)
+
+/*
+ * Some notes about how inet (currently only tcp) works on OSE.
+ * The driver uses OSE signals to communicate with the one_inet
+ * process. Because of the difference in how signals and file descriptors
+ * work the whole select/deselect mechanic is very different.
+ * In ose when a sock_select is done a function is called. That function
+ * notes the changes that the driver want to do, but does not act on it.
+ * later when the function returns the new desired state is compared
+ * to the previous state and the apprioriate actions are taken. The action
+ * is usually to either request more data from the stack or stop requesting
+ * data.
+ *
+ * One thing to note is that the driver never does select/deselect. It always
+ * listens for the signals. Flow of data is regulated by sending or not sending
+ * signals to the ose inet process.
+ *
+ * The interesting functions to look at are:
+ * * inet_driver_select : called when sock_select is called
+ * * tcp_inet_ose_dispatch_signal : checks state changes and sends new signals
+ * * tcp_inet_drv_output_ose : ready output callback, reads signals and calls
+ * dispatch_signal
+ * * tcp_inet_drv_input_ose : ready input callback.
+ */
+
+#include "efs.h"
#include "sys/socket.h"
#include "sys/uio.h"
#include "sfk/sys/sfk_uio.h"
#include "netinet/in.h"
#include "netinet/tcp.h"
#include "netdb.h"
+#include "ose_spi/socket.sig"
-ssize_t writev(int fd, const struct iovec *iov, int iovcnt)
-{
- return 0;
-}
+
+static ssize_t writev_fallback(int fd, const struct iovec *iov, int iovcnt, int max_sz);
#define INVALID_SOCKET -1
#define INVALID_EVENT -1
#define SOCKET_ERROR -1
#define SOCKET int
-#define HANDLE long int
-#define FD_READ ERL_DRV_READ
-#define FD_WRITE ERL_DRV_WRITE
-#define FD_CLOSE 0
-#define FD_CONNECT ERL_DRV_WRITE
-#define FD_ACCEPT ERL_DRV_READ
+#define HANDLE int
+#define FD_READ ERL_DRV_READ
+#define FD_WRITE ERL_DRV_WRITE
+#define FD_CLOSE 0
+#define FD_CONNECT (1<<4)
+#define FD_ACCEPT (1<<5)
+#define SOCK_FD_ERROR (1<<6)
#define sock_connect(s, addr, len) connect((s), (addr), (len))
#define sock_listen(s, b) listen((s), (b))
@@ -335,11 +362,12 @@ ssize_t writev(int fd, const struct iovec *iov, int iovcnt)
#define sock_sendto(s,buf,blen,flag,addr,alen) \
sendto((s),(buf),(blen),(flag),(addr),(alen))
#define sock_sendv(s, vec, size, np, flag) \
- (*(np) = writev((s), (struct iovec*)(vec), (size)))
+ (*(np) = writev_fallback((s), (struct iovec*)(vec), (size), (*(np))))
#define sock_sendmsg(s,msghdr,flag) sendmsg((s),(msghdr),(flag))
#define sock_open(af, type, proto) socket((af), (type), (proto))
#define sock_close(s) close((s))
+#define sock_dup(s) dup((s))
#define sock_shutdown(s, how) shutdown((s), (how))
#define sock_hostname(buf, len) gethostname((buf), (len))
@@ -355,19 +383,6 @@ ssize_t writev(int fd, const struct iovec *iov, int iovcnt)
#define sock_create_event(d) ((d)->s) /* return file descriptor */
#define sock_close_event(e) /* do nothing */
-#define inet_driver_select(port, e, mode, on) \
- driver_select(port, e, mode | (on?ERL_DRV_USE:0), on)
-
-#define sock_select(d, flags, onoff) do { \
- ASSERT(!(d)->is_ignored); \
- (d)->event_mask = (onoff) ? \
- ((d)->event_mask | (flags)) : \
- ((d)->event_mask & ~(flags)); \
- DEBUGF(("sock_select(%ld): flags=%02X, onoff=%d, event_mask=%02lX\r\n", \
- (long) (d)->port, (flags), (onoff), (unsigned long) (d)->event_mask)); \
- inet_driver_select((d)->port, (ErlDrvEvent)(long)(d)->event, (flags), (onoff)); \
- } while(0)
-
#ifndef WANT_NONBLOCKING
#define WANT_NONBLOCKING
#endif
@@ -397,6 +412,16 @@ typedef unsigned long u_long;
#define IN_EXPERIMENTAL(a) ((((in_addr_t)(a)) & 0xe0000000) == 0xe0000000)
#define IN_BADCLASS(a) ((((in_addr_t)(a)) & 0xf0000000) == 0xf0000000)
+#define sock_select(d, flags, onoff) do { \
+ ASSERT(!(d)->is_ignored); \
+ (d)->event_mask = (onoff) ? \
+ ((d)->event_mask | (flags)) : \
+ ((d)->event_mask & ~(flags)); \
+ DEBUGF(("(%s / %d) sock_select(%ld): flags=%02X, onoff=%d, event_mask=%02lX, s=%d\r\n", \
+ __FILE__, __LINE__, (long) (d)->port, (flags), (onoff), (unsigned long) (d)->event_mask, (d)->s)); \
+ inet_driver_select((d), (flags), (onoff)); \
+ } while(0)
+
#else /* !__OSE__ && !__WIN32__ */
#include <sys/time.h>
@@ -438,6 +463,8 @@ typedef unsigned long u_long;
#include <setns.h>
#endif
+#define HAVE_UDP
+
/* SCTP support -- currently for UNIX platforms only: */
#undef HAVE_SCTP
#if defined(HAVE_SCTP_H)
@@ -660,13 +687,13 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n)
(d)->event_mask = (onoff) ? \
((d)->event_mask | (flags)) : \
((d)->event_mask & ~(flags)); \
- DEBUGF(("sock_select(%ld): flags=%02X, onoff=%d, event_mask=%02lX\r\n", \
- (long) (d)->port, (flags), (onoff), (unsigned long) (d)->event_mask)); \
+ DEBUGF(("(%s / %d) sock_select(%ld): flags=%02X, onoff=%d, event_mask=%02lX\r\n", \
+ __FILE__, __LINE__, (long) (d)->port, (flags), (onoff), (unsigned long) (d)->event_mask)); \
inet_driver_select((d)->port, (ErlDrvEvent)(long)(d)->event, (flags), (onoff)); \
} while(0)
-#endif /* #ifdef __WIN32__ #else */
+#endif /* !__WIN32__ && !__OSE__ */
#ifdef HAVE_SOCKLEN_T
# define SOCKLEN_T socklen_t
@@ -1119,6 +1146,13 @@ typedef struct {
char *netns; /* Socket network namespace name
as full file path */
#endif
+#ifdef __OSE__
+ int select_state; /* state to keep track of whether we
+ should trigger another read/write
+ request at end of ready_input/output */
+ ErlDrvEvent events[6];
+#endif
+
} inet_descriptor;
@@ -1134,8 +1168,10 @@ static void tcp_inet_stop(ErlDrvData);
static void tcp_inet_command(ErlDrvData, char*, ErlDrvSizeT);
static void tcp_inet_commandv(ErlDrvData, ErlIOVec*);
static void tcp_inet_flush(ErlDrvData drv_data);
+#ifndef __OSE__
static void tcp_inet_drv_input(ErlDrvData, ErlDrvEvent);
static void tcp_inet_drv_output(ErlDrvData data, ErlDrvEvent event);
+#endif
static ErlDrvData tcp_inet_start(ErlDrvPort, char* command);
static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData, unsigned int,
char*, ErlDrvSizeT, char**, ErlDrvSizeT);
@@ -1147,7 +1183,72 @@ static void tcp_inet_event(ErlDrvData, ErlDrvEvent);
static void find_dynamic_functions(void);
#endif
-static struct erl_drv_entry tcp_inet_driver_entry =
+#ifdef __OSE__
+/* The structure of the signal used for requesting asynchronous
+ * notification from the stack. Under normal circumstances the network stack
+ * shouldn't overwrite the value set in the fd field by the sender
+ * of the request */
+struct OseAsyncSig {
+ struct FmEvent event;
+ int fd;
+};
+
+union SIGNAL {
+ SIGSELECT signo;
+ struct OseAsyncSig async;
+};
+
+static ErlDrvSSizeT tcp_inet_ctl_ose(ErlDrvData e, unsigned int cmd,
+ char* buf, ErlDrvSizeT len,
+ char** rbuf, ErlDrvSizeT rsize);
+static void tcp_inet_commandv_ose(ErlDrvData e, ErlIOVec* ev);
+static void tcp_inet_drv_output_ose(ErlDrvData data, ErlDrvEvent event);
+static void tcp_inet_drv_input_ose(ErlDrvData data, ErlDrvEvent event);
+static ErlDrvOseEventId inet_resolve_signal(union SIGNAL *sig);
+
+#ifdef INET_DRV_DEBUG
+
+static char *read_req = "SO_EVENT_READ_REQUEST";
+static char *read_rep = "SO_EVENT_READ_REPLY";
+static char *write_req = "SO_EVENT_WRITE_REQUEST";
+static char *write_rep = "SO_EVENT_WRITE_REPLY";
+static char *eof_req = "SO_EVENT_EOF_REQUEST";
+static char *eof_rep = "SO_EVENT_EOF_REPLY";
+static char *accept_req = "SO_EVENT_ACCEPT_REQUEST";
+static char *accept_rep = "SO_EVENT_ACCEPT_REPLY";
+static char *connect_req = "SO_EVENT_CONNECT_REQUEST";
+static char *connect_rep = "SO_EVENT_CONNECT_REPLY";
+static char *error_req = "SO_EVENT_ERROR_REQUEST";
+static char *error_rep = "SO_EVENT_ERROR_REPLY";
+static char signo_tmp[32];
+
+static char *signo_to_string(SIGSELECT signo) {
+ switch (signo) {
+ case SO_EVENT_READ_REQUEST: { return read_req; }
+ case SO_EVENT_READ_REPLY: { return read_rep; }
+ case SO_EVENT_WRITE_REQUEST: { return write_req; }
+ case SO_EVENT_WRITE_REPLY: { return write_rep; }
+ case SO_EVENT_EOF_REQUEST: { return eof_req; }
+ case SO_EVENT_EOF_REPLY: { return eof_rep; }
+ case SO_EVENT_ACCEPT_REQUEST: { return accept_req; }
+ case SO_EVENT_ACCEPT_REPLY: { return accept_rep; }
+ case SO_EVENT_CONNECT_REQUEST: { return connect_req; }
+ case SO_EVENT_CONNECT_REPLY: { return connect_rep; }
+ case SO_EVENT_ERROR_REQUEST: { return error_req; }
+ case SO_EVENT_ERROR_REPLY: { return error_rep; }
+ }
+
+ snprintf(signo_tmp,32,"0x%x",signo);
+
+ return signo_tmp;
+}
+
+#endif
+
+#endif /* __OSE__ */
+
+
+static struct erl_drv_entry tcp_inet_driver_entry =
{
tcp_inet_init, /* inet_init will add this driver !! */
tcp_inet_start,
@@ -1156,6 +1257,9 @@ static struct erl_drv_entry tcp_inet_driver_entry =
#ifdef __WIN32__
tcp_inet_event,
NULL,
+#elif defined(__OSE__)
+ tcp_inet_drv_input_ose, /*ready_input*/
+ tcp_inet_drv_output_ose, /*ready_output*/
#else
tcp_inet_drv_input,
tcp_inet_drv_output,
@@ -1163,9 +1267,17 @@ static struct erl_drv_entry tcp_inet_driver_entry =
"tcp_inet",
NULL,
NULL,
+#ifdef __OSE__
+ tcp_inet_ctl_ose,
+#else
tcp_inet_ctl,
+#endif
tcp_inet_timeout,
+#ifdef __OSE__
+ tcp_inet_commandv_ose,
+#else
tcp_inet_commandv,
+#endif
NULL,
tcp_inet_flush,
NULL,
@@ -1181,6 +1293,7 @@ static struct erl_drv_entry tcp_inet_driver_entry =
+#ifdef HAVE_UDP
static int packet_inet_init(void);
static void packet_inet_stop(ErlDrvData);
static void packet_inet_command(ErlDrvData, char*, ErlDrvSizeT);
@@ -1230,6 +1343,7 @@ static struct erl_drv_entry udp_inet_driver_entry =
NULL,
inet_stop_select
};
+#endif
#ifdef HAVE_SCTP
static struct erl_drv_entry sctp_inet_driver_entry =
@@ -1293,6 +1407,7 @@ static int tcp_deliver(tcp_descriptor* desc, int len);
static int tcp_inet_output(tcp_descriptor* desc, HANDLE event);
static int tcp_inet_input(tcp_descriptor* desc, HANDLE event);
+#ifdef HAVE_UDP
typedef struct {
inet_descriptor inet; /* common data structure (DON'T MOVE) */
int read_packets; /* Number of packets to read per invocation */
@@ -1304,10 +1419,19 @@ typedef struct {
static int packet_inet_input(udp_descriptor* udesc, HANDLE event);
static int packet_inet_output(udp_descriptor* udesc, HANDLE event);
+#endif
/* convert descriptor poiner to inet_descriptor pointer */
#define INETP(d) (&(d)->inet)
+#ifdef __OSE__
+static void inet_driver_select(inet_descriptor* desc,
+ int flags, int onoff);
+static void tcp_inet_ose_dispatch_signals(tcp_descriptor *desc,
+ int prev_select_state,
+ union SIGNAL *sig);
+#endif
+
static int async_ref = 0; /* async reference id generator */
#define NEW_ASYNC_ID() ((async_ref++) & 0xffff)
@@ -1324,7 +1448,6 @@ static int async_ref = 0; /* async reference id generator */
static ErlDrvTermData am_ok;
static ErlDrvTermData am_tcp;
-static ErlDrvTermData am_udp;
static ErlDrvTermData am_error;
static ErlDrvTermData am_einval;
static ErlDrvTermData am_inet_async;
@@ -1334,10 +1457,13 @@ static ErlDrvTermData am_closed;
static ErlDrvTermData am_tcp_passive;
static ErlDrvTermData am_tcp_closed;
static ErlDrvTermData am_tcp_error;
-static ErlDrvTermData am_udp_passive;
-static ErlDrvTermData am_udp_error;
static ErlDrvTermData am_empty_out_q;
static ErlDrvTermData am_ssl_tls;
+#ifdef HAVE_UDP
+static ErlDrvTermData am_udp;
+static ErlDrvTermData am_udp_passive;
+static ErlDrvTermData am_udp_error;
+#endif
#ifdef HAVE_SCTP
static ErlDrvTermData am_sctp;
static ErlDrvTermData am_sctp_passive;
@@ -1545,6 +1671,7 @@ static void *realloc_wrapper(void *current, ErlDrvSizeT size){
# define SCTP_ANC_BUFF_SIZE INET_DEF_BUFFER/2 /* XXX: not very good... */
#endif
+#ifdef HAVE_UDP
static int load_ip_port(ErlDrvTermData* spec, int i, char* buf)
{
spec[i++] = ERL_DRV_INT;
@@ -1579,6 +1706,7 @@ static int load_ip_address(ErlDrvTermData* spec, int i, int family, char* buf)
}
return i;
}
+#endif
#ifdef HAVE_SCTP
@@ -1745,10 +1873,12 @@ static void release_buffer(ErlDrvBinary* buf)
}
}
+#ifdef HAVE_UDP
static ErlDrvBinary* realloc_buffer(ErlDrvBinary* buf, ErlDrvSizeT newsz)
{
return driver_realloc_binary(buf, newsz);
}
+#endif
/* use a TRICK, access the refc field to see if any one else has
* a ref to this buffer then call driver_free_binary else
@@ -3409,6 +3539,7 @@ static int tcp_error_message(tcp_descriptor* desc, int err)
return erl_drv_output_term(desc->inet.dport, spec, i);
}
+#ifdef HAVE_UDP
/*
** active mode message:
** {udp, S, IP, Port, [H1,...Hsz | Data]} or
@@ -3499,6 +3630,7 @@ static int packet_binary_message
ASSERT(i <= PACKET_ERL_DRV_TERM_DATA_LEN);
return erl_drv_output_term(desc->dport, spec, i);
}
+#endif
/*
** active mode message: send active-to-passive transition message
@@ -3513,6 +3645,9 @@ static int packet_binary_message
DEBUGF(("packet_passive_message(%ld):\r\n", (long)desc->port));
+#if !defined(HAVE_UDP) && !defined(HAVE_SCTP)
+ i = LOAD_ATOM(spec, i, am_tcp_passive);
+#else
if (desc->sprotocol == IPPROTO_TCP)
i = LOAD_ATOM(spec, i, am_tcp_passive);
else {
@@ -3522,12 +3657,14 @@ static int packet_binary_message
i = LOAD_ATOM(spec, i, am_udp_passive);
#endif
}
+#endif
i = LOAD_PORT(spec, i, desc->dport);
i = LOAD_TUPLE(spec, i, 2);
ASSERT(i <= 6);
return erl_drv_output_term(desc->dport, spec, i);
}
+#ifdef HAVE_UDP
/*
** send active message {udp_error|sctp_error, S, Error}
*/
@@ -3554,7 +3691,7 @@ static int packet_error_message(udp_descriptor* udesc, int err)
ASSERT(i == sizeof(spec)/sizeof(*spec));
return erl_drv_output_term(desc->dport, spec, i);
}
-
+#endif
/*
** active=TRUE:
@@ -3619,7 +3756,7 @@ tcp_reply_binary_data(tcp_descriptor* desc, ErlDrvBinary* bin, int offs, int len
return code;
}
-
+#ifdef HAVE_UDP
static int
packet_reply_binary_data(inet_descriptor* desc, unsigned int hsz,
ErlDrvBinary * bin, int offs, int len,
@@ -3642,6 +3779,7 @@ packet_reply_binary_data(inet_descriptor* desc, unsigned int hsz,
return code;
}
}
+#endif
/* ----------------------------------------------------------------------------
@@ -3817,7 +3955,9 @@ static int inet_init()
INIT_ATOM(ok);
INIT_ATOM(tcp);
+#ifdef HAVE_UDP
INIT_ATOM(udp);
+#endif
INIT_ATOM(error);
INIT_ATOM(einval);
INIT_ATOM(inet_async);
@@ -3827,8 +3967,10 @@ static int inet_init()
INIT_ATOM(tcp_passive);
INIT_ATOM(tcp_closed);
INIT_ATOM(tcp_error);
+#ifdef HAVE_UDP
INIT_ATOM(udp_passive);
INIT_ATOM(udp_error);
+#endif
INIT_ATOM(empty_out_q);
INIT_ATOM(ssl_tls);
@@ -3847,7 +3989,10 @@ static int inet_init()
/* add TCP, UDP and SCTP drivers */
add_driver_entry(&tcp_inet_driver_entry);
+#ifdef HAVE_UDP
add_driver_entry(&udp_inet_driver_entry);
+#endif
+
#ifdef HAVE_SCTP
/* Check the size of SCTP AssocID -- currently both this driver and the
Erlang part require 32 bit: */
@@ -4176,6 +4321,16 @@ static void desc_close(inet_descriptor* desc)
desc->forced_events = 0;
desc->send_would_block = 0;
#endif
+#ifdef __OSE__
+ if (desc->events[0]) {
+ driver_select(desc->port,desc->events[0],FD_READ|FD_WRITE|ERL_DRV_USE,0);
+ driver_select(desc->port,desc->events[1],FD_READ|FD_WRITE|ERL_DRV_USE,0);
+ driver_select(desc->port,desc->events[2],FD_READ|FD_WRITE|ERL_DRV_USE,0);
+ driver_select(desc->port,desc->events[3],FD_READ|FD_WRITE|ERL_DRV_USE,0);
+ driver_select(desc->port,desc->events[4],FD_READ|FD_WRITE|ERL_DRV_USE,0);
+ driver_select(desc->port,desc->events[5],FD_READ|FD_WRITE|ERL_DRV_USE,0);
+ }
+#else
/*
* We should close the fd here, but the other driver might still
* be selecting on it.
@@ -4185,6 +4340,7 @@ static void desc_close(inet_descriptor* desc)
ERL_DRV_USE, 0);
else
inet_stop_select((ErlDrvEvent)(long)desc->event,NULL);
+#endif
desc->event = INVALID_EVENT; /* closed by stop_select callback */
desc->s = INVALID_SOCKET;
desc->event_mask = 0;
@@ -4226,6 +4382,64 @@ static int erl_inet_close(inet_descriptor* desc)
return 0;
}
+#ifdef __OSE__
+static void inet_select_init(inet_descriptor* desc)
+{
+ desc->events[0] =
+ erl_drv_ose_event_alloc(SO_EVENT_READ_REPLY,
+ desc->s,
+ inet_resolve_signal,
+ NULL);
+ driver_select(desc->port, desc->events[0],
+ ERL_DRV_READ|ERL_DRV_USE, 1);
+
+ desc->events[1] =
+ erl_drv_ose_event_alloc(SO_EVENT_EOF_REPLY,
+ desc->s,
+ inet_resolve_signal,
+ NULL);
+ driver_select(desc->port, desc->events[1],
+ ERL_DRV_READ|ERL_DRV_USE, 1);
+
+ desc->events[2] =
+ erl_drv_ose_event_alloc(SO_EVENT_ACCEPT_REPLY,
+ desc->s,
+ inet_resolve_signal,
+ NULL);
+ driver_select(desc->port, desc->events[2],
+ ERL_DRV_READ|ERL_DRV_USE, 1);
+
+ /* trigger tcp_inet_input */
+ desc->events[3] =
+ erl_drv_ose_event_alloc(SO_EVENT_WRITE_REPLY,
+ desc->s,
+ inet_resolve_signal,
+ NULL);
+ driver_select(desc->port, desc->events[3],
+ ERL_DRV_WRITE|ERL_DRV_USE, 1);
+
+ desc->events[4] =
+ erl_drv_ose_event_alloc(SO_EVENT_CONNECT_REPLY,
+ desc->s,
+ inet_resolve_signal,
+ NULL);
+ driver_select(desc->port, desc->events[4],
+ ERL_DRV_WRITE|ERL_DRV_USE, 1);
+
+ desc->events[5] =
+ erl_drv_ose_event_alloc(SO_EVENT_ERROR_REPLY,
+ desc->s,
+ inet_resolve_signal,
+ NULL);
+ driver_select(desc->port, desc->events[5],
+ ERL_DRV_WRITE|ERL_DRV_USE, 1);
+
+ /* Issue a select on error event before any other select to be sure we are
+ prepared to receive error notifications from the stack, even in the
+ situations when select isn't issued */
+ sock_select(desc, SOCK_FD_ERROR, 1);
+}
+#endif
static ErlDrvSSizeT inet_ctl_open(inet_descriptor* desc, int domain, int type,
char** rbuf, ErlDrvSizeT rsize)
@@ -4309,6 +4523,10 @@ static ErlDrvSSizeT inet_ctl_open(inet_descriptor* desc, int domain, int type,
#ifdef __WIN32__
driver_select(desc->port, desc->event, ERL_DRV_READ, 1);
#endif
+#ifdef __OSE__
+ inet_select_init(desc);
+#endif
+
desc->state = INET_STATE_OPEN;
desc->stype = type;
desc->sfamily = domain;
@@ -4328,7 +4546,14 @@ static ErlDrvSSizeT inet_ctl_fdopen(inet_descriptor* desc, int domain, int type,
return ctl_error(sock_errno(), rbuf, rsize);
if (name.sa.sa_family != domain)
return ctl_error(EINVAL, rbuf, rsize);
+#ifdef __OSE__
+ /* for fdopen duplicating the sd will allow to uniquely identify
+ the signal from OSE with erlang port */
+ desc->s = sock_dup(s);
+#else
desc->s = s;
+#endif
+
if ((desc->event = sock_create_event(desc)) == INVALID_EVENT)
return ctl_error(sock_errno(), rbuf, rsize);
SET_NONBLOCKING(desc->s);
@@ -4338,8 +4563,15 @@ static ErlDrvSSizeT inet_ctl_fdopen(inet_descriptor* desc, int domain, int type,
desc->state = INET_STATE_BOUND; /* assume bound */
if (type == SOCK_STREAM) { /* check if connected */
sz = sizeof(name);
- if (!IS_SOCKET_ERROR(sock_peer(s, (struct sockaddr*) &name, &sz)))
+ if (!IS_SOCKET_ERROR(sock_peer(s, (struct sockaddr*) &name, &sz))) {
desc->state = INET_STATE_CONNECTED;
+#ifdef __OSE__
+ /* since we are dealing with different descriptors (i.e. inet and
+ socket) the select part should be initialized with the right
+ values */
+ inet_select_init(desc);
+#endif
+ }
}
desc->prebound = 1; /* used to prevent a real close since
@@ -4365,8 +4597,7 @@ struct addr_if {
#ifndef SIOCGIFNETMASK
-static struct in_addr net_mask(in)
-struct in_addr in;
+static struct in_addr net_mask(struct in_addr in)
{
register u_long i = sock_ntohl(in.s_addr);
@@ -5929,6 +6160,7 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len)
}
continue;
+#ifdef HAVE_UDP
case INET_LOPT_UDP_READ_PACKETS:
if (desc->stype == SOCK_DGRAM) {
udp_descriptor* udesc = (udp_descriptor*) desc;
@@ -5936,6 +6168,7 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len)
udesc->read_packets = ival;
}
continue;
+#endif
#ifdef HAVE_SETNS
case INET_LOPT_NETNS:
@@ -6902,6 +7135,7 @@ static ErlDrvSSizeT inet_fill_opts(inet_descriptor* desc,
}
continue;
+#ifdef HAVE_UDP
case INET_LOPT_UDP_READ_PACKETS:
if (desc->stype == SOCK_DGRAM) {
*ptr++ = opt;
@@ -6911,6 +7145,7 @@ static ErlDrvSSizeT inet_fill_opts(inet_descriptor* desc,
TRUNCATE_TO(0,ptr);
}
continue;
+#endif
#ifdef HAVE_SETNS
case INET_LOPT_NETNS:
@@ -8041,6 +8276,15 @@ static ErlDrvData inet_start(ErlDrvPort port, int size, int protocol)
#ifdef HAVE_SETNS
desc->netns = NULL;
#endif
+#ifdef __OSE__
+ desc->select_state = 0;
+ desc->events[0] = NULL;
+ desc->events[1] = NULL;
+ desc->events[2] = NULL;
+ desc->events[3] = NULL;
+ desc->events[4] = NULL;
+ desc->events[5] = NULL;
+#endif
return (ErlDrvData)desc;
}
@@ -8761,6 +9005,11 @@ static tcp_descriptor* tcp_inet_copy(tcp_descriptor* desc,SOCKET s,
copy_desc->inet.port = port;
copy_desc->inet.dport = driver_mk_port(port);
+
+#ifdef __OSE__
+ inet_select_init(&copy_desc->inet);
+#endif
+
*err = 0;
return copy_desc;
}
@@ -8822,8 +9071,22 @@ static void tcp_inet_stop(ErlDrvData e)
inet_stop(INETP(desc));
}
+#ifdef __OSE__
+
+static ErlDrvSSizeT tcp_inet_ctl_ose(ErlDrvData e, unsigned int cmd,
+ char* buf, ErlDrvSizeT len,
+ char** rbuf, ErlDrvSizeT rsize) {
-
+ tcp_descriptor* desc = (tcp_descriptor*)e;
+ int prev_select_state = INETP(desc)->select_state;
+
+ ErlDrvSSizeT res = tcp_inet_ctl(e,cmd,buf,len,rbuf,rsize);
+
+ tcp_inet_ose_dispatch_signals((tcp_descriptor*)e,prev_select_state,NULL);
+
+ return res;
+}
+#endif
/* TCP requests from Erlang */
static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd,
@@ -9039,7 +9302,7 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd,
ErlDrvTermData caller = driver_caller(desc->inet.port);
tcp_descriptor* accept_desc;
int err;
-
+
if ((accept_desc = tcp_inet_copy(desc,s,caller,&err)) == NULL) {
sock_close(s);
return ctl_error(err, rbuf, rsize);
@@ -9073,7 +9336,8 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd,
char tbuf[2];
int n;
- DEBUGF(("tcp_inet_ctl(%ld): RECV\r\n", (long)desc->inet.port));
+ DEBUGF(("tcp_inet_ctl(%ld): RECV (s=%d)\r\n",
+ (long)desc->inet.port, desc->inet.s));
/* INPUT: Timeout(4), Length(4) */
if (!IS_CONNECTED(INETP(desc))) {
if (desc->tcp_add_flags & TCP_ADDF_DELAYED_CLOSE_RECV) {
@@ -9245,6 +9509,16 @@ static void tcp_inet_command(ErlDrvData e, char *buf, ErlDrvSizeT len)
DEBUGF(("tcp_inet_command(%ld) }\r\n", (long)desc->inet.port));
}
+#ifdef __OSE__
+
+static void tcp_inet_commandv_ose(ErlDrvData e, ErlIOVec* ev) {
+ int prev_select_state = INETP((tcp_descriptor*)e)->select_state;
+ tcp_inet_commandv(e, ev);
+ tcp_inet_ose_dispatch_signals((tcp_descriptor*)e,prev_select_state,NULL);
+}
+
+#endif
+
static void tcp_inet_commandv(ErlDrvData e, ErlIOVec* ev)
{
@@ -9308,6 +9582,22 @@ static void inet_stop_select(ErlDrvEvent event, void* _)
{
#ifdef __WIN32__
WSACloseEvent((HANDLE)event);
+#elif defined(__OSE__)
+ ErlDrvOseEventId id;
+ union SIGNAL *sig;
+ erl_drv_ose_event_fetch(event, NULL, &id,NULL);
+ DEBUGF(("inet_stop_select(?#?) {s=%d\n",id));
+ sock_close((int)id);
+ /* On socket close all the signals waiting to be processed as part of the
+ select should be deallocated */
+ while((sig = erl_drv_ose_get_signal(event))) {
+ DEBUGF(("inet_stop_select(?#?): Freeing signal %s\n",
+ signo_to_string(sig->signo)));
+ free_buf(&sig);
+ }
+ erl_drv_ose_event_free(event);
+ DEBUGF(("inet_stop_select(?#?) }\n"));
+
#else
sock_close((SOCKET)(long)event);
#endif
@@ -9427,12 +9717,13 @@ static int tcp_remain(tcp_descriptor* desc, int* len)
int n = desc->i_ptr - ptr; /* number of bytes read */
int tlen;
- DEBUGF(("tcp_remain(%ld): s=%d, n=%d, nfill=%d nsz=%d\r\n",
- (long)desc->inet.port, desc->inet.s, n, nfill, nsz));
+ DEBUGF(("tcp_remain(%ld): s=%d, n=%d, nfill=%d nsz=%d, tlen %d\r\n",
+ (long)desc->inet.port, desc->inet.s, n, nfill, nsz, tlen));
tlen = packet_get_length(desc->inet.htype, ptr, n,
desc->inet.psize, desc->i_bufsz,
&desc->http_state);
+
if (tlen > 0) {
if (tlen <= n) { /* got a packet */
*len = tlen;
@@ -9840,7 +10131,146 @@ static void tcp_inet_event(ErlDrvData e, ErlDrvEvent event)
return;
}
-#endif /* WIN32 */
+#elif defined(__OSE__) /* !__WIN32__ */
+/* The specific resolve signal function. It will return the socket descriptor
+ for which the select was issued */
+static ErlDrvOseEventId inet_resolve_signal(union SIGNAL *sig) {
+ DEBUGF(("%s(?#?): s=%d got signal %s, status = %d, extra = %d, sender = 0x%x\n",
+ __FUNCTION__,sig->async.fd,signo_to_string(sig->signo),
+ sig->async.event.status,
+ sig->async.event.extra,sender(&sig)));
+ if (sig->signo == SO_EVENT_READ_REPLY ||
+ sig->signo == SO_EVENT_ACCEPT_REPLY ||
+ sig->signo == SO_EVENT_EOF_REPLY ||
+ sig->signo == SO_EVENT_WRITE_REPLY ||
+ sig->signo == SO_EVENT_ERROR_REPLY ||
+ sig->signo == SO_EVENT_CONNECT_REPLY ) {
+ return sig->async.fd;
+ }
+
+ return -1;
+}
+
+static void inet_driver_select(inet_descriptor* desc,
+ int flags, int onoff) {
+ ASSERT(!desc->is_ignored);
+
+ if(onoff) {
+ desc->select_state |= flags;
+ } else {
+ desc->select_state &= ~flags;
+ }
+}
+
+static ssize_t writev_fallback(int fd, const struct iovec *iov, int iovcnt, int max_sz)
+{
+ size_t data_len = 0;
+ size_t sent = 0;
+ ssize_t n;
+ int i;
+
+ for(i = 0; i < iovcnt; i++)
+ {
+ data_len = iov[i].iov_len;
+tryagain:
+ n = sock_send(fd, iov[i].iov_base, data_len, 0);
+ if (IS_SOCKET_ERROR(n)) {
+ /* If buffer length is greater than the amount stack is able to
+ * send out then try to send at least max_sz (this comes with
+ * SO_EVENT_WRITE_REPLY signal*/
+ if ((errno == EMSGSIZE) && (max_sz > 0) && (data_len > max_sz)) {
+ data_len = max_sz;
+ goto tryagain;
+ }
+ break;
+ }
+ sent += n;
+ }
+ return sent;
+}
+
+#define OSE_EVENT_REQ(TCP_DESC,EVENT) do { \
+ union SIGNAL *sig = alloc(sizeof(struct OseAsyncSig), EVENT); \
+ sig->async.fd = INETP(TCP_DESC)->s; \
+ ose_request_event(INETP(TCP_DESC)->s, &sig, 1); \
+ DEBUGF(("%s(%ld): s=%d sent %s\r\n",__FUNCTION__, \
+ INETP(TCP_DESC)->port,INETP(TCP_DESC)->s,signo_to_string(EVENT))); \
+ } while(0)
+
+static void tcp_inet_ose_dispatch_signals(tcp_descriptor *desc,
+ int prev_select_state,
+ union SIGNAL *sig) {
+ if (sig) {
+ DEBUGF(("tcp_inet_ose_dispatch_signals(%ld) {s=%d resend\r\n",
+ (long)INETP(desc)->port,INETP(desc)->s));
+ /* We are reacting to a signal, which means that if
+ the select_state for that signal is still activated
+ we should send a new signal */
+ switch (sig->signo) {
+ case SO_EVENT_READ_REPLY: {
+ if (INETP(desc)->select_state & FD_READ)
+ OSE_EVENT_REQ(desc,SO_EVENT_READ_REQUEST);
+ break;
+ }
+ case SO_EVENT_WRITE_REPLY: {
+ if (INETP(desc)->select_state & FD_WRITE)
+ OSE_EVENT_REQ(desc,SO_EVENT_WRITE_REQUEST);
+ break;
+ }
+ case SO_EVENT_CONNECT_REPLY: {
+ if (INETP(desc)->select_state & FD_CONNECT)
+ OSE_EVENT_REQ(desc,SO_EVENT_CONNECT_REQUEST);
+ break;
+ }
+ case SO_EVENT_ACCEPT_REPLY: {
+ if (INETP(desc)->select_state & FD_ACCEPT)
+ OSE_EVENT_REQ(desc,SO_EVENT_ACCEPT_REQUEST);
+ break;
+ }
+ case SO_EVENT_ERROR_REPLY: {
+ if (INETP(desc)->select_state & SOCK_FD_ERROR)
+ OSE_EVENT_REQ(desc,SO_EVENT_ERROR_REQUEST);
+ break;
+ }
+
+ }
+ DEBUGF(("tcp_inet_ose_dispatch_signals(%ld) }\r\n",
+ (long)INETP(desc)->port));
+ }
+
+ if (INETP(desc)->select_state != prev_select_state) {
+ /* If the select state has changed we have to issue signals for
+ the state parts that have changed. */
+ int xor_select_state = INETP(desc)->select_state ^ prev_select_state;
+ DEBUGF(("tcp_inet_ose_dispatch_signals(%ld) {s=%d select change\r\n",
+ (long)INETP(desc)->port,INETP(desc)->s));
+ if ((xor_select_state & FD_READ) &&
+ (INETP(desc)->select_state & FD_READ)) {
+ OSE_EVENT_REQ(desc,SO_EVENT_READ_REQUEST);
+ }
+ if ((xor_select_state & FD_WRITE) &&
+ (INETP(desc)->select_state & FD_WRITE)) {
+ OSE_EVENT_REQ(desc,SO_EVENT_WRITE_REQUEST);
+ }
+ if ((xor_select_state & FD_CONNECT) &&
+ (INETP(desc)->select_state & FD_CONNECT)) {
+ OSE_EVENT_REQ(desc,SO_EVENT_CONNECT_REQUEST);
+ }
+ if ((xor_select_state & FD_ACCEPT) &&
+ (INETP(desc)->select_state & FD_ACCEPT)) {
+ OSE_EVENT_REQ(desc,SO_EVENT_ACCEPT_REQUEST);
+ }
+ if ((xor_select_state & SOCK_FD_ERROR) &&
+ (INETP(desc)->select_state & SOCK_FD_ERROR)) {
+ OSE_EVENT_REQ(desc,SO_EVENT_ERROR_REQUEST);
+ }
+
+ DEBUGF(("tcp_inet_ose_dispatch_signals(%ld) }\r\n",
+ (long)INETP(desc)->port));
+ }
+}
+
+#endif /* __OSE__ */
/* socket has input:
@@ -9861,7 +10291,7 @@ static int tcp_inet_input(tcp_descriptor* desc, HANDLE event)
unsigned int len;
inet_address remote;
inet_async_op *this_op = desc->inet.opt;
-
+
len = sizeof(desc->inet.remote);
s = sock_accept(desc->inet.s, (struct sockaddr*) &remote, &len);
if (s == INVALID_SOCKET && sock_errno() == ERRNO_BLOCK) {
@@ -9930,7 +10360,6 @@ static int tcp_inet_input(tcp_descriptor* desc, HANDLE event)
while (desc->inet.state == INET_STATE_MULTI_ACCEPTING) {
len = sizeof(desc->inet.remote);
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 */
goto done;
@@ -10256,6 +10685,49 @@ static int tcp_send(tcp_descriptor* desc, char* ptr, ErlDrvSizeT len)
return 0;
}
+#ifdef __OSE__
+
+static void tcp_inet_drv_output_ose(ErlDrvData data, ErlDrvEvent event)
+{
+ union SIGNAL *event_sig = erl_drv_ose_get_signal(event);
+
+ while (event_sig) {
+ int prev_select_state = INETP((tcp_descriptor*)data)->select_state;
+ int res = tcp_inet_output((tcp_descriptor*)data, (HANDLE)event_sig);
+ if (res != -1) {
+ tcp_inet_ose_dispatch_signals((tcp_descriptor*)data,
+ prev_select_state,event_sig);
+ free_buf(&event_sig);
+ event_sig = erl_drv_ose_get_signal(event);
+ } else {
+ /* NOTE: here the event object could have been deallocated!!!!
+ inet_stop_select is called when doing driver_select(ERL_DRV_USE,0)
+ */
+ free_buf(&event_sig);
+ return;
+ }
+ }
+}
+
+static void tcp_inet_drv_input_ose(ErlDrvData data, ErlDrvEvent event)
+{
+ union SIGNAL *event_sig = erl_drv_ose_get_signal(event);
+
+ while (event_sig) {
+ int prev_select_state = INETP((tcp_descriptor*)data)->select_state;
+ int res = tcp_inet_input((tcp_descriptor*)data, (HANDLE)event);
+ if (res != -1) {
+ tcp_inet_ose_dispatch_signals((tcp_descriptor*)data, prev_select_state,
+ event_sig);
+ free_buf(&event_sig);
+ event_sig = erl_drv_ose_get_signal(event);
+ } else {
+ free_buf(&event_sig);
+ return;
+ }
+ }
+}
+#else
static void tcp_inet_drv_output(ErlDrvData data, ErlDrvEvent event)
{
(void)tcp_inet_output((tcp_descriptor*)data, (HANDLE)event);
@@ -10265,6 +10737,7 @@ static void tcp_inet_drv_input(ErlDrvData data, ErlDrvEvent event)
{
(void)tcp_inet_input((tcp_descriptor*)data, (HANDLE)event);
}
+#endif
/* socket ready for ouput:
** 1. INET_STATE_CONNECTING => non block connect ?
@@ -10330,6 +10803,13 @@ static int tcp_inet_output(tcp_descriptor* desc, HANDLE event)
ssize_t n;
SysIOVec* iov;
+#ifdef __OSE__
+ /* For large size buffers case the amount of data that the stack is
+ able to send out (received in the .extra field) should be passed
+ down to writev_fallback */
+ n = event ? ((union SIGNAL*)event)->async.event.extra : 0;
+#endif
+
if ((iov = driver_peekq(ix, &vsize)) == NULL) {
sock_select(INETP(desc), FD_WRITE, 0);
send_empty_out_q_msgs(INETP(desc));
@@ -10341,8 +10821,8 @@ static int tcp_inet_output(tcp_descriptor* desc, HANDLE event)
if (IS_SOCKET_ERROR(sock_sendv(desc->inet.s, iov, vsize, &n, 0))) {
write_error:
if ((sock_errno() != ERRNO_BLOCK) && (sock_errno() != EINTR)) {
- DEBUGF(("tcp_inet_output(%ld): sock_sendv(%d) errno = %d\r\n",
- (long)desc->inet.port, vsize, sock_errno()));
+ DEBUGF(("tcp_inet_output(%ld): sock_sendv(%d) errno = %d (errno %d)\r\n",
+ (long)desc->inet.port, vsize, sock_errno(), errno));
ret = tcp_send_error(desc, sock_errno());
goto done;
}
@@ -10355,6 +10835,12 @@ static int tcp_inet_output(tcp_descriptor* desc, HANDLE event)
sizes > (max 32 bit signed int) */
size_t howmuch = 0x7FFFFFFF; /* max signed 32 bit */
int x;
+#ifdef __OSE__
+ /* For EWOULDBLOCK sock_sendv returns 0 so we have to be sure it
+ wasn't the case */
+ if(sock_errno() == ERRNO_BLOCK)
+ goto done;
+#endif
for(x = 0; x < vsize && iov[x].iov_len == 0; ++x)
;
if (x < vsize) {
@@ -10499,6 +10985,7 @@ static udp_descriptor* sctp_inet_copy(udp_descriptor* desc, SOCKET s, int* err)
+#ifdef HAVE_UDP
static int packet_inet_init()
{
return 0;
@@ -10529,6 +11016,7 @@ static ErlDrvData udp_inet_start(ErlDrvPort port, char *args)
set_default_msgq_limits(port);
return data;
}
+#endif
#ifdef HAVE_SCTP
static ErlDrvData sctp_inet_start(ErlDrvPort port, char *args)
@@ -10539,6 +11027,7 @@ static ErlDrvData sctp_inet_start(ErlDrvPort port, char *args)
}
#endif
+#ifdef HAVE_UDP
static void packet_inet_stop(ErlDrvData e)
{
/* There should *never* be any "empty out q" subscribers on
@@ -11049,7 +11538,7 @@ static void packet_inet_command(ErlDrvData e, char* buf, ErlDrvSizeT len)
else
inet_reply_ok(desc);
}
-
+#endif
#ifdef __WIN32__
static void packet_inet_event(ErlDrvData e, ErlDrvEvent event)
@@ -11071,6 +11560,7 @@ static void packet_inet_event(ErlDrvData e, ErlDrvEvent event)
#endif
+#ifdef HAVE_UDP
static void packet_inet_drv_input(ErlDrvData e, ErlDrvEvent event)
{
(void) packet_inet_input((udp_descriptor*)e, (HANDLE)event);
@@ -11327,6 +11817,7 @@ static int packet_inet_output(udp_descriptor* udesc, HANDLE event)
DEBUGF(("packet_inet_output(%ld) }\r\n", (long)desc->port));
return ret;
}
+#endif
/*---------------------------------------------------------------------------*/
diff --git a/erts/emulator/sys/common/erl_check_io.c b/erts/emulator/sys/common/erl_check_io.c
index 245841a768..1db673e7f3 100644
--- a/erts/emulator/sys/common/erl_check_io.c
+++ b/erts/emulator/sys/common/erl_check_io.c
@@ -527,7 +527,8 @@ ERTS_CIO_EXPORT(driver_select)(ErlDrvPort ix,
/* fast track to stop_select callback */
stop_select_fn = prt->drv_ptr->stop_select;
#ifdef USE_VM_PROBES
- strncpy(name, prt->drv_ptr->name, sizeof(name)-1);
+ strncpy(name, prt->drv_ptr->name,
+ sizeof(DTRACE_CHARBUF_NAME(name))-1);
name[sizeof(name)-1] = '\0';
#endif
ret = 0;
diff --git a/erts/emulator/sys/ose/default.lmconf b/erts/emulator/sys/ose/beam.lmconf
index a66b0ece56..4ad46b01d9 100644
--- a/erts/emulator/sys/ose/default.lmconf
+++ b/erts/emulator/sys/ose/beam.lmconf
@@ -4,12 +4,13 @@ OSE_LM_POOL_SIZE=0x200000
OSE_LM_MAIN_NAME=main
OSE_LM_MAIN_STACK_SIZE=0xF000
OSE_LM_MAIN_PRIORITY=20
+## Has to be of a type that allows MAM
OSE_LM_PROGRAM_TYPE=APP_RAM
OSE_LM_DATA_INIT=YES
OSE_LM_BSS_INIT=YES
OSE_LM_EXEC_MODEL=SHARED
HEAP_MAX_SIZE=1000000000
-HEAP_SMALL_BUF_INIT_SIZE=64000000
+HEAP_SMALL_BUF_INIT_SIZE=20971520
HEAP_LARGE_BUF_THRESHOLD=16000000
HEAP_LOCK_TYPE=2
diff --git a/erts/emulator/sys/ose/erl_main.c b/erts/emulator/sys/ose/erl_main.c
index 03119c3fec..23a9bc93a4 100644
--- a/erts/emulator/sys/ose/erl_main.c
+++ b/erts/emulator/sys/ose/erl_main.c
@@ -30,6 +30,8 @@
int
main(int argc, char **argv) {
+ (void)stdin;(void)stdout;(void)stderr;
+
/* When starting using pm_create -c ARGV="-- -root ..", argv[0] is the first
part of ARGV and not the name of the executable. So we shuffle some
pointers here to make erl_start happy. */
diff --git a/erts/emulator/sys/ose/erl_poll.c b/erts/emulator/sys/ose/erl_poll.c
index ca1ed6e53a..7d2a3d1e0b 100644
--- a/erts/emulator/sys/ose/erl_poll.c
+++ b/erts/emulator/sys/ose/erl_poll.c
@@ -551,7 +551,12 @@ int erts_poll_wait(ErtsPollSet ps,
fd.id, fd.signo, current_process());
erts_send_error_to_logger_nogl(dsbufp);
timeout = 0;
- ASSERT(0);
+ /* Under normal circumstances the signal is deallocated by the
+ * driver that issued the select operation. But in this case
+ * there's no driver waiting for such signal so we have to
+ * deallocate it here */
+ if (sig)
+ free_buf(&sig);
} else {
int i;
struct erts_sys_fd_type *fd = NULL;
@@ -737,6 +742,7 @@ union SIGNAL *erl_drv_ose_get_signal(ErlDrvEvent drv_ev) {
ev->msgs = msg->next;
ethr_mutex_unlock(&ev->mtx);
erts_free(ERTS_ALC_T_FD_SIG_LIST,msg);
+ restore(sig);
return sig;
}
}
diff --git a/erts/emulator/sys/ose/sys.c b/erts/emulator/sys/ose/sys.c
index c892cc69c7..5b950a7dae 100644
--- a/erts/emulator/sys/ose/sys.c
+++ b/erts/emulator/sys/ose/sys.c
@@ -195,7 +195,9 @@ static volatile int children_died;
write_buff += sizeof(struct aiocb *); \
memcpy(write_buff,BUFF,SIZE+1); \
SET_AIO(*write_req,FD,SIZE,write_buff); \
- aio_write(write_req); \
+ if (aio_write(write_req)) \
+ ramlog_printf("%s:%d: write failed with %d\n", \
+ __FILE__,__LINE__,errno); \
} \
} while(0)
@@ -210,13 +212,13 @@ static volatile int children_died;
driver_free(buffer_ptr); \
} while(0)
-/* When we have several schedulers, we need to make sure
- * that scheduler issuing aio_dispatch() is the owner on the signal */
#define DISPATCH_AIO(sig) do { \
- restore(sig); \
- aio_dispatch(sig); \
+ if (aio_dispatch(sig)) \
+ ramlog_printf("%s:%d: dispatch failed with %d\n", \
+ __FILE__,__LINE__,errno); \
} while(0)
+#define AIO_PIPE_SIZE 1024
/* debug print macros */
#define DEBUG_RES 0
@@ -371,6 +373,63 @@ thr_create_prepare_child(void *vtcdp)
#endif /* #ifdef USE_THREADS */
+/* The two functions below are stolen from win_con.c
+ They have to use malloc/free/realloc directly becasue
+ we want to do able to do erts_printf very early on.
+ */
+#define VPRINTF_BUF_INC_SIZE 128
+static erts_dsprintf_buf_t *
+grow_vprintf_buf(erts_dsprintf_buf_t *dsbufp, size_t need)
+{
+ char *buf;
+ size_t size;
+
+ ASSERT(dsbufp);
+
+ if (!dsbufp->str) {
+ size = (((need + VPRINTF_BUF_INC_SIZE - 1)
+ / VPRINTF_BUF_INC_SIZE)
+ * VPRINTF_BUF_INC_SIZE);
+ buf = (char *) malloc(size * sizeof(char));
+ }
+ else {
+ size_t free_size = dsbufp->size - dsbufp->str_len;
+
+ if (need <= free_size)
+ return dsbufp;
+
+ size = need - free_size + VPRINTF_BUF_INC_SIZE;
+ size = (((size + VPRINTF_BUF_INC_SIZE - 1)
+ / VPRINTF_BUF_INC_SIZE)
+ * VPRINTF_BUF_INC_SIZE);
+ size += dsbufp->size;
+ buf = (char *) realloc((void *) dsbufp->str,
+ size * sizeof(char));
+ }
+ if (!buf)
+ return NULL;
+ if (buf != dsbufp->str)
+ dsbufp->str = buf;
+ dsbufp->size = size;
+ return dsbufp;
+}
+
+static int erts_sys_ramlog_printf(char *format, va_list arg_list)
+{
+ int res,i;
+ erts_dsprintf_buf_t dsbuf = ERTS_DSPRINTF_BUF_INITER(grow_vprintf_buf);
+ res = erts_vdsprintf(&dsbuf, format, arg_list);
+ if (res >= 0) {
+ for (i = 0; i < dsbuf.str_len; i+= 50)
+ /* We print 50 characters at a time because otherwise
+ the ramlog looks broken */
+ ramlog_printf("%.*s",dsbuf.str_len-50 < 0?dsbuf.str_len:50,dsbuf.str+i);
+ }
+ if (dsbuf.str)
+ free((void *) dsbuf.str);
+ return res;
+}
+
void
erts_sys_pre_init(void)
{
@@ -409,6 +468,9 @@ erts_sys_pre_init(void)
children_died = 0;
#endif
#endif /* USE_THREADS */
+
+ erts_printf_stdout_func = erts_sys_ramlog_printf;
+
erts_smp_atomic_init_nob(&sys_misc_mem_sz, 0);
}
@@ -650,7 +712,7 @@ static void stop_select(ErlDrvEvent, void*);
static PROCESS
get_signal_proxy_pid(void) {
union SIGNAL *sig;
- SIGSELECT any_sig[] = {0};
+ SIGSELECT any_sig[] = {1,ERTS_SIGNAL_OSE_DRV_ATTACH};
if (!sig_proxy_pid) {
sig = alloc(sizeof(union SIGNAL), ERTS_SIGNAL_OSE_DRV_ATTACH);
@@ -685,7 +747,7 @@ resolve_signal(union SIGNAL* sig) {
struct erl_drv_entry spawn_driver_entry = {
spawn_init,
spawn_start,
- erl_stop,
+ NULL, /* erl_stop, */
output,
ready_input,
ready_output,
@@ -784,7 +846,11 @@ set_driver_data(ErlDrvPort port_num,
/* READ */
if (read_write & DO_READ) {
- efs_examine_fd(ifd, FLIB_FD_HANDLE, &driver_data[ifd].handle, 0);
+ EfsStatus res = efs_examine_fd(ifd, FLIB_FD_HANDLE,
+ &driver_data[ifd].handle, 0);
+ if (res != EFS_SUCCESS)
+ ramlog_printf("%s:%d: efs_examine_fd(%d) failed with %d\n",
+ __FILE__,__LINE__,ifd,errno);
driver_data[ifd].ifd = ifd;
driver_data[ifd].packet_bytes = packet_bytes;
driver_data[ifd].port_num = port_num;
@@ -792,10 +858,9 @@ set_driver_data(ErlDrvPort port_num,
/* async read struct */
memset(&driver_data[ifd].aiocb, 0, sizeof(struct aiocb));
- driver_data[ifd].aiocb.aio_buf = driver_alloc(255);
+ driver_data[ifd].aiocb.aio_buf = driver_alloc(AIO_PIPE_SIZE);
driver_data[ifd].aiocb.aio_fildes = ifd;
- driver_data[ifd].aiocb.aio_nbytes = 255;
-
+ driver_data[ifd].aiocb.aio_nbytes = (packet_bytes?packet_bytes:AIO_PIPE_SIZE);
driver_data[ifd].alive = 1;
driver_data[ifd].status = 0;
driver_data[ifd].input_event =
@@ -826,7 +891,9 @@ set_driver_data(ErlDrvPort port_num,
(void) driver_select(port_num, driver_data[ifd].input_event,
(ERL_DRV_READ | ERL_DRV_USE), 1);
- aio_read(&driver_data[ifd].aiocb);
+ if (aio_read(&driver_data[ifd].aiocb))
+ ramlog_printf("%s:%d: aio_read(%d) failed with %d\n",
+ __FILE__,__LINE__,ifd,errno);
}
else { /* WRITE ONLY */
efs_examine_fd(ofd, FLIB_FD_HANDLE, &driver_data[ofd].handle, 0);
@@ -926,7 +993,7 @@ spawn_start(ErlDrvPort port_num, char* name, SysDriverOpts* opts)
{
int ifd[2];
int ofd[2];
- static uint32_t ticker = 0;
+ static uint32_t ticker = 1;
PmStatus pm_status;
OSDOMAIN domain = PM_NEW_DOMAIN;
PROCESS progpid, mainbid, mainpid;
@@ -938,39 +1005,53 @@ spawn_start(ErlDrvPort port_num, char* name, SysDriverOpts* opts)
int handle_size;
char *ptr;
- /* handle arguments */
- ptr = strchr(name, ' ');
- if (ptr != NULL) {
- *ptr ='\0';
- ptr++;
- args = ptr;
+
+ args = driver_alloc(strlen(name)+1);
+ strcpy(args, name);
+ /* We need to handle name in three parts
+ * - install handle (must be unique)
+ * - install binary (needed for ose_pm_install_load_module())
+ * - full path (as argument to the spawned applications env.var
+ */
+
+ /* full path including arguments */
+ args = driver_alloc(strlen(name)+1);
+ strcpy(args, name);
+
+ /* handle path */
+ tmp_handle = strrchr(name, '/');
+ if (tmp_handle == NULL) {
+ tmp_handle = name;
}
else {
- args = NULL;
+ tmp_handle++;
}
- /* create an install handle */
- ptr = strrchr(name, '/');
+ /* handle args */
+ ptr = strchr(tmp_handle, ' ');
if (ptr != NULL) {
- ptr++;
- tmp_handle = ptr;
+ *ptr = '\0';
+ handle_size = ptr - tmp_handle;
}
else {
- tmp_handle = name;
+ handle_size = strlen(name)+1;
}
- handle_size = strlen(tmp_handle)+1;
- handle_size += (ticker<10)?3:((ticker<100)?4:5);
+ /* make room for ticker */
+ handle_size += (ticker<10)?3:((ticker<100)?4:5);
handle = driver_alloc(handle_size);
- snprintf(handle, handle_size, "%s_%d", tmp_handle, ticker);
-
+
do {
- snprintf(handle, handle_size, "%s_%d", tmp_handle, ticker++);
+ snprintf(handle, handle_size, "%s_%d", tmp_handle, ticker);
pm_status = ose_pm_install_load_module(0, "ELF", name, handle,
0, 0, NULL);
-
+ ticker++;
} while (pm_status == PM_EINSTALL_HANDLE_ALREADY_INSTALLED);
- DEBUG_CHECK_RES(pm_status, PM_SUCCESS);
+
+ if (pm_status != PM_SUCCESS) {
+ errno = ENOSYS; /* FIXME add comment */
+ return ERL_DRV_ERROR_ERRNO;
+ }
/* Create Program */
pm_status = ose_pm_create_program(&domain, handle, 0, 0,
@@ -1143,17 +1224,13 @@ static void erl_stop(ErlDrvData drv_data)
if (data->ifd != data->ofd) { /* read and write */
nbio_stop_fd(data->port_num, data->input_event);
nbio_stop_fd(data->port_num, data->output_event);
- driver_select(data->port_num, data->input_event, ERL_DRV_USE, 0);
- driver_select(data->port_num, data->output_event, ERL_DRV_USE, 0);
}
else { /* write only */
nbio_stop_fd(data->port_num, data->output_event);
- driver_select(data->port_num, data->output_event, ERL_DRV_USE, 0);
}
}
else { /* read only */
nbio_stop_fd(data->port_num, data->input_event);
- driver_select(data->port_num, data->input_event, ERL_DRV_USE, 0);
}
close(data->ifd);
close(data->ofd);
@@ -1177,18 +1254,31 @@ static void output(ErlDrvData drv_data, char* buf, ErlDrvSizeT len)
lbp = lb + (4-(data->packet_bytes));
if ((sz = driver_sizeq(data->port_num)) > 0) {
- driver_enq(data->port_num, lbp, data->packet_bytes);
- driver_enq(data->port_num, buf, len);
- if (sz + len + data->packet_bytes >= (1 << 13))
+ if (data->packet_bytes != 0) {
+ driver_enq(data->port_num, lbp, data->packet_bytes);
+ }
+ driver_enq(data->port_num, buf, len);
+
+ if (sz + len + data->packet_bytes >= (1 << 13))
set_busy_port(data->port_num, 1);
}
else {
- driver_enq(data->port_num, buf, len); /* n is the skip value */
-
+ char *pbbuf;
+ if (data->packet_bytes != 0) {
+ pbbuf = malloc(len + data->packet_bytes);
+ int i;
+ for (i = 0; i < data->packet_bytes; i++) {
+ *pbbuf++ = *lbp++;
+ }
+ strncpy(pbbuf, buf, len);
+ pbbuf -= data->packet_bytes;
+ }
driver_select(data->port_num, data->output_event,
ERL_DRV_WRITE|ERL_DRV_USE, 1);
-
- WRITE_AIO(data->ofd, len, buf);
+ WRITE_AIO(data->ofd,
+ (data->packet_bytes ? len+data->packet_bytes : len),
+ (data->packet_bytes ? pbbuf : buf));
+ if (data->packet_bytes != 0) free(pbbuf);
}
return; /* 0; */
}
@@ -1204,12 +1294,12 @@ static int port_inp_failure(ErlDrvPort port_num, ErlDrvEvent ready_fd, int res)
ASSERT(res <= 0);
erl_drv_ose_event_fetch(ready_fd,&sig_no, NULL, (void **)&fd);
-
/* As we need to handle two signals, we do this in two steps */
if (driver_data[*fd].alive) {
report_exit_status(driver_data[*fd].report_exit, 0); /* status? */
}
else {
+ driver_select(port_num,ready_fd,DO_READ|DO_WRITE,0);
clear_fd_data(*fd);
driver_report_exit(driver_data[*fd].port_num, driver_data[*fd].status);
/* As we do not really know if the spawn has crashed or exited nicely
@@ -1248,6 +1338,10 @@ static void ready_input(ErlDrvData drv_data, ErlDrvEvent ready_fd)
}
else {
res = sig->fm_read_reply.actual;
+ if (res == 0) {
+ port_inp_failure(data->port_num, ready_fd, res);
+ break;
+ }
if (data->packet_bytes == 0) {
if (res < 0) {
@@ -1258,6 +1352,7 @@ static void ready_input(ErlDrvData drv_data, ErlDrvEvent ready_fd)
else if (res == 0) {
/* read of 0 bytes, eof, otherside of pipe is assumed dead */
port_inp_failure(data->port_num, ready_fd, res);
+ break;
}
else {
buf = driver_alloc(res);
@@ -1267,100 +1362,91 @@ static void ready_input(ErlDrvData drv_data, ErlDrvEvent ready_fd)
driver_output(data->port_num, (char*) buf, res);
driver_free(buf);
}
+ /* clear the previous read */
+ memset(data->aiocb.aio_buf, 0, res);
+
+ /* issue a new read */
+ DISPATCH_AIO(sig);
+ aio_read(&data->aiocb);
}
- /* We try to read the remainder */
- else if (fd_data[data->ifd].remain > 0) {
- if (res < 0) {
- if ((errno != EINTR) && (errno != ERRNO_BLOCK)) {
- port_inp_failure(data->port_num, ready_fd, res);
+ else if (data->packet_bytes && fd_data[data->ifd].remain > 0) {
+ /* we've read a partial package, or a header */
+
+ if (res == fd_data[data->ifd].remain) { /* we are done! */
+ char *buf = data->aiocb.aio_buf;
+ int i;
+
+ /* do we have anything buffered? */
+ if (fd_data[data->ifd].buf != NULL) {
+ memcpy(fd_data[data->ifd].buf + fd_data[data->ifd].sz,
+ buf, res);
+ buf = fd_data[data->ifd].buf;
}
- }
- else if (res == 0) {
- port_inp_failure(data->port_num, ready_fd, res);
- }
- else if (res == fd_data[data->ifd].remain) { /* we're done */
- driver_output(data->port_num,
- fd_data[data->ifd].buf,
- fd_data[data->ifd].sz);
+
+ fd_data[data->ifd].sz += res;
+ driver_output(data->port_num, buf, (fd_data[data->ifd].sz>0?fd_data[data->ifd].sz:res));
clear_fd_data(data->ifd);
- }
- else { /* if (res < fd_data[fd].remain) */
- fd_data[data->ifd].cpos += res;
- fd_data[data->ifd].remain -= res;
- }
- }
- else if (fd_data[data->ifd].remain == 0) { /* clean fd */
- if (res < 0) {
- if ((errno != EINTR) && (errno != ERRNO_BLOCK)) {
- port_inp_failure(data->port_num, ready_fd, res);
+
+ /* clear the previous read */
+ memset(data->aiocb.aio_buf, 0, res);
+
+ /* issue a new read */
+ DISPATCH_AIO(sig);
+ data->aiocb.aio_nbytes = data->packet_bytes;
+
+ if (data->aiocb.aio_buf == NULL) {
+ port_inp_failure(data->port_num, ready_fd, -1);
}
+ aio_read(&data->aiocb);
}
- else if (res == 0) { /* eof */
- port_inp_failure(data->port_num, ready_fd, res);
- }
- else if (res < data->packet_bytes - fd_data[data->ifd].psz) {
- memcpy(fd_data[data->ifd].pbuf+fd_data[data->ifd].psz,
- (void *)data->aiocb.aio_buf, res);
- fd_data[data->ifd].psz += res;
- }
- else { /* if (res >= packet_bytes) */
- unsigned char* cpos = (unsigned char*)data->aiocb.aio_buf;
- int bytes_left = res;
-
- while (1) {
- int psz = fd_data[data->ifd].psz;
- char* pbp = fd_data[data->ifd].pbuf + psz;
-
- while (bytes_left && (psz < data->packet_bytes)) {
- *pbp++ = *cpos++;
- bytes_left--;
- psz++;
- }
-
- if (psz < data->packet_bytes) {
- fd_data[data->ifd].psz = psz;
- break;
- }
- fd_data[data->ifd].psz = 0;
-
- switch (data->packet_bytes) {
- case 1: h = get_int8(fd_data[data->ifd].pbuf); break;
- case 2: h = get_int16(fd_data[data->ifd].pbuf); break;
- case 4: h = get_int32(fd_data[data->ifd].pbuf); break;
- default: ASSERT(0); return; /* -1; */
- }
-
- if (h <= (bytes_left)) {
- driver_output(data->port_num, (char*) cpos, h);
- cpos += h;
- bytes_left -= h;
- continue;
- }
- else { /* The last message we got was split */
- char *buf = erts_alloc_fnf(ERTS_ALC_T_FD_ENTRY_BUF, h);
- if (!buf) {
- errno = ENOMEM;
- port_inp_failure(data->port_num, ready_fd, -1);
- }
- else {
- erts_smp_atomic_add_nob(&sys_misc_mem_sz, h);
- sys_memcpy(buf, cpos, bytes_left);
- fd_data[data->ifd].buf = buf;
- fd_data[data->ifd].sz = h;
- fd_data[data->ifd].remain = h - bytes_left;
- fd_data[data->ifd].cpos = buf + bytes_left;
- }
- break;
- }
+ else if(res < fd_data[data->ifd].remain) { /* received part of a package */
+ if (fd_data[data->ifd].sz == 0) {
+
+ fd_data[data->ifd].sz += res;
+ memcpy(fd_data[data->ifd].buf, data->aiocb.aio_buf, res);
+ fd_data[data->ifd].remain -= res;
+ }
+ else {
+ memcpy(fd_data[data->ifd].buf + fd_data[data->ifd].sz,
+ data->aiocb.aio_buf, res);
+ fd_data[data->ifd].sz += res;
+ fd_data[data->ifd].remain -= res;
+ }
+ /* clear the previous read */
+ memset(data->aiocb.aio_buf, 0, res);
+
+ /* issue a new read */
+ DISPATCH_AIO(sig);
+ data->aiocb.aio_nbytes = fd_data[data->ifd].remain;
+
+ if (data->aiocb.aio_buf == NULL) {
+ port_inp_failure(data->port_num, ready_fd, -1);
}
+ aio_read(&data->aiocb);
}
}
+ else if (data->packet_bytes && fd_data[data->ifd].remain == 0) { /* we've recieved a header */
+
+ /* analyze the header FIXME */
+ switch (data->packet_bytes) {
+ case 1: h = get_int8(data->aiocb.aio_buf); break;
+ case 2: h = get_int16(data->aiocb.aio_buf); break;
+ case 4: h = get_int32(data->aiocb.aio_buf); break;
+ }
- /* reset the read buffer and init next asynch read */
- DISPATCH_AIO(sig);
- memset((void *)data->aiocb.aio_buf, 0, 255);
+ fd_data[data->ifd].buf = erts_alloc_fnf(ERTS_ALC_T_FD_ENTRY_BUF, h + data->packet_bytes);
+ fd_data[data->ifd].remain = ((h + data->packet_bytes) - res);
- if (res > 0) {
+ /* clear the previous read */
+ memset(data->aiocb.aio_buf, 0, data->packet_bytes);
+
+ /* issue a new read */
+ DISPATCH_AIO(sig);
+ data->aiocb.aio_nbytes = h;
+
+ if (data->aiocb.aio_buf == NULL) {
+ port_inp_failure(data->port_num, ready_fd, -1);
+ }
aio_read(&data->aiocb);
}
}
@@ -1400,11 +1486,16 @@ static void ready_output(ErlDrvData drv_data, ErlDrvEvent ready_fd)
DISPATCH_AIO(sig);
FREE_AIO(sig->fm_write_reply.buffer);
res = driver_deq(data->port_num, iov[0].iov_len);
- if (res > 0) {
+ if (res > 0) {
iov = driver_peekq(data->port_num, &vlen);
WRITE_AIO(data->ofd, iov[0].iov_len, iov[0].iov_base);
}
}
+ else if (vlen == 0) {
+ DISPATCH_AIO(sig);
+ FREE_AIO(sig->fm_write_reply.buffer);
+ }
+
}
sig = erl_drv_ose_get_signal(ready_fd);
}
@@ -1650,10 +1741,10 @@ erl_assert_error(const char* expr, const char* func,
{
fflush(stdout);
fprintf(stderr, "%s:%d:%s() Assertion failed: %s\n",
- file, func, line, expr);
+ file, line, func, expr);
fflush(stderr);
ramlog_printf("%s:%d:%s() Assertion failed: %s\n",
- file, func, line, expr);
+ file, line, func, expr);
abort();
}
diff --git a/erts/epmd/src/Makefile.in b/erts/epmd/src/Makefile.in
index 2ea8630491..8dc8dae5f6 100644
--- a/erts/epmd/src/Makefile.in
+++ b/erts/epmd/src/Makefile.in
@@ -148,7 +148,7 @@ endif
ifeq ($(findstring ose,$(TARGET)),ose)
$(BINDIR)/$(EPMD): $(EPMD_OBJS) $(ERTS_LIB) $(OSE_LM_OBJS)
- $(call build-ose-load-module, $@, $(EPMD_OBJS) $(OSE_LM_OBJS), $(LIBS), $(LMCONF))
+ $(call build-ose-load-module, $@, $(EPMD_OBJS) $(OSE_LM_OBJS), $(LIBS), $(EPMD_LMCONF))
else
$(BINDIR)/$(EPMD): $(EPMD_OBJS) $(ERTS_LIB)
$(ld_verbose)$(PURIFY) $(LD) $(LDFLAGS) -o $@ $(EPMD_OBJS) $(LIBS)
diff --git a/erts/epmd/src/epmd.c b/erts/epmd/src/epmd.c
index 1678d537d1..3cfa7a782f 100644
--- a/erts/epmd/src/epmd.c
+++ b/erts/epmd/src/epmd.c
@@ -175,6 +175,9 @@ int main(int argc, char** argv)
g->nodes.reg = g->nodes.unreg = g->nodes.unreg_tail = NULL;
g->nodes.unreg_count = 0;
g->active_conn = 0;
+#ifdef HAVE_SYSTEMD_SD_DAEMON_H
+ g->is_systemd = 0;
+#endif
for (i = 0; i < MAX_LISTEN_SOCKETS; i++)
g->listenfd[i] = -1;
@@ -248,8 +251,12 @@ int main(int argc, char** argv)
else
usage(g);
epmd_cleanup_exit(g,0);
- }
- else
+#ifdef HAVE_SYSTEMD_SD_DAEMON_H
+ } else if (strcmp(argv[0], "-systemd") == 0) {
+ g->is_systemd = 1;
+ argv++; argc--;
+#endif
+ } else
usage(g);
}
dbg_printf(g,1,"epmd running - daemon = %d",g->is_daemon);
@@ -454,6 +461,11 @@ static void usage(EpmdVars *g)
fprintf(stderr, " Forcibly unregisters a name with epmd\n");
fprintf(stderr, " (only allowed if -relaxed_command_check was given when \n");
fprintf(stderr, " epmd was started).\n");
+#ifdef HAVE_SYSTEMD_SD_DAEMON_H
+ fprintf(stderr, " -systemd\n");
+ fprintf(stderr, " Wait for socket from systemd. The option makes sense\n");
+ fprintf(stderr, " when started from .socket unit.\n");
+#endif
epmd_cleanup_exit(g,1);
}
diff --git a/erts/epmd/src/epmd_int.h b/erts/epmd/src/epmd_int.h
index d4597be30c..c8f2192f7f 100644
--- a/erts/epmd/src/epmd_int.h
+++ b/erts/epmd/src/epmd_int.h
@@ -125,6 +125,9 @@
# include "sys/select.h"
#endif
+#ifdef HAVE_SYSTEMD_SD_DAEMON_H
+# include <systemd/sd-daemon.h>
+#endif
/* ************************************************************************ */
/* Replace some functions by others by making the function name a macro */
@@ -337,6 +340,9 @@ typedef struct {
int listenfd[MAX_LISTEN_SOCKETS];
char *addresses;
char **argv;
+#ifdef HAVE_SYSTEMD_SD_DAEMON_H
+ int is_systemd;
+#endif
} EpmdVars;
void dbg_printf(EpmdVars*,int,const char*,...);
diff --git a/erts/epmd/src/epmd_srv.c b/erts/epmd/src/epmd_srv.c
index 247fd34d5a..93982c2f60 100644
--- a/erts/epmd/src/epmd_srv.c
+++ b/erts/epmd/src/epmd_srv.c
@@ -213,6 +213,39 @@ void run(EpmdVars *g)
node_init(g);
g->conn = conn_init(g);
+#ifdef HAVE_SYSTEMD_SD_DAEMON_H
+ if (g->is_systemd)
+ {
+ int n;
+
+ dbg_printf(g,2,"try to obtain sockets from systemd");
+
+ n = sd_listen_fds(0);
+ if (n < 0)
+ {
+ dbg_perror(g,"cannot obtain sockets from systemd");
+ epmd_cleanup_exit(g,1);
+ }
+ else if (n == 0)
+ {
+ dbg_tty_printf(g,0,"systemd provides no sockets");
+ epmd_cleanup_exit(g,1);
+ }
+ else if (n > MAX_LISTEN_SOCKETS)
+ {
+ dbg_tty_printf(g,0,"cannot listen on more than %d IP addresses", MAX_LISTEN_SOCKETS);
+ epmd_cleanup_exit(g,1);
+ }
+ num_sockets = n;
+ for (i = 0; i < num_sockets; i++)
+ {
+ g->listenfd[i] = listensock[i] = SD_LISTEN_FDS_START + i;
+ }
+ }
+ else
+ {
+#endif
+
dbg_printf(g,2,"try to initiate listening port %d", g->port);
if (g->addresses != NULL && /* String contains non-separator characters if: */
@@ -277,6 +310,9 @@ void run(EpmdVars *g)
SET_ADDR(iserv_addr[0],EPMD_ADDR_ANY,sport);
num_sockets = 1;
}
+#ifdef HAVE_SYSTEMD_SD_DAEMON_H
+ }
+#endif
#if !defined(__WIN32__) && !defined(__OSE__)
/* We ignore the SIGPIPE signal that is raised when we call write
@@ -294,6 +330,13 @@ void run(EpmdVars *g)
FD_ZERO(&g->orig_read_mask);
g->select_fd_top = 0;
+#ifdef HAVE_SYSTEMD_SD_DAEMON_H
+ if (g->is_systemd)
+ for (i = 0; i < num_sockets; i++)
+ select_fd_set(g, listensock[i]);
+ else
+ {
+#endif
for (i = 0; i < num_sockets; i++)
{
if ((listensock[i] = socket(FAMILY,SOCK_STREAM,0)) < 0)
@@ -356,6 +399,9 @@ void run(EpmdVars *g)
}
select_fd_set(g, listensock[i]);
}
+#ifdef HAVE_SYSTEMD_SD_DAEMON_H
+ }
+#endif
dbg_tty_printf(g,2,"entering the main select() loop");
diff --git a/erts/etc/common/Makefile.in b/erts/etc/common/Makefile.in
index cfd36af962..0cf965f915 100644
--- a/erts/etc/common/Makefile.in
+++ b/erts/etc/common/Makefile.in
@@ -509,7 +509,7 @@ $(OBJDIR)/crt0_lm.o: $(CRT0_LM)
OSE_LM_OBJS += $(OBJDIR)/ose_confd.o $(OBJDIR)/crt0_lm.o
$(BINDIR)/run_erl_lm: $(OBJDIR)/run_erl_main.o $(OBJDIR)/safe_string.o $(OBJDIR)/run_erl.o $(OBJDIR)/run_erl_common.o $(OBJDIR)/to_erl_common.o $(OSE_LM_OBJS)
- $(call build-ose-load-module, $@, $^, $(LIBS), $(LMCONF))
+ $(call build-ose-load-module, $@, $^, $(LIBS), $(RUN_ERL_LMCONF))
$(OBJDIR)/run_erl_main.o: $(OSEETC)/run_erl_main.c $(OSEETC)/run_erl.h ../common/to_erl_common.h $(RC_GENERATED)
diff --git a/erts/etc/common/to_erl_common.c b/erts/etc/common/to_erl_common.c
index a49be44b6c..ab706fffe0 100644
--- a/erts/etc/common/to_erl_common.c
+++ b/erts/etc/common/to_erl_common.c
@@ -126,7 +126,8 @@ static int version_handshake(char* buf, int len, int wfd);
#define READ_AIO(REQ,FD,SIZE,BUFF) \
SET_AIO(REQ,FD,SIZE,BUFF); \
if (aio_read(&(REQ)) != 0) \
- fprintf(stderr,"aio_read of child_read_req(%d) failed\n",FD)
+ fprintf(stderr,"aio_read of child_read_req(%d) failed" \
+ "with error %d\n",FD,errno)
union SIGNAL {
SIGSELECT signo;
diff --git a/erts/etc/ose/etc.lmconf b/erts/etc/ose/etc.lmconf
new file mode 100644
index 0000000000..b402b325b1
--- /dev/null
+++ b/erts/etc/ose/etc.lmconf
@@ -0,0 +1,20 @@
+OSE_LM_STACK_SIZES=256,512,1024,2048,4096,8192,16384,65536
+OSE_LM_SIGNAL_SIZES=31,63,127,255,1023,4095,16383,65535
+OSE_LM_POOL_SIZE=0x200000
+OSE_LM_MAIN_NAME=main
+OSE_LM_MAIN_STACK_SIZE=0xF000
+OSE_LM_MAIN_PRIORITY=20
+## Has to be of a type that allows MAM
+OSE_LM_PROGRAM_TYPE=APP_RAM
+OSE_LM_DATA_INIT=YES
+OSE_LM_BSS_INIT=YES
+OSE_LM_EXEC_MODEL=SHARED
+HEAP_MAX_SIZE=1000000000
+HEAP_SMALL_BUF_INIT_SIZE=64000000
+HEAP_LARGE_BUF_THRESHOLD=16000000
+HEAP_LOCK_TYPE=2
+
+# Setting the environment variable EFS_RESOLVE_TMO on the block to 0.
+# This will eliminiate delays when trying to open files on not mounted
+# volumes.
+EFS_RESOLVE_TMO=0
diff --git a/erts/etc/ose/run_erl_main.c b/erts/etc/ose/run_erl_main.c
index d396ebe93b..2d92924ff2 100644
--- a/erts/etc/ose/run_erl_main.c
+++ b/erts/etc/ose/run_erl_main.c
@@ -45,6 +45,8 @@ int main(int argc, char **argv)
char run_erl_usage[320],
to_erl_usage[120];
+ (void)stdin;(void)stdout;(void)stderr;
+
sprintf(run_erl_usage,RUN_ERL_USAGE,"run_erl [-daemon] [-block blockname]");
sprintf(to_erl_usage,TO_ERL_USAGE,"pipename");
diff --git a/erts/include/internal/ethr_mutex.h b/erts/include/internal/ethr_mutex.h
index ee861065c5..6c931e0cd4 100644
--- a/erts/include/internal/ethr_mutex.h
+++ b/erts/include/internal/ethr_mutex.h
@@ -354,7 +354,7 @@ void ethr_rwmutex_rwunlock(ethr_rwmutex *);
#ifdef ETHR_MTX_HARD_DEBUG
#define ETHR_MTX_HARD_ASSERT(A) \
- ((void) ((A) ? 1 : ethr_assert_failed(__FILE__, __LINE__, #A)))
+ ((void) ((A) ? 1 : ethr_assert_failed(__FILE__, __LINE__, __func__,#A)))
#else
#define ETHR_MTX_HARD_ASSERT(A) ((void) 1)
#endif
diff --git a/erts/include/internal/ethread.h b/erts/include/internal/ethread.h
index 64f1fae6d8..54acd1295a 100644
--- a/erts/include/internal/ethread.h
+++ b/erts/include/internal/ethread.h
@@ -396,6 +396,18 @@ extern ethr_runtime_t ethr_runtime__;
#include "ethr_atomics.h" /* The atomics API */
+#if defined (ETHR_OSE_THREADS)
+static ETHR_INLINE void
+ose_yield(void)
+{
+ if (get_ptype(current_process()) == OS_PRI_PROC) {
+ set_pri(get_pri(current_process()));
+ } else {
+ delay(1);
+ }
+}
+#endif
+
#if defined(__GNUC__) && !defined(ETHR_OSE_THREADS)
# ifndef ETHR_SPIN_BODY
# if defined(__i386__) || defined(__x86_64__)
@@ -414,9 +426,9 @@ extern ethr_runtime_t ethr_runtime__;
# endif
#elif defined(ETHR_OSE_THREADS)
# ifndef ETHR_SPIN_BODY
-# define ETHR_SPIN_BODY set_pri(get_pri(current_process()))
+# define ETHR_SPIN_BODY ose_yield()
# else
-# error "OSE should use set_pri(get_pri(current_process()))"
+# error "OSE should use ose_yield()"
# endif
#endif
@@ -449,7 +461,7 @@ extern ethr_runtime_t ethr_runtime__;
# define ETHR_YIELD() (pthread_yield(), 0)
# endif
# elif defined(ETHR_OSE_THREADS)
-# define ETHR_YIELD() (set_pri(get_pri(current_process())), 0)
+# define ETHR_YIELD() (ose_yield(), 0)
# else
# define ETHR_YIELD() (ethr_compiler_barrier(), 0)
# endif
diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl
index 52d6dfe184..b7422318b2 100644
--- a/lib/compiler/src/sys_core_fold.erl
+++ b/lib/compiler/src/sys_core_fold.erl
@@ -2031,9 +2031,9 @@ case_opt(Arg, Cs0, Sub) ->
case_opt_args([A0|As0], Cs0, Sub, LitExpr, Acc) ->
case case_opt_arg(A0, Sub, Cs0, LitExpr) of
- error ->
+ {error,Cs1} ->
%% Nothing to be done. Move on to the next argument.
- Cs = [{Ps,C,[P|PsAcc],Bs} || {[P|Ps],C,PsAcc,Bs} <- Cs0],
+ Cs = [{Ps,C,[P|PsAcc],Bs} || {[P|Ps],C,PsAcc,Bs} <- Cs1],
case_opt_args(As0, Cs, Sub, LitExpr, [A0|Acc]);
{ok,As1,Cs} ->
%% The argument was either expanded (from tuple/list) or
@@ -2052,7 +2052,7 @@ case_opt_arg(E0, Sub, Cs, LitExpr) ->
E = maybe_replace_var(E0, Sub),
case cerl:is_data(E) of
false ->
- error;
+ {error,Cs};
true ->
case cerl:data_type(E) of
{atomic,_} ->
@@ -2102,35 +2102,44 @@ maybe_replace_var_1(E, #sub{t=Tdb}) ->
%% pattern matching is tricky, so we will give up in that case.
case_opt_lit(Lit, Cs0, LitExpr) ->
- try case_opt_lit_1(Cs0, Lit, LitExpr) of
+ Cs1 = case_opt_lit_1(Lit, Cs0, LitExpr),
+ try case_opt_lit_2(Lit, Cs1) of
Cs ->
{ok,[],Cs}
catch
throw:impossible ->
- error
+ {error,Cs1}
end.
-case_opt_lit_1([{[P|Ps],C,PsAcc,Bs0}|Cs], E, LitExpr) ->
+case_opt_lit_1(E, [{[P|_],C,_,_}=Current|Cs], LitExpr) ->
+ case cerl_clauses:match(P, E) of
+ none ->
+ %% The pattern will not match the literal. Remove the clause.
+ %% Unless the entire case expression is a literal, also
+ %% emit a warning.
+ case LitExpr of
+ false -> add_warning(C, nomatch_clause_type);
+ true -> ok
+ end,
+ case_opt_lit_1(E, Cs, LitExpr);
+ _ ->
+ [Current|case_opt_lit_1(E, Cs, LitExpr)]
+ end;
+case_opt_lit_1(_, [], _) -> [].
+
+case_opt_lit_2(E, [{[P|Ps],C,PsAcc,Bs0}|Cs]) ->
+ %% Non-matching clauses have already been removed in case_opt_lit_1/3.
case cerl_clauses:match(P, E) of
- none ->
- %% The pattern will not match the literal. Remove the clause.
- %% Unless the entire case expression is a literal, also
- %% emit a warning.
- case LitExpr of
- false -> add_warning(C, nomatch_clause_type);
- true -> ok
- end,
- case_opt_lit_1(Cs, E, LitExpr);
{true,Bs} ->
%% The pattern matches the literal. Remove the pattern
%% and update the bindings.
- [{Ps,C,PsAcc,Bs++Bs0}|case_opt_lit_1(Cs, E, LitExpr)];
+ [{Ps,C,PsAcc,Bs++Bs0}|case_opt_lit_2(E, Cs)];
{false,_} ->
%% Binary literal and pattern. We are not sure whether
%% the pattern will match.
throw(impossible)
end;
-case_opt_lit_1([], _, _) -> [].
+case_opt_lit_2(_, []) -> [].
%% case_opt_data(Expr, Clauses0, LitExpr) -> {ok,Exprs,Clauses}
diff --git a/lib/compiler/src/v3_codegen.erl b/lib/compiler/src/v3_codegen.erl
index f1331d1fe7..47a357c23d 100644
--- a/lib/compiler/src/v3_codegen.erl
+++ b/lib/compiler/src/v3_codegen.erl
@@ -960,7 +960,6 @@ select_extract_map(Src, Vs, Fail, I, Vdb, Bef, St) ->
end, {{[],[]},Bef}, Vs),
Code = case {HasKs,GetVs} of
- {[],[]} -> {[],Aft,St};
{HasKs,[]} ->
[{test,has_map_fields,{f,Fail},Rsrc,{list,HasKs}}];
{[],GetVs} ->
@@ -1553,8 +1552,7 @@ map_pair_strip_and_termsort(Es) ->
Ls = [{K,V}||{_,K,V}<-Es],
lists:sort(fun ({{_,A},_}, {{_,B},_}) -> erts_internal:cmp_term(A,B) =< 0;
({nil,_}, {{_,B},_}) -> [] =< B;
- ({{_,A},_}, {nil,_}) -> A =< [];
- ({nil,_}, {nil,_}) -> true
+ ({{_,A},_}, {nil,_}) -> A =< []
end, Ls).
%%%
diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl
index 04210ae243..a548ba2f7c 100644
--- a/lib/compiler/src/v3_core.erl
+++ b/lib/compiler/src/v3_core.erl
@@ -514,15 +514,26 @@ expr({tuple,L,Es0}, St0) ->
expr({map,L,Es0}, St0) ->
% erl_lint should make sure only #{ K => V } are allowed
% in map construction.
- {Es1,Eps,St1} = map_pair_list(Es0, St0),
- A = lineno_anno(L, St1),
- {ann_c_map(A,Es1),Eps,St1};
+ try map_pair_list(Es0, St0) of
+ {Es1,Eps,St1} ->
+ A = lineno_anno(L, St1),
+ {ann_c_map(A,Es1),Eps,St1}
+ catch
+ throw:{bad_map,Warning} ->
+ St = add_warning(L, Warning, St0),
+ LineAnno = lineno_anno(L, St),
+ As = [#c_literal{anno=LineAnno,val=badarg}],
+ {#icall{anno=#a{anno=LineAnno}, %Must have an #a{}
+ module=#c_literal{anno=LineAnno,val=erlang},
+ name=#c_literal{anno=LineAnno,val=error},
+ args=As},[],St}
+ end;
expr({map,L,M0,Es0}, St0) ->
try expr_map(M0,Es0,lineno_anno(L, St0),St0) of
{_,_,_}=Res -> Res
catch
- throw:bad_map ->
- St = add_warning(L, bad_map, St0),
+ throw:{bad_map,Warning} ->
+ St = add_warning(L, Warning, St0),
LineAnno = lineno_anno(L, St),
As = [#c_literal{anno=LineAnno,val=badarg}],
{#icall{anno=#a{anno=LineAnno}, %Must have an #a{}
@@ -762,7 +773,7 @@ expr_map(M0,Es0,A,St0) ->
{Es1,Eps,St2} = map_pair_list(Es0, St1),
{ann_c_map(A,M1,Es1),Mps++Eps,St2}
end;
- false -> throw(bad_map)
+ false -> throw({bad_map,bad_map})
end.
is_valid_map_src(#c_literal{val = M}) when is_map(M) -> true;
@@ -774,18 +785,23 @@ map_pair_list(Es, St) ->
foldr(fun
({map_field_assoc,L,K0,V0}, {Ces,Esp,St0}) ->
{K,Ep0,St1} = safe(K0, St0),
+ ok = ensure_valid_map_key(K),
{V,Ep1,St2} = safe(V0, St1),
A = lineno_anno(L, St2),
Pair = #c_map_pair{op=#c_literal{val=assoc},anno=A,key=K,val=V},
{[Pair|Ces],Ep0 ++ Ep1 ++ Esp,St2};
({map_field_exact,L,K0,V0}, {Ces,Esp,St0}) ->
{K,Ep0,St1} = safe(K0, St0),
+ ok = ensure_valid_map_key(K),
{V,Ep1,St2} = safe(V0, St1),
A = lineno_anno(L, St2),
Pair = #c_map_pair{op=#c_literal{val=exact},anno=A,key=K,val=V},
{[Pair|Ces],Ep0 ++ Ep1 ++ Esp,St2}
end, {[],[],St}, Es).
+ensure_valid_map_key(#c_literal{}) -> ok;
+ensure_valid_map_key(_) -> throw({bad_map,bad_map_key}).
+
%% try_exception([ExcpClause], St) -> {[ExcpVar],Handler,St}.
try_exception(Ecs0, St0) ->
@@ -1595,7 +1611,9 @@ pattern_map_pair({map_field_exact,L,K,V}, St) ->
{bin,L,Es0} ->
case constant_bin(Es0) of
error ->
- throw(badmatch);
+ %% this will throw a cryptic error message
+ %% but it is better than nothing
+ throw(nomatch);
Bin ->
#c_literal{anno=lineno_anno(L,St),val=Bin}
end;
@@ -2299,6 +2317,8 @@ format_error(nomatch) ->
"pattern cannot possibly match";
format_error(bad_binary) ->
"binary construction will fail because of a type mismatch";
+format_error(bad_map_key) ->
+ "map construction will fail because of none literal key (large binaries are not literals)";
format_error(bad_map) ->
"map construction will fail because of a type mismatch".
diff --git a/lib/compiler/src/v3_kernel.erl b/lib/compiler/src/v3_kernel.erl
index d3b785aa14..40d2f72b4c 100644
--- a/lib/compiler/src/v3_kernel.erl
+++ b/lib/compiler/src/v3_kernel.erl
@@ -581,8 +581,7 @@ map_key_clean(#k_literal{val=V}) -> {k_literal,V};
map_key_clean(#k_int{val=V}) -> {k_int,V};
map_key_clean(#k_float{val=V}) -> {k_float,V};
map_key_clean(#k_atom{val=V}) -> {k_atom,V};
-map_key_clean(#k_nil{}) -> k_nil;
-map_key_clean(#k_var{name=V}) -> {k_var,V}.
+map_key_clean(#k_nil{}) -> k_nil.
%% call_type(Module, Function, Arity) -> call | bif | apply | error.
diff --git a/lib/compiler/src/v3_life.erl b/lib/compiler/src/v3_life.erl
index c4f54a7970..cd4b5fd674 100644
--- a/lib/compiler/src/v3_life.erl
+++ b/lib/compiler/src/v3_life.erl
@@ -324,8 +324,7 @@ type(k_binary) -> binary;
type(k_bin_seg) -> bin_seg;
type(k_bin_int) -> bin_int;
type(k_bin_end) -> bin_end;
-type(k_map) -> map;
-type(k_map_pair) -> map_pair.
+type(k_map) -> map.
%% variable(Klit) -> Lit.
%% var_list([Klit]) -> [Lit].
diff --git a/lib/compiler/test/core_fold_SUITE.erl b/lib/compiler/test/core_fold_SUITE.erl
index 9c986576d5..6a7036d728 100644
--- a/lib/compiler/test/core_fold_SUITE.erl
+++ b/lib/compiler/test/core_fold_SUITE.erl
@@ -23,7 +23,7 @@
t_element/1,setelement/1,t_length/1,append/1,t_apply/1,bifs/1,
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]).
+ multiple_aliases/1,redundant_boolean_clauses/1,mixed_matching_clauses/1]).
-export([foo/0,foo/1,foo/2,foo/3]).
@@ -40,7 +40,7 @@ groups() ->
[t_element,setelement,t_length,append,t_apply,bifs,
eq,nested_call_in_case,guard_try_catch,coverage,
unused_multiple_values_error,unused_multiple_values,
- multiple_aliases,redundant_boolean_clauses]}].
+ multiple_aliases,redundant_boolean_clauses,mixed_matching_clauses]}].
init_per_suite(Config) ->
@@ -373,5 +373,15 @@ redundant_boolean_clauses(Config) when is_list(Config) ->
true -> yes
end.
+mixed_matching_clauses(Config) when is_list(Config) ->
+ 0 = case #{} of
+ #{} -> 0;
+ a -> 1
+ end,
+ 0 = case <<>> of
+ <<>> -> 0;
+ a -> 1
+ end,
+ ok.
id(I) -> I.
diff --git a/lib/compiler/test/map_SUITE.erl b/lib/compiler/test/map_SUITE.erl
index 90eae6fb4f..cc018e4305 100644
--- a/lib/compiler/test/map_SUITE.erl
+++ b/lib/compiler/test/map_SUITE.erl
@@ -40,6 +40,8 @@
t_build_and_match_over_alloc/1,
t_build_and_match_empty_val/1,
t_build_and_match_val/1,
+ t_build_and_match_nil/1,
+ t_build_and_match_structure/1,
%% errors in 17.0-rc1
t_update_values/1,
@@ -68,6 +70,8 @@ all() -> [
t_build_and_match_over_alloc,
t_build_and_match_empty_val,
t_build_and_match_val,
+ t_build_and_match_nil,
+ t_build_and_match_structure,
%% errors in 17.0-rc1
t_update_values,
@@ -118,6 +122,7 @@ t_build_and_match_literals(Config) when is_list(Config) ->
{'EXIT',{{badmatch,_},_}} = (catch (#{x:=3} = id({a,b,c}))),
{'EXIT',{{badmatch,_},_}} = (catch (#{x:=3} = id(#{y=>3}))),
{'EXIT',{{badmatch,_},_}} = (catch (#{x:=3} = id(#{x=>"three"}))),
+ {'EXIT',{badarg,_}} = (catch id(#{<<0:258>> =>"three"})),
ok.
t_build_and_match_aliasing(Config) when is_list(Config) ->
@@ -234,7 +239,8 @@ t_update_assoc(Config) when is_list(Config) ->
%% Errors cases.
BadMap = id(badmap),
{'EXIT',{badarg,_}} = (catch BadMap#{nonexisting=>val}),
-
+ {'EXIT',{badarg,_}} = (catch <<>>#{nonexisting=>val}),
+ {'EXIT',{badarg,_}} = (catch M0#{<<0:257>> => val}), %% limitation
ok.
t_update_exact(Config) when is_list(Config) ->
@@ -262,6 +268,8 @@ t_update_exact(Config) when is_list(Config) ->
{'EXIT',{badarg,_}} = (catch M0#{1.0:=v,1.0=>v2}),
{'EXIT',{badarg,_}} = (catch M0#{42.0:=v,42:=v2}),
{'EXIT',{badarg,_}} = (catch M0#{42=>v1,42.0:=v2,42:=v3}),
+ {'EXIT',{badarg,_}} = (catch <<>>#{nonexisting:=val}),
+ {'EXIT',{badarg,_}} = (catch M0#{<<0:257>> := val}), %% limitation
ok.
t_update_values(Config) when is_list(Config) ->
@@ -561,6 +569,32 @@ t_build_and_match_val(Config) when is_list(Config) ->
test_server:fail({no_match, Other})
end.
+t_build_and_match_nil(Config) when is_list(Config) ->
+ %% literals removed the coverage
+ V1 = id(cookie),
+ V2 = id(cake),
+ V3 = id(crisps),
+
+ #{ [] := V1, "treat" := V2, {your,treat} := V3 } = id(#{
+ {your,treat} => V3,
+ "treat" => V2,
+ [] => V1 }),
+ #{ [] := V3, [] := V3 } = id(#{ [] => V1, [] => V3 }),
+ ok.
+
+t_build_and_match_structure(Config) when is_list(Config) ->
+ V2 = id("it"),
+ S = id([42,{"hi", "=)", #{ "a" => 42, any => any, val => "get_" ++ V2}}]),
+
+ %% match deep map values
+ V2 = case S of
+ [42,{"hi",_, #{ "a" := 42, val := "get_" ++ V1, any := _ }}] -> V1
+ end,
+ %% match deep map
+ ok = case S of
+ [42,{"hi",_, #{ }}] -> ok
+ end,
+ ok.
%% Use this function to avoid compile-time evaluation of an expression.
id(I) -> I.
diff --git a/lib/compiler/test/warnings_SUITE.erl b/lib/compiler/test/warnings_SUITE.erl
index c3b02819f9..ad4ad91f74 100644
--- a/lib/compiler/test/warnings_SUITE.erl
+++ b/lib/compiler/test/warnings_SUITE.erl
@@ -573,7 +573,48 @@ maps(Config) when is_list(Config) ->
">>,
[],
{warnings,[{3,sys_core_fold,no_clause_match},
- {9,sys_core_fold,nomatch_clause_type}]}}],
+ {9,sys_core_fold,nomatch_clause_type}]}},
+ {bad_map_src1,
+ <<"
+ t() ->
+ M = {a,[]},
+ {'EXIT',{badarg,_}} = (catch(M#{ a => 1})),
+ ok.
+ ">>,
+ [],
+ {warnings,[{4,v3_kernel,bad_map}]}},
+ {bad_map_src2,
+ <<"
+ t() ->
+ M = id({a,[]}),
+ {'EXIT',{badarg,_}} = (catch(M#{ a => 1})),
+ ok.
+ id(I) -> I.
+ ">>,
+ [inline],
+ {warnings,[{4,v3_kernel,bad_map}]}},
+ {bad_map_src3,
+ <<"
+ t() ->
+ {'EXIT',{badarg,_}} = (catch <<>>#{ a := 1}),
+ ok.
+ ">>,
+ [],
+ {warnings,[{3,v3_core,bad_map}]}},
+ {bad_map_literal_key,
+ <<"
+ t() ->
+ V = id(1),
+ M = id(#{ <<$h,$i>> => V }),
+ V = case M of
+ #{ <<0:257>> := Val } -> Val;
+ #{ <<$h,$i>> := Val } -> Val
+ end,
+ ok.
+ id(I) -> I.
+ ">>,
+ [],
+ {warnings,[{6,v3_core,nomatch}]}}],
run(Config, Ts),
ok.
diff --git a/lib/dialyzer/test/small_SUITE_data/results/invalid_spec_2 b/lib/dialyzer/test/small_SUITE_data/results/invalid_spec_2
new file mode 100644
index 0000000000..4565112ea0
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/results/invalid_spec_2
@@ -0,0 +1,2 @@
+
+scala_user.erl:5: Invalid type specification for function scala_user:is_list/2. The success typing is (maybe_improper_list() | tuple(),_) -> boolean()
diff --git a/lib/dialyzer/test/small_SUITE_data/src/invalid_spec_2/scala_data.erl b/lib/dialyzer/test/small_SUITE_data/src/invalid_spec_2/scala_data.erl
new file mode 100644
index 0000000000..c26787fe24
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/invalid_spec_2/scala_data.erl
@@ -0,0 +1,5 @@
+-module(scala_data).
+
+-export_type([data/0]).
+
+-opaque data() :: {'data', term()}.
diff --git a/lib/dialyzer/test/small_SUITE_data/src/invalid_spec_2/scala_user.erl b/lib/dialyzer/test/small_SUITE_data/src/invalid_spec_2/scala_user.erl
new file mode 100644
index 0000000000..4e981f3b74
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/invalid_spec_2/scala_user.erl
@@ -0,0 +1,8 @@
+-module(scala_user).
+
+-export([is_list/2]).
+
+-spec is_list(atom(), scala_data:data()) -> boolean().
+
+is_list( List,Data) when is_list(List) -> true;
+is_list(Tuple,Data) when is_tuple(Tuple) -> false.
diff --git a/lib/eldap/src/Makefile b/lib/eldap/src/Makefile
index ebb7967e11..2e1110ec2c 100644
--- a/lib/eldap/src/Makefile
+++ b/lib/eldap/src/Makefile
@@ -88,7 +88,7 @@ $(TARGET_FILES): $(HRL_FILES)
# Special Build Targets
# ----------------------------------------------------
$(ASN1_HRL): ../asn1/$(ASN1_FILES)
- $(asn_verbose)$(ERLC) -o $(EBIN) -bber $(ERL_COMPILE_FLAGS) ../asn1/ELDAPv3.asn1
+ $(asn_verbose)$(ERLC) -o $(EBIN) +legacy_erlang_types -bber $(ERL_COMPILE_FLAGS) ../asn1/ELDAPv3.asn1
# ----------------------------------------------------
# Release Target
diff --git a/lib/eldap/test/eldap_misc_SUITE.erl b/lib/eldap/test/eldap_misc_SUITE.erl
new file mode 100644
index 0000000000..ca810ee33c
--- /dev/null
+++ b/lib/eldap/test/eldap_misc_SUITE.erl
@@ -0,0 +1,51 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2012-2014. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(eldap_misc_SUITE).
+
+-compile(export_all). %% Use this only in test suites...
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("eldap/include/eldap.hrl").
+-include_lib("eldap/ebin/ELDAPv3.hrl").
+
+all() ->
+ [
+ encode,
+ decode
+ ].
+
+
+encode(_Config) ->
+ {ok,Bin} = 'ELDAPv3':encode('AddRequest', #'AddRequest'{entry="hejHopp" ,attributes=[]} ),
+ Expected = <<104,11,4,7,104,101,106,72,111,112,112,48,0>>,
+ Expected = Bin.
+
+decode(_Config) ->
+ {ok,Res} = 'ELDAPv3':decode('AddRequest', <<104,11,4,7,104,101,106,72,111,112,112,48,0>>),
+ ct:log("Res = ~p", [Res]),
+ Expected = #'AddRequest'{entry = "hejHopp",attributes = []},
+ case Res of
+ Expected -> ok;
+ #'AddRequest'{entry= <<"hejHopp">>, attributes=[]} ->
+ {fail, "decoded to (correct) binary!!"};
+ _ ->
+ {fail, "Bad decode"}
+ end.
+
diff --git a/lib/erl_interface/aclocal.m4 b/lib/erl_interface/aclocal.m4
index c51c26794a..2b47f7c4bc 100644
--- a/lib/erl_interface/aclocal.m4
+++ b/lib/erl_interface/aclocal.m4
@@ -83,8 +83,10 @@ AC_ARG_VAR(erl_xcomp_ose_LM_POST_LINK, [OSE postlink tool (only used when cross
AC_ARG_VAR(erl_xcomp_ose_LM_SET_CONF, [Sets the configuration for an OSE load module (only used when cross compiling for OSE)])
AC_ARG_VAR(erl_xcomp_ose_LM_ELF_SIZE, [Prints the section size information for an OSE load module (only used when cross compiling for OSE)])
AC_ARG_VAR(erl_xcomp_ose_LM_LCF, [OSE load module linker configuration file (only used when cross compiling for OSE)])
-AC_ARG_VAR(erl_xcomp_ose_LM_CONF, [OSE load module default configuration file (only used when cross compiling for OSE)])
-AC_ARG_VAR(erl_xcomp_ose_CONFD, [OSE OSE confd source file])
+AC_ARG_VAR(erl_xcomp_ose_BEAM_LM_CONF, [BEAM OSE load module default configuration file (only used when cross compiling for OSE)])
+AC_ARG_VAR(erl_xcomp_ose_EPMD_LM_CONF, [EPMD OSE load module default configuration file (only used when cross compiling for OSE)])
+AC_ARG_VAR(erl_xcomp_ose_RUN_ERL_LM_CONF, [run_erl_lm OSE load module default configuration file (only used when cross compiling for OSE)])
+AC_ARG_VAR(erl_xcomp_ose_CONFD, [OSE confd source file])
AC_ARG_VAR(erl_xcomp_ose_CRT0_LM, [OSE crt0 lm source file])
])
diff --git a/lib/hipe/cerl/erl_types.erl b/lib/hipe/cerl/erl_types.erl
index 5938d94e65..28281a2fac 100644
--- a/lib/hipe/cerl/erl_types.erl
+++ b/lib/hipe/cerl/erl_types.erl
@@ -618,7 +618,7 @@ t_decorate_with_opaque(T1, T2, Opaques) ->
end
end.
-decorate(?none=Type, _, _Opaques) -> Type;
+decorate(Type, ?none, _Opaques) -> Type;
decorate(?function(Domain, Range), ?function(D, R), Opaques) ->
?function(decorate(Domain, D, Opaques), decorate(Range, R, Opaques));
decorate(?list(Types, Tail, Size), ?list(Ts, Tl, _Sz), Opaques) ->
@@ -684,6 +684,7 @@ union_decorate(U1, U2, Opaques) ->
List = [A,B,F,I,L,N,T,M,Map],
DecList = [Dec ||
E <- List,
+ not t_is_none(E),
not t_is_none(Dec = decorate(E, Opaque, Opaques))],
t_sup([Union|DecList]).
diff --git a/lib/hipe/rtl/hipe_icode2rtl.erl b/lib/hipe/rtl/hipe_icode2rtl.erl
index 034153a3cb..6ab40adcc8 100644
--- a/lib/hipe/rtl/hipe_icode2rtl.erl
+++ b/lib/hipe/rtl/hipe_icode2rtl.erl
@@ -427,8 +427,6 @@ gen_type_test([X], Type, TrueLbl, FalseLbl, Pred, ConstTab) ->
hipe_rtl:mk_branch(X, eq, TmpF, TrueLbl, FalseLbl, Pred)], ConstTab};
cons ->
{hipe_tagscheme:test_cons(X, TrueLbl, FalseLbl, Pred), ConstTab};
- constant ->
- {hipe_tagscheme:test_constant(X, TrueLbl, FalseLbl, Pred), ConstTab};
fixnum ->
{hipe_tagscheme:test_fixnum(X, TrueLbl, FalseLbl, Pred), ConstTab};
float ->
diff --git a/lib/hipe/rtl/hipe_tagscheme.erl b/lib/hipe/rtl/hipe_tagscheme.erl
index f1e8d1ef41..4725889d8d 100644
--- a/lib/hipe/rtl/hipe_tagscheme.erl
+++ b/lib/hipe/rtl/hipe_tagscheme.erl
@@ -40,13 +40,12 @@
test_any_pid/4, test_any_port/4,
test_ref/4, test_fun/4, test_fun2/5, test_matchstate/4,
test_binary/4, test_bitstr/4, test_list/4,
- test_integer/4, test_number/4, test_constant/4, test_tuple_N/5]).
+ test_integer/4, test_number/4, test_tuple_N/5]).
-export([realtag_fixnum/2, tag_fixnum/2, realuntag_fixnum/2, untag_fixnum/2]).
-export([test_two_fixnums/3, test_fixnums/4, unsafe_fixnum_add/3,
unsafe_fixnum_sub/3,
fixnum_gt/5, fixnum_lt/5, fixnum_ge/5, fixnum_le/5, fixnum_val/1,
- fixnum_mul/4,
- fixnum_addsub/5, fixnum_andorxor/4, fixnum_not/2,
+ fixnum_mul/4, fixnum_addsub/5, fixnum_andorxor/4, fixnum_not/2,
fixnum_bsr/3, fixnum_bsl/3]).
-export([unsafe_car/2, unsafe_cdr/2,
unsafe_constant_element/3, unsafe_update_element/3, element/6]).
@@ -405,17 +404,6 @@ test_number(X, TrueLab, FalseLab, Pred) ->
hipe_rtl:mk_branch(Tmp, 'eq', hipe_rtl:mk_imm(HeaderFlonum),
TrueLab, FalseLab, Pred)].
-%% CONS, NIL, and TUPLE are not constants, everything else is
-test_constant(X, TrueLab, FalseLab, Pred) ->
- Lab1 = hipe_rtl:mk_new_label(),
- Lab2 = hipe_rtl:mk_new_label(),
- Pred1 = 1-Pred,
- [test_cons(X, FalseLab, hipe_rtl:label_name(Lab1), Pred1),
- Lab1,
- test_nil(X, FalseLab, hipe_rtl:label_name(Lab2), Pred1),
- Lab2,
- test_tuple(X, FalseLab, TrueLab, Pred1)].
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
tag_fixnum(DestVar, SrcReg) ->
diff --git a/lib/inets/test/inets_sup_SUITE.erl b/lib/inets/test/inets_sup_SUITE.erl
index 12b85a816f..cf28f5a245 100644
--- a/lib/inets/test/inets_sup_SUITE.erl
+++ b/lib/inets/test/inets_sup_SUITE.erl
@@ -260,10 +260,10 @@ tftpd_worker(suite) ->
[];
tftpd_worker(Config) when is_list(Config) ->
[] = supervisor:which_children(tftp_sup),
- {ok, Pid0} = inets:start(tftpd, [{host, "localhost"},
- {port, inet_port()}]),
- {ok, _Pid1} = inets:start(tftpd, [{host, "localhost"},
- {port, inet_port()}], stand_alone),
+ {ok, Pid0} = inets:start(tftpd, [{host, inets_test_lib:hostname()},
+ {port, 0}]),
+ {ok, _Pid1} = inets:start(tftpd, [{host, inets_test_lib:hostname()},
+ {port, 0}], stand_alone),
[{_,Pid0, worker, _}] = supervisor:which_children(tftp_sup),
inets:stop(tftpd, Pid0),
@@ -397,13 +397,6 @@ httpc_subtree(Config) when is_list(Config) ->
tsp("httpc_subtree -> done"),
ok.
-inet_port() ->
- {ok, Socket} = gen_tcp:listen(0, [{reuseaddr, true}]),
- {ok, Port} = inet:port(Socket),
- gen_tcp:close(Socket),
- Port.
-
-
tsp(F) ->
tsp(F, []).
tsp(F, A) ->
diff --git a/lib/kernel/src/inet_config.erl b/lib/kernel/src/inet_config.erl
index 2461f3ff25..fdc244f959 100644
--- a/lib/kernel/src/inet_config.erl
+++ b/lib/kernel/src/inet_config.erl
@@ -197,6 +197,9 @@ do_load_resolv({win32,Type}, longnames) ->
win32_load_from_registry(Type),
inet_db:set_lookup([native]);
+do_load_resolv({ose,_}, _) ->
+ inet_db:set_lookup([file]);
+
do_load_resolv(_, _) ->
inet_db:set_lookup([native]).
diff --git a/lib/kernel/src/os.erl b/lib/kernel/src/os.erl
index 3bda391b8e..187fd0001b 100644
--- a/lib/kernel/src/os.erl
+++ b/lib/kernel/src/os.erl
@@ -67,7 +67,7 @@ unsetenv(_) ->
%%% End of BIFs
-spec type() -> {Osfamily, Osname} when
- Osfamily :: unix | win32,
+ Osfamily :: unix | win32 | ose,
Osname :: atom().
type() ->
diff --git a/lib/kernel/test/gen_tcp_misc_SUITE.erl b/lib/kernel/test/gen_tcp_misc_SUITE.erl
index ee8bfcceb1..a261766eaa 100644
--- a/lib/kernel/test/gen_tcp_misc_SUITE.erl
+++ b/lib/kernel/test/gen_tcp_misc_SUITE.erl
@@ -50,6 +50,14 @@
oct_acceptor/1,
otp_7731_server/1, zombie_server/2, do_iter_max_socks/2]).
+init_per_testcase(wrapping_oct, Config) when is_list(Config) ->
+ Dog = case os:type() of
+ {ose,_} ->
+ test_server:timetrap(test_server:minutes(20));
+ _Else ->
+ test_server:timetrap(test_server:seconds(600))
+ end,
+ [{watchdog, Dog}|Config];
init_per_testcase(iter_max_socks, Config) when is_list(Config) ->
Dog = case os:type() of
{win32,_} ->
@@ -58,6 +66,14 @@ init_per_testcase(iter_max_socks, Config) when is_list(Config) ->
test_server:timetrap(test_server:seconds(240))
end,
[{watchdog, Dog}|Config];
+init_per_testcase(accept_system_limit, Config) when is_list(Config) ->
+ case os:type() of
+ {ose,_} ->
+ {skip,"Skip in OSE"};
+ _ ->
+ Dog = test_server:timetrap(test_server:seconds(240)),
+ [{watchdog,Dog}|Config]
+ end;
init_per_testcase(_Func, Config) when is_list(Config) ->
Dog = test_server:timetrap(test_server:seconds(240)),
[{watchdog, Dog}|Config].
@@ -2705,13 +2721,11 @@ wrapping_oct(doc) ->
wrapping_oct(suite) ->
[];
wrapping_oct(Config) when is_list(Config) ->
- Dog = test_server:timetrap(test_server:seconds(600)),
{ok,Sock} = gen_tcp:listen(0,[{active,false},{mode,binary}]),
{ok,Port} = inet:port(Sock),
spawn_link(?MODULE,oct_acceptor,[Sock]),
Res = oct_datapump(Port,16#1FFFFFFFF),
gen_tcp:close(Sock),
- test_server:timetrap_cancel(Dog),
ok = Res,
ok.
diff --git a/lib/megaco/aclocal.m4 b/lib/megaco/aclocal.m4
index c51c26794a..2b47f7c4bc 100644
--- a/lib/megaco/aclocal.m4
+++ b/lib/megaco/aclocal.m4
@@ -83,8 +83,10 @@ AC_ARG_VAR(erl_xcomp_ose_LM_POST_LINK, [OSE postlink tool (only used when cross
AC_ARG_VAR(erl_xcomp_ose_LM_SET_CONF, [Sets the configuration for an OSE load module (only used when cross compiling for OSE)])
AC_ARG_VAR(erl_xcomp_ose_LM_ELF_SIZE, [Prints the section size information for an OSE load module (only used when cross compiling for OSE)])
AC_ARG_VAR(erl_xcomp_ose_LM_LCF, [OSE load module linker configuration file (only used when cross compiling for OSE)])
-AC_ARG_VAR(erl_xcomp_ose_LM_CONF, [OSE load module default configuration file (only used when cross compiling for OSE)])
-AC_ARG_VAR(erl_xcomp_ose_CONFD, [OSE OSE confd source file])
+AC_ARG_VAR(erl_xcomp_ose_BEAM_LM_CONF, [BEAM OSE load module default configuration file (only used when cross compiling for OSE)])
+AC_ARG_VAR(erl_xcomp_ose_EPMD_LM_CONF, [EPMD OSE load module default configuration file (only used when cross compiling for OSE)])
+AC_ARG_VAR(erl_xcomp_ose_RUN_ERL_LM_CONF, [run_erl_lm OSE load module default configuration file (only used when cross compiling for OSE)])
+AC_ARG_VAR(erl_xcomp_ose_CONFD, [OSE confd source file])
AC_ARG_VAR(erl_xcomp_ose_CRT0_LM, [OSE crt0 lm source file])
])
diff --git a/lib/odbc/aclocal.m4 b/lib/odbc/aclocal.m4
index c51c26794a..2b47f7c4bc 100644
--- a/lib/odbc/aclocal.m4
+++ b/lib/odbc/aclocal.m4
@@ -83,8 +83,10 @@ AC_ARG_VAR(erl_xcomp_ose_LM_POST_LINK, [OSE postlink tool (only used when cross
AC_ARG_VAR(erl_xcomp_ose_LM_SET_CONF, [Sets the configuration for an OSE load module (only used when cross compiling for OSE)])
AC_ARG_VAR(erl_xcomp_ose_LM_ELF_SIZE, [Prints the section size information for an OSE load module (only used when cross compiling for OSE)])
AC_ARG_VAR(erl_xcomp_ose_LM_LCF, [OSE load module linker configuration file (only used when cross compiling for OSE)])
-AC_ARG_VAR(erl_xcomp_ose_LM_CONF, [OSE load module default configuration file (only used when cross compiling for OSE)])
-AC_ARG_VAR(erl_xcomp_ose_CONFD, [OSE OSE confd source file])
+AC_ARG_VAR(erl_xcomp_ose_BEAM_LM_CONF, [BEAM OSE load module default configuration file (only used when cross compiling for OSE)])
+AC_ARG_VAR(erl_xcomp_ose_EPMD_LM_CONF, [EPMD OSE load module default configuration file (only used when cross compiling for OSE)])
+AC_ARG_VAR(erl_xcomp_ose_RUN_ERL_LM_CONF, [run_erl_lm OSE load module default configuration file (only used when cross compiling for OSE)])
+AC_ARG_VAR(erl_xcomp_ose_CONFD, [OSE confd source file])
AC_ARG_VAR(erl_xcomp_ose_CRT0_LM, [OSE crt0 lm source file])
])
diff --git a/lib/ose/doc/src/ose_intro.xml b/lib/ose/doc/src/ose_intro.xml
index 0dd3ec409e..b5e3ef8b33 100644
--- a/lib/ose/doc/src/ose_intro.xml
+++ b/lib/ose/doc/src/ose_intro.xml
@@ -78,7 +78,7 @@ rtose@acp3400> pm_start 0x110059</code>
seperate machine the paths have to be updated. In the example above
<c>/usr/local/lib/erlang</c> was replaced by <c>/mst/erlang/</c>. The
goal is to in future releases not have to do the special argument handling
- but for now (17.0-rc2) you have to do it.
+ but for now (OTP 17.0) you have to do it.
</p>
<note>
Because of a limitation in the way the OSE handles stdio when starting
@@ -146,7 +146,7 @@ os:type().
It is possible to set the priorities you want for the OSE processes that
thr emulator creates in the lmconf. An example of how to do it can be
found in the default lmconf file in
- $ERL_TOP/erts/emulator/sys/ose/default.lmconf.
+ $ERL_TOP/erts/emulator/sys/ose/beam.lmconf.
</p>
</section>
diff --git a/lib/public_key/src/pubkey_cert.erl b/lib/public_key/src/pubkey_cert.erl
index dc8d68c78f..ae517ca642 100644
--- a/lib/public_key/src/pubkey_cert.erl
+++ b/lib/public_key/src/pubkey_cert.erl
@@ -319,6 +319,8 @@ verify_fun(Otpcert, Result, UserState0, VerifyFun) ->
%%
%% Description: Extracts a specific extension from a list of extensions.
%%--------------------------------------------------------------------
+select_extension(_, asn1_NOVALUE) ->
+ undefined;
select_extension(_, []) ->
undefined;
select_extension(Id, [#'Extension'{extnID = Id} = Extension | _]) ->
@@ -342,8 +344,11 @@ match_name(uniformResourceIdentifier, URI, [PermittedName | Rest]) ->
incomplete ->
false;
{_, _, Host, _, _} ->
- match_name(fun is_valid_host_or_domain/2, Host,
- PermittedName, Rest)
+ PN = case split_uri(PermittedName) of
+ {_, _, PNhost, _, _} -> PNhost;
+ _X -> PermittedName
+ end,
+ match_name(fun is_valid_host_or_domain/2, Host, PN, Rest)
end;
match_name(emailAddress, Name, [PermittedName | Rest]) ->
@@ -511,10 +516,10 @@ is_dir_name2(Value, Value) -> true;
is_dir_name2({printableString, Value1}, {printableString, Value2}) ->
string:to_lower(strip_spaces(Value1)) =:=
string:to_lower(strip_spaces(Value2));
-is_dir_name2({utf8String, Value1}, String) -> %% BUGBUG FIX UTF8 conv
- is_dir_name2({printableString, binary_to_list(Value1)}, String);
-is_dir_name2(String, {utf8String, Value1}) -> %% BUGBUG FIX UTF8 conv
- is_dir_name2(String, {printableString, binary_to_list(Value1)});
+is_dir_name2({utf8String, Value1}, String) ->
+ is_dir_name2({printableString, unicode:characters_to_list(Value1)}, String);
+is_dir_name2(String, {utf8String, Value1}) ->
+ is_dir_name2(String, {printableString, unicode:characters_to_list(Value1)});
is_dir_name2(_, _) ->
false.
diff --git a/lib/public_key/src/pubkey_crl.erl b/lib/public_key/src/pubkey_crl.erl
index eaba5bfa1b..f0df4bc3f2 100644
--- a/lib/public_key/src/pubkey_crl.erl
+++ b/lib/public_key/src/pubkey_crl.erl
@@ -39,7 +39,13 @@ validate(OtpCert, OtherDPCRLs, DP, {DerCRL, CRL}, {DerDeltaCRL, DeltaCRL},
CertIssuer = TBSCert#'OTPTBSCertificate'.issuer,
TBSCRL = CRL#'CertificateList'.tbsCertList,
CRLIssuer = TBSCRL#'TBSCertList'.issuer,
- AltNames = subject_alt_names(TBSCert#'OTPTBSCertificate'.extensions),
+ AltNames = case pubkey_cert:select_extension(?'id-ce-subjectAltName',
+ TBSCert#'OTPTBSCertificate'.extensions) of
+ undefined ->
+ [];
+ Ext ->
+ Ext#'Extension'.extnValue
+ end,
revoked_status(DP, IDP, {directoryName, CRLIssuer},
[ {directoryName, CertIssuer} | AltNames], SerialNumber, Revoked,
DeltaRevoked, RevokedState1);
@@ -397,16 +403,18 @@ verify_dp_name(IDPNames, DPorIssuerNames) ->
match_one([], _) ->
false;
match_one([{Type, Name} | Names], CandidateNames) ->
- Candidates = [NameName || {NameType, NameName} <- CandidateNames, NameType == Type],
+ Candidates = [NameName || {NameType, NameName} <- CandidateNames,
+ NameType == Type],
case Candidates of
[] ->
false;
- [_|_] -> case pubkey_cert:match_name(Type, Name, Candidates) of
- true ->
- true;
- false ->
- match_one(Names, CandidateNames)
- end
+ [_|_] ->
+ case pubkey_cert:match_name(Type, Name, Candidates) of
+ true ->
+ true;
+ false ->
+ match_one(Names, CandidateNames)
+ end
end.
verify_dp_bools(TBSCert, IDP) ->
@@ -664,6 +672,8 @@ verify_extensions([#'TBSCertList_revokedCertificates_SEQOF'{crlEntryExtensions =
verify_extensions(pubkey_cert:extensions_list(Ext)) and verify_extensions(Rest);
verify_extensions([]) ->
true;
+verify_extensions(asn1_NOVALUE) ->
+ true;
verify_extensions([#'Extension'{critical = true, extnID = Id} | Rest]) ->
case lists:member(Id, [?'id-ce-authorityKeyIdentifier',
?'id-ce-issuerAltName',
@@ -689,13 +699,3 @@ authority_key_identifier(Extensions) ->
Enc = extension_value(?'id-ce-authorityKeyIdentifier',
'AuthorityKeyIdentifier', Extensions),
pubkey_cert_records:transform(Enc, decode).
-
-subject_alt_names(Extensions) ->
- Enc = extension_value(?'id-ce-subjectAltName',
- 'GeneralNames', Extensions),
- case Enc of
- undefined ->
- [];
- _ ->
- pubkey_cert_records:transform(Enc, decode)
- end.
diff --git a/lib/sasl/src/systools_make.erl b/lib/sasl/src/systools_make.erl
index 3d370a93a5..e5da797efb 100644
--- a/lib/sasl/src/systools_make.erl
+++ b/lib/sasl/src/systools_make.erl
@@ -2233,7 +2233,7 @@ format_error({undefined_applications,Apps}) ->
io_lib:format("Undefined applications: ~p~n",[Apps]);
format_error({duplicate_modules,Dups}) ->
io_lib:format("Duplicated modules: ~n~ts",
- [map(fun({{Mod,_,App1,_,_},{Mod,_,App2,_,_}}) ->
+ [map(fun({{Mod,App1,_},{Mod,App2,_}}) ->
io_lib:format("\t~w specified in ~w and ~w~n",
[Mod,App1,App2])
end, Dups)]);
diff --git a/lib/sasl/test/systools_SUITE.erl b/lib/sasl/test/systools_SUITE.erl
index e3f6933476..1d3a71e94e 100644
--- a/lib/sasl/test/systools_SUITE.erl
+++ b/lib/sasl/test/systools_SUITE.erl
@@ -47,6 +47,7 @@
abnormal_script/1, src_tests_script/1, crazy_script/1,
included_script/1, included_override_script/1,
included_fail_script/1, included_bug_script/1, exref_script/1,
+ duplicate_modules_script/1,
otp_3065_circular_dependenies/1, included_and_used_sort_script/1]).
-export([tar_options/1, normal_tar/1, no_mod_vsn_tar/1, system_files_tar/1,
system_files_tar/2, invalid_system_files_tar/1,
@@ -84,6 +85,7 @@ groups() ->
src_tests_script, crazy_script,
included_script, included_override_script,
included_fail_script, included_bug_script, exref_script,
+ duplicate_modules_script,
otp_3065_circular_dependenies, included_and_used_sort_script]},
{tar, [],
[tar_options, normal_tar, no_mod_vsn_tar, system_files_tar,
@@ -822,6 +824,33 @@ no_hipe({ok, Value}) ->
{ok, Value}
end.
+%% duplicate_modules_script: Check that make_script rejects two
+%% applications providing the same module.
+duplicate_modules_script(Config) when is_list(Config) ->
+ {ok, OldDir} = file:get_cwd(),
+
+ {LatestDir, LatestName} = create_script(duplicate_modules,Config),
+
+ DataDir = filename:absname(?copydir),
+
+ ok = file:set_cwd(LatestDir),
+ LibDir = fname([DataDir, d_duplicate_modules, lib]),
+ P = [fname([LibDir, 'app1-1.0', ebin]),
+ fname([LibDir, 'app2-1.0', ebin])],
+
+ %% Check wrong app vsn
+ error = systools:make_script(LatestName, [{path, P}]),
+ {error,
+ systools_make,
+ {duplicate_modules, [
+ {{myapp,app1,_}, {myapp,app2,_}}
+ ]
+ }
+ } = systools:make_script(LatestName, [silent, {path, P}]),
+
+ ok = file:set_cwd(OldDir),
+ ok.
+
%% tar_options: Check illegal tar options.
tar_options(Config) when is_list(Config) ->
{'EXIT',{{badarg,[{path,["Path",12,"Another"]}]}, _}} =
@@ -2186,7 +2215,10 @@ create_script(current_all_future_sasl,Config) ->
do_create_script(current_all_future_sasl,Config,current,Apps);
create_script({unicode,RelVsn},Config) ->
Apps = core_apps(current) ++ [{ua,"1.0"}],
- do_create_script(unicode,RelVsn,Config,current,Apps).
+ do_create_script(unicode,RelVsn,Config,current,Apps);
+create_script(duplicate_modules,Config) ->
+ Apps = core_apps(current) ++ [{app1,"1.0"},{app2,"1.0"}],
+ do_create_script(duplicate_modules,Config,current,Apps).
do_create_script(Id,Config,ErtsVsn,AppVsns) ->
diff --git a/lib/sasl/test/systools_SUITE_data/d_duplicate_modules/lib/app1-1.0/ebin/app1.app b/lib/sasl/test/systools_SUITE_data/d_duplicate_modules/lib/app1-1.0/ebin/app1.app
new file mode 100644
index 0000000000..dea9257f2f
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_duplicate_modules/lib/app1-1.0/ebin/app1.app
@@ -0,0 +1,7 @@
+{application, app1,
+ [{description, "Application 1"},
+ {vsn, "1.0"},
+ {modules, [myapp]},
+ {registered, []},
+ {applications, []},
+ {env, []}]}.
diff --git a/lib/sasl/test/systools_SUITE_data/d_duplicate_modules/lib/app1-1.0/src/myapp.erl b/lib/sasl/test/systools_SUITE_data/d_duplicate_modules/lib/app1-1.0/src/myapp.erl
new file mode 100644
index 0000000000..bf2ab7c79c
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_duplicate_modules/lib/app1-1.0/src/myapp.erl
@@ -0,0 +1,2 @@
+-module(myapp).
+-vsn("1.0").
diff --git a/lib/sasl/test/systools_SUITE_data/d_duplicate_modules/lib/app2-1.0/ebin/app2.app b/lib/sasl/test/systools_SUITE_data/d_duplicate_modules/lib/app2-1.0/ebin/app2.app
new file mode 100644
index 0000000000..476750d8b2
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_duplicate_modules/lib/app2-1.0/ebin/app2.app
@@ -0,0 +1,7 @@
+{application, app2,
+ [{description, "Application 2"},
+ {vsn, "1.0"},
+ {modules, [myapp]},
+ {registered, []},
+ {applications, []},
+ {env, []}]}.
diff --git a/lib/sasl/test/systools_SUITE_data/d_duplicate_modules/lib/app2-1.0/src/myapp.erl b/lib/sasl/test/systools_SUITE_data/d_duplicate_modules/lib/app2-1.0/src/myapp.erl
new file mode 100644
index 0000000000..bf2ab7c79c
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_duplicate_modules/lib/app2-1.0/src/myapp.erl
@@ -0,0 +1,2 @@
+-module(myapp).
+-vsn("1.0").
diff --git a/lib/snmp/test/Makefile b/lib/snmp/test/Makefile
index f22b7ea8ee..7bc9dd07d4 100644
--- a/lib/snmp/test/Makefile
+++ b/lib/snmp/test/Makefile
@@ -93,10 +93,10 @@ ifeq ($(SNMP_DEBUG),e)
SNMP_FLAGS += -Dsnmp_error
endif
ifeq ($(SNMP_DEBUG),l)
- SNMP_FLAGS += -Dsnmp_log
+ SNMP_FLAGS += -Dsnmp_error -Dsnmp_log
endif
ifeq ($(SNMP_DEBUG),d)
- SNMP_FLAGS += -Dsnmp_debug
+ SNMP_FLAGS += -Dsnmp_error -Dsnmp_log -Dsnmp_debug
endif
ifeq ($(DONT_USE_TS),true)
diff --git a/lib/snmp/test/modules.mk b/lib/snmp/test/modules.mk
index 3d658bf8e8..fd8315ec4d 100644
--- a/lib/snmp/test/modules.mk
+++ b/lib/snmp/test/modules.mk
@@ -2,7 +2,7 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2012. All Rights Reserved.
+# Copyright Ericsson AB 2004-2014. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -42,6 +42,7 @@ TEST_UTIL_MODULES = \
snmp_test_manager \
snmp_test_mgr \
snmp_test_mgr_misc \
+ snmp_test_mgr_counter_server \
sa \
klas3 \
test1 \
diff --git a/lib/snmp/test/snmp_agent_test.erl b/lib/snmp/test/snmp_agent_test.erl
index 89a6ce1253..2a9f2e842d 100644
--- a/lib/snmp/test/snmp_agent_test.erl
+++ b/lib/snmp/test/snmp_agent_test.erl
@@ -19,10 +19,6 @@
-module(snmp_agent_test).
-%% TODO
-%% * Test fault-tolerance (kill master etc)
-%%
-
-export([
all/0,
groups/0,
@@ -41,7 +37,7 @@
v1_processing/1,
big/1,
big2/1,
- loop_mib/1,
+ loop_mib_1/1,
api/1,
subagent/1,
mnesia/1,
@@ -394,8 +390,9 @@
usm_read/0,
usm_del_user/0,
usm_bad/0,
- loop_mib_1/0,
- loop_mib_2/0,
+ loop_mib_1_test/0,
+ loop_mib_2_test/0,
+ loop_mib_3_test/0,
otp_1129_i/1,
otp_1162_test/0,
otp_1131_test/0,
@@ -546,8 +543,9 @@ groups() ->
init_per_suite(Config0) when is_list(Config0) ->
- ?DBG("init_per_suite -> entry with"
- "~n Config0: ~p", [Config0]),
+ p("init_per_suite -> entry with"
+ "~n Config: ~p"
+ "~n Nodes: ~p", [Config0, erlang:nodes()]),
Config1 = snmp_test_lib:init_suite_top_dir(?MODULE, Config0),
Config2 = snmp_test_lib:fix_data_dir(Config1),
@@ -558,16 +556,32 @@ init_per_suite(Config0) when is_list(Config0) ->
Config3 = [{mib_dir, MibDir}, {std_mib_dir, StdMibDir} | Config2],
- ?DBG("init_per_suite -> end with"
- "~n Config3: ~p", [Config3]),
+ snmp_test_mgr_counter_server:start(),
+
+ p("init_per_suite -> end when"
+ "~n Config: ~p"
+ "~n Nodes: ~p", [Config3, erlang:nodes()]),
Config3.
end_per_suite(Config) when is_list(Config) ->
- ?DBG("end_per_suite -> entry with"
- "~n Config: ~p", [Config]),
+ p("end_per_suite -> entry with"
+ "~n Config: ~p"
+ "~n Nodes: ~p", [Config, erlang:nodes()]),
+
+ case snmp_test_mgr_counter_server:stop() of
+ {ok, _Counters} ->
+ p("end_per_suite -> sucessfully stopped counter server"
+ "~n Counters: ~p", [_Counters]);
+
+ {error, Reason} ->
+ p("end_per_suite -> failed stopping counter server"
+ "~n Reason: ~p", [Reason])
+ end,
+ p("end_per_suite -> end when"
+ "~n Nodes: ~p", [erlang:nodes()]),
Config.
@@ -675,10 +689,16 @@ end_per_group(_GroupName, Config) ->
%% ---- Init Per TestCase ----
init_per_testcase(Case, Config) when is_list(Config) ->
- ?DBG("init_per_testcase -> entry with"
- "~n Config: ~p", [Config]),
+ p("init_per_testcase -> entry with"
+ "~n Config: ~p"
+ "~n Nodes: ~p", [Config, erlang:nodes()]),
- init_per_testcase1(Case, Config).
+ Result = init_per_testcase1(Case, Config),
+
+ p("init_per_testcase -> done when"
+ "~n Result: ~p"
+ "~n Nodes: ~p", [Result, erlang:nodes()]),
+ Result.
init_per_testcase1(otp8395 = Case, Config) when is_list(Config) ->
?DBG("init_per_testcase1 -> entry with"
@@ -719,12 +739,18 @@ init_per_testcase1(_Case, Config) when is_list(Config) ->
%% ---- End Per TestCase ----
end_per_testcase(Case, Config) when is_list(Config) ->
- ?DBG("end_per_testcase -> entry with"
- "~n Config: ~p", [Config]),
+ p("end_per_testcase -> entry with"
+ "~n Config: ~p"
+ "~n Nodes: ~p", [Config, erlang:nodes()]),
display_log(Config),
- end_per_testcase1(Case, Config).
+ Result = end_per_testcase1(Case, Config),
+
+ p("end_per_testcase -> done with"
+ "~n Result: ~p"
+ "~n Nodes: ~p", [Result, erlang:nodes()]),
+ Result.
end_per_testcase1(otp8395, Config) when is_list(Config) ->
otp8395({fin, Config});
@@ -1173,7 +1199,7 @@ mse_simple(X) -> ?P(mse_simple), simple(X).
mse_v1_processing(X) -> ?P(mse_v1_processing), v1_processing(X).
mse_big(X) -> ?P(mse_big), big(X).
mse_big2(X) -> ?P(mse_big2), big2(X).
-mse_loop_mib(X) -> ?P(mse_loop_mib), loop_mib(X).
+mse_loop_mib(X) -> ?P(mse_loop_mib), loop_mib_1(X).
mse_api(X) -> ?P(mse_api), api(X).
mse_sa_register(X) -> ?P(mse_sa_register), sa_register(X).
mse_v1_trap(X) -> ?P(mse_v1_trap), v1_trap(X).
@@ -1194,7 +1220,7 @@ msd_simple(X) -> ?P(msd_simple), simple(X).
msd_v1_processing(X) -> ?P(msd_v1_processing), v1_processing(X).
msd_big(X) -> ?P(msd_big), big(X).
msd_big2(X) -> ?P(msd_big2), big2(X).
-msd_loop_mib(X) -> ?P(msd_loop_mib), loop_mib(X).
+msd_loop_mib(X) -> ?P(msd_loop_mib), loop_mib_1(X).
msd_api(X) -> ?P(msd_api), api(X).
msd_sa_register(X) -> ?P(msd_sa_register), sa_register(X).
msd_v1_trap(X) -> ?P(msd_v1_trap), v1_trap(X).
@@ -1215,7 +1241,7 @@ msm_simple(X) -> ?P(msm_simple), simple(X).
msm_v1_processing(X) -> ?P(msm_v1_processing), v1_processing(X).
msm_big(X) -> ?P(msm_big2), big(X).
msm_big2(X) -> ?P(msm_loop_mib), big2(X).
-msm_loop_mib(X) -> ?P(msm_loop_mib), loop_mib(X).
+msm_loop_mib(X) -> ?P(msm_loop_mib), loop_mib_1(X).
msm_api(X) -> ?P(msm_api), api(X).
msm_sa_register(X) -> ?P(msm_sa_register), sa_register(X).
msm_v1_trap(X) -> ?P(msm_v1_trap), v1_trap(X).
@@ -1618,7 +1644,7 @@ v1_cases() ->
v1_processing,
big,
big2,
- loop_mib,
+ loop_mib_1,
api,
subagent,
mnesia,
@@ -2095,9 +2121,9 @@ await_dummy_manager_started(Pid) ->
{ok,Pid,Port};
{'EXIT', Pid, Reason} ->
{error, Pid, Reason};
- O ->
+ _O ->
?LOG("dummy_manager_start -> received unknown message:"
- "~n ~p",[O]),
+ "~n ~p",[_O]),
await_dummy_manager_started(Pid)
end.
@@ -2120,16 +2146,16 @@ dummy_manager_send_trap2(Pid) ->
dummy_manager_await_trap2_ack() ->
?DBG("dummy_manager_await_trap2 -> entry",[]),
receive
- {received_trap,Trap} ->
- ?LOG("dummy_manager_await_trap2 -> received trap: ~p",[Trap]),
+ {received_trap, _Trap} ->
+ ?LOG("dummy_manager_await_trap2 -> received trap: ~p", [_Trap]),
%% Note:
%% Without this sleep the v2_inform_i testcase failes! There
%% is no relation between these two test cases as far as I
%% able to figure out...
?SLEEP(60000),
ok;
- O ->
- ?ERR("dummy_manager_await_trap2 -> unexpected message: ~p",[O]),
+ _O ->
+ ?ERR("dummy_manager_await_trap2 -> unexpected message: ~p",[_O]),
ok
after 10000 ->
?ERR("dummy_manager_await_trap2 -> timeout",[]),
@@ -2155,32 +2181,34 @@ dummy_manager_loop(P,S,MA) ->
"~n Trap: ~p",[Trap]),
snmpa:send_trap(MA, Trap, "standard trap"),
dummy_manager_loop(P,S,MA);
- {udp, _UdpId, Ip, UdpPort, Bytes} ->
+ {udp, _UdpId, _Ip, _UdpPort, Bytes} ->
?LOG("dummy_manager_loop -> received upd message"
"~n from: ~p:~p"
"~n size: ~p",
- [Ip, UdpPort, dummy_manager_message_sz(Bytes)]),
+ [_Ip, _UdpPort, dummy_manager_message_sz(Bytes)]),
R = dummy_manager_handle_message(Bytes),
- ?DBG("dummy_manager_loop -> R: ~p",[R]),
+ ?DBG("dummy_manager_loop -> R: ~p", [R]),
P ! R,
- dummy_manager_loop(P,S,MA);
+ dummy_manager_loop(P, S, MA);
stop ->
?DBG("dummy_manager_loop -> received stop request",[]),
P ! {dummy_manager_stopping, self()},
gen_udp:close(S),
exit(normal);
- O ->
+ _O ->
?LOG("dummy_manager_loop -> received unknown message:"
- "~n ~p",[O]),
- dummy_manager_loop(P,S,MA)
+ "~n ~p", [_O]),
+ dummy_manager_loop(P, S, MA)
end.
+-ifdef(snmp_log).
dummy_manager_message_sz(B) when is_binary(B) ->
size(B);
dummy_manager_message_sz(L) when is_list(L) ->
length(L);
dummy_manager_message_sz(_) ->
undefined.
+-endif.
dummy_manager_handle_message(Bytes) ->
case (catch snmp_pdus:dec_message(Bytes)) of
@@ -3398,11 +3426,11 @@ simple_standard_test() ->
db_notify_client(suite) -> [];
db_notify_client(Config) when is_list(Config) ->
?P(db_notify_client),
- {SaNode, MgrNode, MibDir} = init_case(Config),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
?DBG("db_notify_client -> case initiated: "
"~n SaNode: ~p"
"~n MgrNode: ~p"
- "~n MibDir: ~p", [SaNode, MgrNode, MibDir]),
+ "~n MibDir: ~p", [_SaNode, _MgrNode, _MibDir]),
?DBG("db_notify_client -> maximize verbosity", []),
snmpa_local_db:verbosity(trace),
Self = self(),
@@ -4153,8 +4181,8 @@ ma_v2_inform1(MA) ->
CmdExp =
fun(ok) ->
ok;
- ({ok, Val}) ->
- ?DBG("ma_v2_inform -> [cmd2] Val: ~p", [Val]),
+ ({ok, _Val}) ->
+ ?DBG("ma_v2_inform -> [cmd2] Val: ~p", [_Val]),
ok;
({error, Id, Extra}) ->
{error, {unexpected, Id, Extra}};
@@ -4189,10 +4217,10 @@ ma_v2_inform1(MA) ->
CmdSnmpTargets =
fun(T) ->
receive
- {snmp_targets, T, [Addr]} ->
+ {snmp_targets, T, [_Addr]} ->
?DBG("ma_v2_inform1 -> "
"received expected snmp_targets "
- "~n with receiver: ~p",[Addr]),
+ "~n with receiver: ~p", [_Addr]),
ok;
{snmp_targets, T, Addrs} ->
?ERR("ma_v2_inform1 -> "
@@ -4210,16 +4238,16 @@ ma_v2_inform1(MA) ->
Cmd06 =
fun() ->
receive
- {snmp_notification, Tag03, {got_response, Addr}} ->
+ {snmp_notification, Tag03, {got_response, _Addr}} ->
?DBG("ma_v2_inform1 -> "
"received expected snmp_notification "
- "[with manager response] from: ~n ~p",[Addr]),
+ "[with manager response] from: ~n ~p", [_Addr]),
ok;
- {snmp_notification, Tag03, {no_response, Addr}} ->
+ {snmp_notification, Tag03, {no_response, _Addr}} ->
?ERR("ma_v2_inform1 -> "
"received unexpected snmp_notification "
"[without manager response] from: ~n ~p",
- [Addr]),
+ [_Addr]),
{error, no_response}
after
20000 ->
@@ -4249,16 +4277,16 @@ ma_v2_inform1(MA) ->
Cmd10 =
fun() ->
receive
- {snmp_notification, Tag07, {got_response, Addr}} ->
+ {snmp_notification, Tag07, {got_response, _Addr}} ->
?ERR("ma_v2_inform1 -> "
"received unexpected snmp_notification "
- "[with manager response] from: ~n ~p", [Addr]),
+ "[with manager response] from: ~n ~p", [_Addr]),
{error, got_response};
- {snmp_notification, Tag07, {no_response, Addr}} ->
+ {snmp_notification, Tag07, {no_response, _Addr}} ->
?DBG("ma_v2_inform1 -> "
"received expected snmp_notification "
"[without manager response] from: ~n ~p",
- [Addr]),
+ [_Addr]),
ok
after
240000 ->
@@ -4302,8 +4330,8 @@ ma_v2_inform2(MA) ->
CmdExp =
fun(ok) ->
ok;
- ({ok, Val}) ->
- ?DBG("ma_v2_inform -> [cmd2] Val: ~p", [Val]),
+ ({ok, _Val}) ->
+ ?DBG("ma_v2_inform -> [cmd2] Val: ~p", [_Val]),
ok;
({error, Id, Extra}) ->
{error, {unexpected, Id, Extra}};
@@ -4383,8 +4411,8 @@ ma_v2_inform3(MA) ->
"~n send notification: testTrapv22", [MA]),
CmdExpectInform =
- fun(No, Response) ->
- ?DBG("CmdExpectInform -> ~p: ~n~p", [No, Response]),
+ fun(_No, Response) ->
+ ?DBG("CmdExpectInform -> ~p: ~n~p", [_No, Response]),
?expect2({inform, Response},
[{[sysUpTime, 0], any},
{[snmpTrapOID, 0], ?system ++ [0,1]}])
@@ -4393,8 +4421,8 @@ ma_v2_inform3(MA) ->
CmdExp =
fun(ok) ->
ok;
- ({ok, Val}) ->
- ?DBG("CmdExp -> Val: ~p", [Val]),
+ ({ok, _Val}) ->
+ ?DBG("CmdExp -> Val: ~p", [_Val]),
ok;
({error, Id, Extra}) ->
{error, {unexpected, Id, Extra}};
@@ -4505,17 +4533,17 @@ delivery_info(Tag, Address, DeliveryResult, Extra) ->
command_handler([]) ->
ok;
-command_handler([{No, Desc, Cmd}|Rest]) ->
- ?LOG("command_handler -> command ~w: ~n ~s", [No, Desc]),
+command_handler([{_No, _Desc, Cmd}|Rest]) ->
+ ?LOG("command_handler -> command ~w: ~n ~s", [_No, _Desc]),
case (catch Cmd()) of
ok ->
- ?LOG("command_handler -> ~w: ok",[No]),
+ ?LOG("command_handler -> ~w: ok", [_No]),
command_handler(Rest);
{error, Reason} ->
- ?ERR("command_handler -> ~w error: ~n~p",[No, Reason]),
+ ?ERR("command_handler -> ~w error: ~n~p", [_No, Reason]),
?line ?FAIL(Reason);
Error ->
- ?ERR("command_handler -> ~w unexpected: ~n~p",[No, Error]),
+ ?ERR("command_handler -> ~w unexpected: ~n~p", [_No, Error]),
?line ?FAIL({unexpected_command_result, Error})
end.
@@ -5516,57 +5544,59 @@ usm_bad() ->
%% works.
%% Load all std mibs that are not loaded by default.
%%-----------------------------------------------------------------
-loop_mib(suite) -> [];
-loop_mib(Config) when is_list(Config) ->
- ?P(loop_mib),
- ?LOG("loop_mib -> initiate case",[]),
+loop_mib_1(suite) -> [];
+loop_mib_1(Config) when is_list(Config) ->
+ ?P(loop_mib_1),
+ ?LOG("loop_mib_1 -> initiate case",[]),
%% snmpa:verbosity(master_agent,debug),
%% snmpa:verbosity(mib_server,info),
- {SaNode, MgrNode, MibDir} = init_case(Config),
- ?DBG("loop_mib -> ~n"
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?DBG("loop_mib_1 -> ~n"
"\tSaNode: ~p~n"
"\tMgrNode: ~p~n"
- "\tMibDir: ~p",[SaNode, MgrNode, MibDir]),
- ?DBG("loop_mib -> load mib SNMP-COMMUNITY-MIB",[]),
+ "\tMibDir: ~p", [_SaNode, _MgrNode, _MibDir]),
+ ?DBG("loop_mib_1 -> load mib SNMP-COMMUNITY-MIB",[]),
?line load_master_std("SNMP-COMMUNITY-MIB"),
- ?DBG("loop_mib -> load mib SNMP-MPD-MIB",[]),
+ ?DBG("loop_mib_1 -> load mib SNMP-MPD-MIB",[]),
?line load_master_std("SNMP-MPD-MIB"),
- ?DBG("loop_mib -> load mib SNMP-TARGET-MIB",[]),
+ ?DBG("loop_mib_1 -> load mib SNMP-TARGET-MIB",[]),
?line load_master_std("SNMP-TARGET-MIB"),
- ?DBG("loop_mib -> load mib SNMP-NOTIFICATION-MIB",[]),
+ ?DBG("loop_mib_1 -> load mib SNMP-NOTIFICATION-MIB",[]),
?line load_master_std("SNMP-NOTIFICATION-MIB"),
- ?DBG("loop_mib -> load mib SNMP-FRAMEWORK-MIB",[]),
+ ?DBG("loop_mib_1 -> load mib SNMP-FRAMEWORK-MIB",[]),
?line load_master_std("SNMP-FRAMEWORK-MIB"),
- ?DBG("loop_mib -> load mib SNMP-VIEW-BASED-ACM-MIB",[]),
+ ?DBG("loop_mib_1 -> load mib SNMP-VIEW-BASED-ACM-MIB",[]),
?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
- ?DBG("loop_mib -> try",[]),
- try_test(loop_mib_1),
- ?DBG("loop_mib -> unload mib SNMP-COMMUNITY-MIB",[]),
+ ?DBG("loop_mib_1 -> try",[]),
+
+ try_test(loop_mib_1_test),
+
+ ?DBG("loop_mib_1 -> unload mib SNMP-COMMUNITY-MIB",[]),
?line unload_master("SNMP-COMMUNITY-MIB"),
- ?DBG("loop_mib -> unload mib SNMP-MPD-MIB",[]),
+ ?DBG("loop_mib_1 -> unload mib SNMP-MPD-MIB",[]),
?line unload_master("SNMP-MPD-MIB"),
- ?DBG("loop_mib -> unload mib SNMP-TARGET-MIB",[]),
+ ?DBG("loop_mib_1 -> unload mib SNMP-TARGET-MIB",[]),
?line unload_master("SNMP-TARGET-MIB"),
- ?DBG("loop_mib -> unload mib SNMP-NOTIFICATION-MIB",[]),
+ ?DBG("loop_mib_1 -> unload mib SNMP-NOTIFICATION-MIB",[]),
?line unload_master("SNMP-NOTIFICATION-MIB"),
- ?DBG("loop_mib -> unload mib SNMP-FRAMEWORK-MIB",[]),
+ ?DBG("loop_mib_1 -> unload mib SNMP-FRAMEWORK-MIB",[]),
?line unload_master("SNMP-FRAMEWORK-MIB"),
- ?DBG("loop_mib -> unload mib SNMP-VIEW-BASED-ACM-MIB",[]),
+ ?DBG("loop_mib_1 -> unload mib SNMP-VIEW-BASED-ACM-MIB",[]),
?line unload_master("SNMP-VIEW-BASED-ACM-MIB"),
%% snmpa:verbosity(master_agent,log),
%% snmpa:verbosity(mib_server,silence),
- ?LOG("loop_mib -> done",[]).
+ ?LOG("loop_mib_1 -> done",[]).
loop_mib_2(suite) -> [];
loop_mib_2(Config) when is_list(Config) ->
?P(loop_mib_2),
?LOG("loop_mib_2 -> initiate case",[]),
- {SaNode, MgrNode, MibDir} = init_case(Config),
- ?DBG("loop_mib_2 -> ~n"
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?DBG("do_loop_mib_2 -> ~n"
"\tSaNode: ~p~n"
"\tMgrNode: ~p~n"
- "\tMibDir: ~p",[SaNode, MgrNode, MibDir]),
+ "\tMibDir: ~p", [_SaNode, _MgrNode, _MibDir]),
?DBG("loop_mib_2 -> load mibs",[]),
?line load_master_std("SNMP-COMMUNITY-MIB"),
?line load_master_std("SNMP-MPD-MIB"),
@@ -5574,7 +5604,9 @@ loop_mib_2(Config) when is_list(Config) ->
?line load_master_std("SNMP-NOTIFICATION-MIB"),
?line load_master_std("SNMP-FRAMEWORK-MIB"),
?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
- try_test(loop_mib_2),
+
+ try_test(loop_mib_2_test),
+
?DBG("loop_mib_2 -> unload mibs",[]),
?line unload_master("SNMP-COMMUNITY-MIB"),
?line unload_master("SNMP-MPD-MIB"),
@@ -5589,18 +5621,18 @@ loop_mib_3(suite) -> [];
loop_mib_3(Config) when is_list(Config) ->
?P(loop_mib_3),
?LOG("loop_mib_3 -> initiate case",[]),
- {SaNode, MgrNode, MibDir} = init_case(Config),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
?DBG("loop_mib_3 -> ~n"
"\tSaNode: ~p~n"
"\tMgrNode: ~p~n"
- "\tMibDir: ~p",[SaNode, MgrNode, MibDir]),
+ "\tMibDir: ~p", [_SaNode, _MgrNode, _MibDir]),
?DBG("loop_mib_3 -> load mibs",[]),
?line load_master_std("SNMP-TARGET-MIB"),
?line load_master_std("SNMP-NOTIFICATION-MIB"),
?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
?line load_master_std("SNMP-USER-BASED-SM-MIB"),
- try_test(loop_mib_2),
+ try_test(loop_mib_3_test),
?DBG("loop_mib_3 -> unload mibs",[]),
?line unload_master("SNMP-TARGET-MIB"),
@@ -5611,17 +5643,16 @@ loop_mib_3(Config) when is_list(Config) ->
%% Req. As many mibs all possible
-loop_mib_1() ->
- ?DBG("loop_mib_1 -> entry",[]),
+loop_mib_1_test() ->
+ ?DBG("loop_mib_1_test -> entry",[]),
N = loop_it_1([1,1], 0),
io:format(user, "found ~w varibles\n", [N]),
?line N = if N < 100 -> 100;
true -> N
end.
-
loop_it_1(Oid, N) ->
- ?DBG("loop_it_1 -> entry with~n"
+ ?DBG("loop_it_1_test -> entry with~n"
"\tOid: ~p~n"
"\tN: ~p",[Oid,N]),
case get_next_req([Oid]) of
@@ -5629,13 +5660,13 @@ loop_it_1(Oid, N) ->
error_status = noError,
error_index = 0,
varbinds = [#varbind{oid = NOid,
- value = Value}]} when NOid > Oid ->
- ?DBG("loop_it_1 -> "
+ value = _Value}]} when NOid > Oid ->
+ ?DBG("loop_it_1_test -> "
"~n NOid: ~p"
- "~n Value: ~p",[NOid, Value]),
- ?line [Value2] = get_req(1, [NOid]), % must not be same
- ?DBG("loop_it_1 -> "
- "~n Value2: ~p",[Value2]),
+ "~n Value: ~p", [NOid, _Value]),
+ ?line [_Value2] = get_req(1, [NOid]), % must not be same
+ ?DBG("loop_it_1_test -> "
+ "~n Value2: ~p", [_Value2]),
loop_it_1(NOid, N+1);
#pdu{type = 'get-response',
@@ -5648,7 +5679,7 @@ loop_it_1(Oid, N) ->
error_status = noSuchName,
error_index = 1,
varbinds = [_]} ->
- ?DBG("loop_it_1 -> done: ~p",[N]),
+ ?DBG("loop_it_1_test -> done: ~p",[N]),
N;
#pdu{type = 'get-response',
@@ -5669,14 +5700,13 @@ loop_it_1(Oid, N) ->
%% Req. As many mibs all possible
-loop_mib_2() ->
- ?DBG("loop_mib_1 -> entry",[]),
+loop_mib_2_test() ->
+ ?DBG("loop_mib_2_test -> entry",[]),
N = loop_it_2([1,1], 0),
io:format(user, "found ~w varibles\n", [N]),
?line N = if N < 100 -> 100;
true -> N
end.
-
loop_it_2(Oid, N) ->
?DBG("loop_it_2 -> entry with"
@@ -5686,22 +5716,22 @@ loop_it_2(Oid, N) ->
#pdu{type = 'get-response',
error_status = noError,
error_index = 0,
- varbinds = [#varbind{oid = NOid, value = endOfMibView}]} ->
+ varbinds = [#varbind{oid = _NOid, value = endOfMibView}]} ->
?DBG("loop_it_2 -> "
- "~n NOid: ~p",[NOid]),
+ "~n NOid: ~p", [_NOid]),
N;
#pdu{type = 'get-response',
error_status = noError,
error_index = 0,
varbinds = [#varbind{oid = NOid,
- value = Value}]} when NOid > Oid ->
+ value = _Value}]} when NOid > Oid ->
?DBG("loop_it_2 -> "
"~n NOid: ~p"
- "~n Value: ~p",[NOid, Value]),
- ?line [Value2] = get_req(1, [NOid]), % must not be same
+ "~n Value: ~p", [NOid, _Value]),
+ ?line [_Value2] = get_req(1, [NOid]), % must not be same
?DBG("loop_it_2 -> "
- "~n Value2: ~p",[Value2]),
+ "~n Value2: ~p", [_Value2]),
loop_it_2(NOid, N+1);
#pdu{type = 'get-response',
@@ -5744,6 +5774,10 @@ loop_it_2(Oid, N) ->
end.
+loop_mib_3_test() ->
+ ?DBG("loop_mib_3_test -> entry",[]),
+ loop_mib_2_test().
+
%%%-----------------------------------------------------------------
%%% Testing of reported bugs and other tickets.
@@ -6611,16 +6645,16 @@ otp8395(Config) when is_list(Config) ->
AgentNode = ?config(agent_node, Config),
AgentLogDir = ?config(agent_log_dir, Config),
OutFile = join([AgentLogDir, "otp8395.txt"]),
- {ok, LogInfo} = rpc:call(AgentNode, snmpa, log_info, []),
- ?DBG("otp8395 -> LogInfo: ~p", [LogInfo]),
+ {ok, _LogInfo} = rpc:call(AgentNode, snmpa, log_info, []),
+ ?DBG("otp8395 -> LogInfo: ~p", [_LogInfo]),
%% SyncRes = rpc:call(AgentNode, snmp, log_sync, [?audit_trail_log_name]),
%% ?DBG("otp8395 -> SyncRes: ~p", [SyncRes]),
ok = agent_log_validation(AgentNode),
- LTTRes =
+ _LTTRes =
rpc:call(AgentNode, snmpa, log_to_txt, [AgentLogDir, [], OutFile]),
- ?DBG("otp8395 -> LTTRes: ~p", [LTTRes]),
+ ?DBG("otp8395 -> LTTRes: ~p", [_LTTRes]),
?SLEEP(1000),
?DBG("otp8395 -> done", []),
@@ -6941,10 +6975,10 @@ stop_stdalone_agent(Pid) when (node(Pid) =/= node()) ->
MRef = erlang:monitor(process, Pid),
rpc:call(node(Pid), ?MODULE, stop_stdalone_agent, [Pid]),
receive
- {'DOWN', MRef, process, Pid, Info} ->
+ {'DOWN', MRef, process, Pid, _Info} ->
?DBG("received expected DOWN message "
"regarding snmp agent supervisor: "
- "~n Info: ~p", [Info]),
+ "~n Info: ~p", [_Info]),
ok
after 5000 ->
?DBG("no DOWN message "
@@ -7003,9 +7037,9 @@ do_info(MaNode) ->
tree_size_bytes,
db_memory]}],
verify_info(Info, Keys),
- OldInfo = snmpa:old_info_format(Info),
- ?DBG("info_test1 -> OldInfo: ~n~p", [OldInfo]),
- verify_old_info(OldInfo),
+ %% OldInfo = snmpa:old_info_format(Info),
+ %% ?DBG("info_test1 -> OldInfo: ~n~p", [OldInfo]),
+ %% verify_old_info(OldInfo),
ok.
verify_info([], []) ->
@@ -7048,20 +7082,20 @@ verify_subinfo(Info0, [Key|Keys]) ->
verify_subinfo(Info, Keys)
end.
-verify_old_info(Info) ->
- Keys = [vsns, subagents, loaded_mibs,
- tree_size_bytes, process_memory, db_memory],
- verify_old_info(Keys, Info).
-
-verify_old_info([], _) ->
- ok;
-verify_old_info([Key|Keys], Info) ->
- case lists:keymember(Key, 1, Info) of
- true ->
- verify_old_info(Keys, Info);
- false ->
- ?FAIL({missing_old_info, Key})
- end.
+%% verify_old_info(Info) ->
+%% Keys = [vsns, subagents, loaded_mibs,
+%% tree_size_bytes, process_memory, db_memory],
+%% verify_old_info(Keys, Info).
+
+%% verify_old_info([], _) ->
+%% ok;
+%% verify_old_info([Key|Keys], Info) ->
+%% case lists:keymember(Key, 1, Info) of
+%% true ->
+%% verify_old_info(Keys, Info);
+%% false ->
+%% ?FAIL({missing_old_info, Key})
+%% end.
%% Index String - string used in index
is(S) -> [length(S) | S].
diff --git a/lib/snmp/test/snmp_agent_test_lib.erl b/lib/snmp/test/snmp_agent_test_lib.erl
index 122289c28e..d7109253f7 100644
--- a/lib/snmp/test/snmp_agent_test_lib.erl
+++ b/lib/snmp/test/snmp_agent_test_lib.erl
@@ -299,10 +299,10 @@ call(N,M,F,A) ->
"~n Loc: ~p", [Rn, Loc]),
put(test_server_loc, Loc),
exit(Rn);
- {done, Ret, Zed} ->
+ {done, Ret, _Zed} ->
?DBG("call -> done:"
"~n Ret: ~p"
- "~n Zed: ~p", [Ret, Zed]),
+ "~n Zed: ~p", [Ret, _Zed]),
case Ret of
{error, Reason} ->
exit(Reason);
@@ -338,8 +338,8 @@ run(Mod, Func, Args, Opts) ->
CtxEngineID = snmp_misc:get_option(context_engine_id, Opts, EngineID),
Community = snmp_misc:get_option(community, Opts, "all-rights"),
?DBG("run -> start crypto app",[]),
- Crypto = ?CRYPTO_START(),
- ?DBG("run -> Crypto: ~p", [Crypto]),
+ _CryptoRes = ?CRYPTO_START(),
+ ?DBG("run -> Crypto: ~p", [_CryptoRes]),
catch snmp_test_mgr:stop(), % If we had a running mgr from a failed case
StdM = join(code:priv_dir(snmp), "mibs") ++ "/",
Vsn = get(vsn),
@@ -676,9 +676,9 @@ stop_agent(Config) when is_list(Config) ->
(catch process_info(Sup)),
(catch process_info(Par))]),
- Info = agent_info(Sup),
+ _Info = agent_info(Sup),
?DBG("stop_agent -> Agent info: "
- "~n ~p", [Info]),
+ "~n ~p", [_Info]),
stop_sup(Sup, Par),
@@ -1303,10 +1303,10 @@ get_req(Id, Vars) ->
{ok, Val} ->
?DBG("get_req -> response: ~p",[Val]),
Val;
- {error, _, {ExpFmt, ExpArg}, {ActFmt, ActArg}} ->
+ {error, _, {_ExpFmt, ExpArg}, {_ActFmt, ActArg}} ->
?DBG("get_req -> error for ~p: "
- "~n " ++ ExpFmt ++
- "~n " ++ ActFmt,
+ "~n " ++ _ExpFmt ++
+ "~n " ++ _ActFmt,
[Id] ++ ExpArg ++ ActArg),
exit({unexpected_response, ExpArg, ActArg});
Error ->
@@ -1527,9 +1527,9 @@ rewrite_target_addr_conf(Dir, NewPort) ->
case file:read_file_info(TAFile) of
{ok, _} ->
ok;
- {error, R} ->
+ {error, _R} ->
?ERR("failure reading file info of "
- "target address config file: ~p",[R]),
+ "target address config file: ~p", [_R]),
ok
end,
diff --git a/lib/snmp/test/snmp_manager_test.erl b/lib/snmp/test/snmp_manager_test.erl
index 5fe18980bc..3a654a2805 100644
--- a/lib/snmp/test/snmp_manager_test.erl
+++ b/lib/snmp/test/snmp_manager_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -139,6 +139,8 @@
-define(NS_TIMEOUT, 10000).
+-define(DEFAULT_MNESIA_DEBUG, none).
+
%%----------------------------------------------------------------------
%% Records
@@ -173,7 +175,9 @@ end_per_suite(Config) when is_list(Config) ->
init_per_testcase(Case, Config) when is_list(Config) ->
- io:format(user, "~n~n*** INIT ~w:~w ***~n~n", [?MODULE,Case]),
+ io:format(user, "~n~n*** INIT ~w:~w ***~n~n", [?MODULE, Case]),
+ p(Case, "init_per_testcase begin when"
+ "~n Nodes: ~p~n~n", [erlang:nodes()]),
%% This version of the API, based on Addr and Port, has been deprecated
DeprecatedApiCases =
[
@@ -187,16 +191,25 @@ init_per_testcase(Case, Config) when is_list(Config) ->
simple_async_get_bulk1,
misc_async1
],
- case lists:member(Case, DeprecatedApiCases) of
- true ->
- %% ?SKIP(api_no_longer_supported);
- {skip, api_no_longer_supported};
- false ->
- init_per_testcase2(Case, Config)
- end.
+ Result =
+ case lists:member(Case, DeprecatedApiCases) of
+ true ->
+ %% ?SKIP(api_no_longer_supported);
+ {skip, api_no_longer_supported};
+ false ->
+ init_per_testcase2(Case, Config)
+ end,
+ p(Case, "init_per_testcase end when"
+ "~n Nodes: ~p"
+ "~n Result: ~p"
+ "~n~n", [Result, erlang:nodes()]),
+ Result.
init_per_testcase2(Case, Config) ->
- ?DBG("init_per_testcase2 -> ~p", [erlang:nodes()]),
+ ?DBG("init_per_testcase2 -> "
+ "~n Case: ~p"
+ "~n Config: ~p"
+ "~n Nodes: ~p", [Case, Config, erlang:nodes()]),
CaseTopDir = snmp_test_lib:init_testcase_top_dir(Case, Config),
@@ -314,6 +327,8 @@ init_per_testcase3(Case, Config) ->
end.
end_per_testcase(Case, Config) when is_list(Config) ->
+ p(Case, "end_per_testcase begin when"
+ "~n Nodes: ~p~n~n", [erlang:nodes()]),
?DBG("fin [~w] Nodes [1]: ~p", [Case, erlang:nodes()]),
Dog = ?config(watchdog, Config),
?WD_STOP(Dog),
@@ -322,6 +337,8 @@ end_per_testcase(Case, Config) when is_list(Config) ->
?DBG("fin [~w] Nodes [2]: ~p", [Case, erlang:nodes()]),
%% TopDir = ?config(top_dir, Conf2),
%% ?DEL_DIR(TopDir),
+ p(Case, "end_per_testcase end when"
+ "~n Nodes: ~p~n~n", [erlang:nodes()]),
Conf2.
end_per_testcase2(Case, Config) ->
@@ -428,10 +445,10 @@ groups() ->
{request_tests, [],
[
{group, get_tests},
- {group, get_next_tests},
+ {group, get_next_tests},
{group, set_tests},
- {group, bulk_tests},
- {group, misc_request_tests}
+ {group, bulk_tests},
+ {group, misc_request_tests}
]
},
{request_tests_mt, [],
@@ -5303,34 +5320,59 @@ init_manager(AutoInform, Config) ->
?line Node = start_manager_node(),
+ %% The point with this (try catch block) is to be
+ %% able to do some cleanup in case we fail to
+ %% start some of the apps. That is, if we fail to
+ %% start the apps (mnesia, crypto and snmp agent)
+ %% we stop the (agent) node!
- %% --
- %% Start and initiate crypto on manager node
- %%
-
- ?line ok = init_crypto(Node),
+ try
+ begin
- %%
- %% Write manager config
- %%
+ %% --
+ %% Start and initiate crypto on manager node
+ %%
+
+ ?line ok = init_crypto(Node),
+
+ %%
+ %% Write manager config
+ %%
+
+ ?line ok = write_manager_config(Config),
+
+ IRB = case AutoInform of
+ true ->
+ auto;
+ _ ->
+ user
+ end,
+ Conf = [{manager_node, Node}, {irb, IRB} | Config],
+ Vsns = [v1,v2,v3],
+ start_manager(Node, Vsns, Conf)
+ end
+ catch
+ T:E ->
+ StackTrace = ?STACK(),
+ p("Failure during manager start: "
+ "~n Error Type: ~p"
+ "~n Error: ~p"
+ "~n StackTrace: ~p", [T, E, StackTrace]),
+ %% And now, *try* to cleanup
+ (catch stop_node(Node)),
+ ?FAIL({failed_starting_manager, T, E, StackTrace})
+ end.
- ?line ok = write_manager_config(Config),
-
- IRB = case AutoInform of
- true ->
- auto;
- _ ->
- user
- end,
- Conf = [{manager_node, Node}, {irb, IRB} | Config],
- Vsns = [v1,v2,v3],
- start_manager(Node, Vsns, Conf).
-
fin_manager(Config) ->
Node = ?config(manager_node, Config),
- stop_manager(Node, Config),
- fin_crypto(Node),
- stop_node(Node),
+ StopMgrRes = stop_manager(Node),
+ StopCryptoRes = fin_crypto(Node),
+ StopNode = stop_node(Node),
+ p("fin_agent -> stop apps and (mgr node ~p) node results: "
+ "~n SNMP Mgr: ~p"
+ "~n Crypto: ~p"
+ "~n Node: ~p",
+ [Node, StopMgrRes, StopCryptoRes, StopNode]),
Config.
@@ -5352,52 +5394,93 @@ init_agent(Config) ->
?line Node = start_agent_node(),
+ %% The point with this (try catch block) is to be
+ %% able to do some cleanup in case we fail to
+ %% start some of the apps. That is, if we fail to
+ %% start the apps (mnesia, crypto and snmp agent)
+ %% we stop the (agent) node!
- %% --
- %% Start and initiate mnesia on agent node
- %%
-
- ?line ok = init_mnesia(Node, Dir),
-
-
- %% --
- %% Start and initiate crypto on agent node
- %%
-
- ?line ok = init_crypto(Node),
-
-
- %%
- %% Write agent config
- %%
-
- Vsns = [v1,v2],
- ?line ok = write_agent_config(Vsns, Config),
-
- Conf = [{agent_node, Node},
- {mib_dir, MibDir} | Config],
+ try
+ begin
+
+ %% --
+ %% Start and initiate mnesia on agent node
+ %%
+
+ ?line ok = init_mnesia(Node, Dir, ?config(mnesia_debug, Config)),
+
+
+ %% --
+ %% Start and initiate crypto on agent node
+ %%
+
+ ?line ok = init_crypto(Node),
+
+
+ %%
+ %% Write agent config
+ %%
+
+ Vsns = [v1,v2],
+ ?line ok = write_agent_config(Vsns, Config),
+
+ Conf = [{agent_node, Node},
+ {mib_dir, MibDir} | Config],
- %%
- %% Start the agent
- %%
-
- start_agent(Node, Vsns, Conf).
+ %%
+ %% Start the agent
+ %%
+
+ start_agent(Node, Vsns, Conf)
+ end
+ catch
+ T:E ->
+ StackTrace = ?STACK(),
+ p("Failure during agent start: "
+ "~n Error Type: ~p"
+ "~n Error: ~p"
+ "~n StackTrace: ~p", [T, E, StackTrace]),
+ %% And now, *try* to cleanup
+ (catch stop_node(Node)),
+ ?FAIL({failed_starting_agent, T, E, StackTrace})
+ end.
+
fin_agent(Config) ->
Node = ?config(agent_node, Config),
- stop_agent(Node, Config),
- fin_crypto(Node),
- fin_mnesia(Node),
- stop_node(Node),
+ StopAgentRes = stop_agent(Node),
+ StopCryptoRes = fin_crypto(Node),
+ StopMnesiaRes = fin_mnesia(Node),
+ StopNode = stop_node(Node),
+ p("fin_agent -> stop apps and (agent node ~p) node results: "
+ "~n SNMP Agent: ~p"
+ "~n Crypto: ~p"
+ "~n Mnesia: ~p"
+ "~n Node: ~p",
+ [Node, StopAgentRes, StopCryptoRes, StopMnesiaRes, StopNode]),
Config.
-init_mnesia(Node, Dir) ->
+init_mnesia(Node, Dir, MnesiaDebug)
+ when ((MnesiaDebug =/= none) andalso
+ (MnesiaDebug =/= debug) andalso (MnesiaDebug =/= trace)) ->
+ init_mnesia(Node, Dir, ?DEFAULT_MNESIA_DEBUG);
+init_mnesia(Node, Dir, MnesiaDebug) ->
?DBG("init_mnesia -> load application mnesia", []),
?line ok = load_mnesia(Node),
?DBG("init_mnesia -> application mnesia: set_env dir: ~n~p",[Dir]),
?line ok = set_mnesia_env(Node, dir, filename:join(Dir, "mnesia")),
+ %% Just in case, only set (known to be) valid values for debug
+ if
+ ((MnesiaDebug =:= debug) orelse (MnesiaDebug =:= trace)) ->
+ ?DBG("init_mnesia -> application mnesia: set_env debug: ~w",
+ [MnesiaDebug]),
+ ?line ok = set_mnesia_env(Node, debug, MnesiaDebug);
+ true ->
+ ok
+ end,
+
?DBG("init_mnesia -> create mnesia schema",[]),
?line case create_schema(Node) of
ok ->
@@ -5434,25 +5517,89 @@ fin_crypto(Node) ->
%% -- Misc application wrapper functions --
-load_app(Node, App) when (Node =:= node()) andalso is_atom(App) ->
- application:load(App);
-load_app(Node, App) when is_atom(App) ->
- rcall(Node, application, load, [App]).
-
-start_app(Node, App) when (Node =:= node()) andalso is_atom(App) ->
- application:start(App);
+load_app(Node, App) ->
+ VerifySuccess = fun(ok) ->
+ ok;
+ ({error, {already_loaded, LoadedApp}}) when (LoadedApp =:= App) ->
+ ok;
+ ({error, Reason}) ->
+ p("failed loading app ~w on ~p: "
+ "~n ~p", [App, Node, Reason]),
+ ?FAIL({failed_load, Node, App, Reason})
+ end,
+ do_load_app(Node, App, VerifySuccess).
+
+do_load_app(Node, App, VerifySuccess)
+ when (Node =:= node()) andalso is_atom(App) ->
+ %% Local app
+ exec(fun() -> application:load(App) end, VerifySuccess);
+do_load_app(Node, App, VerifySuccess) ->
+ %% Remote app
+ exec(fun() -> rcall(Node, application, load, [App]) end, VerifySuccess).
+
+
start_app(Node, App) ->
- rcall(Node, application, start, [App]).
+ VerifySuccess = fun(ok) ->
+ ok;
+ ({error, {already_started, LoadedApp}}) when (LoadedApp =:= App) ->
+ ok;
+ ({error, Reason}) ->
+ p("failed starting app ~w on ~p: "
+ "~n ~p", [App, Node, Reason]),
+ ?FAIL({failed_start, Node, App, Reason})
+ end,
+ start_app(Node, App, VerifySuccess).
+
+start_app(Node, App, VerifySuccess)
+ when (Node =:= node()) andalso is_atom(App) ->
+ exec(fun() -> application:start(App) end, VerifySuccess);
+start_app(Node, App, VerifySuccess) ->
+ exec(fun() -> rcall(Node, application, start, [App]) end, VerifySuccess).
+
+
+stop_app(Node, App) ->
+ VerifySuccess = fun(ok) ->
+ ok;
+ ({error, {not_started, LoadedApp}}) when (LoadedApp =:= App) ->
+ ok;
+ ({error, Reason}) ->
+ p("failed stopping app ~w on ~p: "
+ "~n ~p", [App, Node, Reason]),
+ ?FAIL({failed_stop, Node, App, Reason})
+ end,
+ stop_app(Node, App, VerifySuccess).
+
+stop_app(Node, App, VerifySuccess)
+ when (Node =:= node()) andalso is_atom(App) ->
+ exec(fun() -> application:stop(App) end, VerifySuccess);
+stop_app(Node, App, VerifySuccess) when is_atom(App) ->
+ exec(fun() -> rcall(Node, application, stop, [App]) end, VerifySuccess).
+
+
+set_app_env(Node, App, Key, Val) ->
+ VerifySuccess = fun(ok) ->
+ ok;
+ ({error, Reason}) ->
+ p("failed setting app ~w env on ~p"
+ "~n Key: ~p"
+ "~n Val: ~p"
+ "~n Reason: ~p"
+ "~n ~p", [App, Node, Key, Val, Reason]),
+ ?FAIL({failed_set_app_env,
+ Node, App, Key, Val, Reason})
+ end,
+ set_app_env(Node, App, Key, Val, VerifySuccess).
-stop_app(Node, App) when (Node =:= node()) andalso is_atom(App) ->
- application:stop(App);
-stop_app(Node, App) when is_atom(App) ->
- rcall(Node, application, stop, [App]).
+set_app_env(Node, App, Key, Val, VerifySuccess)
+ when (Node =:= node()) andalso is_atom(App) ->
+ exec(fun() -> application:set_env(App, Key, Val) end, VerifySuccess);
+set_app_env(Node, App, Key, Val, VerifySuccess) when is_atom(App) ->
+ exec(fun() -> rcall(Node, application, set_env, [App, Key, Val]) end,
+ VerifySuccess).
-set_app_env(Node, App, Key, Val) when (Node =:= node()) andalso is_atom(App) ->
- application:set_env(App, Key, Val);
-set_app_env(Node, App, Key, Val) when is_atom(App) ->
- rcall(Node, application, set_env, [App, Key, Val]).
+
+exec(Cmd, VerifySuccess) ->
+ VerifySuccess(Cmd()).
%% -- Misc snmp wrapper functions --
@@ -5900,9 +6047,9 @@ start_manager(Node, Vsns, Conf0, _Opts) ->
Conf0.
-stop_manager(Node, Conf) ->
- stop_snmp(Node),
- Conf.
+stop_manager(Node) ->
+ stop_snmp(Node).
+
%% -- Misc agent wrapper functions --
@@ -5951,9 +6098,8 @@ start_agent(Node, Vsns, Conf0, _Opts) ->
?line ok = start_snmp(Node),
Conf0.
-stop_agent(Node, Conf) ->
- stop_snmp(Node),
- Conf.
+stop_agent(Node) ->
+ stop_snmp(Node).
agent_load_mib(Node, Mib) ->
rcall(Node, snmpa, load_mibs, [[Mib]]).
@@ -6015,17 +6161,18 @@ stop_node(Node) ->
rpc:cast(Node, erlang, halt, []),
await_stopped(Node, 5).
-await_stopped(_, 0) ->
+await_stopped(Node, 0) ->
+ p("await_stopped -> ~p still exist: giving up", [Node]),
ok;
await_stopped(Node, N) ->
Nodes = erlang:nodes(),
case lists:member(Node, Nodes) of
true ->
- ?DBG("[~w] ~p still exist", [N, Node]),
+ p("await_stopped -> ~p still exist: ~w", [Node, N]),
?SLEEP(1000),
await_stopped(Node, N-1);
false ->
- ?DBG("[~w] ~p gone", [N, Node]),
+ p("await_stopped -> ~p gone: ~w", [Node, N]),
ok
end.
@@ -6271,7 +6418,7 @@ p(F, A) ->
p(TName, F, A) ->
io:format("*** [~w][~s] ***"
- "~n" ++ F ++ "~n", [TName, formated_timestamp()|A]).
+ "~n " ++ F ++ "~n", [TName, formated_timestamp()|A]).
formated_timestamp() ->
snmp_test_lib:formated_timestamp().
diff --git a/lib/snmp/test/snmp_test_mgr.erl b/lib/snmp/test/snmp_test_mgr.erl
index 40fcbce8f1..d4eb00ff91 100644
--- a/lib/snmp/test/snmp_test_mgr.erl
+++ b/lib/snmp/test/snmp_test_mgr.erl
@@ -657,7 +657,8 @@ make_vb(Oid) ->
#varbind{oid = Oid, variabletype = 'NULL', value = 'NULL'}.
make_request_id() ->
- random:uniform(16#FFFFFFF-1).
+ %% random:uniform(16#FFFFFFF-1).
+ snmp_test_mgr_counter_server:increment(mgr_request_id, 1, 1, 2147483647).
echo_pdu(PDU, MiniMIB) ->
io:format("~s", [snmp_misc:format_pdu(PDU, MiniMIB)]).
diff --git a/lib/snmp/test/snmp_test_mgr_counter_server.erl b/lib/snmp/test/snmp_test_mgr_counter_server.erl
new file mode 100644
index 0000000000..db31e0380b
--- /dev/null
+++ b/lib/snmp/test/snmp_test_mgr_counter_server.erl
@@ -0,0 +1,152 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2014-2014. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%% The reason for this (test) counter server is that the
+%% agent test suite is implemented in such a way that the
+%% agent is started once and then used for several test cases.
+%% Each request is given a request id which *was* generated using
+%% random! It is therefor possible, although unlikely, that a
+%% request may get a request id that has recently been used,
+%% which will cause the agent to silently reject the request.
+%% For this reason, we start this server at the start of the
+%% agent suite and stop it at the end and all request ids are
+%% generated by this server.
+%%
+
+-module(snmp_test_mgr_counter_server).
+
+-export([start/0, stop/0, increment/4]).
+
+-define(SERVER, ?MODULE).
+-define(TAB, snmp_test_mgr_counter_tab).
+
+
+%%%-------------------------------------------------------------------
+%%% API
+%%%-------------------------------------------------------------------
+
+-spec start() -> ok.
+
+start() ->
+ Parent = self(),
+ ReqIdServer = spawn(fun() -> init(Parent) end),
+ receive
+ {ReqIdServer, ok} ->
+ ok;
+ {ReqIdServer, {error, Reason}} ->
+ exit({failed_starting_counter_server, Reason})
+ after 5000 ->
+ exit(ReqIdServer, kill), % Cleanup, just in case
+ exit({failed_starting_counter_server, timeout})
+ end.
+
+-spec stop() -> {ok, Counters :: list()} | {error, Reason :: term()}.
+
+stop() ->
+ request(stop).
+
+
+-spec increment(Counter :: atom(),
+ Initial :: non_neg_integer(),
+ Increment :: pos_integer(),
+ Max :: pos_integer()) ->
+ Next :: pos_integer().
+
+increment(Counter, Initial, Increment, Max) ->
+ Request = {increment, Counter, Initial, Increment, Max},
+ case request(Request) of
+ {ok, ReqId} ->
+ ReqId;
+ {error, Reason} ->
+ exit(Reason)
+ end.
+
+
+request(Request) ->
+ Id = make_ref(),
+ Msg = {self(), Id, Request},
+ try
+ begin
+ global:send(?SERVER, Msg),
+ receive
+ {reply, Id, Reply} ->
+ {ok, Reply}
+ end
+ end
+ catch
+ T:E ->
+ {error, {T, E}}
+ end.
+
+
+%%%-------------------------------------------------------------------
+%%% Internal functions
+%%%-------------------------------------------------------------------
+
+init(Parent) ->
+ p("starting"),
+ case global:register_name(?SERVER, self()) of
+ yes ->
+ p("name registration ok"),
+ Parent ! {self(), ok};
+ no ->
+ p("name registration failed"),
+ Parent ! {self(), registration_failed},
+ exit(registration_failed)
+ end,
+ ets:new(?TAB, [set, named_table, {keypos, 1}]),
+ loop().
+
+loop() ->
+ receive
+ {From, Id, {increment, Counter, Initial, Increment, Max}} ->
+ Position = 2,
+ Threshold = Max,
+ SetValue = Initial,
+ UpdateOp = {Position, Increment, Threshold, SetValue},
+ NextVal =
+ try ets:update_counter(?TAB, Counter, UpdateOp) of
+ Next when is_integer(Next) ->
+ p("increment ~w: (next) ~w", [Counter, Next]),
+ Next
+ catch
+ error:badarg ->
+ %% Oups, first time
+ p("increment ~w: (initial) ~w", [Counter, Initial]),
+ ets:insert(?TAB, {Counter, Initial}),
+ Initial
+ end,
+ From ! {reply, Id, NextVal},
+ loop();
+
+ {From, Id, stop} ->
+ p("stop"),
+ Counters = ets:tab2list(?TAB),
+ From ! {reply, Id, Counters},
+ exit(normal)
+ end.
+
+
+p(F) ->
+ p(F, []).
+
+p(F, A) ->
+ io:format("*** [~s] COUNTER-SERVER [~w] " ++ F ++ "~n",
+ [snmp_test_lib:formated_timestamp(), self() | A]).
diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml
index eaf96d0230..7fbd70c87e 100644
--- a/lib/ssh/doc/src/ssh.xml
+++ b/lib/ssh/doc/src/ssh.xml
@@ -304,6 +304,23 @@
<c><![CDATA[true]]></c> if the password is valid and
<c><![CDATA[false]]></c> otherwise.</p>
</item>
+
+ <tag><c><![CDATA[{negotiation_timeout, integer()}]]></c></tag>
+ <item>
+ <p>Max time in milliseconds for the authentication negotiation. The default value is 2 minutes.
+ </p>
+ </item>
+
+ <tag><c><![CDATA[{parallel_login, boolean()}]]></c></tag>
+ <item>
+ <p>If set to false (the default value), only one login is handled a time. If set to true, an unlimited logins will be allowed simultanously. Note that this affects only the connections with authentication in progress, not the already authenticated connections.
+ </p>
+ <warning>
+ <p>Do not enable parallel_logins without protecting the server by other means like a firewall. If set to true, there is no protection against dos attacs.</p>
+ </warning>
+
+ </item>
+
<tag><c><![CDATA[{key_cb, atom()}]]></c></tag>
<item>
<p>Module implementing the behaviour <seealso marker="ssh_server_key_api">ssh_server_key_api</seealso>.
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index d50d5a0cb3..de6e8cc421 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -1,4 +1,4 @@
-%%
+%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2004-2013. All Rights Reserved.
@@ -332,6 +332,12 @@ handle_option([{idle_time, _} = Opt | Rest], SocketOptions, SshOptions) ->
handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
handle_option([{rekey_limit, _} = Opt|Rest], SocketOptions, SshOptions) ->
handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
+handle_option([{negotiation_timeout, _} = Opt|Rest], SocketOptions, SshOptions) ->
+ handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
+handle_option([{parallel_login, _} = Opt|Rest], SocketOptions, SshOptions) ->
+ handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
+handle_option([parallel_login|Rest], SocketOptions, SshOptions) ->
+ handle_option(Rest, SocketOptions, [handle_ssh_option({parallel_login,true}) | SshOptions]);
handle_option([Opt | Rest], SocketOptions, SshOptions) ->
handle_option(Rest, [handle_inet_option(Opt) | SocketOptions], SshOptions).
@@ -360,6 +366,10 @@ handle_ssh_option({pref_public_key_algs, Value} = Opt) when is_list(Value), leng
end;
handle_ssh_option({connect_timeout, Value} = Opt) when is_integer(Value); Value == infinity ->
Opt;
+handle_ssh_option({negotiation_timeout, Value} = Opt) when is_integer(Value); Value == infinity ->
+ Opt;
+handle_ssh_option({parallel_login, Value} = Opt) when Value==true ; Value==false ->
+ Opt;
handle_ssh_option({user, Value} = Opt) when is_list(Value) ->
Opt;
handle_ssh_option({dsa_pass_phrase, Value} = Opt) when is_list(Value) ->
diff --git a/lib/ssh/src/ssh_acceptor.erl b/lib/ssh/src/ssh_acceptor.erl
index 91905b2eaf..e57b07cee8 100644
--- a/lib/ssh/src/ssh_acceptor.erl
+++ b/lib/ssh/src/ssh_acceptor.erl
@@ -84,11 +84,14 @@ handle_connection(_Callback, Address, Port, Options, Socket) ->
SystemSup = ssh_system_sup:system_supervisor(Address, Port),
{ok, SubSysSup} = ssh_system_sup:start_subsystem(SystemSup, Options),
ConnectionSup = ssh_subsystem_sup:connection_supervisor(SubSysSup),
+ Timeout = proplists:get_value(negotiation_timeout,
+ proplists:get_value(ssh_opts, Options, []),
+ 2*60*1000),
ssh_connection_handler:start_connection(server, Socket,
[{supervisors, [{system_sup, SystemSup},
{subsystem_sup, SubSysSup},
{connection_sup, ConnectionSup}]}
- | Options], infinity).
+ | Options], Timeout).
handle_error(timeout) ->
ok;
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 070a2db5a8..322da50f21 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -110,8 +110,16 @@ start_connection(server = Role, Socket, Options, Timeout) ->
{ok, Pid} = ssh_connection_sup:start_child(ConnectionSup, [Role, Socket, Opts]),
{_, Callback, _} = proplists:get_value(transport, Options, {tcp, gen_tcp, tcp_closed}),
socket_control(Socket, Pid, Callback),
- Ref = erlang:monitor(process, Pid),
- handshake(Pid, Ref, Timeout)
+ case proplists:get_value(parallel_login, Opts, false) of
+ true ->
+ spawn(fun() ->
+ Ref = erlang:monitor(process, Pid),
+ handshake(Pid, Ref, Timeout)
+ end);
+ false ->
+ Ref = erlang:monitor(process, Pid),
+ handshake(Pid, Ref, Timeout)
+ end
catch
exit:{noproc, _} ->
{error, ssh_not_started};
@@ -206,7 +214,7 @@ global_request(ConnectionHandler, Type, false = Reply, Data) ->
send_all_state_event(ConnectionHandler, {global_request, self(), Type, Reply, Data}).
%%--------------------------------------------------------------------
--spec send(pid(), channel_id(), integer(), iolist(), timeout()) ->
+-spec send(pid(), channel_id(), integer(), iodata(), timeout()) ->
ok | {error, timeout} | {error, closed}.
%%--------------------------------------------------------------------
send(ConnectionHandler, ChannelId, Type, Data, Timeout) ->
diff --git a/lib/ssl/src/dtls_connection.erl b/lib/ssl/src/dtls_connection.erl
index da2e076856..57f8dd86d3 100644
--- a/lib/ssl/src/dtls_connection.erl
+++ b/lib/ssl/src/dtls_connection.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -20,222 +20,514 @@
%% Internal application API
-%%====================================================================
+-behaviour(gen_fsm).
+
+-include("dtls_connection.hrl").
+-include("dtls_handshake.hrl").
+-include("ssl_alert.hrl").
+-include("dtls_record.hrl").
+-include("ssl_cipher.hrl").
+-include("ssl_api.hrl").
+-include("ssl_internal.hrl").
+-include("ssl_srp.hrl").
+-include_lib("public_key/include/public_key.hrl").
+
%% Internal application API
-%%====================================================================
+%% Setup
+-export([start_fsm/8]).
+
+%% State transition handling
+-export([next_record/1, next_state/4%,
+ %%next_state_connection/2
+ ]).
+
+%% Handshake handling
+-export([%%renegotiate/1,
+ send_handshake/2, send_change_cipher/2]).
+
+%% Alert and close handling
+-export([send_alert/2, handle_own_alert/4, %%handle_close_alert/3,
+ handle_normal_shutdown/3
+ %%handle_unexpected_message/3,
+ %%alert_user/5, alert_user/8
+ ]).
+
+%% Data handling
+-export([%%write_application_data/3,
+ read_application_data/2%%,
+%% passive_receive/2, next_record_if_active/1
+ ]).
+
+%% Called by tls_connection_sup
+-export([start_link/7]).
+%% gen_fsm callbacks
+-export([init/1, hello/2, certify/2, cipher/2,
+ abbreviated/2, connection/2, handle_event/3,
+ handle_sync_event/4, handle_info/3, terminate/3, code_change/4]).
-%% %%====================================================================
-%% %% State functions
-%% %%====================================================================
-
-%% -spec hello(start | #hello_request{} | #client_hello{} | #server_hello{} | term(),
-%% #state{}) -> gen_fsm_state_return().
-%% %%--------------------------------------------------------------------
-%% hello(start, #state{host = Host, port = Port, role = client,
-%% ssl_options = SslOpts,
-%% session = #session{own_certificate = Cert} = Session0,
-%% session_cache = Cache, session_cache_cb = CacheCb,
-%% connection_states = ConnectionStates0,
-%% renegotiation = {Renegotiation, _},
-%% client_cookie = Cookie} = State0) ->
-%% Hello = dtls_handshake:client_hello(Host, Port, Cookie, ConnectionStates0, SslOpts,
-%% Cache, CacheCb, Renegotiation, Cert),
-
-%% Version = Hello#client_hello.client_version,
-%% State1 = State0#state{negotiated_version = Version, %% Requested version
-%% session =
-%% Session0#session{session_id = Hello#client_hello.session_id},
-%% dtls_handshake_history = ssl_handshake:init_handshake_history()},
-
-%% State2 = send_flight(Hello, waiting, State1),
-
-%% {Record, State} = next_record(State2),
-%% next_state(hello, hello, Record, State);
-
-%% hello(start, #state{role = server} = State0) ->
-%% {Record, State} = next_record(State0),
-%% next_state(hello, hello, Record, State);
-
-%% hello(#hello_request{}, #state{role = client} = State0) ->
-%% {Record, State} = next_record(State0),
-%% next_state(hello, hello, Record, State);
-
-%% hello(#server_hello{cipher_suite = CipherSuite,
-%% compression_method = Compression} = Hello,
-%% #state{session = #session{session_id = OldId},
-%% connection_states = ConnectionStates0,
-%% role = client,
-%% negotiated_version = ReqVersion,
-%% renegotiation = {Renegotiation, _},
-%% ssl_options = SslOptions} = State1) ->
-%% State0 = flight_done(State1),
-%% case ssl_handshake:hello(Hello, SslOptions, ConnectionStates0, Renegotiation) of
-%% #alert{} = Alert ->
-%% handle_own_alert(Alert, ReqVersion, hello, State0);
-%% {Version, NewId, ConnectionStates, NextProtocol} ->
-%% {KeyAlgorithm, _, _, _} =
-%% ssl_cipher:suite_definition(CipherSuite),
-
-%% PremasterSecret = make_premaster_secret(ReqVersion, KeyAlgorithm),
-
-%% NewNextProtocol = case NextProtocol of
-%% undefined ->
-%% State0#state.next_protocol;
-%% _ ->
-%% NextProtocol
-%% end,
-
-%% State = State0#state{key_algorithm = KeyAlgorithm,
-%% hashsign_algorithm = default_hashsign(Version, KeyAlgorithm),
-%% negotiated_version = Version,
-%% connection_states = ConnectionStates,
-%% premaster_secret = PremasterSecret,
-%% expecting_next_protocol_negotiation = NextProtocol =/= undefined,
-%% next_protocol = NewNextProtocol},
-
-%% case ssl_session:is_new(OldId, NewId) of
-%% true ->
-%% handle_new_session(NewId, CipherSuite, Compression,
-%% State#state{connection_states = ConnectionStates});
-%% false ->
-%% handle_resumed_session(NewId, State#state{connection_states = ConnectionStates})
-%% end
-%% end;
-
-%% hello(#hello_verify_request{cookie = Cookie},
-%% #state{host = Host, port = Port,
-%% session = #session{own_certificate = Cert},
-%% session_cache = Cache, session_cache_cb = CacheCb,
-%% ssl_options = SslOpts,
-%% connection_states = ConnectionStates0,
-%% renegotiation = {Renegotiation, _}} = State0) ->
-%% Hello = ssl_handshake:client_hello(Host, Port, Cookie, ConnectionStates0, SslOpts,
-%% Cache, CacheCb, Renegotiation, Cert),
-%% State1 = State0#state{
-%% tls_handshake_history = ssl_handshake:init_handshake_history(),
-%% client_cookie = Cookie},
-%% State2 = send_flight(Hello, waiting, State1),
-
-%% {Record, State} = next_record(State2),
-%% next_state(hello, hello, Record, State);
-
-
-%% %%--------------------------------------------------------------------
-%% -spec abbreviated(#hello_request{} | #finished{} | term(),
-%% #state{}) -> gen_fsm_state_return().
-%% %%--------------------------------------------------------------------
-
-%% abbreviated(timeout, State) ->
-%% { next_state, abbreviated, State, hibernate };
-
-%% abbreviated(Msg, State) ->
-%% handle_unexpected_message(Msg, abbreviated, State).
-
-%% %%--------------------------------------------------------------------
-%% -spec certify(#hello_request{} | #certificate{} | #server_key_exchange{} |
-%% #certificate_request{} | #server_hello_done{} | #client_key_exchange{} | term(),
-%% #state{}) -> gen_fsm_state_return().
-%% %%--------------------------------------------------------------------
-
-
-%% certify(timeout, State) ->
-%% { next_state, certify, State, hibernate };
-
-%% certify(Msg, State) ->
-%% handle_unexpected_message(Msg, certify, State).
-
-
-%% %%--------------------------------------------------------------------
-%% -spec cipher(#hello_request{} | #certificate_verify{} | #finished{} | term(),
-%% #state{}) -> gen_fsm_state_return().
-%% %%--------------------------------------------------------------------
-
-%% cipher(timeout, State) ->
-%% { next_state, cipher, State, hibernate };
-
-%% cipher(Msg, State) ->
-%% handle_unexpected_message(Msg, cipher, State).
-
-%% %%--------------------------------------------------------------------
-%% -spec connection(#hello_request{} | #client_hello{} | term(),
-%% #state{}) -> gen_fsm_state_return().
-%% %%--------------------------------------------------------------------
-
-%% connection(timeout, State) ->
-%% {next_state, connection, State, hibernate};
-
-%% connection(Msg, State) ->
-%% handle_unexpected_message(Msg, connection, State).
-
-%% %%--------------------------------------------------------------------
-%% %%% Internal functions
-%% %%--------------------------------------------------------------------
-%% handle_unexpected_message(Msg, Info, #state{negotiated_version = Version} = State) ->
-%% Alert = ?ALERT_REC(?FATAL,?UNEXPECTED_MESSAGE),
-%% handle_own_alert(Alert, Version, {Info, Msg}, State).
-
-%% send_flight(HandshakeRec, FlightState, State) ->
-%% send_flight(FlightState, buffer_flight(HandshakeRec, State)).
-
-%% send_flight(FlightState, State = #state{negotiated_version = Version,
-%% flight_buffer = Buffer}) ->
-
-%% State1 = do_send_flight(queue:to_list(Buffer), [], State),
-%% finish_send_flight(Version, FlightState, State1).
-
-%% resend_flight(State = #state{negotiated_version = Version,
-%% flight_state = FlightState,
-%% flight_buffer = Buffer})
-%% when FlightState == finished; FlightState == waiting ->
-%% State1 = do_send_flight(queue:to_list(Buffer), [], State),
-%% finish_send_flight(Version, FlightState, State1);
-
-%% resend_flight(State) ->
-%% State.
-
-%% flight_done(State) ->
-%% cancel_dtls_retransmit_timer(State#state{flight_state = done,
-%% flight_buffer = undefined}).
-
-%% do_send_flight([], BinMsgs, State = #state{transport_cb = Transport, socket = Socket}) ->
-%% Transport:send(Socket, lists:reverse(BinMsgs)),
-%% State;
-%% do_send_flight([{Epoch, MsgSeq, HandshakeRec}|T], BinMsgs0,
-%% State = #state{negotiated_version = Version,
-%% connection_states = ConnectionStates0}) ->
-%% CS0 = ssl_record:connection_state_by_epoch(ConnectionStates0, Epoch, write),
-%% {BinMsgs, CS1} = encode_handshake_rec(HandshakeRec, Version, MsgSeq, BinMsgs0, CS0),
-%% ConnectionStates1 = ssl_record:set_connection_state_by_epoch(ConnectionStates0, CS1, write),
-%% do_send_flight(T, BinMsgs, State#state{connection_states = ConnectionStates1}).
-
-%% cancel_dtls_retransmit_timer(State = #state{dtls_retransmit_timer = TimerRef}) ->
-%% cancel_timer(TimerRef),
-%% State#state{dtls_retransmit_timer = undefined}.
-
-%% rearm_dtls_retransmit_timer(State = #state{dtls_retransmit_timer = undefined}) ->
-%% TimerRef = erlang:start_timer(1000, self(), dtls_retransmit),
-%% State#state{dtls_retransmit_timer = TimerRef};
-%% rearm_dtls_retransmit_timer(State) ->
-%% State.
-
-%% finish_send_flight({254, _}, waiting, State) ->
-%% TimerRef = erlang:start_timer(1000, self(), dtls_retransmit),
-%% State#state{
-%% dtls_retransmit_timer = TimerRef,
-%% last_retransmit = timestamp(),
-%% flight_state = waiting};
-
-%% finish_send_flight(_, FlightState, State) ->
-%% State#state{flight_state = FlightState}.
-
-%% timestamp() ->
-%% {Mega, Sec, Micro} = erlang:now(),
-%% Mega * 1000000 * 1000 + Sec * 1000 + (Micro div 1000).
-
-%% encode_handshake_rec(HandshakeRec, Version, MsgSeq, BinMsgs0, CS0) ->
-%% {_, Fragments} = ssl_handshake:encode_handshake(HandshakeRec, Version, MsgSeq, 1400),
-%% lists:foldl(fun(F, {Bin, C0}) ->
-%% {B, C1} = ssl_record:encode_handshake(F, Version, C0),
-%% {[B|Bin], C1} end, {BinMsgs0, CS0}, Fragments).
+%%====================================================================
+%% Internal application API
+%%====================================================================
+start_fsm(Role, Host, Port, Socket, {#ssl_options{erl_dist = false},_} = Opts,
+ User, {CbModule, _,_, _} = CbInfo,
+ Timeout) ->
+ try
+ {ok, Pid} = dtls_connection_sup:start_child([Role, Host, Port, Socket,
+ Opts, User, CbInfo]),
+ {ok, SslSocket} = ssl_connection:socket_control(?MODULE, Socket, Pid, CbModule),
+ ok = ssl_connection:handshake(SslSocket, Timeout),
+ {ok, SslSocket}
+ catch
+ error:{badmatch, {error, _} = Error} ->
+ Error
+ end;
+
+start_fsm(Role, Host, Port, Socket, {#ssl_options{erl_dist = true},_} = Opts,
+ User, {CbModule, _,_, _} = CbInfo,
+ Timeout) ->
+ try
+ {ok, Pid} = dtls_connection_sup:start_child_dist([Role, Host, Port, Socket,
+ Opts, User, CbInfo]),
+ {ok, SslSocket} = ssl_connection:socket_control(?MODULE, Socket, Pid, CbModule),
+ ok = ssl_connection:handshake(SslSocket, Timeout),
+ {ok, SslSocket}
+ catch
+ error:{badmatch, {error, _} = Error} ->
+ Error
+ end.
+
+send_handshake(Handshake, #state{negotiated_version = Version,
+ tls_handshake_history = Hist0,
+ connection_states = ConnectionStates0} = State0) ->
+ {BinHandshake, ConnectionStates, Hist} =
+ encode_handshake(Handshake, Version, ConnectionStates0, Hist0),
+ send_flight(BinHandshake, State0#state{connection_states = ConnectionStates,
+ tls_handshake_history = Hist
+ }).
+
+send_alert(Alert, #state{negotiated_version = Version,
+ socket = Socket,
+ transport_cb = Transport,
+ connection_states = ConnectionStates0} = State0) ->
+ {BinMsg, ConnectionStates} =
+ ssl_alert:encode(Alert, Version, ConnectionStates0),
+ Transport:send(Socket, BinMsg),
+ State0#state{connection_states = ConnectionStates}.
+
+send_change_cipher(Msg, #state{connection_states = ConnectionStates0,
+ socket = Socket,
+ negotiated_version = Version,
+ transport_cb = Transport} = State0) ->
+ {BinChangeCipher, ConnectionStates} =
+ encode_change_cipher(Msg, Version, ConnectionStates0),
+ Transport:send(Socket, BinChangeCipher),
+ State0#state{connection_states = ConnectionStates}.
+
+%%====================================================================
+%% tls_connection_sup API
+%%====================================================================
+
+%%--------------------------------------------------------------------
+-spec start_link(atom(), host(), inet:port_number(), port(), list(), pid(), tuple()) ->
+ {ok, pid()} | ignore | {error, reason()}.
+%%
+%% Description: Creates a gen_fsm process which calls Module:init/1 to
+%% initialize. To ensure a synchronized start-up procedure, this function
+%% does not return until Module:init/1 has returned.
+%%--------------------------------------------------------------------
+start_link(Role, Host, Port, Socket, Options, User, CbInfo) ->
+ {ok, proc_lib:spawn_link(?MODULE, init, [[Role, Host, Port, Socket, Options, User, CbInfo]])}.
+
+init([Role, Host, Port, Socket, {SSLOpts0, _} = Options, User, CbInfo]) ->
+ process_flag(trap_exit, true),
+ State0 = initial_state(Role, Host, Port, Socket, Options, User, CbInfo),
+ Handshake = ssl_handshake:init_handshake_history(),
+ TimeStamp = calendar:datetime_to_gregorian_seconds({date(), time()}),
+ try ssl_config:init(SSLOpts0, Role) of
+ {ok, Ref, CertDbHandle, FileRefHandle, CacheHandle, OwnCert, Key, DHParams} ->
+ Session = State0#state.session,
+ State = State0#state{
+ tls_handshake_history = Handshake,
+ session = Session#session{own_certificate = OwnCert,
+ time_stamp = TimeStamp},
+ file_ref_db = FileRefHandle,
+ cert_db_ref = Ref,
+ cert_db = CertDbHandle,
+ session_cache = CacheHandle,
+ private_key = Key,
+ diffie_hellman_params = DHParams},
+ gen_fsm:enter_loop(?MODULE, [], hello, State, get_timeout(State))
+ catch
+ throw:Error ->
+ gen_fsm:enter_loop(?MODULE, [], error, {Error,State0}, get_timeout(State0))
+ end.
+
+%%--------------------------------------------------------------------
+%% Description:There should be one instance of this function for each
+%% possible state name. Whenever a gen_fsm receives an event sent
+%% using gen_fsm:send_event/2, the instance of this function with the
+%% same name as the current state name StateName is called to handle
+%% the event. It is also called if a timeout occurs.
+%%
+hello(start, #state{host = Host, port = Port, role = client,
+ ssl_options = SslOpts,
+ session = #session{own_certificate = Cert} = Session0,
+ session_cache = Cache, session_cache_cb = CacheCb,
+ transport_cb = Transport, socket = Socket,
+ connection_states = ConnectionStates0,
+ renegotiation = {Renegotiation, _}} = State0) ->
+ Hello = dtls_handshake:client_hello(Host, Port, ConnectionStates0, SslOpts,
+ Cache, CacheCb, Renegotiation, Cert),
+
+ Version = Hello#client_hello.client_version,
+ Handshake0 = ssl_handshake:init_handshake_history(),
+ {BinMsg, ConnectionStates, Handshake} =
+ encode_handshake(Hello, Version, ConnectionStates0, Handshake0),
+ Transport:send(Socket, BinMsg),
+ State1 = State0#state{connection_states = ConnectionStates,
+ negotiated_version = Version, %% Requested version
+ session =
+ Session0#session{session_id = Hello#client_hello.session_id},
+ tls_handshake_history = Handshake},
+ {Record, State} = next_record(State1),
+ next_state(hello, hello, Record, State);
+
+hello(Hello = #client_hello{client_version = ClientVersion,
+ extensions = #hello_extensions{hash_signs = HashSigns}},
+ State = #state{connection_states = ConnectionStates0,
+ port = Port, session = #session{own_certificate = Cert} = Session0,
+ renegotiation = {Renegotiation, _},
+ session_cache = Cache,
+ session_cache_cb = CacheCb,
+ ssl_options = SslOpts}) ->
+ HashSign = ssl_handshake:select_hashsign(HashSigns, Cert),
+ case dtls_handshake:hello(Hello, SslOpts, {Port, Session0, Cache, CacheCb,
+ ConnectionStates0, Cert}, Renegotiation) of
+ {Version, {Type, Session},
+ ConnectionStates,
+ #hello_extensions{ec_point_formats = EcPointFormats,
+ elliptic_curves = EllipticCurves} = ServerHelloExt} ->
+ ssl_connection:hello({common_client_hello, Type, ServerHelloExt, HashSign},
+ State#state{connection_states = ConnectionStates,
+ negotiated_version = Version,
+ session = Session,
+ client_ecc = {EllipticCurves, EcPointFormats}}, ?MODULE);
+ #alert{} = Alert ->
+ handle_own_alert(Alert, ClientVersion, hello, State)
+ end;
+hello(Hello,
+ #state{connection_states = ConnectionStates0,
+ negotiated_version = ReqVersion,
+ role = client,
+ renegotiation = {Renegotiation, _},
+ ssl_options = SslOptions} = State) ->
+ case dtls_handshake:hello(Hello, SslOptions, ConnectionStates0, Renegotiation) of
+ #alert{} = Alert ->
+ handle_own_alert(Alert, ReqVersion, hello, State);
+ {Version, NewId, ConnectionStates, NextProtocol} ->
+ ssl_connection:handle_session(Hello,
+ Version, NewId, ConnectionStates, NextProtocol, State)
+ end;
+
+hello(Msg, State) ->
+ ssl_connection:hello(Msg, State, ?MODULE).
+
+abbreviated(Msg, State) ->
+ ssl_connection:abbreviated(Msg, State, ?MODULE).
+
+certify(Msg, State) ->
+ ssl_connection:certify(Msg, State, ?MODULE).
+
+cipher(Msg, State) ->
+ ssl_connection:cipher(Msg, State, ?MODULE).
+
+connection(#hello_request{}, #state{host = Host, port = Port,
+ session = #session{own_certificate = Cert} = Session0,
+ session_cache = Cache, session_cache_cb = CacheCb,
+ ssl_options = SslOpts,
+ connection_states = ConnectionStates0,
+ renegotiation = {Renegotiation, _}} = State0) ->
+ Hello = dtls_handshake:client_hello(Host, Port, ConnectionStates0, SslOpts,
+ Cache, CacheCb, Renegotiation, Cert),
+ %% TODO DTLS version State1 = send_handshake(Hello, State0),
+ State1 = State0,
+ {Record, State} =
+ next_record(
+ State1#state{session = Session0#session{session_id
+ = Hello#client_hello.session_id}}),
+ next_state(connection, hello, Record, State);
+
+connection(#client_hello{} = Hello, #state{role = server, allow_renegotiate = true} = State) ->
+ %% Mitigate Computational DoS attack
+ %% http://www.educatedguesswork.org/2011/10/ssltls_and_computational_dos.html
+ %% http://www.thc.org/thc-ssl-dos/ Rather than disabling client
+ %% initiated renegotiation we will disallow many client initiated
+ %% renegotiations immediately after each other.
+ erlang:send_after(?WAIT_TO_ALLOW_RENEGOTIATION, self(), allow_renegotiate),
+ hello(Hello, State#state{allow_renegotiate = false});
+
+connection(#client_hello{}, #state{role = server, allow_renegotiate = false} = State0) ->
+ Alert = ?ALERT_REC(?WARNING, ?NO_RENEGOTIATION),
+ State = send_alert(Alert, State0),
+ next_state_connection(connection, State);
+
+connection(Msg, State) ->
+ ssl_connection:connection(Msg, State, tls_connection).
+
+%%--------------------------------------------------------------------
+%% Description: Whenever a gen_fsm receives an event sent using
+%% gen_fsm:send_all_state_event/2, this function is called to handle
+%% the event. Not currently used!
+%%--------------------------------------------------------------------
+handle_event(_Event, StateName, State) ->
+ {next_state, StateName, State, get_timeout(State)}.
+
+%%--------------------------------------------------------------------
+%% Description: Whenever a gen_fsm receives an event sent using
+%% gen_fsm:sync_send_all_state_event/2,3, this function is called to handle
+%% the event.
+%%--------------------------------------------------------------------
+handle_sync_event(Event, From, StateName, State) ->
+ ssl_connection:handle_sync_event(Event, From, StateName, State).
+
+%%--------------------------------------------------------------------
+%% Description: This function is called by a gen_fsm when it receives any
+%% other message than a synchronous or asynchronous event
+%% (or a system message).
+%%--------------------------------------------------------------------
+
+%% raw data from socket, unpack records
+handle_info({Protocol, _, Data}, StateName,
+ #state{data_tag = Protocol} = State0) ->
+ %% Simplify for now to avoid dialzer warnings before implementation is compleate
+ %% case next_tls_record(Data, State0) of
+ %% {Record, State} ->
+ %% next_state(StateName, StateName, Record, State);
+ %% #alert{} = Alert ->
+ %% handle_normal_shutdown(Alert, StateName, State0),
+ %% {stop, {shutdown, own_alert}, State0}
+ %% end;
+ {Record, State} = next_tls_record(Data, State0),
+ next_state(StateName, StateName, Record, State);
+
+handle_info({CloseTag, Socket}, StateName,
+ #state{socket = Socket, close_tag = CloseTag,
+ negotiated_version = _Version} = State) ->
+ handle_normal_shutdown(?ALERT_REC(?FATAL, ?CLOSE_NOTIFY), StateName, State),
+ {stop, {shutdown, transport_closed}, State};
+
+handle_info(Msg, StateName, State) ->
+ ssl_connection:handle_info(Msg, StateName, State).
+
+%%--------------------------------------------------------------------
+%% Description:This function is called by a gen_fsm when it is about
+%% to terminate. It should be the opposite of Module:init/1 and do any
+%% necessary cleaning up. When it returns, the gen_fsm terminates with
+%% Reason. The return value is ignored.
+%%--------------------------------------------------------------------
+terminate(Reason, StateName, State) ->
+ ssl_connection:terminate(Reason, StateName, State).
+
+%%--------------------------------------------------------------------
+%% code_change(OldVsn, StateName, State, Extra) -> {ok, StateName, NewState}
+%% Description: Convert process state when code is changed
+%%--------------------------------------------------------------------
+code_change(_OldVsn, StateName, State, _Extra) ->
+ {ok, StateName, State}.
+
+%%--------------------------------------------------------------------
+%%% Internal functions
+%%--------------------------------------------------------------------
+encode_handshake(Handshake, Version, ConnectionStates0, Hist0) ->
+ Seq = sequence(ConnectionStates0),
+ {EncHandshake, FragmentedHandshake} = dtls_handshake:encode_handshake(Handshake, Version,
+ Seq),
+ Hist = ssl_handshake:update_handshake_history(Hist0, EncHandshake),
+ {Encoded, ConnectionStates} =
+ dtls_record:encode_handshake(FragmentedHandshake,
+ Version, ConnectionStates0),
+ {Encoded, ConnectionStates, Hist}.
+
+next_record(#state{%%flight = #flight{state = finished},
+ protocol_buffers =
+ #protocol_buffers{dtls_packets = [], dtls_cipher_texts = [CT | Rest]}
+ = Buffers,
+ connection_states = ConnStates0} = State) ->
+ case dtls_record:decode_cipher_text(CT, ConnStates0) of
+ {Plain, ConnStates} ->
+ {Plain, State#state{protocol_buffers =
+ Buffers#protocol_buffers{dtls_cipher_texts = Rest},
+ connection_states = ConnStates}};
+ #alert{} = Alert ->
+ {Alert, State}
+ end;
+next_record(#state{socket = Socket,
+ transport_cb = Transport} = State) -> %% when FlightState =/= finished
+ ssl_socket:setopts(Transport, Socket, [{active,once}]),
+ {no_record, State};
+
+
+next_record(State) ->
+ {no_record, State}.
+
+next_state(Current,_, #alert{} = Alert, #state{negotiated_version = Version} = State) ->
+ handle_own_alert(Alert, Version, Current, State);
+
+next_state(_,Next, no_record, State) ->
+ {next_state, Next, State, get_timeout(State)};
+
+%% next_state(_,Next, #ssl_tls{type = ?ALERT, fragment = EncAlerts}, State) ->
+%% Alerts = decode_alerts(EncAlerts),
+%% handle_alerts(Alerts, {next_state, Next, State, get_timeout(State)});
+
+next_state(Current, Next, #ssl_tls{type = ?HANDSHAKE, fragment = Data},
+ State0 = #state{protocol_buffers =
+ #protocol_buffers{dtls_handshake_buffer = Buf0} = Buffers,
+ negotiated_version = Version}) ->
+ Handle =
+ fun({#hello_request{} = Packet, _}, {next_state, connection = SName, State}) ->
+ %% This message should not be included in handshake
+ %% message hashes. Starts new handshake (renegotiation)
+ Hs0 = ssl_handshake:init_handshake_history(),
+ ?MODULE:SName(Packet, State#state{tls_handshake_history=Hs0,
+ renegotiation = {true, peer}});
+ ({#hello_request{} = Packet, _}, {next_state, SName, State}) ->
+ %% This message should not be included in handshake
+ %% message hashes. Already in negotiation so it will be ignored!
+ ?MODULE:SName(Packet, State);
+ ({#client_hello{} = Packet, Raw}, {next_state, connection = SName, State}) ->
+ Version = Packet#client_hello.client_version,
+ Hs0 = ssl_handshake:init_handshake_history(),
+ Hs1 = ssl_handshake:update_handshake_history(Hs0, Raw),
+ ?MODULE:SName(Packet, State#state{tls_handshake_history=Hs1,
+ renegotiation = {true, peer}});
+ ({Packet, Raw}, {next_state, SName, State = #state{tls_handshake_history=Hs0}}) ->
+ Hs1 = ssl_handshake:update_handshake_history(Hs0, Raw),
+ ?MODULE:SName(Packet, State#state{tls_handshake_history=Hs1});
+ (_, StopState) -> StopState
+ end,
+ try
+ {Packets, Buf} = tls_handshake:get_tls_handshake(Version,Data,Buf0),
+ State = State0#state{protocol_buffers =
+ Buffers#protocol_buffers{dtls_packets = Packets,
+ dtls_handshake_buffer = Buf}},
+ handle_dtls_handshake(Handle, Next, State)
+ catch throw:#alert{} = Alert ->
+ handle_own_alert(Alert, Version, Current, State0)
+ end;
+
+next_state(_, StateName, #ssl_tls{type = ?APPLICATION_DATA, fragment = Data}, State0) ->
+ %% Simplify for now to avoid dialzer warnings before implementation is compleate
+ %% case read_application_data(Data, State0) of
+ %% Stop = {stop,_,_} ->
+ %% Stop;
+ %% {Record, State} ->
+ %% next_state(StateName, StateName, Record, State)
+ %% end;
+ {Record, State} = read_application_data(Data, State0),
+ next_state(StateName, StateName, Record, State);
+
+next_state(Current, Next, #ssl_tls{type = ?CHANGE_CIPHER_SPEC, fragment = <<1>>} =
+ _ChangeCipher,
+ #state{connection_states = ConnectionStates0} = State0) ->
+ ConnectionStates1 =
+ ssl_record:activate_pending_connection_state(ConnectionStates0, read),
+ {Record, State} = next_record(State0#state{connection_states = ConnectionStates1}),
+ next_state(Current, Next, Record, State);
+next_state(Current, Next, #ssl_tls{type = _Unknown}, State0) ->
+ %% Ignore unknown type
+ {Record, State} = next_record(State0),
+ next_state(Current, Next, Record, State).
+
+handle_dtls_handshake(Handle, StateName,
+ #state{protocol_buffers =
+ #protocol_buffers{dtls_packets = [Packet]} = Buffers} = State) ->
+ FsmReturn = {next_state, StateName, State#state{protocol_buffers =
+ Buffers#protocol_buffers{dtls_packets = []}}},
+ Handle(Packet, FsmReturn);
+
+handle_dtls_handshake(Handle, StateName,
+ #state{protocol_buffers =
+ #protocol_buffers{dtls_packets = [Packet | Packets]} = Buffers} =
+ State0) ->
+ FsmReturn = {next_state, StateName, State0#state{protocol_buffers =
+ Buffers#protocol_buffers{dtls_packets =
+ Packets}}},
+ case Handle(Packet, FsmReturn) of
+ {next_state, NextStateName, State, _Timeout} ->
+ handle_dtls_handshake(Handle, NextStateName, State);
+ {stop, _,_} = Stop ->
+ Stop
+ end.
+
+
+send_flight(Fragments, #state{transport_cb = Transport, socket = Socket,
+ protocol_buffers = _PBuffers} = State) ->
+ Transport:send(Socket, Fragments),
+ %% Start retransmission
+ %% State#state{protocol_buffers =
+ %% (PBuffers#protocol_buffers){ #flight{state = waiting}}}}.
+ State.
+
+handle_own_alert(_,_,_, State) -> %% Place holder
+ {stop, {shutdown, own_alert}, State}.
+
+handle_normal_shutdown(_, _, _State) -> %% Place holder
+ ok.
+
+encode_change_cipher(#change_cipher_spec{}, Version, ConnectionStates) ->
+ dtls_record:encode_change_cipher_spec(Version, ConnectionStates).
+
+initial_state(Role, Host, Port, Socket, {SSLOptions, SocketOptions}, User,
+ {CbModule, DataTag, CloseTag, ErrorTag}) ->
+ ConnectionStates = ssl_record:init_connection_states(Role),
+
+ SessionCacheCb = case application:get_env(ssl, session_cb) of
+ {ok, Cb} when is_atom(Cb) ->
+ Cb;
+ _ ->
+ ssl_session_cache
+ end,
+
+ Monitor = erlang:monitor(process, User),
+
+ #state{socket_options = SocketOptions,
+ %% We do not want to save the password in the state so that
+ %% could be written in the clear into error logs.
+ ssl_options = SSLOptions#ssl_options{password = undefined},
+ session = #session{is_resumable = new},
+ transport_cb = CbModule,
+ data_tag = DataTag,
+ close_tag = CloseTag,
+ error_tag = ErrorTag,
+ role = Role,
+ host = Host,
+ port = Port,
+ socket = Socket,
+ connection_states = ConnectionStates,
+ protocol_buffers = #protocol_buffers{},
+ user_application = {Monitor, User},
+ user_data_buffer = <<>>,
+ session_cache_cb = SessionCacheCb,
+ renegotiation = {false, first},
+ start_or_recv_from = undefined,
+ send_queue = queue:new(),
+ protocol_cb = ?MODULE
+ }.
+read_application_data(_,State) ->
+ {#ssl_tls{fragment = <<"place holder">>}, State}.
+
+next_tls_record(_, State) ->
+ {#ssl_tls{fragment = <<"place holder">>}, State}.
+
+get_timeout(_) -> %% Place holder
+ infinity.
+
+next_state_connection(_, State) -> %% Place holder
+ {next_state, connection, State, get_timeout(State)}.
+
+sequence(_) ->
+ %%TODO real imp
+ 1.
diff --git a/lib/ssl/src/dtls_connection.hrl b/lib/ssl/src/dtls_connection.hrl
index b8dff479d5..08707dc8de 100644
--- a/lib/ssl/src/dtls_connection.hrl
+++ b/lib/ssl/src/dtls_connection.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -28,24 +28,19 @@
-include("ssl_connection.hrl").
-record(protocol_buffers, {
- dtls_packets = [] ::[binary()], % Not yet handled decode ssl/tls packets.
- dtls_record_buffer :: binary(), % Buffer of incomplete records
- dtls_handshake_buffer :: binary(), % Buffer of incomplete handshakes
- dtls_cipher_texts :: [binary()],
- dtls_cipher_texts_next :: [binary()] % Received for Epoch not yet active
+ dtls_packets = [], %%::[binary()], % Not yet handled decode ssl/tls packets.
+ dtls_record_buffer = <<>>, %%:: binary(), % Buffer of incomplete records
+ dtls_handshake_buffer = <<>>, %%:: binary(), % Buffer of incomplete handshakes
+ dtls_cipher_texts = [], %%:: [binary()],
+ dtls_cipher_texts_next %%:: [binary()] % Received for Epoch not yet active
}).
-record(flight, {
last_retransmit,
last_read_seq,
msl_timer,
- flight_state,
- flight_buffer, % buffer of not yet ACKed TLS records
- }).
-
--record(message_sequences, {
- read = 0,
- write = 0
+ state,
+ buffer % buffer of not yet ACKed TLS records
}).
-endif. % -ifdef(dtls_connection).
diff --git a/lib/ssl/src/dtls_connection_sup.erl b/lib/ssl/src/dtls_connection_sup.erl
index 9fe545be18..0b4711cfb4 100644
--- a/lib/ssl/src/dtls_connection_sup.erl
+++ b/lib/ssl/src/dtls_connection_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -26,8 +26,8 @@
-behaviour(supervisor).
%% API
--export([start_link/0]).
--export([start_child/1]).
+-export([start_link/0, start_link_dist/0]).
+-export([start_child/1, start_child_dist/1]).
%% Supervisor callback
-export([init/1]).
@@ -38,8 +38,14 @@
start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
+start_link_dist() ->
+ supervisor:start_link({local, dtls_connection_sup_dist}, ?MODULE, []).
+
start_child(Args) ->
supervisor:start_child(?MODULE, Args).
+
+start_child_dist(Args) ->
+ supervisor:start_child(dtls_connection_sup_dist, Args).
%%%=========================================================================
%%% Supervisor callback
diff --git a/lib/ssl/src/dtls_handshake.erl b/lib/ssl/src/dtls_handshake.erl
index 5db2434753..31d525b295 100644
--- a/lib/ssl/src/dtls_handshake.erl
+++ b/lib/ssl/src/dtls_handshake.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -20,11 +20,15 @@
-include("dtls_handshake.hrl").
-include("dtls_record.hrl").
-include("ssl_internal.hrl").
+-include("ssl_alert.hrl").
--export([client_hello/8, client_hello/9, hello/3,
+-export([client_hello/8, client_hello/9, hello/4,
get_dtls_handshake/2,
- dtls_handshake_new_flight/1, dtls_handshake_new_epoch/1,
- encode_handshake/4]).
+ %%dtls_handshake_new_flight/1, dtls_handshake_new_epoch/1,
+ encode_handshake/3]).
+
+-type dtls_handshake() :: #client_hello{} | #hello_verify_request{} |
+ ssl_handshake:ssl_handshake().
%%====================================================================
%% Internal application API
@@ -54,12 +58,12 @@ client_hello(Host, Port, Cookie, ConnectionStates,
ciphers = UserSuites
} = SslOpts,
Cache, CacheCb, Renegotiation, OwnCert) ->
- Version = dtls_record:highest_protocol_version(Versions),
+ Version = dtls_record:highest_protocol_version(Versions),
Pending = ssl_record:pending_connection_state(ConnectionStates, read),
SecParams = Pending#connection_state.security_parameters,
CipherSuites = ssl_handshake:available_suites(UserSuites, Version),
- Extensions = ssl_handshake:client_hello_extensions(Host, Version, CipherSuites,
+ Extensions = ssl_handshake:client_hello_extensions(Host, dtls_v1:corresponding_tls_version(Version), CipherSuites,
SslOpts, ConnectionStates, Renegotiation),
Id = ssl_session:client_id({Host, Port, SslOpts}, Cache, CacheCb, OwnCert),
@@ -73,163 +77,197 @@ client_hello(Host, Port, Cookie, ConnectionStates,
extensions = Extensions
}.
-hello(Address, Port,
- #ssl_tls{epoch = _Epoch, record_seq = _Seq,
- version = Version} = Record) ->
- {[{Hello, _}], _, _} =
- get_dtls_handshake(Record,
- dtls_handshake_new_flight(undefined)),
- #client_hello{client_version = {Major, Minor},
- random = Random,
- session_id = SessionId,
- cipher_suites = CipherSuites,
- compression_methods = CompressionMethods} = Hello,
- CookieData = [address_to_bin(Address, Port),
- <<?BYTE(Major), ?BYTE(Minor)>>,
- Random, SessionId, CipherSuites, CompressionMethods],
- Cookie = crypto:hmac(sha, <<"secret">>, CookieData),
-
- case Hello of
- #client_hello{cookie = Cookie} ->
- accept;
- _ ->
- %% generate HelloVerifyRequest
- HelloVerifyRequest = encode_handshake(#hello_verify_request{protocol_version = Version,
- cookie = Cookie},
- Version, 0, 1400),
- {reply, HelloVerifyRequest}
- end.
+hello(#server_hello{server_version = Version, random = Random,
+ cipher_suite = CipherSuite,
+ compression_method = Compression,
+ session_id = SessionId, extensions = HelloExt},
+ #ssl_options{versions = SupportedVersions} = SslOpt,
+ ConnectionStates0, Renegotiation) ->
+ case dtls_record:is_acceptable_version(Version, SupportedVersions) of
+ true ->
+ handle_server_hello_extensions(Version, SessionId, Random, CipherSuite,
+ Compression, HelloExt, SslOpt, ConnectionStates0, Renegotiation);
+ false ->
+ ?ALERT_REC(?FATAL, ?PROTOCOL_VERSION)
+ end;
-%%--------------------------------------------------------------------
-encode_handshake(Package, Version, MsgSeq, Mss) ->
- {MsgType, Bin} = enc_hs(Package, Version),
+hello(#client_hello{client_version = ClientVersion}, _Options, {_,_,_,_,ConnectionStates,_}, _Renegotiation) ->
+ %% Return correct typ to make dialyzer happy until we have time to make the real imp.
+ {ClientVersion, {new, #session{}}, ConnectionStates, #hello_extensions{}}.
+
+%% hello(Address, Port,
+%% #ssl_tls{epoch = _Epoch, sequence_number = _Seq,
+%% version = Version} = Record) ->
+%% case get_dtls_handshake(Record,
+%% dtls_handshake_new_flight(undefined)) of
+%% {[Hello | _], _} ->
+%% hello(Address, Port, Version, Hello);
+%% {retransmit, HandshakeState} ->
+%% {retransmit, HandshakeState}
+%% end.
+
+%% hello(Address, Port, Version, Hello) ->
+%% #client_hello{client_version = {Major, Minor},
+%% random = Random,
+%% session_id = SessionId,
+%% cipher_suites = CipherSuites,
+%% compression_methods = CompressionMethods} = Hello,
+%% CookieData = [address_to_bin(Address, Port),
+%% <<?BYTE(Major), ?BYTE(Minor)>>,
+%% Random, SessionId, CipherSuites, CompressionMethods],
+%% Cookie = crypto:hmac(sha, <<"secret">>, CookieData),
+
+%% case Hello of
+%% #client_hello{cookie = Cookie} ->
+%% accept;
+%% _ ->
+%% %% generate HelloVerifyRequest
+%% HelloVerifyRequest = enc_hs(#hello_verify_request{protocol_version = Version,
+%% cookie = Cookie},
+%% Version, 0, 1400),
+%% {reply, HelloVerifyRequest}
+%% end.
+
+%% %%--------------------------------------------------------------------
+encode_handshake(Handshake, Version, MsgSeq) ->
+ {MsgType, Bin} = enc_handshake(Handshake, Version),
Len = byte_size(Bin),
- HsHistory = [MsgType, ?uint24(Len), ?uint16(MsgSeq), ?uint24(0), ?uint24(Len), Bin],
- BinMsg = dtls_split_handshake(Mss, MsgType, Len, MsgSeq, Bin, 0, []),
- {HsHistory, BinMsg}.
+ EncHandshake = [MsgType, ?uint24(Len), ?uint16(MsgSeq), ?uint24(0), ?uint24(Len), Bin],
+ FragmentedHandshake = dtls_fragment(erlang:iolist_size(EncHandshake), MsgType, Len, MsgSeq, Bin, 0, []),
+ {EncHandshake, FragmentedHandshake}.
-%--------------------------------------------------------------------
+%%--------------------------------------------------------------------
-spec get_dtls_handshake(#ssl_tls{}, #dtls_hs_state{} | binary()) ->
- {[dtls_handshake()], #dtls_hs_state{}} | {retransmit, #dtls_hs_state{}}.
-%
-% Description: Given a DTLS state and new data from ssl_record, collects
-% and returns it as a list of handshake messages, also returns a new
-% DTLS state
-%--------------------------------------------------------------------
-% get_dtls_handshake(Record, <<>>) ->
-% get_dtls_handshake_aux(Record, dtls_hs_state_init());
+ {[dtls_handshake()], #dtls_hs_state{}} | {retransmit, #dtls_hs_state{}}.
+%%
+%% Description: Given a DTLS state and new data from ssl_record, collects
+%% and returns it as a list of handshake messages, also returns a new
+%% DTLS state
+%%--------------------------------------------------------------------
+get_dtls_handshake(Record, <<>>) ->
+ get_dtls_handshake_aux(Record, #dtls_hs_state{}); %% Init handshake state!?
get_dtls_handshake(Record, HsState) ->
get_dtls_handshake_aux(Record, HsState).
-%--------------------------------------------------------------------
--spec dtls_handshake_new_epoch(#dtls_hs_state{}) -> #dtls_hs_state{}.
-%
-% Description: Reset the DTLS decoder state for a new Epoch
-%--------------------------------------------------------------------
-% dtls_handshake_new_epoch(<<>>) ->
-% dtls_hs_state_init();
-dtls_handshake_new_epoch(HsState) ->
- HsState#dtls_hs_state{highest_record_seq = 0,
- starting_read_seq = HsState#dtls_hs_state.current_read_seq,
- fragments = gb_trees:empty(), completed = []}.
-
-%--------------------------------------------------------------------
--spec dtls_handshake_new_flight(integer() | undefined) -> #dtls_hs_state{}.
-%
-% Description: Init the DTLS decoder state for a new Flight
-dtls_handshake_new_flight(ExpectedReadReq) ->
- #dtls_hs_state{current_read_seq = ExpectedReadReq,
- highest_record_seq = 0,
- starting_read_seq = 0,
- fragments = gb_trees:empty(), completed = []}.
+%% %%--------------------------------------------------------------------
+%% -spec dtls_handshake_new_epoch(#dtls_hs_state{}) -> #dtls_hs_state{}.
+%% %%
+%% %% Description: Reset the DTLS decoder state for a new Epoch
+%% %%--------------------------------------------------------------------
+%% dtls_handshake_new_epoch(<<>>) ->
+%% dtls_hs_state_init();
+%% dtls_handshake_new_epoch(HsState) ->
+%% HsState#dtls_hs_state{highest_record_seq = 0,
+%% starting_read_seq = HsState#dtls_hs_state.current_read_seq,
+%% fragments = gb_trees:empty(), completed = []}.
+
+%% %--------------------------------------------------------------------
+%% -spec dtls_handshake_new_flight(integer() | undefined) -> #dtls_hs_state{}.
+%% %
+%% % Description: Init the DTLS decoder state for a new Flight
+%% dtls_handshake_new_flight(ExpectedReadReq) ->
+%% #dtls_hs_state{current_read_seq = ExpectedReadReq,
+%% highest_record_seq = 0,
+%% starting_read_seq = 0,
+%% fragments = gb_trees:empty(), completed = []}.
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
+handle_server_hello_extensions(Version, SessionId, Random, CipherSuite,
+ Compression, HelloExt, SslOpt, ConnectionStates0, Renegotiation) ->
+ case ssl_handshake:handle_server_hello_extensions(dtls_record, Random, CipherSuite,
+ Compression, HelloExt, Version,
+ SslOpt, ConnectionStates0, Renegotiation) of
+ #alert{} = Alert ->
+ Alert;
+ {ConnectionStates, Protocol} ->
+ {Version, SessionId, ConnectionStates, Protocol}
+ end.
-dtls_split_handshake(Mss, MsgType, Len, MsgSeq, Bin, Offset, Acc)
+dtls_fragment(Mss, MsgType, Len, MsgSeq, Bin, Offset, Acc)
when byte_size(Bin) + 12 < Mss ->
FragmentLen = byte_size(Bin),
BinMsg = [MsgType, ?uint24(Len), ?uint16(MsgSeq), ?uint24(Offset), ?uint24(FragmentLen), Bin],
lists:reverse([BinMsg|Acc]);
-dtls_split_handshake(Mss, MsgType, Len, MsgSeq, Bin, Offset, Acc) ->
+dtls_fragment(Mss, MsgType, Len, MsgSeq, Bin, Offset, Acc) ->
FragmentLen = Mss - 12,
<<Fragment:FragmentLen/bytes, Rest/binary>> = Bin,
BinMsg = [MsgType, ?uint24(Len), ?uint16(MsgSeq), ?uint24(Offset), ?uint24(FragmentLen), Fragment],
- dtls_split_handshake(Mss, MsgType, Len, MsgSeq, Rest, Offset + FragmentLen, [BinMsg|Acc]).
+ dtls_fragment(Mss, MsgType, Len, MsgSeq, Rest, Offset + FragmentLen, [BinMsg|Acc]).
get_dtls_handshake_aux(#ssl_tls{version = Version,
- record_seq = SeqNo,
- fragment = Data}, HsState) ->
+ sequence_number = SeqNo,
+ fragment = Data}, HsState) ->
get_dtls_handshake_aux(Version, SeqNo, Data, HsState).
get_dtls_handshake_aux(Version, SeqNo,
- <<?BYTE(Type), ?UINT24(Length),
- ?UINT16(MessageSeq),
- ?UINT24(FragmentOffset), ?UINT24(FragmentLength),
- Body:FragmentLength/binary, Rest/binary>>,
- HsState0) ->
+ <<?BYTE(Type), ?UINT24(Length),
+ ?UINT16(MessageSeq),
+ ?UINT24(FragmentOffset), ?UINT24(FragmentLength),
+ Body:FragmentLength/binary, Rest/binary>>,
+ HsState0) ->
case reassemble_dtls_fragment(SeqNo, Type, Length, MessageSeq,
- FragmentOffset, FragmentLength,
- Body, HsState0) of
- {retransmit, HsState1} ->
- case Rest of
- <<>> ->
- {retransmit, HsState1};
- _ ->
- get_dtls_handshake_aux(Version, SeqNo, Rest, HsState1)
- end;
- {HsState1, HighestSeqNo, MsgBody} ->
- HsState2 = dec_dtls_fragment(Version, HighestSeqNo, Type, Length, MessageSeq, MsgBody, HsState1),
- HsState3 = process_dtls_fragments(Version, HsState2),
- get_dtls_handshake_aux(Version, SeqNo, Rest, HsState3);
- HsState2 ->
- HsState3 = process_dtls_fragments(Version, HsState2),
- get_dtls_handshake_aux(Version, SeqNo, Rest, HsState3)
- end;
+ FragmentOffset, FragmentLength,
+ Body, HsState0) of
+ {retransmit, HsState1} ->
+ case Rest of
+ <<>> ->
+ {retransmit, HsState1};
+ _ ->
+ get_dtls_handshake_aux(Version, SeqNo, Rest, HsState1)
+ end;
+ {HsState1, HighestSeqNo, MsgBody} ->
+ HsState2 = dec_dtls_fragment(Version, HighestSeqNo, Type, Length, MessageSeq, MsgBody, HsState1),
+ HsState3 = process_dtls_fragments(Version, HsState2),
+ get_dtls_handshake_aux(Version, SeqNo, Rest, HsState3);
+ HsState2 ->
+ HsState3 = process_dtls_fragments(Version, HsState2),
+ get_dtls_handshake_aux(Version, SeqNo, Rest, HsState3)
+ end;
get_dtls_handshake_aux(_Version, _SeqNo, <<>>, HsState) ->
- {lists:reverse(HsState#dtls_hs_state.completed),
- HsState#dtls_hs_state{completed = []}}.
+ {lists:reverse(HsState#dtls_hs_state.completed),
+ HsState#dtls_hs_state{completed = []}}.
dec_dtls_fragment(Version, SeqNo, Type, Length, MessageSeq, MsgBody,
- HsState = #dtls_hs_state{highest_record_seq = HighestSeqNo, completed = Acc}) ->
+ HsState = #dtls_hs_state{highest_record_seq = HighestSeqNo, completed = Acc}) ->
Raw = <<?BYTE(Type), ?UINT24(Length), ?UINT16(MessageSeq), ?UINT24(0), ?UINT24(Length), MsgBody/binary>>,
H = decode_handshake(Version, Type, MsgBody),
HsState#dtls_hs_state{completed = [{H,Raw}|Acc], highest_record_seq = erlang:max(HighestSeqNo, SeqNo)}.
process_dtls_fragments(Version,
- HsState0 = #dtls_hs_state{current_read_seq = CurrentReadSeq,
- fragments = Fragments0}) ->
+ HsState0 = #dtls_hs_state{current_read_seq = CurrentReadSeq,
+ fragments = Fragments0}) ->
case gb_trees:is_empty(Fragments0) of
- true ->
- HsState0;
- _ ->
- case gb_trees:smallest(Fragments0) of
- {CurrentReadSeq, {SeqNo, Type, Length, CurrentReadSeq, {Length, [{0, Length}], MsgBody}}} ->
- HsState1 = dtls_hs_state_process_seq(HsState0),
- HsState2 = dec_dtls_fragment(Version, SeqNo, Type, Length, CurrentReadSeq, MsgBody, HsState1),
- process_dtls_fragments(Version, HsState2);
- _ ->
- HsState0
- end
- end.
+ true ->
+ HsState0;
+ _ ->
+ case gb_trees:smallest(Fragments0) of
+ {CurrentReadSeq, {SeqNo, Type, Length, CurrentReadSeq, {Length, [{0, Length}], MsgBody}}} ->
+ HsState1 = dtls_hs_state_process_seq(HsState0),
+ HsState2 = dec_dtls_fragment(Version, SeqNo, Type, Length, CurrentReadSeq, MsgBody, HsState1),
+ process_dtls_fragments(Version, HsState2);
+ _ ->
+ HsState0
+ end
+ end.
dtls_hs_state_process_seq(HsState0 = #dtls_hs_state{current_read_seq = CurrentReadSeq,
- fragments = Fragments0}) ->
+ fragments = Fragments0}) ->
Fragments1 = gb_trees:delete_any(CurrentReadSeq, Fragments0),
HsState0#dtls_hs_state{current_read_seq = CurrentReadSeq + 1,
- fragments = Fragments1}.
+ fragments = Fragments1}.
dtls_hs_state_add_fragment(MessageSeq, Fragment, HsState0 = #dtls_hs_state{fragments = Fragments0}) ->
Fragments1 = gb_trees:enter(MessageSeq, Fragment, Fragments0),
HsState0#dtls_hs_state{fragments = Fragments1}.
reassemble_dtls_fragment(SeqNo, Type, Length, MessageSeq, 0, Length,
- Body, HsState0 = #dtls_hs_state{current_read_seq = undefined})
+ Body, HsState0 = #dtls_hs_state{current_read_seq = undefined})
when Type == ?CLIENT_HELLO;
Type == ?SERVER_HELLO;
- Type == ?HELLO_VERIFY_REQUEST ->
+ Type == ?HELLO_VERIFY_REQUEST ->
%% First message, should be client hello
%% return the current message and set the next expected Sequence
%%
@@ -245,8 +283,8 @@ reassemble_dtls_fragment(_SeqNo, _Type, Length, _MessageSeq, _, Length,
HsState;
reassemble_dtls_fragment(SeqNo, _Type, Length, MessageSeq, 0, Length,
- Body, HsState0 =
- #dtls_hs_state{starting_read_seq = StartingReadSeq})
+ Body, HsState0 =
+ #dtls_hs_state{starting_read_seq = StartingReadSeq})
when MessageSeq < StartingReadSeq ->
%% this has to be the start of a new flight, let it through
%%
@@ -257,69 +295,69 @@ reassemble_dtls_fragment(SeqNo, _Type, Length, MessageSeq, 0, Length,
{HsState, SeqNo, Body};
reassemble_dtls_fragment(_SeqNo, _Type, Length, MessageSeq, 0, Length,
- _Body, HsState =
- #dtls_hs_state{current_read_seq = CurrentReadSeq})
+ _Body, HsState =
+ #dtls_hs_state{current_read_seq = CurrentReadSeq})
when MessageSeq < CurrentReadSeq ->
{retransmit, HsState};
reassemble_dtls_fragment(_SeqNo, _Type, Length, MessageSeq, 0, Length,
- _Body, HsState = #dtls_hs_state{current_read_seq = CurrentReadSeq})
+ _Body, HsState = #dtls_hs_state{current_read_seq = CurrentReadSeq})
when MessageSeq < CurrentReadSeq ->
HsState;
reassemble_dtls_fragment(SeqNo, _Type, Length, MessageSeq, 0, Length,
- Body, HsState0 = #dtls_hs_state{current_read_seq = MessageSeq}) ->
+ Body, HsState0 = #dtls_hs_state{current_read_seq = MessageSeq}) ->
%% Message fully contained and it's the current seq
HsState1 = dtls_hs_state_process_seq(HsState0),
{HsState1, SeqNo, Body};
reassemble_dtls_fragment(SeqNo, Type, Length, MessageSeq, 0, Length,
- Body, HsState) ->
+ Body, HsState) ->
%% Message fully contained and it's the NOT the current seq -> buffer
Fragment = {SeqNo, Type, Length, MessageSeq,
- dtls_fragment_init(Length, 0, Length, Body)},
+ dtls_fragment_init(Length, 0, Length, Body)},
dtls_hs_state_add_fragment(MessageSeq, Fragment, HsState);
reassemble_dtls_fragment(_SeqNo, _Type, Length, MessageSeq, FragmentOffset, FragmentLength,
- _Body,
- HsState = #dtls_hs_state{current_read_seq = CurrentReadSeq})
+ _Body,
+ HsState = #dtls_hs_state{current_read_seq = CurrentReadSeq})
when FragmentOffset + FragmentLength == Length andalso MessageSeq == (CurrentReadSeq - 1) ->
{retransmit, HsState};
reassemble_dtls_fragment(_SeqNo, _Type, _Length, MessageSeq, _FragmentOffset, _FragmentLength,
- _Body,
- HsState = #dtls_hs_state{current_read_seq = CurrentReadSeq})
+ _Body,
+ HsState = #dtls_hs_state{current_read_seq = CurrentReadSeq})
when MessageSeq < CurrentReadSeq ->
HsState;
reassemble_dtls_fragment(SeqNo, Type, Length, MessageSeq,
- FragmentOffset, FragmentLength,
- Body,
- HsState = #dtls_hs_state{fragments = Fragments0}) ->
+ FragmentOffset, FragmentLength,
+ Body,
+ HsState = #dtls_hs_state{fragments = Fragments0}) ->
case gb_trees:lookup(MessageSeq, Fragments0) of
- {value, Fragment} ->
- dtls_fragment_reassemble(SeqNo, Type, Length, MessageSeq,
- FragmentOffset, FragmentLength,
- Body, Fragment, HsState);
- none ->
- dtls_fragment_start(SeqNo, Type, Length, MessageSeq,
- FragmentOffset, FragmentLength,
- Body, HsState)
+ {value, Fragment} ->
+ dtls_fragment_reassemble(SeqNo, Type, Length, MessageSeq,
+ FragmentOffset, FragmentLength,
+ Body, Fragment, HsState);
+ none ->
+ dtls_fragment_start(SeqNo, Type, Length, MessageSeq,
+ FragmentOffset, FragmentLength,
+ Body, HsState)
end.
dtls_fragment_start(SeqNo, Type, Length, MessageSeq,
- FragmentOffset, FragmentLength,
- Body, HsState = #dtls_hs_state{fragments = Fragments0}) ->
+ FragmentOffset, FragmentLength,
+ Body, HsState = #dtls_hs_state{fragments = Fragments0}) ->
Fragment = {SeqNo, Type, Length, MessageSeq,
- dtls_fragment_init(Length, FragmentOffset, FragmentLength, Body)},
- Fragments1 = gb_trees:insert(MessageSeq, Fragment, Fragments0),
+ dtls_fragment_init(Length, FragmentOffset, FragmentLength, Body)},
+ Fragments1 = gb_trees:insert(MessageSeq, Fragment, Fragments0),
HsState#dtls_hs_state{fragments = Fragments1}.
dtls_fragment_reassemble(SeqNo, Type, Length, MessageSeq,
FragmentOffset, FragmentLength,
- Body,
- {LastSeqNo, Type, Length, MessageSeq, FragBuffer0},
- HsState = #dtls_hs_state{fragments = Fragments0}) ->
+ Body,
+ {LastSeqNo, Type, Length, MessageSeq, FragBuffer0},
+ HsState = #dtls_hs_state{fragments = Fragments0}) ->
FragBuffer1 = dtls_fragment_add(FragBuffer0, FragmentOffset, FragmentLength, Body),
Fragment = {erlang:max(SeqNo, LastSeqNo), Type, Length, MessageSeq, FragBuffer1},
Fragments1 = gb_trees:enter(MessageSeq, Fragment, Fragments0),
@@ -328,8 +366,8 @@ dtls_fragment_reassemble(SeqNo, Type, Length, MessageSeq,
%% Type, Length or Seq mismatch, drop everything...
%% Note: the RFC is not clear on how to handle this...
dtls_fragment_reassemble(_SeqNo, _Type, _Length, MessageSeq,
- _FragmentOffset, _FragmentLength, _Body, _Fragment,
- HsState = #dtls_hs_state{fragments = Fragments0}) ->
+ _FragmentOffset, _FragmentLength, _Body, _Fragment,
+ HsState = #dtls_hs_state{fragments = Fragments0}) ->
Fragments1 = gb_trees:delete_any(MessageSeq, Fragments0),
HsState#dtls_hs_state{fragments = Fragments1}.
@@ -360,7 +398,7 @@ merge_fragment_list(Rest = [{HStart, _HEnd}|_], Frag = {_FStart, FEnd}, Acc)
lists:reverse(Acc) ++ [Frag|Rest];
merge_fragment_list([{HStart, HEnd}|Rest], _Frag = {FStart, FEnd}, Acc)
- when
+ when
FStart =< HEnd orelse FEnd >= HStart ->
Start = erlang:min(HStart, FStart),
End = erlang:max(HEnd, FEnd),
@@ -370,20 +408,20 @@ merge_fragment_list([{HStart, HEnd}|Rest], _Frag = {FStart, FEnd}, Acc)
add_fragment(List, {FragmentOffset, FragmentLength}) ->
merge_fragment_list(List, {FragmentOffset, FragmentOffset + FragmentLength}, []).
-enc_hs(#hello_verify_request{protocol_version = {Major, Minor},
- cookie = Cookie}, _Version) ->
- CookieLength = byte_size(Cookie),
+enc_handshake(#hello_verify_request{protocol_version = {Major, Minor},
+ cookie = Cookie}, _Version) ->
+ CookieLength = byte_size(Cookie),
{?HELLO_VERIFY_REQUEST, <<?BYTE(Major), ?BYTE(Minor),
- ?BYTE(CookieLength),
- Cookie/binary>>};
-
-enc_hs(#client_hello{client_version = {Major, Minor},
- random = Random,
- session_id = SessionID,
- cookie = Cookie,
- cipher_suites = CipherSuites,
- compression_methods = CompMethods,
- extensions = HelloExtensions}, Version) ->
+ ?BYTE(CookieLength),
+ Cookie/binary>>};
+
+enc_handshake(#client_hello{client_version = {Major, Minor},
+ random = Random,
+ session_id = SessionID,
+ cookie = Cookie,
+ cipher_suites = CipherSuites,
+ compression_methods = CompMethods,
+ extensions = HelloExtensions}, Version) ->
SIDLength = byte_size(SessionID),
BinCookie = enc_client_hello_cookie(Version, Cookie),
BinCompMethods = list_to_binary(CompMethods),
@@ -391,13 +429,13 @@ enc_hs(#client_hello{client_version = {Major, Minor},
BinCipherSuites = list_to_binary(CipherSuites),
CsLength = byte_size(BinCipherSuites),
ExtensionsBin = ssl_handshake:encode_hello_extensions(HelloExtensions),
-
+
{?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
- ?BYTE(SIDLength), SessionID/binary,
- BinCookie/binary,
- ?UINT16(CsLength), BinCipherSuites/binary,
- ?BYTE(CmLength), BinCompMethods/binary, ExtensionsBin/binary>>};
-enc_hs(HandshakeMsg, Version) ->
+ ?BYTE(SIDLength), SessionID/binary,
+ BinCookie/binary,
+ ?UINT16(CsLength), BinCipherSuites/binary,
+ ?BYTE(CmLength), BinCompMethods/binary, ExtensionsBin/binary>>};
+enc_handshake(HandshakeMsg, Version) ->
ssl_handshake:encode_handshake(HandshakeMsg, Version).
enc_client_hello_cookie(_, <<>>) ->
@@ -407,26 +445,26 @@ enc_client_hello_cookie(_, Cookie) ->
<<?BYTE(CookieLength), Cookie/binary>>.
decode_handshake(_Version, ?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
- ?BYTE(SID_length), Session_ID:SID_length/binary,
- ?BYTE(Cookie_length), Cookie:Cookie_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,
+ ?BYTE(Cookie_length), Cookie:Cookie_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(Extensions),
-
+
#client_hello{
client_version = {Major,Minor},
random = Random,
- session_id = Session_ID,
+ session_id = Session_ID,
cookie = Cookie,
cipher_suites = ssl_handshake:decode_suites('2_bytes', CipherSuites),
compression_methods = Comp_methods,
extensions = DecodedExtensions
- };
+ };
decode_handshake(_Version, ?HELLO_VERIFY_REQUEST, <<?BYTE(Major), ?BYTE(Minor),
- ?BYTE(CookieLength), Cookie:CookieLength/binary>>) ->
+ ?BYTE(CookieLength), Cookie:CookieLength/binary>>) ->
#hello_verify_request{
protocol_version = {Major,Minor},
@@ -434,7 +472,7 @@ decode_handshake(_Version, ?HELLO_VERIFY_REQUEST, <<?BYTE(Major), ?BYTE(Minor),
decode_handshake(Version, Tag, Msg) ->
ssl_handshake:decode_handshake(Version, Tag, Msg).
-address_to_bin({A,B,C,D}, Port) ->
- <<0:80,16#ffff:16,A,B,C,D,Port:16>>;
-address_to_bin({A,B,C,D,E,F,G,H}, Port) ->
- <<A:16,B:16,C:16,D:16,E:16,F:16,G:16,H:16,Port:16>>.
+%% address_to_bin({A,B,C,D}, Port) ->
+%% <<0:80,16#ffff:16,A,B,C,D,Port:16>>;
+%% address_to_bin({A,B,C,D,E,F,G,H}, Port) ->
+%% <<A:16,B:16,C:16,D:16,E:16,F:16,G:16,H:16,Port:16>>.
diff --git a/lib/ssl/src/dtls_handshake.hrl b/lib/ssl/src/dtls_handshake.hrl
index 5bdf45f627..3b57575b6d 100644
--- a/lib/ssl/src/dtls_handshake.hrl
+++ b/lib/ssl/src/dtls_handshake.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -53,6 +53,4 @@
completed
}).
--type dtls_handshake() :: #client_hello{} | #hello_verify_request{} | ssl_handshake().
-
-endif. % -ifdef(dtls_handshake).
diff --git a/lib/ssl/src/dtls_record.erl b/lib/ssl/src/dtls_record.erl
index b0a7976864..a7bbb6bc40 100644
--- a/lib/ssl/src/dtls_record.erl
+++ b/lib/ssl/src/dtls_record.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -35,7 +35,7 @@
-export([decode_cipher_text/2]).
%% Encoding
--export([encode_plain_text/4]).
+-export([encode_plain_text/4, encode_handshake/3, encode_change_cipher_spec/2]).
%% Protocol version handling
-export([protocol_version/1, lowest_protocol_version/2,
@@ -46,6 +46,11 @@
-export([init_connection_state_seq/2, current_connection_state_epoch/2,
set_connection_state_by_epoch/3, connection_state_by_epoch/3]).
+-export_type([dtls_version/0, dtls_atom_version/0]).
+
+-type dtls_version() :: ssl_record:ssl_version().
+-type dtls_atom_version() :: dtlsv1 | 'dtlsv1.2'.
+
-compile(inline).
%%====================================================================
@@ -70,7 +75,7 @@ get_dtls_records_aux(<<?BYTE(?APPLICATION_DATA),?BYTE(MajVer),?BYTE(MinVer),
Acc) ->
get_dtls_records_aux(Rest, [#ssl_tls{type = ?APPLICATION_DATA,
version = {MajVer, MinVer},
- epoch = Epoch, record_seq = SequenceNumber,
+ epoch = Epoch, sequence_number = SequenceNumber,
fragment = Data} | Acc]);
get_dtls_records_aux(<<?BYTE(?HANDSHAKE),?BYTE(MajVer),?BYTE(MinVer),
?UINT16(Epoch), ?UINT48(SequenceNumber),
@@ -78,7 +83,7 @@ get_dtls_records_aux(<<?BYTE(?HANDSHAKE),?BYTE(MajVer),?BYTE(MinVer),
Data:Length/binary, Rest/binary>>, Acc) when MajVer >= 128 ->
get_dtls_records_aux(Rest, [#ssl_tls{type = ?HANDSHAKE,
version = {MajVer, MinVer},
- epoch = Epoch, record_seq = SequenceNumber,
+ epoch = Epoch, sequence_number = SequenceNumber,
fragment = Data} | Acc]);
get_dtls_records_aux(<<?BYTE(?ALERT),?BYTE(MajVer),?BYTE(MinVer),
?UINT16(Epoch), ?UINT48(SequenceNumber),
@@ -86,7 +91,7 @@ get_dtls_records_aux(<<?BYTE(?ALERT),?BYTE(MajVer),?BYTE(MinVer),
Rest/binary>>, Acc) ->
get_dtls_records_aux(Rest, [#ssl_tls{type = ?ALERT,
version = {MajVer, MinVer},
- epoch = Epoch, record_seq = SequenceNumber,
+ epoch = Epoch, sequence_number = SequenceNumber,
fragment = Data} | Acc]);
get_dtls_records_aux(<<?BYTE(?CHANGE_CIPHER_SPEC),?BYTE(MajVer),?BYTE(MinVer),
?UINT16(Epoch), ?UINT48(SequenceNumber),
@@ -94,7 +99,7 @@ get_dtls_records_aux(<<?BYTE(?CHANGE_CIPHER_SPEC),?BYTE(MajVer),?BYTE(MinVer),
Acc) ->
get_dtls_records_aux(Rest, [#ssl_tls{type = ?CHANGE_CIPHER_SPEC,
version = {MajVer, MinVer},
- epoch = Epoch, record_seq = SequenceNumber,
+ epoch = Epoch, sequence_number = SequenceNumber,
fragment = Data} | Acc]);
get_dtls_records_aux(<<0:1, _CT:7, ?BYTE(_MajVer), ?BYTE(_MinVer),
@@ -125,14 +130,15 @@ encode_plain_text(Type, Version, Data,
{Comp, CompS1} = ssl_record:compress(CompAlg, Data, CompS0),
WriteState1 = WriteState0#connection_state{compression_state = CompS1},
MacHash = calc_mac_hash(WriteState1, Type, Version, Epoch, Seq, Comp),
- {CipherFragment, WriteState} = ssl_record:cipher(Version, Comp, WriteState1, MacHash),
+ {CipherFragment, WriteState} = ssl_record:cipher(dtls_v1:corresponding_tls_version(Version),
+ Comp, WriteState1, MacHash),
CipherText = encode_tls_cipher_text(Type, Version, Epoch, Seq, CipherFragment),
{CipherText, ConnectionStates#connection_states{current_write =
WriteState#connection_state{sequence_number = Seq +1}}}.
decode_cipher_text(#ssl_tls{type = Type, version = Version,
epoch = Epoch,
- record_seq = Seq,
+ sequence_number = Seq,
fragment = CipherFragment} = CipherText,
#connection_states{current_read =
#connection_state{compression_state = CompressionS0,
@@ -141,7 +147,7 @@ decode_cipher_text(#ssl_tls{type = Type, version = Version,
CompressAlg = SecParams#security_parameters.compression_algorithm,
{PlainFragment, Mac, ReadState1} = ssl_record:decipher(dtls_v1:corresponding_tls_version(Version),
CipherFragment, ReadState0),
- MacHash = calc_mac_hash(Type, Version, Epoch, Seq, PlainFragment, ReadState1),
+ MacHash = calc_mac_hash(ReadState1, Type, Version, Epoch, Seq, PlainFragment),
case ssl_record:is_correct_mac(Mac, MacHash) of
true ->
{Plain, CompressionS1} = ssl_record:uncompress(CompressAlg,
@@ -153,10 +159,27 @@ decode_cipher_text(#ssl_tls{type = Type, version = Version,
false ->
?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)
end.
+%%--------------------------------------------------------------------
+-spec encode_handshake(iolist(), dtls_version(), #connection_states{}) ->
+ {iolist(), #connection_states{}}.
+%%
+%% Description: Encodes a handshake message to send on the ssl-socket.
+%%--------------------------------------------------------------------
+encode_handshake(Frag, Version, ConnectionStates) ->
+ encode_plain_text(?HANDSHAKE, Version, Frag, ConnectionStates).
+
+%%--------------------------------------------------------------------
+-spec encode_change_cipher_spec(dtls_version(), #connection_states{}) ->
+ {iolist(), #connection_states{}}.
+%%
+%% Description: Encodes a change_cipher_spec-message to send on the ssl socket.
+%%--------------------------------------------------------------------
+encode_change_cipher_spec(Version, ConnectionStates) ->
+ encode_plain_text(?CHANGE_CIPHER_SPEC, Version, <<1:8>>, ConnectionStates).
%%--------------------------------------------------------------------
--spec protocol_version(tls_atom_version() | tls_version()) ->
- tls_version() | tls_atom_version().
+-spec protocol_version(dtls_atom_version() | dtls_version()) ->
+ dtls_version() | dtls_atom_version().
%%
%% Description: Creates a protocol version record from a version atom
%% or vice versa.
@@ -170,7 +193,7 @@ protocol_version({254, 253}) ->
protocol_version({254, 255}) ->
dtlsv1.
%%--------------------------------------------------------------------
--spec lowest_protocol_version(tls_version(), tls_version()) -> tls_version().
+-spec lowest_protocol_version(dtls_version(), dtls_version()) -> dtls_version().
%%
%% Description: Lowes protocol version of two given versions
%%--------------------------------------------------------------------
@@ -183,7 +206,7 @@ lowest_protocol_version(Version = {M,_}, {N, _}) when M > N ->
lowest_protocol_version(_,Version) ->
Version.
%%--------------------------------------------------------------------
--spec highest_protocol_version([tls_version()]) -> tls_version().
+-spec highest_protocol_version([dtls_version()]) -> dtls_version().
%%
%% Description: Highest protocol version present in a list
%%--------------------------------------------------------------------
@@ -203,7 +226,7 @@ highest_protocol_version(_, [Version | Rest]) ->
%%--------------------------------------------------------------------
--spec supported_protocol_versions() -> [tls_version()].
+-spec supported_protocol_versions() -> [dtls_version()].
%%
%% Description: Protocol versions supported
%%--------------------------------------------------------------------
@@ -234,7 +257,7 @@ supported_connection_protocol_versions([]) ->
?ALL_DATAGRAM_SUPPORTED_VERSIONS.
%%--------------------------------------------------------------------
--spec is_acceptable_version(tls_version(), Supported :: [tls_version()]) -> boolean().
+-spec is_acceptable_version(dtls_version(), Supported :: [dtls_version()]) -> boolean().
%%
%% Description: ssl version 2 is not acceptable security risks are too big.
%%
@@ -244,7 +267,7 @@ is_acceptable_version(Version, Versions) ->
%%--------------------------------------------------------------------
--spec init_connection_state_seq(tls_version(), #connection_states{}) ->
+-spec init_connection_state_seq(dtls_version(), #connection_states{}) ->
#connection_state{}.
%%
%% Description: Copy the read sequence number to the write sequence number
@@ -343,5 +366,5 @@ calc_mac_hash(#connection_state{mac_secret = MacSecret,
Length, Fragment).
mac_hash(Version, MacAlg, MacSecret, SeqNo, Type, Length, Fragment) ->
- dtls_v1:mac_hash(MacAlg, MacSecret, SeqNo, Type, Version,
+ dtls_v1:mac_hash(Version, MacAlg, MacSecret, SeqNo, Type,
Length, Fragment).
diff --git a/lib/ssl/src/dtls_record.hrl b/lib/ssl/src/dtls_record.hrl
index e935d84bdf..edb77fb2b1 100644
--- a/lib/ssl/src/dtls_record.hrl
+++ b/lib/ssl/src/dtls_record.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -28,16 +28,15 @@
-include("ssl_record.hrl"). %% Common TLS and DTLS records and Constantes
-%% Used to handle tls_plain_text, tls_compressed and tls_cipher_text
+%% Used to handle dtls_plain_text, dtls_compressed and dtls_cipher_text
-record(ssl_tls, {
type,
version,
- record_seq, % used in plain_text
- epoch, % used in plain_text
- message_seq,
- fragment_offset,
- fragment_length,
+ epoch,
+ sequence_number,
+ offset,
+ length,
fragment
}).
diff --git a/lib/ssl/src/dtls_v1.erl b/lib/ssl/src/dtls_v1.erl
index 6e41641483..5a7ab32887 100644
--- a/lib/ssl/src/dtls_v1.erl
+++ b/lib/ssl/src/dtls_v1.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -22,7 +22,7 @@
-export([suites/1, mac_hash/7, ecc_curves/1, corresponding_tls_version/1]).
--spec suites(Minor:: 253|255) -> [cipher_suite()].
+-spec suites(Minor:: 253|255) -> [ssl_cipher:cipher_suite()].
suites(Minor) ->
tls_v1:suites(corresponding_minor_tls_version(Minor)).
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index 9e098e12c4..a88bf45293 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -276,7 +276,7 @@ controlling_process(#sslsocket{pid = {Listen,
Transport:controlling_process(Listen, NewOwner).
%%--------------------------------------------------------------------
--spec connection_info(#sslsocket{}) -> {ok, {tls_atom_version(), erl_cipher_suite()}} |
+-spec connection_info(#sslsocket{}) -> {ok, {tls_record:tls_atom_version(), ssl_cipher:erl_cipher_suite()}} |
{error, reason()}.
%%
%% Description: Returns ssl protocol and cipher used for the connection
@@ -312,7 +312,7 @@ peercert(#sslsocket{pid = {Listen, _}}) when is_port(Listen) ->
{error, enotconn}.
%%--------------------------------------------------------------------
--spec suite_definition(cipher_suite()) -> erl_cipher_suite().
+-spec suite_definition(ssl_cipher:cipher_suite()) -> ssl_cipher:erl_cipher_suite().
%%
%% Description: Return erlang cipher suite definition.
%%--------------------------------------------------------------------
@@ -330,8 +330,8 @@ negotiated_next_protocol(#sslsocket{pid = Pid}) ->
ssl_connection:negotiated_next_protocol(Pid).
%%--------------------------------------------------------------------
--spec cipher_suites() -> [erl_cipher_suite()].
--spec cipher_suites(erlang | openssl | all) -> [erl_cipher_suite()] | [string()].
+-spec cipher_suites() -> [ssl_cipher:erl_cipher_suite()].
+-spec cipher_suites(erlang | openssl | all) -> [ssl_cipher:erl_cipher_suite()] | [string()].
%% Description: Returns all supported cipher suites.
%%--------------------------------------------------------------------
@@ -437,8 +437,8 @@ session_info(#sslsocket{pid = {Listen,_}}) when is_port(Listen) ->
{error, enotconn}.
%%---------------------------------------------------------------
--spec versions() -> [{ssl_app, string()} | {supported, [tls_atom_version()]} |
- {available, [tls_atom_version()]}].
+-spec versions() -> [{ssl_app, string()} | {supported, [tls_record:tls_atom_version()]} |
+ {available, [tls_record:tls_atom_version()]}].
%%
%% Description: Returns a list of relevant versions.
%%--------------------------------------------------------------------
@@ -558,6 +558,8 @@ handle_options(Opts0, _Role) ->
Opts = proplists:expand([{binary, [{mode, binary}]},
{list, [{mode, list}]}], Opts0),
assert_proplist(Opts),
+ RecordCb = record_cb(Opts),
+
ReuseSessionFun = fun(_, _, _, _) -> true end,
DefaultVerifyNoneFun =
@@ -600,12 +602,14 @@ handle_options(Opts0, _Role) ->
end,
CertFile = handle_option(certfile, Opts, <<>>),
-
+
+ RecordCb = record_cb(Opts),
+
Versions = case handle_option(versions, Opts, []) of
[] ->
- tls_record:supported_protocol_versions();
+ RecordCb:supported_protocol_versions();
Vsns ->
- [tls_record:protocol_version(Vsn) || Vsn <- Vsns]
+ [RecordCb:protocol_version(Vsn) || Vsn <- Vsns]
end,
SSLOptions = #ssl_options{
@@ -1035,6 +1039,13 @@ connection_cb(dtls) ->
connection_cb(Opts) ->
connection_cb(proplists:get_value(protocol, Opts, tls)).
+record_cb(tls) ->
+ tls_record;
+record_cb(dtls) ->
+ dtls_record;
+record_cb(Opts) ->
+ record_cb(proplists:get_value(protocol, Opts, tls)).
+
connection_sup(tls_connection) ->
tls_connection_sup;
connection_sup(dtls_connection) ->
diff --git a/lib/ssl/src/ssl_alert.erl b/lib/ssl/src/ssl_alert.erl
index 5c842b4d19..db1535b5ec 100644
--- a/lib/ssl/src/ssl_alert.erl
+++ b/lib/ssl/src/ssl_alert.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -38,7 +38,7 @@
%%====================================================================
%%--------------------------------------------------------------------
--spec encode(#alert{}, tls_version(), #connection_states{}) ->
+-spec encode(#alert{}, ssl_record:ssl_version(), #connection_states{}) ->
{iolist(), #connection_states{}}.
%%
%% Description:
@@ -124,5 +124,17 @@ description_txt(?USER_CANCELED) ->
"user canceled";
description_txt(?NO_RENEGOTIATION) ->
"no renegotiation";
+description_txt(?UNSUPPORTED_EXTENSION) ->
+ "unsupported extension";
+description_txt(?CERTIFICATE_UNOBTAINABLE) ->
+ "certificate unobtainable";
+description_txt(?UNRECOGNISED_NAME) ->
+ "unrecognised name";
+description_txt(?BAD_CERTIFICATE_STATUS_RESPONSE) ->
+ "bad certificate status response";
+description_txt(?BAD_CERTIFICATE_HASH_VALUE) ->
+ "bad certificate hash value";
description_txt(?UNKNOWN_PSK_IDENTITY) ->
- "unknown psk identity".
+ "unknown psk identity";
+description_txt(Enum) ->
+ lists:flatten(io_lib:format("unsupported/unknown alert: ~p", [Enum])).
diff --git a/lib/ssl/src/ssl_alert.hrl b/lib/ssl/src/ssl_alert.hrl
index 2a8a91aefa..2d1f323085 100644
--- a/lib/ssl/src/ssl_alert.hrl
+++ b/lib/ssl/src/ssl_alert.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -48,7 +48,7 @@
%% unsupported_certificate(43),
%% certificate_revoked(44),
%% certificate_expired(45),
- %% certificate_unknown(46),
+%% certificate_unknown(46),
%% illegal_parameter(47),
%% unknown_ca(48),
%% access_denied(49),
@@ -60,6 +60,13 @@
%% internal_error(80),
%% user_canceled(90),
%% no_renegotiation(100),
+%% RFC 4366
+%% unsupported_extension(110),
+%% certificate_unobtainable(111),
+%% unrecognized_name(112),
+%% bad_certificate_status_response(113),
+%% bad_certificate_hash_value(114),
+%% RFC 4366
%% unknown_psk_identity(115),
%% (255)
%% } AlertDescription;
@@ -88,6 +95,11 @@
-define(INTERNAL_ERROR, 80).
-define(USER_CANCELED, 90).
-define(NO_RENEGOTIATION, 100).
+-define(UNSUPPORTED_EXTENSION, 110).
+-define(CERTIFICATE_UNOBTAINABLE, 111).
+-define(UNRECOGNISED_NAME, 112).
+-define(BAD_CERTIFICATE_STATUS_RESPONSE, 113).
+-define(BAD_CERTIFICATE_HASH_VALUE, 114).
-define(UNKNOWN_PSK_IDENTITY, 115).
-define(ALERT_REC(Level,Desc), #alert{level=Level,description=Desc,where={?FILE, ?LINE}}).
diff --git a/lib/ssl/src/ssl_api.hrl b/lib/ssl/src/ssl_api.hrl
index 607991750f..22185ff60a 100644
--- a/lib/ssl/src/ssl_api.hrl
+++ b/lib/ssl/src/ssl_api.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -24,8 +24,6 @@
%% Visible in API
-export_type([connect_option/0, listen_option/0, ssl_option/0, transport_option/0,
- erl_cipher_suite/0, %% From ssl_cipher.hrl
- tls_atom_version/0, %% From ssl_internal.hrl
prf_random/0, sslsocket/0]).
@@ -39,23 +37,24 @@
-type listen_option() :: socket_listen_option() | ssl_option() | transport_option().
-type socket_listen_option() :: gen_tcp:listen_option().
--type ssl_option() :: {verify, verify_type()} |
- {verify_fun, {fun(), InitialUserState::term()}} |
- {fail_if_no_peer_cert, boolean()} | {depth, integer()} |
- {cert, Der::binary()} | {certfile, path()} | {key, Der::binary()} |
- {keyfile, path()} | {password, string()} | {cacerts, [Der::binary()]} |
- {cacertfile, path()} | {dh, Der::binary()} | {dhfile, path()} |
- {user_lookup_fun, {fun(), InitialUserState::term()}} |
- {psk_identity, string()} |
- {srp_identity, {string(), string()}} |
- {ciphers, ciphers()} | {ssl_imp, ssl_imp()} | {reuse_sessions, boolean()} |
- {reuse_session, fun()} | {hibernate_after, integer()|undefined} |
- {next_protocols_advertised, list(binary())} |
- {client_preferred_next_protocols, binary(), client | server, list(binary())}.
+-type ssl_option() :: {versions, ssl_record:ssl_atom_version()} |
+ {verify, verify_type()} |
+ {verify_fun, {fun(), InitialUserState::term()}} |
+ {fail_if_no_peer_cert, boolean()} | {depth, integer()} |
+ {cert, Der::binary()} | {certfile, path()} | {key, Der::binary()} |
+ {keyfile, path()} | {password, string()} | {cacerts, [Der::binary()]} |
+ {cacertfile, path()} | {dh, Der::binary()} | {dhfile, path()} |
+ {user_lookup_fun, {fun(), InitialUserState::term()}} |
+ {psk_identity, string()} |
+ {srp_identity, {string(), string()}} |
+ {ciphers, ciphers()} | {ssl_imp, ssl_imp()} | {reuse_sessions, boolean()} |
+ {reuse_session, fun()} | {hibernate_after, integer()|undefined} |
+ {next_protocols_advertised, list(binary())} |
+ {client_preferred_next_protocols, binary(), client | server, list(binary())}.
-type verify_type() :: verify_none | verify_peer.
-type path() :: string().
--type ciphers() :: [erl_cipher_suite()] |
+-type ciphers() :: [ssl_cipher:erl_cipher_suite()] |
string(). % (according to old API)
-type ssl_imp() :: new | old.
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl
index b2077c662a..78a328ace8 100644
--- a/lib/ssl/src/ssl_cipher.erl
+++ b/lib/ssl/src/ssl_cipher.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -38,6 +38,21 @@
openssl_suite/1, openssl_suite_name/1, filter/2, filter_suites/1,
hash_algorithm/1, sign_algorithm/1, is_acceptable_hash/2]).
+-export_type([cipher_suite/0,
+ erl_cipher_suite/0, openssl_cipher_suite/0,
+ key_algo/0]).
+
+-type cipher() :: null |rc4_128 | idea_cbc | des40_cbc | des_cbc | '3des_ede_cbc'
+ | aes_128_cbc | aes_256_cbc.
+-type hash() :: null | sha | md5 | sha224 | sha256 | sha384 | sha512.
+-type key_algo() :: null | rsa | dhe_rsa | dhe_dss | ecdhe_ecdsa| ecdh_ecdsa | ecdh_rsa| srp_rsa| srp_dss | psk | dhe_psk | rsa_psk | dh_anon | ecdh_anon | srp_anon.
+-type erl_cipher_suite() :: {key_algo(), cipher(), hash()}.
+-type int_cipher_suite() :: {key_algo(), cipher(), hash(), hash() | default_prf}.
+-type cipher_suite() :: binary().
+-type cipher_enum() :: integer().
+-type openssl_cipher_suite() :: string().
+
+
-compile(inline).
%%--------------------------------------------------------------------
@@ -51,7 +66,7 @@ security_parameters(?TLS_NULL_WITH_NULL_NULL = CipherSuite, SecParams) ->
security_parameters(undefined, CipherSuite, SecParams).
%%--------------------------------------------------------------------
--spec security_parameters(tls_version() | undefined, cipher_suite(), #security_parameters{}) ->
+-spec security_parameters(ssl_record:ssl_version() | undefined, cipher_suite(), #security_parameters{}) ->
#security_parameters{}.
%%
%% Description: Returns a security parameters record where the
@@ -72,7 +87,7 @@ security_parameters(Version, CipherSuite, SecParams) ->
hash_size = hash_size(Hash)}.
%%--------------------------------------------------------------------
--spec cipher(cipher_enum(), #cipher_state{}, binary(), iolist(), tls_version()) ->
+-spec cipher(cipher_enum(), #cipher_state{}, binary(), iodata(), ssl_record:ssl_version()) ->
{binary(), #cipher_state{}}.
%%
%% Description: Encrypts the data and the MAC using chipher described
@@ -127,7 +142,7 @@ block_cipher(Fun, BlockSz, #cipher_state{key=Key, iv=IV} = CS0,
{T, CS0#cipher_state{iv=NextIV}}.
%%--------------------------------------------------------------------
--spec decipher(cipher_enum(), integer(), #cipher_state{}, binary(), tls_version()) ->
+-spec decipher(cipher_enum(), integer(), #cipher_state{}, binary(), ssl_record:ssl_version()) ->
{binary(), binary(), #cipher_state{}} | #alert{}.
%%
%% Description: Decrypts the data and the MAC using cipher described
@@ -200,7 +215,7 @@ block_decipher(Fun, #cipher_state{key=Key, iv=IV} = CipherState0,
?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)
end.
%%--------------------------------------------------------------------
--spec suites(tls_version()) -> [cipher_suite()].
+-spec suites(ssl_record:ssl_version()) -> [cipher_suite()].
%%
%% Description: Returns a list of supported cipher suites.
%%--------------------------------------------------------------------
@@ -229,7 +244,7 @@ anonymous_suites() ->
?TLS_ECDH_anon_WITH_AES_256_CBC_SHA].
%%--------------------------------------------------------------------
--spec psk_suites(tls_version() | integer()) -> [cipher_suite()].
+-spec psk_suites(ssl_record:ssl_version() | integer()) -> [cipher_suite()].
%%
%% Description: Returns a list of the PSK cipher suites, only supported
%% if explicitly set by user.
diff --git a/lib/ssl/src/ssl_cipher.hrl b/lib/ssl/src/ssl_cipher.hrl
index 62a5269def..3ce9c19aa9 100644
--- a/lib/ssl/src/ssl_cipher.hrl
+++ b/lib/ssl/src/ssl_cipher.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -26,16 +26,6 @@
-ifndef(ssl_cipher).
-define(ssl_cipher, true).
--type cipher() :: null |rc4_128 | idea_cbc | des40_cbc | des_cbc | '3des_ede_cbc'
- | aes_128_cbc | aes_256_cbc.
--type hash() :: null | sha | md5 | sha224 | sha256 | sha384 | sha512.
--type key_algo() :: null | rsa | dhe_rsa | dhe_dss | ecdhe_ecdsa| ecdh_ecdsa | ecdh_rsa| srp_rsa| srp_dss | psk | dhe_psk | rsa_psk | dh_anon | ecdh_anon | srp_anon.
--type erl_cipher_suite() :: {key_algo(), cipher(), hash()}.
--type int_cipher_suite() :: {key_algo(), cipher(), hash(), hash() | default_prf}.
--type cipher_suite() :: binary().
--type cipher_enum() :: integer().
--type openssl_cipher_suite() :: string().
-
%%% SSL cipher protocol %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-define(CHANGE_CIPHER_SPEC_PROTO, 1). % _PROTO to not clash with
% SSL record protocol
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index e283e6079e..ed9e4d344f 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -52,6 +52,7 @@
%% SSL all state functions
-export([handle_sync_event/4, handle_info/3, terminate/3]).
+
%%====================================================================
%% Internal application API
%%====================================================================
diff --git a/lib/ssl/src/ssl_connection.hrl b/lib/ssl/src/ssl_connection.hrl
index 341a4217e4..b01c6cb1b3 100644
--- a/lib/ssl/src/ssl_connection.hrl
+++ b/lib/ssl/src/ssl_connection.hrl
@@ -48,17 +48,17 @@
socket_options :: #socket_options{},
connection_states :: #connection_states{},
protocol_buffers :: term(), %% #protocol_buffers{} from tls_record.hrl or dtls_recor.hrl
- tls_handshake_history ::tls_handshake_history(),
+ tls_handshake_history :: ssl_handshake:ssl_handshake_history(),
cert_db :: reference(),
session :: #session{},
session_cache :: db_handle(),
session_cache_cb :: atom(),
- negotiated_version :: tls_version(),
+ negotiated_version :: ssl_record:ssl_version(),
client_certificate_requested = false :: boolean(),
- key_algorithm :: key_algo(),
+ key_algorithm :: ssl_cipher:key_algo(),
hashsign_algorithm = {undefined, undefined},
cert_hashsign_algorithm,
- public_key_info ::public_key_info(),
+ public_key_info ::ssl_handshake:public_key_info(),
private_key ::public_key:private_key(),
diffie_hellman_params, % PKIX: #'DHParameter'{} relevant for server side
diffie_hellman_keys, % {PublicKey, PrivateKey}
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index 74ca7ca699..1108edcf48 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -31,6 +31,18 @@
-include("ssl_srp.hrl").
-include_lib("public_key/include/public_key.hrl").
+-export_type([ssl_handshake/0, ssl_handshake_history/0,
+ public_key_info/0, oid/0]).
+
+-type oid() :: tuple().
+-type public_key_params() :: #'Dss-Parms'{} | {namedCurve, oid()} | #'ECParameters'{} | term().
+-type public_key_info() :: {oid(), #'RSAPublicKey'{} | integer() | #'ECPoint'{}, public_key_params()}.
+-type ssl_handshake_history() :: {[binary()], [binary()]}.
+
+-type ssl_handshake() :: #server_hello{} | #server_hello_done{} | #certificate{} | #certificate_request{} |
+ #client_key_exchange{} | #finished{} | #certificate_verify{} |
+ #hello_request{} | #next_protocol{}.
+
%% Handshake messages
-export([hello_request/0, server_hello/4, server_hello_done/0,
certificate/4, certificate_request/4, key_exchange/3,
@@ -80,7 +92,7 @@ hello_request() ->
#hello_request{}.
%%--------------------------------------------------------------------
--spec server_hello(#session{}, tls_version(), #connection_states{},
+-spec server_hello(#session{}, ssl_record:ssl_version(), #connection_states{},
#hello_extensions{}) -> #server_hello{}.
%%
%% Description: Creates a server hello message.
@@ -164,8 +176,8 @@ next_protocol(SelectedProtocol) ->
%%--------------------------------------------------------------------
-spec client_certificate_verify(undefined | der_cert(), binary(),
- tls_version(), term(), public_key:private_key(),
- tls_handshake_history()) ->
+ ssl_record:ssl_version(), term(), public_key:private_key(),
+ ssl_handshake_history()) ->
#certificate_verify{} | ignore | #alert{}.
%%
%% Description: Creates a certificate_verify message, called by the client.
@@ -188,7 +200,7 @@ client_certificate_verify(OwnCert, MasterSecret, Version,
end.
%%--------------------------------------------------------------------
--spec certificate_request(erl_cipher_suite(), db_handle(), certdb_ref(), tls_version()) ->
+-spec certificate_request(ssl_cipher:erl_cipher_suite(), db_handle(), certdb_ref(), ssl_record:ssl_version()) ->
#certificate_request{}.
%%
%% Description: Creates a certificate_request message, called by the server.
@@ -203,7 +215,7 @@ certificate_request(CipherSuite, CertDbHandle, CertDbRef, Version) ->
certificate_authorities = Authorities
}.
%%--------------------------------------------------------------------
--spec key_exchange(client | server, tls_version(),
+-spec key_exchange(client | server, ssl_record:ssl_version(),
{premaster_secret, binary(), public_key_info()} |
{dh, binary()} |
{dh, {binary(), binary()}, #'DHParameter'{}, {HashAlgo::atom(), SignAlgo::atom()},
@@ -304,7 +316,7 @@ key_exchange(server, Version, {srp, {PublicKey, _},
ClientRandom, ServerRandom, PrivateKey).
%%--------------------------------------------------------------------
--spec finished(tls_version(), client | server, integer(), binary(), tls_handshake_history()) ->
+-spec finished(ssl_record:ssl_version(), client | server, integer(), binary(), ssl_handshake_history()) ->
#finished{}.
%%
%% Description: Creates a handshake finished message
@@ -331,8 +343,8 @@ verify_server_key(#server_key_params{params_bin = EncParams,
verify_signature(Version, Hash, HashSign, Signature, PubKeyInfo).
%%--------------------------------------------------------------------
--spec certificate_verify(binary(), public_key_info(), tls_version(), term(),
- binary(), tls_handshake_history()) -> valid | #alert{}.
+-spec certificate_verify(binary(), public_key_info(), ssl_record:ssl_version(), term(),
+ binary(), ssl_handshake_history()) -> valid | #alert{}.
%%
%% Description: Checks that the certificate_verify message is valid.
%%--------------------------------------------------------------------
@@ -346,7 +358,7 @@ certificate_verify(Signature, PublicKeyInfo, Version,
?ALERT_REC(?FATAL, ?BAD_CERTIFICATE)
end.
%%--------------------------------------------------------------------
--spec verify_signature(tls_version(), binary(), {term(), term()}, binary(),
+-spec verify_signature(ssl_record:ssl_version(), binary(), {term(), term()}, binary(),
public_key_info()) -> true | false.
%%
%% Description: Checks that a public_key signature is valid.
@@ -426,8 +438,8 @@ certify(#certificate{asn1_certificates = ASN1Certs}, CertDbHandle, CertDbRef,
end.
%%--------------------------------------------------------------------
--spec verify_connection(tls_version(), #finished{}, client | server, integer(), binary(),
- tls_handshake_history()) -> verified | #alert{}.
+-spec verify_connection(ssl_record:ssl_version(), #finished{}, client | server, integer(), binary(),
+ ssl_handshake_history()) -> verified | #alert{}.
%%
%% Description: Checks the ssl handshake finished message to verify
%% the connection.
@@ -443,7 +455,7 @@ verify_connection(Version, #finished{verify_data = Data},
end.
%%--------------------------------------------------------------------
--spec init_handshake_history() -> tls_handshake_history().
+-spec init_handshake_history() -> ssl_handshake_history().
%%
%% Description: Initialize the empty handshake history buffer.
@@ -452,8 +464,8 @@ init_handshake_history() ->
{[], []}.
%%--------------------------------------------------------------------
--spec update_handshake_history(tls_handshake_history(), Data ::term()) ->
- tls_handshake_history().
+-spec update_handshake_history(ssl_handshake:ssl_handshake_history(), Data ::term()) ->
+ ssl_handshake:ssl_handshake_history().
%%
%% Description: Update the handshake history buffer with Data.
%%--------------------------------------------------------------------
@@ -567,7 +579,7 @@ server_key_exchange_hash(md5sha, Value) ->
server_key_exchange_hash(Hash, Value) ->
crypto:hash(Hash, Value).
%%--------------------------------------------------------------------
--spec prf(tls_version(), binary(), binary(), [binary()], non_neg_integer()) ->
+-spec prf(ssl_record:ssl_version(), binary(), binary(), [binary()], non_neg_integer()) ->
{ok, binary()} | {error, undefined}.
%%
%% Description: use the TLS PRF to generate key material
@@ -611,7 +623,7 @@ select_hashsign(#hash_sign_algos{hash_sign_algos = HashSigns}, Cert) ->
HashSign
end.
%%--------------------------------------------------------------------
--spec select_cert_hashsign(#hash_sign_algos{}| undefined, oid(), tls_version() | {undefined, undefined}) ->
+-spec select_cert_hashsign(#hash_sign_algos{}| undefined, oid(), ssl_record:ssl_version() | {undefined, undefined}) ->
{atom(), atom()}.
%%
@@ -631,7 +643,7 @@ select_cert_hashsign(undefined, ?'id-dsa', _) ->
{sha, dsa}.
%%--------------------------------------------------------------------
--spec master_secret(atom(), tls_version(), #session{} | binary(), #connection_states{},
+-spec master_secret(atom(), ssl_record:ssl_version(), #session{} | binary(), #connection_states{},
client | server) -> {binary(), #connection_states{}} | #alert{}.
%%
%% Description: Sets or calculates the master secret and calculate keys,
@@ -816,7 +828,7 @@ enc_server_key_exchange(Version, Params, {HashAlgo, SignAlgo},
end.
%%--------------------------------------------------------------------
--spec decode_client_key(binary(), key_algo(), tls_version()) ->
+-spec decode_client_key(binary(), ssl_cipher:key_algo(), ssl_record:ssl_version()) ->
#encrypted_premaster_secret{}
| #client_diffie_hellman_public{}
| #client_ec_diffie_hellman_public{}
@@ -831,7 +843,7 @@ decode_client_key(ClientKey, Type, Version) ->
dec_client_key(ClientKey, key_exchange_alg(Type), Version).
%%--------------------------------------------------------------------
--spec decode_server_key(binary(), key_algo(), tls_version()) ->
+-spec decode_server_key(binary(), ssl_cipher:key_algo(), ssl_record:ssl_version()) ->
#server_key_params{}.
%%
%% Description: Decode server_key data and return appropriate type
diff --git a/lib/ssl/src/ssl_handshake.hrl b/lib/ssl/src/ssl_handshake.hrl
index 75160526b9..80284faef0 100644
--- a/lib/ssl/src/ssl_handshake.hrl
+++ b/lib/ssl/src/ssl_handshake.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -352,18 +352,4 @@
hostname = undefined
}).
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Dialyzer types
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
--type oid() :: tuple().
--type public_key_params() :: #'Dss-Parms'{} | {namedCurve, oid()} | #'ECParameters'{} | term().
--type public_key_info() :: {oid(), #'RSAPublicKey'{} | integer() | #'ECPoint'{}, public_key_params()}.
--type tls_handshake_history() :: {[binary()], [binary()]}.
-
--type ssl_handshake() :: #server_hello{} | #server_hello_done{} | #certificate{} | #certificate_request{} |
- #client_key_exchange{} | #finished{} | #certificate_verify{} |
- #hello_request{} | #next_protocol{}.
-
-
-endif. % -ifdef(ssl_handshake).
diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl
index 64b89e9f95..cec5d8fbb1 100644
--- a/lib/ssl/src/ssl_internal.hrl
+++ b/lib/ssl/src/ssl_internal.hrl
@@ -30,8 +30,6 @@
-type from() :: term().
-type host() :: inet:ip_address() | inet:hostname().
-type session_id() :: 0 | binary().
--type tls_version() :: {integer(), integer()}.
--type tls_atom_version() :: sslv3 | tlsv1 | 'tlsv1.1' | 'tlsv1.2'.
-type certdb_ref() :: reference().
-type db_handle() :: term().
-type der_cert() :: binary().
@@ -73,7 +71,7 @@
-record(ssl_options, {
protocol :: tls | dtls,
- versions :: ['tlsv1.2' | 'tlsv1.1' | tlsv1 | sslv3] | ['dtlsv1.2' | dtlsv1],
+ versions :: [ssl_record:ssl_version()], %% ssl_record:atom_version() in API
verify :: verify_none | verify_peer,
verify_fun, %%:: fun(CertVerifyErrors::term()) -> boolean(),
fail_if_no_peer_cert :: boolean(),
diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl
index 018c8befe0..b0e9943e6d 100644
--- a/lib/ssl/src/ssl_record.erl
+++ b/lib/ssl/src/ssl_record.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -50,6 +50,11 @@
%% Payload encryption/decryption
-export([cipher/4, decipher/3, is_correct_mac/2]).
+-export_type([ssl_version/0, ssl_atom_version/0]).
+
+-type ssl_version() :: {integer(), integer()}.
+-type ssl_atom_version() :: tls_record:tls_atom_version().
+
%%====================================================================
%% Internal application API
%%====================================================================
@@ -299,7 +304,7 @@ set_pending_cipher_state(#connection_states{pending_read = Read,
%%--------------------------------------------------------------------
--spec encode_handshake(iolist(), tls_version(), #connection_states{}) ->
+-spec encode_handshake(iolist(), ssl_version(), #connection_states{}) ->
{iolist(), #connection_states{}}.
%%
%% Description: Encodes a handshake message to send on the ssl-socket.
@@ -308,7 +313,7 @@ encode_handshake(Frag, Version, ConnectionStates) ->
encode_plain_text(?HANDSHAKE, Version, Frag, ConnectionStates).
%%--------------------------------------------------------------------
--spec encode_alert_record(#alert{}, tls_version(), #connection_states{}) ->
+-spec encode_alert_record(#alert{}, ssl_version(), #connection_states{}) ->
{iolist(), #connection_states{}}.
%%
%% Description: Encodes an alert message to send on the ssl-socket.
@@ -319,7 +324,7 @@ encode_alert_record(#alert{level = Level, description = Description},
ConnectionStates).
%%--------------------------------------------------------------------
--spec encode_change_cipher_spec(tls_version(), #connection_states{}) ->
+-spec encode_change_cipher_spec(ssl_version(), #connection_states{}) ->
{iolist(), #connection_states{}}.
%%
%% Description: Encodes a change_cipher_spec-message to send on the ssl socket.
@@ -328,7 +333,7 @@ encode_change_cipher_spec(Version, ConnectionStates) ->
encode_plain_text(?CHANGE_CIPHER_SPEC, Version, <<1:8>>, ConnectionStates).
%%--------------------------------------------------------------------
--spec encode_data(binary(), tls_version(), #connection_states{}) ->
+-spec encode_data(binary(), ssl_version(), #connection_states{}) ->
{iolist(), #connection_states{}}.
%%
%% Description: Encodes data to send on the ssl-socket.
@@ -356,7 +361,7 @@ compressions() ->
[?byte(?NULL)].
%%--------------------------------------------------------------------
--spec cipher(tls_version(), iolist(), #connection_state{}, MacHash::binary()) ->
+-spec cipher(ssl_version(), iodata(), #connection_state{}, MacHash::binary()) ->
{CipherFragment::binary(), #connection_state{}}.
%%
%% Description: Payload encryption
@@ -372,7 +377,7 @@ cipher(Version, Fragment,
ssl_cipher:cipher(BulkCipherAlgo, CipherS0, MacHash, Fragment, Version),
{CipherFragment, WriteState0#connection_state{cipher_state = CipherS1}}.
%%--------------------------------------------------------------------
--spec decipher(tls_version(), binary(), #connection_state{}) -> {binary(), binary(), #connection_state{}}.
+-spec decipher(ssl_version(), binary(), #connection_state{}) -> {binary(), binary(), #connection_state{}}.
%%
%% Description: Payload decryption
%%--------------------------------------------------------------------
diff --git a/lib/ssl/src/ssl_record.hrl b/lib/ssl/src/ssl_record.hrl
index c17fa53a62..87ed233c0a 100644
--- a/lib/ssl/src/ssl_record.hrl
+++ b/lib/ssl/src/ssl_record.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -20,7 +20,7 @@
%%
%%----------------------------------------------------------------------
%% Purpose: Record and constant defenitions for the SSL-record protocol
-%% see RFC 2246
+% see RFC 2246
%%----------------------------------------------------------------------
-ifndef(ssl_record).
diff --git a/lib/ssl/src/ssl_v3.erl b/lib/ssl/src/ssl_v3.erl
index d477b3df81..68f7f5dee2 100644
--- a/lib/ssl/src/ssl_v3.erl
+++ b/lib/ssl/src/ssl_v3.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -130,7 +130,7 @@ setup_keys(MasterSecret, ServerRandom, ClientRandom, HS, KML, _EKML, IVS) ->
{ClientWriteMacSecret, ServerWriteMacSecret, ClientWriteKey,
ServerWriteKey, ClientIV, ServerIV}.
--spec suites() -> [cipher_suite()].
+-spec suites() -> [ssl_cipher:cipher_suite()].
suites() ->
[
diff --git a/lib/ssl/src/tls_handshake.erl b/lib/ssl/src/tls_handshake.erl
index 01abefca46..183cabcfcd 100644
--- a/lib/ssl/src/tls_handshake.erl
+++ b/lib/ssl/src/tls_handshake.erl
@@ -33,6 +33,8 @@
-export([client_hello/8, hello/4,
get_tls_handshake/3, encode_handshake/2, decode_handshake/3]).
+-type tls_handshake() :: #client_hello{} | ssl_handshake:ssl_handshake().
+
%%====================================================================
%% Internal application API
%%====================================================================
@@ -71,11 +73,11 @@ client_hello(Host, Port, ConnectionStates,
#connection_states{} | {inet:port_number(), #session{}, db_handle(),
atom(), #connection_states{}, binary() | undefined},
boolean()) ->
- {tls_version(), session_id(), #connection_states{}, binary() | undefined}|
- {tls_version(), {resumed | new, #session{}}, #connection_states{},
- [binary()] | undefined,
- [oid()] | undefined, [oid()] | undefined} |
- #alert{}.
+ {tls_record:tls_version(), session_id(), #connection_states{}, binary() | undefined}|
+ {tls_record:tls_version(), {resumed | new, #session{}}, #connection_states{},
+ [binary()] | undefined,
+ [ssl_handshake:oid()] | undefined, [ssl_handshake:oid()] | undefined} |
+ #alert{}.
%%
%% Description: Handles a recieved hello message
%%--------------------------------------------------------------------
@@ -122,7 +124,7 @@ hello(#client_hello{client_version = ClientVersion,
end.
%%--------------------------------------------------------------------
--spec encode_handshake(tls_handshake(), tls_version()) -> iolist().
+-spec encode_handshake(tls_handshake(), tls_record:tls_version()) -> iolist().
%%
%% Description: Encode a handshake packet
%%--------------------------------------------------------------------x
@@ -132,7 +134,7 @@ encode_handshake(Package, Version) ->
[MsgType, ?uint24(Len), Bin].
%%--------------------------------------------------------------------
--spec get_tls_handshake(tls_version(), binary(), binary() | iolist()) ->
+-spec get_tls_handshake(tls_record:tls_version(), binary(), binary() | iolist()) ->
{[tls_handshake()], binary()}.
%%
%% Description: Given buffered and new data from ssl_record, collects
diff --git a/lib/ssl/src/tls_handshake.hrl b/lib/ssl/src/tls_handshake.hrl
index dbe930cb90..1646e5b6f2 100644
--- a/lib/ssl/src/tls_handshake.hrl
+++ b/lib/ssl/src/tls_handshake.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -37,6 +37,4 @@
extensions
}).
--type tls_handshake() :: #client_hello{} | ssl_handshake().
-
-endif. % -ifdef(tls_handshake).
diff --git a/lib/ssl/src/tls_record.erl b/lib/ssl/src/tls_record.erl
index 8c0c4f3c91..4da08e9c51 100644
--- a/lib/ssl/src/tls_record.erl
+++ b/lib/ssl/src/tls_record.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -44,6 +44,11 @@
highest_protocol_version/1, supported_protocol_versions/0,
is_acceptable_version/1, is_acceptable_version/2]).
+-export_type([tls_version/0, tls_atom_version/0]).
+
+-type tls_version() :: ssl_record:ssl_version().
+-type tls_atom_version() :: sslv3 | tlsv1 | 'tlsv1.1' | 'tlsv1.2'.
+
-compile(inline).
%%====================================================================
diff --git a/lib/ssl/src/tls_v1.erl b/lib/ssl/src/tls_v1.erl
index 7b1f53b969..067417d163 100644
--- a/lib/ssl/src/tls_v1.erl
+++ b/lib/ssl/src/tls_v1.erl
@@ -166,7 +166,7 @@ setup_keys(Version, PrfAlgo, MasterSecret, ServerRandom, ClientRandom, HashSize,
{ClientWriteMacSecret, ServerWriteMacSecret, ClientWriteKey,
ServerWriteKey, ClientIV, ServerIV}.
--spec mac_hash(integer(), binary(), integer(), integer(), tls_version(),
+-spec mac_hash(integer(), binary(), integer(), integer(), tls_record:tls_version(),
integer(), binary()) -> binary().
mac_hash(Method, Mac_write_secret, Seq_num, Type, {Major, Minor},
@@ -181,7 +181,7 @@ mac_hash(Method, Mac_write_secret, Seq_num, Type, {Major, Minor},
Fragment]),
Mac.
--spec suites(1|2|3) -> [cipher_suite()].
+-spec suites(1|2|3) -> [ssl_cipher:cipher_suite()].
suites(Minor) when Minor == 1; Minor == 2->
case sufficent_ec_support() of
diff --git a/lib/ssl/test/Makefile b/lib/ssl/test/Makefile
index 244eb5ce0a..2f8ff6f04e 100644
--- a/lib/ssl/test/Makefile
+++ b/lib/ssl/test/Makefile
@@ -39,6 +39,7 @@ MODULES = \
ssl_basic_SUITE \
ssl_cipher_SUITE \
ssl_certificate_verify_SUITE\
+ ssl_crl_SUITE\
ssl_dist_SUITE \
ssl_handshake_SUITE \
ssl_npn_hello_SUITE \
diff --git a/lib/ssl/test/make_certs.erl b/lib/ssl/test/make_certs.erl
index 4603a9f846..c438ae2b87 100644
--- a/lib/ssl/test/make_certs.erl
+++ b/lib/ssl/test/make_certs.erl
@@ -18,23 +18,68 @@
%%
-module(make_certs).
+-compile([export_all]).
--export([all/2]).
+%-export([all/1, all/2, rootCA/2, intermediateCA/3, endusers/3, enduser/3, revoke/3, gencrl/2, verify/3]).
--record(dn, {commonName,
+-record(config, {commonName,
organizationalUnitName = "Erlang OTP",
organizationName = "Ericsson AB",
localityName = "Stockholm",
countryName = "SE",
- emailAddress = "[email protected]"}).
+ emailAddress = "[email protected]",
+ default_bits = 2048,
+ v2_crls = true,
+ ecc_certs = false,
+ issuing_distribution_point = false,
+ openssl_cmd = "openssl"}).
+
+
+default_config() ->
+ #config{}.
+
+make_config(Args) ->
+ make_config(Args, #config{}).
+
+make_config([], C) ->
+ C;
+make_config([{organizationalUnitName, Name}|T], C) when is_list(Name) ->
+ make_config(T, C#config{organizationalUnitName = Name});
+make_config([{organizationName, Name}|T], C) when is_list(Name) ->
+ make_config(T, C#config{organizationName = Name});
+make_config([{localityName, Name}|T], C) when is_list(Name) ->
+ make_config(T, C#config{localityName = Name});
+make_config([{countryName, Name}|T], C) when is_list(Name) ->
+ make_config(T, C#config{countryName = Name});
+make_config([{emailAddress, Name}|T], C) when is_list(Name) ->
+ make_config(T, C#config{emailAddress = Name});
+make_config([{default_bits, Bits}|T], C) when is_integer(Bits) ->
+ make_config(T, C#config{default_bits = Bits});
+make_config([{v2_crls, Bool}|T], C) when is_boolean(Bool) ->
+ make_config(T, C#config{v2_crls = Bool});
+make_config([{ecc_certs, Bool}|T], C) when is_boolean(Bool) ->
+ make_config(T, C#config{ecc_certs = Bool});
+make_config([{issuing_distribution_point, Bool}|T], C) when is_boolean(Bool) ->
+ make_config(T, C#config{issuing_distribution_point = Bool});
+make_config([{openssl_cmd, Cmd}|T], C) when is_list(Cmd) ->
+ make_config(T, C#config{openssl_cmd = Cmd}).
+
+
+all([DataDir, PrivDir]) ->
+ all(DataDir, PrivDir).
all(DataDir, PrivDir) ->
- OpenSSLCmd = "openssl",
+ all(DataDir, PrivDir, #config{}).
+
+all(DataDir, PrivDir, C) when is_list(C) ->
+ all(DataDir, PrivDir, make_config(C));
+all(DataDir, PrivDir, C = #config{}) ->
+ ok = filelib:ensure_dir(filename:join(PrivDir, "erlangCA")),
create_rnd(DataDir, PrivDir), % For all requests
- rootCA(PrivDir, OpenSSLCmd, "erlangCA"),
- intermediateCA(PrivDir, OpenSSLCmd, "otpCA", "erlangCA"),
- endusers(PrivDir, OpenSSLCmd, "otpCA", ["client", "server"]),
- collect_certs(PrivDir, ["erlangCA", "otpCA"], ["client", "server"]),
+ rootCA(PrivDir, "erlangCA", C),
+ intermediateCA(PrivDir, "otpCA", "erlangCA", C),
+ endusers(PrivDir, "otpCA", ["client", "server", "revoked"], C),
+ endusers(PrivDir, "erlangCA", ["localhost"], C),
%% Create keycert files
SDir = filename:join([PrivDir, "server"]),
SC = filename:join([SDir, "cert.pem"]),
@@ -46,7 +91,14 @@ all(DataDir, PrivDir) ->
CK = filename:join([CDir, "key.pem"]),
CKC = filename:join([CDir, "keycert.pem"]),
append_files([CK, CC], CKC),
- remove_rnd(PrivDir).
+ RDir = filename:join([PrivDir, "revoked"]),
+ RC = filename:join([RDir, "cert.pem"]),
+ RK = filename:join([RDir, "key.pem"]),
+ RKC = filename:join([RDir, "keycert.pem"]),
+ revoke(PrivDir, "otpCA", "revoked", C),
+ append_files([RK, RC], RKC),
+ remove_rnd(PrivDir),
+ {ok, C}.
append_files(FileNames, ResultFileName) ->
{ok, ResultFile} = file:open(ResultFileName, [write]),
@@ -59,111 +111,176 @@ do_append_files([F|Fs], RF) ->
ok = file:write(RF, Data),
do_append_files(Fs, RF).
-rootCA(Root, OpenSSLCmd, Name) ->
- create_ca_dir(Root, Name, ca_cnf(Name)),
- DN = #dn{commonName = Name},
- create_self_signed_cert(Root, OpenSSLCmd, Name, req_cnf(DN)),
- ok.
+rootCA(Root, Name, C) ->
+ create_ca_dir(Root, Name, ca_cnf(C#config{commonName = Name})),
+ create_self_signed_cert(Root, Name, req_cnf(C#config{commonName = Name}), C),
+ file:copy(filename:join([Root, Name, "cert.pem"]), filename:join([Root, Name, "cacerts.pem"])),
+ gencrl(Root, Name, C).
-intermediateCA(Root, OpenSSLCmd, CA, ParentCA) ->
- CA = "otpCA",
- create_ca_dir(Root, CA, ca_cnf(CA)),
+intermediateCA(Root, CA, ParentCA, C) ->
+ create_ca_dir(Root, CA, ca_cnf(C#config{commonName = CA})),
CARoot = filename:join([Root, CA]),
- DN = #dn{commonName = CA},
CnfFile = filename:join([CARoot, "req.cnf"]),
- file:write_file(CnfFile, req_cnf(DN)),
+ file:write_file(CnfFile, req_cnf(C#config{commonName = CA})),
KeyFile = filename:join([CARoot, "private", "key.pem"]),
ReqFile = filename:join([CARoot, "req.pem"]),
- create_req(Root, OpenSSLCmd, CnfFile, KeyFile, ReqFile),
+ create_req(Root, CnfFile, KeyFile, ReqFile, C),
CertFile = filename:join([CARoot, "cert.pem"]),
- sign_req(Root, OpenSSLCmd, ParentCA, "ca_cert", ReqFile, CertFile).
-
-endusers(Root, OpenSSLCmd, CA, Users) ->
- lists:foreach(fun(User) -> enduser(Root, OpenSSLCmd, CA, User) end, Users).
-
-enduser(Root, OpenSSLCmd, CA, User) ->
+ sign_req(Root, ParentCA, "ca_cert", ReqFile, CertFile, C),
+ CACertsFile = filename:join(CARoot, "cacerts.pem"),
+ file:copy(filename:join([Root, ParentCA, "cacerts.pem"]), CACertsFile),
+ %% append this CA's cert to the cacerts file
+ {ok, Bin} = file:read_file(CertFile),
+ {ok, FD} = file:open(CACertsFile, [append]),
+ file:write(FD, ["\n", Bin]),
+ file:close(FD),
+ gencrl(Root, CA, C).
+
+endusers(Root, CA, Users, C) ->
+ [enduser(Root, CA, User, C) || User <- Users].
+
+enduser(Root, CA, User, C) ->
UsrRoot = filename:join([Root, User]),
file:make_dir(UsrRoot),
CnfFile = filename:join([UsrRoot, "req.cnf"]),
- DN = #dn{commonName = User},
- file:write_file(CnfFile, req_cnf(DN)),
+ file:write_file(CnfFile, req_cnf(C#config{commonName = User})),
KeyFile = filename:join([UsrRoot, "key.pem"]),
ReqFile = filename:join([UsrRoot, "req.pem"]),
- create_req(Root, OpenSSLCmd, CnfFile, KeyFile, ReqFile),
+ create_req(Root, CnfFile, KeyFile, ReqFile, C),
+ %create_req(Root, CnfFile, KeyFile, ReqFile),
CertFileAllUsage = filename:join([UsrRoot, "cert.pem"]),
- sign_req(Root, OpenSSLCmd, CA, "user_cert", ReqFile, CertFileAllUsage),
+ sign_req(Root, CA, "user_cert", ReqFile, CertFileAllUsage, C),
CertFileDigitalSigOnly = filename:join([UsrRoot, "digital_signature_only_cert.pem"]),
- sign_req(Root, OpenSSLCmd, CA, "user_cert_digital_signature_only", ReqFile, CertFileDigitalSigOnly).
-
-collect_certs(Root, CAs, Users) ->
- Bins = lists:foldr(
- fun(CA, Acc) ->
- File = filename:join([Root, CA, "cert.pem"]),
- {ok, Bin} = file:read_file(File),
- [Bin, "\n" | Acc]
- end, [], CAs),
- lists:foreach(
- fun(User) ->
- File = filename:join([Root, User, "cacerts.pem"]),
- file:write_file(File, Bins)
- end, Users).
+ sign_req(Root, CA, "user_cert_digital_signature_only", ReqFile, CertFileDigitalSigOnly, C),
+ CACertsFile = filename:join(UsrRoot, "cacerts.pem"),
+ file:copy(filename:join([Root, CA, "cacerts.pem"]), CACertsFile),
+ ok.
+
+revoke(Root, CA, User, C) ->
+ UsrCert = filename:join([Root, User, "cert.pem"]),
+ CACnfFile = filename:join([Root, CA, "ca.cnf"]),
+ Cmd = [C#config.openssl_cmd, " ca"
+ " -revoke ", UsrCert,
+ [" -crl_reason keyCompromise" || C#config.v2_crls ],
+ " -config ", CACnfFile],
+ Env = [{"ROOTDIR", filename:absname(Root)}],
+ cmd(Cmd, Env),
+ gencrl(Root, CA, C).
+
+gencrl(Root, CA, C) ->
+ CACnfFile = filename:join([Root, CA, "ca.cnf"]),
+ CACRLFile = filename:join([Root, CA, "crl.pem"]),
+ Cmd = [C#config.openssl_cmd, " ca"
+ " -gencrl ",
+ " -crlhours 24",
+ " -out ", CACRLFile,
+ " -config ", CACnfFile],
+ Env = [{"ROOTDIR", filename:absname(Root)}],
+ cmd(Cmd, Env).
-create_self_signed_cert(Root, OpenSSLCmd, CAName, Cnf) ->
+verify(Root, CA, User, C) ->
+ CAFile = filename:join([Root, User, "cacerts.pem"]),
+ CACRLFile = filename:join([Root, CA, "crl.pem"]),
+ CertFile = filename:join([Root, User, "cert.pem"]),
+ Cmd = [C#config.openssl_cmd, " verify"
+ " -CAfile ", CAFile,
+ " -CRLfile ", CACRLFile, %% this is undocumented, but seems to work
+ " -crl_check ",
+ CertFile],
+ Env = [{"ROOTDIR", filename:absname(Root)}],
+ try cmd(Cmd, Env) catch
+ exit:{eval_cmd, _, _} ->
+ invalid
+ end.
+
+create_self_signed_cert(Root, CAName, Cnf, C = #config{ecc_certs = true}) ->
CARoot = filename:join([Root, CAName]),
CnfFile = filename:join([CARoot, "req.cnf"]),
file:write_file(CnfFile, Cnf),
KeyFile = filename:join([CARoot, "private", "key.pem"]),
CertFile = filename:join([CARoot, "cert.pem"]),
- Cmd = [OpenSSLCmd, " req"
+ Cmd = [C#config.openssl_cmd, " ecparam"
+ " -out ", KeyFile,
+ " -name secp521r1 ",
+ %" -name sect283k1 ",
+ " -genkey "],
+ Env = [{"ROOTDIR", filename:absname(Root)}],
+ cmd(Cmd, Env),
+
+ Cmd2 = [C#config.openssl_cmd, " req"
" -new"
" -x509"
" -config ", CnfFile,
- " -keyout ", KeyFile,
+ " -key ", KeyFile,
+ " -outform PEM ",
" -out ", CertFile],
- Env = [{"ROOTDIR", Root}],
- cmd(Cmd, Env),
- fix_key_file(OpenSSLCmd, KeyFile).
-
-% openssl 1.0 generates key files in pkcs8 format by default and we don't handle this format
-fix_key_file(OpenSSLCmd, KeyFile) ->
- KeyFileTmp = KeyFile ++ ".tmp",
- Cmd = [OpenSSLCmd, " rsa",
- " -in ",
- KeyFile,
- " -out ",
- KeyFileTmp],
- cmd(Cmd, []),
- ok = file:rename(KeyFileTmp, KeyFile).
+ cmd(Cmd2, Env);
+create_self_signed_cert(Root, CAName, Cnf, C) ->
+ CARoot = filename:join([Root, CAName]),
+ CnfFile = filename:join([CARoot, "req.cnf"]),
+ file:write_file(CnfFile, Cnf),
+ KeyFile = filename:join([CARoot, "private", "key.pem"]),
+ CertFile = filename:join([CARoot, "cert.pem"]),
+ Cmd = [C#config.openssl_cmd, " req"
+ " -new"
+ " -x509"
+ " -config ", CnfFile,
+ " -keyout ", KeyFile,
+ " -outform PEM",
+ " -out ", CertFile],
+ Env = [{"ROOTDIR", filename:absname(Root)}],
+ cmd(Cmd, Env).
+
create_ca_dir(Root, CAName, Cnf) ->
CARoot = filename:join([Root, CAName]),
+ ok = filelib:ensure_dir(CARoot),
file:make_dir(CARoot),
create_dirs(CARoot, ["certs", "crl", "newcerts", "private"]),
create_rnd(Root, filename:join([CAName, "private"])),
create_files(CARoot, [{"serial", "01\n"},
+ {"crlnumber", "01"},
{"index.txt", ""},
{"ca.cnf", Cnf}]).
-create_req(Root, OpenSSLCmd, CnfFile, KeyFile, ReqFile) ->
- Cmd = [OpenSSLCmd, " req"
+create_req(Root, CnfFile, KeyFile, ReqFile, C = #config{ecc_certs = true}) ->
+ Cmd = [C#config.openssl_cmd, " ecparam"
+ " -out ", KeyFile,
+ " -name secp521r1 ",
+ %" -name sect283k1 ",
+ " -genkey "],
+ Env = [{"ROOTDIR", filename:absname(Root)}],
+ cmd(Cmd, Env),
+ Cmd2 = [C#config.openssl_cmd, " req"
+ " -new ",
+ " -key ", KeyFile,
+ " -outform PEM ",
+ " -out ", ReqFile,
+ " -config ", CnfFile],
+ cmd(Cmd2, Env);
+ %fix_key_file(KeyFile).
+create_req(Root, CnfFile, KeyFile, ReqFile, C) ->
+ Cmd = [C#config.openssl_cmd, " req"
" -new"
" -config ", CnfFile,
+ " -outform PEM ",
" -keyout ", KeyFile,
" -out ", ReqFile],
- Env = [{"ROOTDIR", Root}],
- cmd(Cmd, Env),
- fix_key_file(OpenSSLCmd, KeyFile).
+ Env = [{"ROOTDIR", filename:absname(Root)}],
+ cmd(Cmd, Env).
+ %fix_key_file(KeyFile).
+
-sign_req(Root, OpenSSLCmd, CA, CertType, ReqFile, CertFile) ->
+sign_req(Root, CA, CertType, ReqFile, CertFile, C) ->
CACnfFile = filename:join([Root, CA, "ca.cnf"]),
- Cmd = [OpenSSLCmd, " ca"
+ Cmd = [C#config.openssl_cmd, " ca"
" -batch"
" -notext"
" -config ", CACnfFile,
" -extensions ", CertType,
" -in ", ReqFile,
" -out ", CertFile],
- Env = [{"ROOTDIR", Root}],
+ Env = [{"ROOTDIR", filename:absname(Root)}],
cmd(Cmd, Env).
%%
@@ -194,19 +311,19 @@ cmd(Cmd, Env) ->
FCmd = lists:flatten(Cmd),
Port = open_port({spawn, FCmd}, [stream, eof, exit_status, stderr_to_stdout,
{env, Env}]),
- eval_cmd(Port).
+ eval_cmd(Port, FCmd).
-eval_cmd(Port) ->
+eval_cmd(Port, Cmd) ->
receive
{Port, {data, _}} ->
- eval_cmd(Port);
+ eval_cmd(Port, Cmd);
{Port, eof} ->
ok
end,
receive
{Port, {exit_status, Status}} when Status /= 0 ->
%% io:fwrite("exit status: ~w~n", [Status]),
- exit({eval_cmd, Status})
+ exit({eval_cmd, Cmd, Status})
after 0 ->
ok
end.
@@ -215,7 +332,7 @@ eval_cmd(Port) ->
%% Contents of configuration files
%%
-req_cnf(DN) ->
+req_cnf(C) ->
["# Purpose: Configuration for requests (end users and CAs)."
"\n"
"ROOTDIR = $ENV::ROOTDIR\n"
@@ -224,7 +341,7 @@ req_cnf(DN) ->
"[req]\n"
"input_password = secret\n"
"output_password = secret\n"
- "default_bits = 1024\n"
+ "default_bits = ", integer_to_list(C#config.default_bits), "\n"
"RANDFILE = $ROOTDIR/RAND\n"
"encrypt_key = no\n"
"default_md = sha1\n"
@@ -235,12 +352,12 @@ req_cnf(DN) ->
"\n"
"[name]\n"
- "commonName = ", DN#dn.commonName, "\n"
- "organizationalUnitName = ", DN#dn.organizationalUnitName, "\n"
- "organizationName = ", DN#dn.organizationName, "\n"
- "localityName = ", DN#dn.localityName, "\n"
- "countryName = ", DN#dn.countryName, "\n"
- "emailAddress = ", DN#dn.emailAddress, "\n"
+ "commonName = ", C#config.commonName, "\n"
+ "organizationalUnitName = ", C#config.organizationalUnitName, "\n"
+ "organizationName = ", C#config.organizationName, "\n"
+ "localityName = ", C#config.localityName, "\n"
+ "countryName = ", C#config.countryName, "\n"
+ "emailAddress = ", C#config.emailAddress, "\n"
"\n"
"[ca_ext]\n"
@@ -249,8 +366,7 @@ req_cnf(DN) ->
"subjectKeyIdentifier = hash\n"
"subjectAltName = email:copy\n"].
-
-ca_cnf(CA) ->
+ca_cnf(C) ->
["# Purpose: Configuration for CAs.\n"
"\n"
"ROOTDIR = $ENV::ROOTDIR\n"
@@ -258,21 +374,23 @@ ca_cnf(CA) ->
"\n"
"[ca]\n"
- "dir = $ROOTDIR/", CA, "\n"
+ "dir = $ROOTDIR/", C#config.commonName, "\n"
"certs = $dir/certs\n"
"crl_dir = $dir/crl\n"
"database = $dir/index.txt\n"
"new_certs_dir = $dir/newcerts\n"
"certificate = $dir/cert.pem\n"
"serial = $dir/serial\n"
- "crl = $dir/crl.pem\n"
+ "crl = $dir/crl.pem\n",
+ ["crlnumber = $dir/crlnumber\n" || C#config.v2_crls],
"private_key = $dir/private/key.pem\n"
"RANDFILE = $dir/private/RAND\n"
"\n"
- "x509_extensions = user_cert\n"
+ "x509_extensions = user_cert\n",
+ ["crl_extensions = crl_ext\n" || C#config.v2_crls],
"unique_subject = no\n"
"default_days = 3600\n"
- "default_md = sha1\n"
+ "default_md = sha256\n"
"preserve = no\n"
"policy = policy_match\n"
"\n"
@@ -286,6 +404,13 @@ ca_cnf(CA) ->
"emailAddress = supplied\n"
"\n"
+ "[crl_ext]\n"
+ "authorityKeyIdentifier=keyid:always,issuer:always\n",
+ ["issuingDistributionPoint=critical, @idpsec\n" || C#config.issuing_distribution_point],
+
+ "[idpsec]\n"
+ "fullname=URI:http://localhost:8000/",C#config.commonName,"/crl.pem\n"
+
"[user_cert]\n"
"basicConstraints = CA:false\n"
"keyUsage = nonRepudiation, digitalSignature, keyEncipherment\n"
@@ -293,6 +418,12 @@ ca_cnf(CA) ->
"authorityKeyIdentifier = keyid,issuer:always\n"
"subjectAltName = email:copy\n"
"issuerAltName = issuer:copy\n"
+ "crlDistributionPoints=@crl_section\n"
+
+ "[crl_section]\n"
+ %% intentionally invalid
+ "URI.1=http://localhost/",C#config.commonName,"/crl.pem\n"
+ "URI.2=http://localhost:8000/",C#config.commonName,"/crl.pem\n"
"\n"
"[user_cert_digital_signature_only]\n"
@@ -310,4 +441,7 @@ ca_cnf(CA) ->
"subjectKeyIdentifier = hash\n"
"authorityKeyIdentifier = keyid:always,issuer:always\n"
"subjectAltName = email:copy\n"
- "issuerAltName = issuer:copy\n"].
+ "issuerAltName = issuer:copy\n"
+ "crlDistributionPoints=@crl_section\n"
+ ].
+
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index 64a93440c7..0148e1f5bc 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -309,7 +309,11 @@ alerts(Config) when is_list(Config) ->
?ILLEGAL_PARAMETER, ?UNKNOWN_CA, ?ACCESS_DENIED, ?DECODE_ERROR,
?DECRYPT_ERROR, ?EXPORT_RESTRICTION, ?PROTOCOL_VERSION,
?INSUFFICIENT_SECURITY, ?INTERNAL_ERROR, ?USER_CANCELED,
- ?NO_RENEGOTIATION],
+ ?NO_RENEGOTIATION, ?UNSUPPORTED_EXTENSION, ?CERTIFICATE_UNOBTAINABLE,
+ ?UNRECOGNISED_NAME, ?BAD_CERTIFICATE_STATUS_RESPONSE,
+ ?BAD_CERTIFICATE_HASH_VALUE, ?UNKNOWN_PSK_IDENTITY,
+ 255 %% Unsupported/unknow alert will result in a description too
+ ],
Alerts = [?ALERT_REC(?WARNING, ?CLOSE_NOTIFY) |
[?ALERT_REC(?FATAL, Desc) || Desc <- Descriptions]],
lists:foreach(fun(Alert) ->
diff --git a/lib/ssl/test/ssl_crl_SUITE.erl b/lib/ssl/test/ssl_crl_SUITE.erl
new file mode 100644
index 0000000000..da0349904c
--- /dev/null
+++ b/lib/ssl/test/ssl_crl_SUITE.erl
@@ -0,0 +1,530 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+
+-module(ssl_crl_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("public_key/include/public_key.hrl").
+
+-define(TIMEOUT, 120000).
+-define(LONG_TIMEOUT, 600000).
+-define(SLEEP, 1000).
+-define(OPENSSL_RENEGOTIATE, "R\n").
+-define(OPENSSL_QUIT, "Q\n").
+-define(OPENSSL_GARBAGE, "P\n").
+-define(EXPIRE, 10).
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+
+suite() -> [{ct_hooks,[ts_install_cth]}].
+
+all() ->
+ [
+ {group, basic},
+ {group, v1_crl},
+ {group, idp_crl}
+ ].
+
+groups() ->
+ [{basic, [], basic_tests()},
+ {v1_crl, [], v1_crl_tests()},
+ {idp_crl, [], idp_crl_tests()}].
+
+basic_tests() ->
+ [crl_verify_valid, crl_verify_revoked].
+
+v1_crl_tests() ->
+ [crl_verify_valid, crl_verify_revoked].
+
+idp_crl_tests() ->
+ [crl_verify_valid, crl_verify_revoked].
+
+%%%================================================================
+%%% Suite init/end
+
+init_per_suite(Config0) ->
+ Dog = ct:timetrap(?LONG_TIMEOUT *2),
+ case os:find_executable("openssl") of
+ false ->
+ {skip, "Openssl not found"};
+ _ ->
+ TLSVersion = ?config(tls_version, Config0),
+ OpenSSL_version = (catch os:cmd("openssl version")),
+ ct:log("TLS version: ~p~nOpenSSL version: ~p~n~n~p:module_info(): ~p~n~nssh:module_info(): ~p~n",
+ [TLSVersion, OpenSSL_version, ?MODULE, ?MODULE:module_info(), ssh:module_info()]),
+ case ssl_test_lib:enough_openssl_crl_support(OpenSSL_version) of
+ false ->
+ {skip, io_lib:format("Bad openssl version: ~p",[OpenSSL_version])};
+ _ ->
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ ssl:start(),
+ [{watchdog, Dog}, {openssl_version,OpenSSL_version} | Config0]
+ catch _C:_E ->
+ ct:log("crypto:start() caught ~p:~p",[_C,_E]),
+ {skip, "Crypto did not start"}
+ end
+ end
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:stop(crypto).
+
+%%%================================================================
+%%% Group init/end
+
+init_per_group(Group, Config) ->
+ ct:log("~p:~p~nlisteners to port 8000:~n~p~n)",[?MODULE,?LINE,os:cmd("netstat -tln|grep ':8000'")]),
+ ssl:start(),
+ inets:start(),
+ CertDir = filename:join(?config(priv_dir, Config), Group),
+ DataDir = ?config(data_dir, Config),
+ ServerRoot = make_dir_path([?config(priv_dir,Config), Group, tmp]),
+ Result = make_certs:all(DataDir, CertDir, cert_opts(Group)),
+ ct:log("~p:~p~nmake_certs:all(~n DataDir=~p,~n CertDir=~p,~n ServerRoot=~p~n Opts=~p~n) returned ~p~n", [?MODULE,?LINE,DataDir, CertDir, ServerRoot, cert_opts(Group), Result]),
+ %% start a HTTP server to serve the CRLs
+ {ok, Httpd} = inets:start(httpd, [{server_name, "localhost"}, {port, 8000},
+ {server_root, ServerRoot},
+ {document_root, CertDir},
+ {modules, [mod_get]}
+ ]),
+ ct:log("~p:~p~nlisteners to port 8000:~n~p~n)",[?MODULE,?LINE,os:cmd("netstat -tln|grep ':8000'")]),
+ [{make_cert_result, Result}, {cert_dir, CertDir}, {httpd, Httpd} | Config].
+
+cert_opts(v1_crl) -> [{v2_crls, false}];
+cert_opts(idp_crl) -> [{issuing_distribution_point, true}];
+cert_opts(_) -> [].
+
+make_dir_path(PathComponents) ->
+ lists:foldl(fun(F,P0) -> file:make_dir(P=filename:join(P0,F)), P end,
+ "",
+ PathComponents).
+
+
+end_per_group(_GroupName, Config) ->
+ case ?config(httpd, Config) of
+ undefined -> ok;
+ Pid ->
+ ct:log("Stop httpd ~p",[Pid]),
+ ok = inets:stop(httpd, Pid)
+ ,ct:log("Stopped",[])
+ end,
+ inets:stop(),
+ ct:log("~p:~p~nlisteners to port 8000:~n~p~n)",[?MODULE,?LINE,os:cmd("netstat -tln|grep ':8000'")]),
+ Config.
+
+%%%================================================================
+%%% Test cases
+
+crl_verify_valid() ->
+ [{doc,"Verify a simple valid CRL chain"}].
+crl_verify_valid(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ PrivDir = ?config(cert_dir, Config),
+ ServerOpts = [{keyfile, filename:join([PrivDir, "server", "key.pem"])},
+ {certfile, filename:join([PrivDir, "server", "cert.pem"])},
+ {cacertfile, filename:join([PrivDir, "server", "cacerts.pem"])}],
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Data = "From openssl to erlang",
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, erlang_ssl_receive, [Data]}},
+ %{mfa, {ssl_test_lib, no_result, []}},
+ {options, ServerOpts}]),
+ ct:log("~p:~p~nreturn from ssl_test_lib:start_server:~n~p",[?MODULE,?LINE,Server]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ CACerts = load_cert(filename:join([PrivDir, "erlangCA", "cacerts.pem"])),
+
+ ClientOpts = [{cacerts, CACerts},
+ {verify, verify_peer},
+ {verify_fun, {fun validate_function/3, {CACerts, []}}}],
+
+
+ ct:log("~p:~p~ncalling ssl_test_lib:start_client",[?MODULE,?LINE]),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ erlang_ssl_send, [Data]}},
+ %{mfa, {ssl_test_lib, no_result, []}},
+ {options, ClientOpts}]),
+ ct:log("~p:~p~nreturn from ssl_test_lib:start_client:~n~p",[?MODULE,?LINE,Client]),
+
+ ssl_test_lib:check_result(Client, ok, Server, ok),
+
+ %% Clean close down! Server needs to be closed first !!
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client),
+ process_flag(trap_exit, false).
+
+crl_verify_revoked() ->
+ [{doc,"Verify a simple valid CRL chain"}].
+crl_verify_revoked(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ PrivDir = ?config(cert_dir, Config),
+ ServerOpts = [{keyfile, filename:join([PrivDir, "revoked", "key.pem"])},
+ {certfile, filename:join([PrivDir, "revoked", "cert.pem"])},
+ {cacertfile, filename:join([PrivDir, "revoked", "cacerts.pem"])}],
+ ct:log("~p:~p~nserver opts ~p~n", [?MODULE,?LINE, ServerOpts]),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ %{mfa, {?MODULE, erlang_ssl_receive, [Data]}},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ CACerts = load_cert(filename:join([PrivDir, "erlangCA", "cacerts.pem"])),
+ ClientOpts = [{cacerts, CACerts},
+ {verify, verify_peer},
+ {verify_fun, {fun validate_function/3, {CACerts, []}}}],
+
+ {connect_failed, _} = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ %{mfa, {?MODULE,
+ %erlang_ssl_receive, [Data]}},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, ClientOpts}]),
+
+ %% Clean close down! Server needs to be closed first !!
+ ssl_test_lib:close(Server),
+ process_flag(trap_exit, false).
+
+%%%================================================================
+%%% Lib
+
+erlang_ssl_receive(Socket, Data) ->
+ ct:log("~p:~p~nConnection info: ~p~n",
+ [?MODULE,?LINE, ssl:connection_info(Socket)]),
+ receive
+ {ssl, Socket, Data} ->
+ ct:log("~p:~p~nReceived ~p~n",[?MODULE,?LINE, Data]),
+ %% open_ssl server sometimes hangs waiting in blocking read
+ ssl:send(Socket, "Got it"),
+ ok;
+ {ssl, Socket, Byte} when length(Byte) == 1 ->
+ erlang_ssl_receive(Socket, tl(Data));
+ {Port, {data,Debug}} when is_port(Port) ->
+ ct:log("~p:~p~nopenssl ~s~n",[?MODULE,?LINE, Debug]),
+ erlang_ssl_receive(Socket,Data);
+ Other ->
+ ct:fail({unexpected_message, Other})
+ after 4000 ->
+ ct:fail({did_not_get, Data})
+ end.
+
+
+erlang_ssl_send(Socket, Data) ->
+ ct:log("~p:~p~nConnection info: ~p~n",
+ [?MODULE,?LINE, ssl:connection_info(Socket)]),
+ ssl:send(Socket, Data),
+ ok.
+
+load_certs(undefined) ->
+ undefined;
+load_certs(CertDir) ->
+ case file:list_dir(CertDir) of
+ {ok, Certs} ->
+ load_certs(lists:map(fun(Cert) -> filename:join(CertDir, Cert)
+ end, Certs), []);
+ {error, _} ->
+ undefined
+ end.
+
+load_certs([], Acc) ->
+ ct:log("~p:~p~nSuccessfully loaded ~p CA certificates~n", [?MODULE,?LINE, length(Acc)]),
+ Acc;
+load_certs([Cert|Certs], Acc) ->
+ case filelib:is_dir(Cert) of
+ true ->
+ load_certs(Certs, Acc);
+ _ ->
+ %ct:log("~p:~p~nLoading certificate ~p~n", [?MODULE,?LINE, Cert]),
+ load_certs(Certs, load_cert(Cert) ++ Acc)
+ end.
+
+load_cert(Cert) ->
+ {ok, Bin} = file:read_file(Cert),
+ case filename:extension(Cert) of
+ ".der" ->
+ %% no decoding necessary
+ [Bin];
+ _ ->
+ %% assume PEM otherwise
+ Contents = public_key:pem_decode(Bin),
+ [DER || {Type, DER, Cipher} <- Contents, Type == 'Certificate', Cipher == 'not_encrypted']
+ end.
+
+%% @doc Validator function for SSL negotiation.
+%%
+validate_function(Cert, valid_peer, State) ->
+ ct:log("~p:~p~nvaliding peer ~p with ~p intermediate certs~n",
+ [?MODULE,?LINE, get_common_name(Cert),
+ length(element(2, State))]),
+ %% peer certificate validated, now check the CRL
+ Res = (catch check_crl(Cert, State)),
+ ct:log("~p:~p~nCRL validate result for ~p: ~p~n",
+ [?MODULE,?LINE, get_common_name(Cert), Res]),
+ {Res, State};
+validate_function(Cert, valid, {TrustedCAs, IntermediateCerts}=State) ->
+ case public_key:pkix_is_self_signed(Cert) of
+ true ->
+ ct:log("~p:~p~nroot certificate~n",[?MODULE,?LINE]),
+ %% this is a root cert, no CRL
+ {valid, {TrustedCAs, [Cert|IntermediateCerts]}};
+ false ->
+ %% check is valid CA certificate, add to the list of
+ %% intermediates
+ Res = (catch check_crl(Cert, State)),
+ ct:log("~p:~p~nCRL intermediate CA validate result for ~p: ~p~n",
+ [?MODULE,?LINE, get_common_name(Cert), Res]),
+ {Res, {TrustedCAs, [Cert|IntermediateCerts]}}
+ end;
+validate_function(_Cert, _Event, State) ->
+ %ct:log("~p:~p~nignoring event ~p~n", [?MODULE,?LINE, _Event]),
+ {valid, State}.
+
+%% @doc Given a certificate, find CRL distribution points for the given
+%% certificate, fetch, and attempt to validate each CRL through
+%% issuer_function/4.
+%%
+check_crl(Cert, State) ->
+ %% pull the CRL distribution point(s) out of the certificate, if any
+ ct:log("~p:~p~ncheck_crl(~n Cert=~p,~nState=~p~n)",[?MODULE,?LINE,Cert,State]),
+ case pubkey_cert:select_extension(
+ ?'id-ce-cRLDistributionPoints',
+ pubkey_cert:extensions_list(Cert#'OTPCertificate'.tbsCertificate#'OTPTBSCertificate'.extensions)) of
+ undefined ->
+ ct:log("~p:~p~nno CRL distribution points for ~p~n",
+ [?MODULE,?LINE, get_common_name(Cert)]),
+ %% fail; we can't validate if there's no CRL
+ no_crl;
+ CRLExtension ->
+ ct:log("~p:~p~nCRLExtension=~p)",[?MODULE,?LINE,CRLExtension]),
+ CRLDistPoints = CRLExtension#'Extension'.extnValue,
+ DPointsAndCRLs = lists:foldl(fun(Point, Acc) ->
+ %% try to read the CRL over http or from a
+ %% local file
+ case fetch_point(Point) of
+ not_available ->
+ ct:log("~p:~p~nfetch_point returned~n~p~n)",[?MODULE,?LINE,not_available]),
+ Acc;
+ Res ->
+ ct:log("~p:~p~nfetch_point returned~n~p~n)",[?MODULE,?LINE,Res]),
+ [{Point, Res} | Acc]
+ end
+ end, [], CRLDistPoints),
+ public_key:pkix_crls_validate(Cert,
+ DPointsAndCRLs,
+ [{issuer_fun,
+ {fun issuer_function/4, State}}])
+ end.
+
+%% @doc Given a list of distribution points for CRLs, certificates and
+%% both trusted and intermediary certificates, attempt to build and
+%% authority chain back via build_chain to verify that it is valid.
+%%
+issuer_function(_DP, CRL, _Issuer, {TrustedCAs, IntermediateCerts}) ->
+ %% XXX the 'Issuer' we get passed here is the AuthorityKeyIdentifier,
+ %% which we are not currently smart enough to understand
+ %% Read the CA certs out of the file
+ ct:log("~p:~p~nissuer_function(~nCRL=~p,~nLast param=~p)",[?MODULE,?LINE,CRL, {TrustedCAs, IntermediateCerts}]),
+ Certs = [public_key:pkix_decode_cert(DER, otp) || DER <- TrustedCAs],
+ %% get the real issuer out of the CRL
+ Issuer = public_key:pkix_normalize_name(
+ pubkey_cert_records:transform(
+ CRL#'CertificateList'.tbsCertList#'TBSCertList'.issuer, decode)),
+ %% assume certificates are ordered from root to tip
+ case find_issuer(Issuer, IntermediateCerts ++ Certs) of
+ undefined ->
+ ct:log("~p:~p~nunable to find certificate matching CRL issuer ~p~n",
+ [?MODULE,?LINE, Issuer]),
+ error;
+ IssuerCert ->
+ ct:log("~p:~p~nIssuerCert=~p~n)",[?MODULE,?LINE,IssuerCert]),
+ case build_chain({public_key:pkix_encode('OTPCertificate',
+ IssuerCert,
+ otp),
+ IssuerCert}, IntermediateCerts, Certs, []) of
+ undefined ->
+ error;
+ {OTPCert, Path} ->
+ {ok, OTPCert, Path}
+ end
+ end.
+
+%% @doc Attempt to build authority chain back using intermediary
+%% certificates, falling back on trusted certificates if the
+%% intermediary chain of certificates does not fully extend to the
+%% root.
+%%
+%% Returns: {RootCA :: #OTPCertificate{}, Chain :: [der_encoded()]}
+%%
+build_chain({DER, Cert}, IntCerts, TrustedCerts, Acc) ->
+ %% check if this cert is self-signed, if it is, we've reached the
+ %% root of the chain
+ Issuer = public_key:pkix_normalize_name(
+ Cert#'OTPCertificate'.tbsCertificate#'OTPTBSCertificate'.issuer),
+ Subject = public_key:pkix_normalize_name(
+ Cert#'OTPCertificate'.tbsCertificate#'OTPTBSCertificate'.subject),
+ case Issuer == Subject of
+ true ->
+ case find_issuer(Issuer, TrustedCerts) of
+ undefined ->
+ ct:log("~p:~p~nself-signed certificate is NOT trusted~n",[?MODULE,?LINE]),
+ undefined;
+ TrustedCert ->
+ %% return the cert from the trusted list, to prevent
+ %% issuer spoofing
+ {TrustedCert,
+ [public_key:pkix_encode(
+ 'OTPCertificate', TrustedCert, otp)|Acc]}
+ end;
+ false ->
+ Match = lists:foldl(
+ fun(C, undefined) ->
+ S = public_key:pkix_normalize_name(C#'OTPCertificate'.tbsCertificate#'OTPTBSCertificate'.subject),
+ %% compare the subject to the current issuer
+ case Issuer == S of
+ true ->
+ %% we've found our man
+ {public_key:pkix_encode('OTPCertificate', C, otp), C};
+ false ->
+ undefined
+ end;
+ (_E, A) ->
+ %% already matched
+ A
+ end, undefined, IntCerts),
+ case Match of
+ undefined when IntCerts /= TrustedCerts ->
+ %% continue the chain by using the trusted CAs
+ ct:log("~p:~p~nRan out of intermediate certs, switching to trusted certs~n",[?MODULE,?LINE]),
+ build_chain({DER, Cert}, TrustedCerts, TrustedCerts, Acc);
+ undefined ->
+ ct:log("Can't construct chain of trust beyond ~p~n",
+ [?MODULE,?LINE, get_common_name(Cert)]),
+ %% can't find the current cert's issuer
+ undefined;
+ Match ->
+ build_chain(Match, IntCerts, TrustedCerts, [DER|Acc])
+ end
+ end.
+
+%% @doc Given a certificate and a list of trusted or intermediary
+%% certificates, attempt to find a match in the list or bail with
+%% undefined.
+find_issuer(Issuer, Certs) ->
+ lists:foldl(
+ fun(OTPCert, undefined) ->
+ %% check if this certificate matches the issuer
+ Normal = public_key:pkix_normalize_name(
+ OTPCert#'OTPCertificate'.tbsCertificate#'OTPTBSCertificate'.subject),
+ case Normal == Issuer of
+ true ->
+ OTPCert;
+ false ->
+ undefined
+ end;
+ (_E, Acc) ->
+ %% already found a match
+ Acc
+ end, undefined, Certs).
+
+%% @doc Find distribution points for a given CRL and then attempt to
+%% fetch the CRL from the first available.
+fetch_point(#'DistributionPoint'{distributionPoint={fullName, Names}}) ->
+ Decoded = [{NameType,
+ pubkey_cert_records:transform(Name, decode)}
+ || {NameType, Name} <- Names],
+ ct:log("~p:~p~ncall fetch(~nDecoded=~p~n)",[?MODULE,?LINE,Decoded]),
+ fetch(Decoded).
+
+%% @doc Given a list of locations to retrieve a CRL from, attempt to
+%% retrieve either from a file or http resource and bail as soon as
+%% it can be found.
+%%
+%% Currently, only hand a armored PEM or DER encoded file, with
+%% defaulting to DER.
+%%
+fetch([]) ->
+ not_available;
+fetch([{uniformResourceIdentifier, "http"++_=URL}|Rest]) ->
+ ct:log("~p:~p~ngetting CRL from ~p~n", [?MODULE,?LINE, URL]),
+ ct:log("~p:~p~nlisteners to port 8000:~n~p~n)",[?MODULE,?LINE,os:cmd("netstat -tln|grep ':8000'")]),
+ case httpc:request(get, {URL, []}, [], [{body_format, binary}]) of
+ {ok, {_Status, _Headers, Body}} ->
+ case Body of
+ <<"-----BEGIN", _/binary>> ->
+ ct:log("~p:~p~npublic_key:pem_decode,~nBody=~p~n)",[?MODULE,?LINE,Body]),
+ [{'CertificateList',
+ DER, _}=CertList] = public_key:pem_decode(Body),
+ ct:log("~p:~p~npublic_key:pem_entry_decode,~nCertList=~p~n)",[?MODULE,?LINE,CertList]),
+ {DER, public_key:pem_entry_decode(CertList)};
+ _ ->
+ ct:log("~p:~p~npublic_key:pem_entry_decode,~nBody=~p~n)",[?MODULE,?LINE,{'CertificateList', Body, not_encrypted}]),
+ %% assume DER encoded
+ CertList = public_key:pem_entry_decode(
+ {'CertificateList', Body, not_encrypted}),
+ {Body, CertList}
+ end;
+ {error, _Reason} ->
+ ct:log("~p:~p~nfailed to get CRL ~p~n", [?MODULE,?LINE, _Reason]),
+ fetch(Rest);
+ Other ->
+ ct:log("~p:~p~nreally failed to get CRL ~p~n", [?MODULE,?LINE, Other]),
+ fetch(Rest)
+ end;
+fetch([Loc|Rest]) ->
+ %% unsupported CRL location
+ ct:log("~p:~p~nunable to fetch CRL from unsupported location ~p~n",
+ [?MODULE,?LINE, Loc]),
+ fetch(Rest).
+
+%% get the common name attribute out of an OTPCertificate record
+get_common_name(OTPCert) ->
+ %% You'd think there'd be an easier way than this giant mess, but I
+ %% couldn't find one.
+ {rdnSequence, Subject} = OTPCert#'OTPCertificate'.tbsCertificate#'OTPTBSCertificate'.subject,
+ case [Attribute#'AttributeTypeAndValue'.value || [Attribute] <- Subject,
+ Attribute#'AttributeTypeAndValue'.type == ?'id-at-commonName'] of
+ [Att] ->
+ case Att of
+ {teletexString, Str} -> Str;
+ {printableString, Str} -> Str;
+ {utf8String, Bin} -> binary_to_list(Bin)
+ end;
+ _ ->
+ unknown
+ end.
+
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index 7ed9adfcd9..7d8ece8d19 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -60,7 +60,7 @@ run_server(Opts) ->
Options = proplists:get_value(options, Opts),
Pid = proplists:get_value(from, Opts),
Transport = proplists:get_value(transport, Opts, ssl),
- ct:log("ssl:listen(~p, ~p)~n", [Port, Options]),
+ ct:log("~p:~p~nssl:listen(~p, ~p)~n", [?MODULE,?LINE, Port, Options]),
{ok, ListenSocket} = rpc:call(Node, Transport, listen, [Port, Options]),
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
@@ -78,13 +78,13 @@ do_run_server(ListenSocket, AcceptSocket, Opts) ->
Pid = proplists:get_value(from, Opts),
Transport = proplists:get_value(transport, Opts, ssl),
{Module, Function, Args} = proplists:get_value(mfa, Opts),
- ct:log("Server: apply(~p,~p,~p)~n",
- [Module, Function, [AcceptSocket | Args]]),
+ ct:log("~p:~p~nServer: apply(~p,~p,~p)~n",
+ [?MODULE,?LINE, Module, Function, [AcceptSocket | Args]]),
case rpc:call(Node, Module, Function, [AcceptSocket | Args]) of
no_result_msg ->
ok;
Msg ->
- ct:log("Server Msg: ~p ~n", [Msg]),
+ ct:log("~p:~p~nServer Msg: ~p ~n", [?MODULE,?LINE, Msg]),
Pid ! {self(), Msg}
end,
receive
@@ -93,10 +93,10 @@ do_run_server(ListenSocket, AcceptSocket, Opts) ->
{listen, MFA} ->
run_server(ListenSocket, [MFA | proplists:delete(mfa, Opts)]);
close ->
- ct:log("Server closing ~p ~n", [self()]),
+ ct:log("~p:~p~nServer closing ~p ~n", [?MODULE,?LINE, self()]),
Result = rpc:call(Node, Transport, close, [AcceptSocket], 500),
Result1 = rpc:call(Node, Transport, close, [ListenSocket], 500),
- ct:log("Result ~p : ~p ~n", [Result, Result1]);
+ ct:log("~p:~p~nResult ~p : ~p ~n", [?MODULE,?LINE, Result, Result1]);
{ssl_closed, _} ->
ok
end.
@@ -116,7 +116,7 @@ connect(#sslsocket{} = ListenSocket, Opts) ->
end;
connect(ListenSocket, Opts) ->
Node = proplists:get_value(node, Opts),
- ct:log("gen_tcp:accept(~p)~n", [ListenSocket]),
+ ct:log("~p:~p~ngen_tcp:accept(~p)~n", [?MODULE,?LINE, ListenSocket]),
{ok, AcceptSocket} = rpc:call(Node, gen_tcp, accept,
[ListenSocket]),
AcceptSocket.
@@ -124,15 +124,17 @@ connect(ListenSocket, Opts) ->
connect(_, _, 0, AcceptSocket, _) ->
AcceptSocket;
connect(ListenSocket, Node, N, _, Timeout) ->
- ct:log("ssl:transport_accept(~p)~n", [ListenSocket]),
+ ct:log("~p:~p~nssl:transport_accept(~p)~n", [?MODULE,?LINE, ListenSocket]),
{ok, AcceptSocket} = rpc:call(Node, ssl, transport_accept,
[ListenSocket]),
- ct:log("ssl:ssl_accept(~p, ~p)~n", [AcceptSocket, Timeout]),
+ ct:log("~p:~p~nssl:ssl_accept(~p, ~p)~n", [?MODULE,?LINE, AcceptSocket, Timeout]),
case rpc:call(Node, ssl, ssl_accept, [AcceptSocket, Timeout]) of
ok ->
+ct:log("~p:~p~nok from ssl:ssl_accept@~p",[?MODULE,?LINE, Node]),
connect(ListenSocket, Node, N-1, AcceptSocket, Timeout);
Result ->
+ct:log("~p:~p~nssl:ssl_accept@~p ret ~p",[?MODULE,?LINE, Node,Result]),
Result
end.
@@ -148,11 +150,13 @@ remove_close_msg(ReconnectTimes) ->
start_client(Args) ->
Result = spawn_link(?MODULE, run_client_init, [lists:delete(return_socket, Args)]),
receive
- { connected, Socket } ->
- case lists:member(return_socket, Args) of
- true -> { Result, Socket };
- false -> Result
- end
+ {connected, Socket} ->
+ case lists:member(return_socket, Args) of
+ true -> {Result, Socket};
+ false -> Result
+ end;
+ {connect_failed, Reason} ->
+ {connect_failed, Reason}
end.
run_client_init(Opts) ->
@@ -166,27 +170,30 @@ run_client(Opts) ->
Pid = proplists:get_value(from, Opts),
Transport = proplists:get_value(transport, Opts, ssl),
Options = proplists:get_value(options, Opts),
- ct:log("ssl:connect(~p, ~p, ~p)~n", [Host, Port, Options]),
+ ct:log("~p:~p~nssl:connect(~p, ~p, ~p)~n", [?MODULE,?LINE, Host, Port, Options]),
+ct:log("~p:~p~nnet_adm:ping(~p)=~p",[?MODULE,?LINE, Node,net_adm:ping(Node)]),
+%%ct:log("~p:~p~n~p:connect(~p, ~p, ~p)@~p~n", [?MODULE,?LINE, Transport, Host, Port, Options, Node]),
+ct:log("~p:~p~n~p:connect(~p, ~p, ...)@~p~n", [?MODULE,?LINE, Transport, Host, Port, Node]),
case rpc:call(Node, Transport, connect, [Host, Port, Options]) of
{ok, Socket} ->
- Pid ! { connected, Socket },
- ct:log("Client: connected~n", []),
+ Pid ! {connected, Socket},
+ ct:log("~p:~p~nClient: connected~n", [?MODULE,?LINE]),
%% In special cases we want to know the client port, it will
%% be indicated by sending {port, 0} in options list!
send_selected_port(Pid, proplists:get_value(port, Options), Socket),
{Module, Function, Args} = proplists:get_value(mfa, Opts),
- ct:log("Client: apply(~p,~p,~p)~n",
- [Module, Function, [Socket | Args]]),
+ ct:log("~p:~p~nClient: apply(~p,~p,~p)~n",
+ [?MODULE,?LINE, Module, Function, [Socket | Args]]),
case rpc:call(Node, Module, Function, [Socket | Args]) of
no_result_msg ->
ok;
Msg ->
- ct:log("Client Msg: ~p ~n", [Msg]),
+ ct:log("~p:~p~nClient Msg: ~p ~n", [?MODULE,?LINE, Msg]),
Pid ! {self(), Msg}
end,
receive
close ->
- ct:log("Client closing~n", []),
+ ct:log("~p:~p~nClient closing~n", [?MODULE,?LINE]),
rpc:call(Node, Transport, close, [Socket]);
{ssl_closed, Socket} ->
ok;
@@ -196,50 +203,42 @@ run_client(Opts) ->
{error, econnrefused = Reason} ->
case get(retries) of
N when N < 5 ->
+ ct:log("~p:~p~neconnrefused retries=~p sleep ~p",[?MODULE,?LINE, N,?SLEEP]),
put(retries, N+1),
ct:sleep(?SLEEP),
run_client(Opts);
_ ->
- ct:log("Client faild several times: connection failed: ~p ~n", [Reason]),
+ ct:log("~p:~p~nClient faild several times: connection failed: ~p ~n", [?MODULE,?LINE, Reason]),
Pid ! {self(), {error, Reason}}
end;
{error, Reason} ->
- ct:log("Client: connection failed: ~p ~n", [Reason]),
- Pid ! {self(), {error, Reason}}
+ ct:log("~p:~p~nClient: connection failed: ~p ~n", [?MODULE,?LINE, Reason]),
+ Pid ! {connect_failed, Reason};
+ {badrpc,BadRPC} ->
+ ct:log("~p:~p~nBad rpc: ~p",[?MODULE,?LINE, BadRPC]),
+ Pid ! {connect_failed, {badrpc,BadRPC}}
end.
close(Pid) ->
- ct:log("Close ~p ~n", [Pid]),
+ ct:log("~p:~p~nClose ~p ~n", [?MODULE,?LINE, Pid]),
Monitor = erlang:monitor(process, Pid),
Pid ! close,
receive
{'DOWN', Monitor, process, Pid, Reason} ->
erlang:demonitor(Monitor),
- ct:log("Pid: ~p down due to:~p ~n", [Pid, Reason])
+ ct:log("~p:~p~nPid: ~p down due to:~p ~n", [?MODULE,?LINE, Pid, Reason])
end.
check_result(Server, ServerMsg, Client, ClientMsg) ->
receive
- {Server, ServerMsg} ->
- receive
- {Client, ClientMsg} ->
- ok;
- Unexpected ->
- Reason = {{expected, {Client, ClientMsg}},
- {got, Unexpected}},
- ct:fail(Reason)
- end;
- {Client, ClientMsg} ->
- receive
- {Server, ServerMsg} ->
- ok;
- Unexpected ->
- Reason = {{expected, {Server, ClientMsg}},
- {got, Unexpected}},
- ct:fail(Reason)
- end;
+ {Server, ServerMsg} ->
+ check_result(Client, ClientMsg);
+
+ {Client, ClientMsg} ->
+ check_result(Server, ServerMsg);
+
{Port, {data,Debug}} when is_port(Port) ->
- io:format("openssl ~s~n",[Debug]),
+ ct:log("~p:~p~nopenssl ~s~n",[?MODULE,?LINE, Debug]),
check_result(Server, ServerMsg, Client, ClientMsg);
Unexpected ->
@@ -253,7 +252,7 @@ check_result(Pid, Msg) ->
{Pid, Msg} ->
ok;
{Port, {data,Debug}} when is_port(Port) ->
- io:format("openssl ~s~n",[Debug]),
+ ct:log("~p:~p~nopenssl ~s~n",[?MODULE,?LINE, Debug]),
check_result(Pid,Msg);
Unexpected ->
Reason = {{expected, {Pid, Msg}},
@@ -278,7 +277,7 @@ wait_for_result(Server, ServerMsg, Client, ClientMsg) ->
%% Unexpected
end;
{Port, {data,Debug}} when is_port(Port) ->
- io:format("openssl ~s~n",[Debug]),
+ ct:log("~p:~p~nopenssl ~s~n",[?MODULE,?LINE, Debug]),
wait_for_result(Server, ServerMsg, Client, ClientMsg)
%% Unexpected ->
%% Unexpected
@@ -290,7 +289,7 @@ wait_for_result(Pid, Msg) ->
{Pid, Msg} ->
ok;
{Port, {data,Debug}} when is_port(Port) ->
- io:format("openssl ~s~n",[Debug]),
+ ct:log("~p:~p~nopenssl ~s~n",[?MODULE,?LINE, Debug]),
wait_for_result(Pid,Msg)
%% Unexpected ->
%% Unexpected
@@ -515,33 +514,33 @@ run_upgrade_server(Opts) ->
SslOptions = proplists:get_value(ssl_options, Opts),
Pid = proplists:get_value(from, Opts),
- ct:log("gen_tcp:listen(~p, ~p)~n", [Port, TcpOptions]),
+ ct:log("~p:~p~ngen_tcp:listen(~p, ~p)~n", [?MODULE,?LINE, Port, TcpOptions]),
{ok, ListenSocket} = rpc:call(Node, gen_tcp, listen, [Port, TcpOptions]),
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
- ct:log("gen_tcp:accept(~p)~n", [ListenSocket]),
+ ct:log("~p:~p~ngen_tcp:accept(~p)~n", [?MODULE,?LINE, ListenSocket]),
{ok, AcceptSocket} = rpc:call(Node, gen_tcp, accept, [ListenSocket]),
try
{ok, SslAcceptSocket} = case TimeOut of
infinity ->
- ct:log("ssl:ssl_accept(~p, ~p)~n",
- [AcceptSocket, SslOptions]),
+ ct:log("~p:~p~nssl:ssl_accept(~p, ~p)~n",
+ [?MODULE,?LINE, AcceptSocket, SslOptions]),
rpc:call(Node, ssl, ssl_accept,
[AcceptSocket, SslOptions]);
_ ->
- ct:log("ssl:ssl_accept(~p, ~p, ~p)~n",
- [AcceptSocket, SslOptions, TimeOut]),
+ ct:log("~p:~p~nssl:ssl_accept(~p, ~p, ~p)~n",
+ [?MODULE,?LINE, AcceptSocket, SslOptions, TimeOut]),
rpc:call(Node, ssl, ssl_accept,
[AcceptSocket, SslOptions, TimeOut])
end,
{Module, Function, Args} = proplists:get_value(mfa, Opts),
Msg = rpc:call(Node, Module, Function, [SslAcceptSocket | Args]),
- ct:log("Upgrade Server Msg: ~p ~n", [Msg]),
+ ct:log("~p:~p~nUpgrade Server Msg: ~p ~n", [?MODULE,?LINE, Msg]),
Pid ! {self(), Msg},
receive
close ->
- ct:log("Upgrade Server closing~n", []),
+ ct:log("~p:~p~nUpgrade Server closing~n", [?MODULE,?LINE]),
rpc:call(Node, ssl, close, [SslAcceptSocket])
end
catch error:{badmatch, Error} ->
@@ -559,24 +558,24 @@ run_upgrade_client(Opts) ->
TcpOptions = proplists:get_value(tcp_options, Opts),
SslOptions = proplists:get_value(ssl_options, Opts),
- ct:log("gen_tcp:connect(~p, ~p, ~p)~n",
- [Host, Port, TcpOptions]),
+ ct:log("~p:~p~ngen_tcp:connect(~p, ~p, ~p)~n",
+ [?MODULE,?LINE, Host, Port, TcpOptions]),
{ok, Socket} = rpc:call(Node, gen_tcp, connect, [Host, Port, TcpOptions]),
send_selected_port(Pid, Port, Socket),
- ct:log("ssl:connect(~p, ~p)~n", [Socket, SslOptions]),
+ ct:log("~p:~p~nssl:connect(~p, ~p)~n", [?MODULE,?LINE, Socket, SslOptions]),
{ok, SslSocket} = rpc:call(Node, ssl, connect, [Socket, SslOptions]),
{Module, Function, Args} = proplists:get_value(mfa, Opts),
- ct:log("apply(~p, ~p, ~p)~n",
- [Module, Function, [SslSocket | Args]]),
+ ct:log("~p:~p~napply(~p, ~p, ~p)~n",
+ [?MODULE,?LINE, Module, Function, [SslSocket | Args]]),
Msg = rpc:call(Node, Module, Function, [SslSocket | Args]),
- ct:log("Upgrade Client Msg: ~p ~n", [Msg]),
+ ct:log("~p:~p~nUpgrade Client Msg: ~p ~n", [?MODULE,?LINE, Msg]),
Pid ! {self(), Msg},
receive
close ->
- ct:log("Upgrade Client closing~n", []),
+ ct:log("~p:~p~nUpgrade Client closing~n", [?MODULE,?LINE]),
rpc:call(Node, ssl, close, [SslSocket])
end.
@@ -595,21 +594,21 @@ run_upgrade_server_error(Opts) ->
SslOptions = proplists:get_value(ssl_options, Opts),
Pid = proplists:get_value(from, Opts),
- ct:log("gen_tcp:listen(~p, ~p)~n", [Port, TcpOptions]),
+ ct:log("~p:~p~ngen_tcp:listen(~p, ~p)~n", [?MODULE,?LINE, Port, TcpOptions]),
{ok, ListenSocket} = rpc:call(Node, gen_tcp, listen, [Port, TcpOptions]),
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
- ct:log("gen_tcp:accept(~p)~n", [ListenSocket]),
+ ct:log("~p:~p~ngen_tcp:accept(~p)~n", [?MODULE,?LINE, ListenSocket]),
{ok, AcceptSocket} = rpc:call(Node, gen_tcp, accept, [ListenSocket]),
Error = case TimeOut of
infinity ->
- ct:log("ssl:ssl_accept(~p, ~p)~n",
- [AcceptSocket, SslOptions]),
+ ct:log("~p:~p~nssl:ssl_accept(~p, ~p)~n",
+ [?MODULE,?LINE, AcceptSocket, SslOptions]),
rpc:call(Node, ssl, ssl_accept,
[AcceptSocket, SslOptions]);
_ ->
- ct:log("ssl:ssl_accept(~p, ~p, ~p)~n",
- [AcceptSocket, SslOptions, TimeOut]),
+ ct:log("~p:~p~nssl:ssl_accept(~p, ~p, ~p)~n",
+ [?MODULE,?LINE, AcceptSocket, SslOptions, TimeOut]),
rpc:call(Node, ssl, ssl_accept,
[AcceptSocket, SslOptions, TimeOut])
end,
@@ -628,26 +627,26 @@ run_server_error(Opts) ->
Options = proplists:get_value(options, Opts),
Pid = proplists:get_value(from, Opts),
Transport = proplists:get_value(transport, Opts, ssl),
- ct:log("ssl:listen(~p, ~p)~n", [Port, Options]),
+ ct:log("~p:~p~nssl:listen(~p, ~p)~n", [?MODULE,?LINE, Port, Options]),
case rpc:call(Node, Transport, listen, [Port, Options]) of
{ok, #sslsocket{} = ListenSocket} ->
%% To make sure error_client will
%% get {error, closed} and not {error, connection_refused}
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
- ct:log("ssl:transport_accept(~p)~n", [ListenSocket]),
+ ct:log("~p:~p~nssl:transport_accept(~p)~n", [?MODULE,?LINE, ListenSocket]),
case rpc:call(Node, Transport, transport_accept, [ListenSocket]) of
{error, _} = Error ->
Pid ! {self(), Error};
{ok, AcceptSocket} ->
- ct:log("ssl:ssl_accept(~p)~n", [AcceptSocket]),
+ ct:log("~p:~p~nssl:ssl_accept(~p)~n", [?MODULE,?LINE, AcceptSocket]),
Error = rpc:call(Node, ssl, ssl_accept, [AcceptSocket]),
Pid ! {self(), Error}
end;
{ok, ListenSocket} ->
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
- ct:log("~p:accept(~p)~n", [Transport, ListenSocket]),
+ ct:log("~p:~p~n~p:accept(~p)~n", [?MODULE,?LINE, Transport, ListenSocket]),
case rpc:call(Node, Transport, accept, [ListenSocket]) of
{error, _} = Error ->
Pid ! {self(), Error}
@@ -669,7 +668,7 @@ run_client_error(Opts) ->
Pid = proplists:get_value(from, Opts),
Transport = proplists:get_value(transport, Opts, ssl),
Options = proplists:get_value(options, Opts),
- ct:log("ssl:connect(~p, ~p, ~p)~n", [Host, Port, Options]),
+ ct:log("~p:~p~nssl:connect(~p, ~p, ~p)~n", [?MODULE,?LINE, Host, Port, Options]),
Error = rpc:call(Node, Transport, connect, [Host, Port, Options]),
Pid ! {self(), Error}.
@@ -892,7 +891,7 @@ der_to_pem(File, Entries) ->
cipher_result(Socket, Result) ->
Result = ssl:connection_info(Socket),
- ct:log("Successfull connect: ~p~n", [Result]),
+ ct:log("~p:~p~nSuccessfull connect: ~p~n", [?MODULE,?LINE, Result]),
%% Importante to send two packets here
%% to properly test "cipher state" handling
ssl:send(Socket, "Hello\n"),
@@ -1061,10 +1060,13 @@ check_sane_openssl_version(Version) ->
true
end.
+enough_openssl_crl_support("OpenSSL 0." ++ _) -> false;
+enough_openssl_crl_support(_) -> true.
+
wait_for_openssl_server() ->
receive
{Port, {data, Debug}} when is_port(Port) ->
- ct:log("openssl ~s~n",[Debug]),
+ ct:log("~p:~p~nopenssl ~s~n",[?MODULE,?LINE, Debug]),
%% openssl has started make sure
%% it will be in accept. Parsing
%% output is too error prone. (Even
diff --git a/lib/stdlib/doc/src/zip.xml b/lib/stdlib/doc/src/zip.xml
index 66c21da193..48b376743d 100644
--- a/lib/stdlib/doc/src/zip.xml
+++ b/lib/stdlib/doc/src/zip.xml
@@ -123,6 +123,18 @@
</taglist>
</desc>
</datatype>
+ <datatype>
+ <name name="filename"/>
+ <p>The name of a zip file.</p>
+ </datatype>
+ <datatype><name name="extension"/></datatype>
+ <datatype><name name="extension_spec"/></datatype>
+ <datatype>
+ <name name="create_option"/>
+ <desc>
+ <p>These options are described in <seealso marker="#zip_options">create/3</seealso>.</p>
+ </desc>
+ </datatype>
</datatypes>
<funcs>
<func>
@@ -160,6 +172,7 @@
set to <c>["gif", "jpg"]</c> and <c>uncompress</c> is set to
<c>["jpg"]</c>, only files with <c>"gif"</c> as extension will
be compressed. No other files will be compressed.</p>
+ <marker id="zip_options"></marker>
<p>The following options are available:</p>
<taglist>
<tag><c>cooked</c></tag>
diff --git a/lib/stdlib/src/escript.erl b/lib/stdlib/src/escript.erl
index a8a82272d6..6bd0eb8a22 100644
--- a/lib/stdlib/src/escript.erl
+++ b/lib/stdlib/src/escript.erl
@@ -59,7 +59,6 @@
file:filename()
| {file:filename(), binary()}
| {file:filename(), binary(), file:file_info()}.
--type zip_create_option() :: term().
-type section() ::
shebang
| {shebang, shebang() | default | undefined}
@@ -68,8 +67,8 @@
| {emu_args, emu_args() | undefined}
| {source, file:filename() | binary()}
| {beam, file:filename() | binary()}
- | {archive, file:filename() | binary()}
- | {archive, [zip_file()], [zip_create_option()]}.
+ | {archive, zip:filename() | binary()}
+ | {archive, [zip_file()], [zip:create_option()]}.
%%-----------------------------------------------------------------------
diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl
index 380bc3eccc..971a2e2baa 100644
--- a/lib/stdlib/src/otp_internal.erl
+++ b/lib/stdlib/src/otp_internal.erl
@@ -250,12 +250,12 @@ obsolete_1(snmp, N, A) ->
false ->
no;
true ->
- {deprecated, "Deprecated (will be removed in R17B); use snmpa:"++atom_to_list(N)++"/"++
+ {deprecated, "Deprecated (will be removed in OTP 18); use snmpa:"++atom_to_list(N)++"/"++
integer_to_list(A)++" instead"}
end;
obsolete_1(snmpa, old_info_format, 1) ->
- {deprecated, "Deprecated; (will be removed in R17B); use \"new\" format instead"};
+ {deprecated, "Deprecated; (will be removed in OTP 18); use \"new\" format instead"};
obsolete_1(snmpm, agent_info, 3) ->
{removed, {snmpm, agent_info, 2}, "R16B"};
obsolete_1(snmpm, update_agent_info, 5) ->
@@ -366,23 +366,6 @@ obsolete_1(auth, node_cookie, 1) ->
obsolete_1(auth, node_cookie, 2) ->
{deprecated, "Deprecated; use erlang:set_cookie/2 and net_adm:ping/1 instead"};
-obsolete_1(erlang, is_constant, 1) ->
- {removed, "Removed in R13B"};
-
-%% Added in R12B-0.
-obsolete_1(ssl, port, 1) ->
- {removed, {ssl, sockname, 1}, "R13B"};
-obsolete_1(ssl, accept, A) when A =:= 1; A =:= 2 ->
- {removed, "deprecated; use ssl:transport_accept/1,2 and ssl:ssl_accept/1,2"};
-obsolete_1(erlang, fault, 1) ->
- {removed, {erlang,error,1}, "R13B"};
-obsolete_1(erlang, fault, 2) ->
- {removed, {erlang,error,2}, "R13B"};
-
-%% Added in R12B-2.
-obsolete_1(file, rawopen, 2) ->
- {removed, "deprecated (will be removed in R13B); use file:open/2 with the raw option"};
-
obsolete_1(http, request, 1) -> {removed,{httpc,request,1},"R15B"};
obsolete_1(http, request, 2) -> {removed,{httpc,request,2},"R15B"};
obsolete_1(http, request, 4) -> {removed,{httpc,request,4},"R15B"};
@@ -524,7 +507,7 @@ obsolete_1(docb_xml_check, _, _) ->
%% Added in R15B
obsolete_1(asn1rt, F, _) when F == load_driver; F == unload_driver ->
- {deprecated,"deprecated (will be removed in R16A); has no effect as drivers are no longer used."};
+ {deprecated,"deprecated (will be removed in OTP 18); has no effect as drivers are no longer used"};
obsolete_1(ssl, pid, 1) ->
{removed,"was removed in R16; is no longer needed"};
obsolete_1(inviso, _, _) ->
@@ -532,7 +515,7 @@ obsolete_1(inviso, _, _) ->
%% Added in R15B01.
obsolete_1(gs, _, _) ->
- {deprecated,"the gs application has been deprecated and will be removed in R17; use the wx application instead"};
+ {deprecated,"the gs application has been deprecated and will be removed in OTP 18; use the wx application instead"};
obsolete_1(ssh, sign_data, 2) ->
{deprecated,"deprecated (will be removed in R16A); use public_key:pem_decode/1, public_key:pem_entry_decode/1 "
"and public_key:sign/3 instead"};
diff --git a/lib/stdlib/src/slave.erl b/lib/stdlib/src/slave.erl
index 3e647635bc..1898dc8aba 100644
--- a/lib/stdlib/src/slave.erl
+++ b/lib/stdlib/src/slave.erl
@@ -290,7 +290,10 @@ register_unique_name(Number) ->
%% no need to use rsh.
mk_cmd(Host, Name, Args, Waiter, Prog0) ->
- Prog = quote_progname(Prog0),
+ Prog = case os:type() of
+ {ose,_} -> mk_ose_prog(Prog0);
+ _ -> quote_progname(Prog0)
+ end,
BasicCmd = lists:concat([Prog,
" -detached -noinput -master ", node(),
" ", long_or_short(), Name, "@", Host,
@@ -310,6 +313,24 @@ mk_cmd(Host, Name, Args, Waiter, Prog0) ->
end
end.
+%% On OSE we have to pass the beam arguments directory to the slave
+%% process. To find out what arguments that should be passed on we
+%% make an assumption. All arguments after the last "--" should be
+%% skipped. So given these arguments:
+%% -Muycs256 -A 1 -- -root /mst/ -progname beam.debug.smp -- -home /mst/ -- -kernel inetrc '"/mst/inetrc.conf"' -- -name test@localhost
+%% we send
+%% -Muycs256 -A 1 -- -root /mst/ -progname beam.debug.smp -- -home /mst/ -- -kernel inetrc '"/mst/inetrc.conf"' --
+%% to the slave with whatever other args that are added in mk_cmd.
+mk_ose_prog(Prog) ->
+ SkipTail = fun("--",[]) ->
+ ["--"];
+ (_,[]) ->
+ [];
+ (Arg,Args) ->
+ [Arg," "|Args]
+ end,
+ [Prog,tl(lists:foldr(SkipTail,[],erlang:system_info(emu_args)))].
+
%% This is an attempt to distinguish between spaces in the program
%% path and spaces that separate arguments. The program is quoted to
%% allow spaces in the path.
diff --git a/lib/stdlib/src/zip.erl b/lib/stdlib/src/zip.erl
index c40ce8e203..b768c6d0b9 100644
--- a/lib/stdlib/src/zip.erl
+++ b/lib/stdlib/src/zip.erl
@@ -203,8 +203,18 @@
zip_comment_length}).
--type zip_file() :: #zip_file{}.
+-type create_option() :: memory | cooked | verbose | {comment, string()}
+ | {cwd, file:filename()}
+ | {compress, extension_spec()}
+ | {uncompress, extension_spec()}.
+-type extension() :: string().
+-type extension_spec() :: all | [extension()] | {add, [extension()]} | {del, [extension()]}.
+-type filename() :: file:filename().
+
-type zip_comment() :: #zip_comment{}.
+-type zip_file() :: #zip_file{}.
+
+-export_type([create_option/0, filename/0]).
%% Open a zip archive with options
%%
@@ -340,13 +350,13 @@ unzip(F) -> unzip(F, []).
-spec(unzip(Archive, Options) -> RetValue when
Archive :: file:name() | binary(),
Options :: [Option],
- Option :: {file_list, FileList}
+ Option :: {file_list, FileList} | cooked
| keep_old_files | verbose | memory |
{file_filter, FileFilter} | {cwd, CWD},
FileList :: [file:name()],
FileBinList :: [{file:name(),binary()}],
FileFilter :: fun((ZipFile) -> boolean()),
- CWD :: string(),
+ CWD :: file:filename(),
ZipFile :: zip_file(),
RetValue :: {ok, FileList}
| {ok, FileBinList}
@@ -430,7 +440,7 @@ zip(F, Files) -> zip(F, Files, []).
What :: all | [Extension] | {add, [Extension]} | {del, [Extension]},
Extension :: string(),
Comment :: string(),
- CWD :: string(),
+ CWD :: file:filename(),
RetValue :: {ok, FileName :: file:name()}
| {ok, {FileName :: file:name(), binary()}}
| {error, Reason :: term()}).
@@ -712,8 +722,8 @@ table(F, O) -> list_dir(F, O).
FileList :: [FileSpec],
FileSpec :: file:name() | {file:name(), binary()}
| {file:name(), binary(), file:file_info()},
- RetValue :: {ok, FileName :: file:name()}
- | {ok, {FileName :: file:name(), binary()}}
+ RetValue :: {ok, FileName :: filename()}
+ | {ok, {FileName :: filename(), binary()}}
| {error, Reason :: term()}).
create(F, Fs) -> zip(F, Fs).
@@ -724,14 +734,9 @@ create(F, Fs) -> zip(F, Fs).
FileSpec :: file:name() | {file:name(), binary()}
| {file:name(), binary(), file:file_info()},
Options :: [Option],
- Option :: memory | cooked | verbose | {comment, Comment}
- | {cwd, CWD} | {compress, What} | {uncompress, What},
- What :: all | [Extension] | {add, [Extension]} | {del, [Extension]},
- Extension :: string(),
- Comment :: string(),
- CWD :: string(),
- RetValue :: {ok, FileName :: file:name()}
- | {ok, {FileName :: file:name(), binary()}}
+ Option :: create_option(),
+ RetValue :: {ok, FileName :: filename()}
+ | {ok, {FileName :: filename(), binary()}}
| {error, Reason :: term()}).
create(F, Fs, O) -> zip(F, Fs, O).
@@ -755,7 +760,7 @@ extract(F) -> unzip(F).
FileList :: [file:name()],
FileBinList :: [{file:name(),binary()}],
FileFilter :: fun((ZipFile) -> boolean()),
- CWD :: string(),
+ CWD :: file:filename(),
ZipFile :: zip_file(),
RetValue :: {ok, FileList}
| {ok, FileBinList}
@@ -1153,7 +1158,7 @@ zip_open(Archive) -> zip_open(Archive, []).
Archive :: file:name() | binary(),
ZipHandle :: pid(),
Options :: [Option],
- Option :: cooked | memory | {cwd, CWD :: string()},
+ Option :: cooked | memory | {cwd, CWD :: file:filename()},
Reason :: term()).
zip_open(Archive, Options) ->
diff --git a/lib/stdlib/test/erl_lint_SUITE.erl b/lib/stdlib/test/erl_lint_SUITE.erl
index f822986981..bb14de333d 100644
--- a/lib/stdlib/test/erl_lint_SUITE.erl
+++ b/lib/stdlib/test/erl_lint_SUITE.erl
@@ -1279,10 +1279,9 @@ guard(Config) when is_list(Config) ->
tuple.
">>,
[nowarn_obsolete_guard],
- {error,
+ {errors,
[{6,erl_lint,illegal_guard_expr},{18,erl_lint,illegal_guard_expr}],
- [{18,erl_lint,{removed,{erlang,is_constant,1},
- "Removed in R13B"}}]}},
+ []}},
{guard2,
<<"-record(apa,{}).
t1(A) when atom(A), atom(A) ->
@@ -1341,14 +1340,11 @@ guard(Config) when is_list(Config) ->
tuple.
">>,
[nowarn_obsolete_guard],
- {error,[{6,erl_lint,illegal_guard_expr},
- {6,erl_lint,illegal_guard_expr},
- {18,erl_lint,illegal_guard_expr},
- {18,erl_lint,illegal_guard_expr}],
- [{18,erl_lint,{removed,{erlang,is_constant,1},
- "Removed in R13B"}},
- {18,erl_lint,{removed,{erlang,is_constant,1},
- "Removed in R13B"}}]}},
+ {errors,[{6,erl_lint,illegal_guard_expr},
+ {6,erl_lint,illegal_guard_expr},
+ {18,erl_lint,illegal_guard_expr},
+ {18,erl_lint,illegal_guard_expr}],
+ []}},
{guard3,
<<"-record(apa,{}).
t2(A) when atom(A); atom(A) ->
diff --git a/lib/test_server/src/test_server.erl b/lib/test_server/src/test_server.erl
index 82672521f7..9b05bddf63 100644
--- a/lib/test_server/src/test_server.erl
+++ b/lib/test_server/src/test_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -1208,6 +1208,10 @@ do_init_per_testcase(Mod, Args) ->
"a Config list.\n",[]},
{skip,{failed,{Mod,init_per_testcase,bad_return}}}
catch
+ throw:{Skip,Reason} when Skip =:= skip; Skip =:= skipped ->
+ {skip,Reason};
+ exit:{Skip,Reason} when Skip =:= skip; Skip =:= skipped ->
+ {skip,Reason};
throw:Other ->
set_loc(erlang:get_stacktrace()),
Line = get_loc(),
@@ -1378,6 +1382,10 @@ ts_tc(M, F, A) ->
Result = try
apply(M, F, A)
catch
+ throw:{skip, Reason} -> {skip, Reason};
+ throw:{skipped, Reason} -> {skip, Reason};
+ exit:{skip, Reason} -> {skip, Reason};
+ exit:{skipped, Reason} -> {skip, Reason};
Type:Reason ->
Stk = erlang:get_stacktrace(),
set_loc(Stk),
diff --git a/lib/wx/aclocal.m4 b/lib/wx/aclocal.m4
index c51c26794a..2b47f7c4bc 100644
--- a/lib/wx/aclocal.m4
+++ b/lib/wx/aclocal.m4
@@ -83,8 +83,10 @@ AC_ARG_VAR(erl_xcomp_ose_LM_POST_LINK, [OSE postlink tool (only used when cross
AC_ARG_VAR(erl_xcomp_ose_LM_SET_CONF, [Sets the configuration for an OSE load module (only used when cross compiling for OSE)])
AC_ARG_VAR(erl_xcomp_ose_LM_ELF_SIZE, [Prints the section size information for an OSE load module (only used when cross compiling for OSE)])
AC_ARG_VAR(erl_xcomp_ose_LM_LCF, [OSE load module linker configuration file (only used when cross compiling for OSE)])
-AC_ARG_VAR(erl_xcomp_ose_LM_CONF, [OSE load module default configuration file (only used when cross compiling for OSE)])
-AC_ARG_VAR(erl_xcomp_ose_CONFD, [OSE OSE confd source file])
+AC_ARG_VAR(erl_xcomp_ose_BEAM_LM_CONF, [BEAM OSE load module default configuration file (only used when cross compiling for OSE)])
+AC_ARG_VAR(erl_xcomp_ose_EPMD_LM_CONF, [EPMD OSE load module default configuration file (only used when cross compiling for OSE)])
+AC_ARG_VAR(erl_xcomp_ose_RUN_ERL_LM_CONF, [run_erl_lm OSE load module default configuration file (only used when cross compiling for OSE)])
+AC_ARG_VAR(erl_xcomp_ose_CONFD, [OSE confd source file])
AC_ARG_VAR(erl_xcomp_ose_CRT0_LM, [OSE crt0 lm source file])
])
diff --git a/make/ose_lm.mk.in b/make/ose_lm.mk.in
index 2e659ada1a..5455ad94c6 100644
--- a/make/ose_lm.mk.in
+++ b/make/ose_lm.mk.in
@@ -37,7 +37,9 @@ LDR1FLAGS = @erl_xcomp_ose_ldflags_pass1@
LDR2FLAGS = @erl_xcomp_ose_ldflags_pass2@
OSEROOT = @erl_xcomp_ose_OSEROOT@
LCF = @erl_xcomp_ose_LM_LCF@
-LMCONF = @erl_xcomp_ose_LM_CONF@
+BEAM_LMCONF = @erl_xcomp_ose_BEAM_LM_CONF@
+EPMD_LMCONF = @erl_xcomp_ose_EPMD_LM_CONF@
+RUN_ERL_LMCONF = @erl_xcomp_ose_RUN_ERL_LM_CONF@
STRIP = @erl_xcomp_ose_STRIP@
LM_POST_LINK = @erl_xcomp_ose_LM_POST_LINK@
LM_SET_CONF = @erl_xcomp_ose_LM_SET_CONF@
diff --git a/system/doc/design_principles/spec_proc.xml b/system/doc/design_principles/spec_proc.xml
index 69bf2e0448..e4fb5fdca7 100644
--- a/system/doc/design_principles/spec_proc.xml
+++ b/system/doc/design_principles/spec_proc.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1997</year><year>2013</year>
+ <year>1997</year><year>2014</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -431,11 +431,11 @@ loop(...) ->
<section>
<title>User-Defined Behaviours</title>
- <p>To implement a user-defined behaviour, write code similar to
+ <p><marker id="behaviours"/>To implement a user-defined behaviour, write code similar to
code for a special process but calling functions in a callback
module for handling specific tasks.</p>
<p>If it is desired that the compiler should warn for missing callback
- functions, as it does for the OTP behaviours, add callback attributes in the
+ functions, as it does for the OTP behaviours, add <c>-callback</c> attributes in the
behaviour module to describe the expected callbacks:</p>
<code type="none">
-callback Name1(Arg1_1, Arg1_2, ..., Arg1_N1) -> Res1.
@@ -445,15 +445,15 @@ loop(...) ->
<p>where <c>NameX</c> are the names of the expected callbacks and
<c>ArgX_Y</c>, <c>ResX</c> are types as they are described in Specifications
for functions in <seealso marker="../reference_manual/typespec">Types and
- Function Specifications</seealso>. The whole syntax of spec attributes is
- supported by callback attributes.</p>
+ Function Specifications</seealso>. The whole syntax of <c>-spec</c> attribute is
+ supported by <c>-callback</c> attribute.</p>
<p>Alternatively you may directly implement and export the function:</p>
<code type="none">
behaviour_info(callbacks) ->
- [{Name1,Arity1},...,{NameN,ArityN}].</code>
- <p>where each <c>{Name,Arity}</c> specifies the name and arity of a callback
+ [{Name1, Arity1},...,{NameN, ArityN}].</code>
+ <p>where each <c>{Name, Arity}</c> specifies the name and arity of a callback
function. This function is otherwise automatically generated by the compiler
- using the callback attributes.</p>
+ using the <c>-callback</c> attributes.</p>
<p>When the compiler encounters the module attribute
<c>-behaviour(Behaviour).</c> in a module <c>Mod</c>, it will call
<c>Behaviour:behaviour_info(callbacks)</c> and compare the result with the
diff --git a/system/doc/reference_manual/modules.xml b/system/doc/reference_manual/modules.xml
index 9e5f4de385..cd4c3a1b1b 100644
--- a/system/doc/reference_manual/modules.xml
+++ b/system/doc/reference_manual/modules.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2003</year><year>2013</year>
+ <year>2003</year><year>2014</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -134,8 +134,21 @@ fact(0) -> % |
standard behaviours <c>gen_server</c>, <c>gen_fsm</c>,
<c>gen_event</c> or <c>supervisor</c>.</p>
<p>The spelling <c>behavior</c> is also accepted.</p>
- <p>Read more about behaviours and callback modules in OTP Design
- Principles.</p>
+ <p>The callback functions of the module can be specified either
+ directly by the exported function <c>behaviour_info/1</c>:</p>
+ <pre>
+behaviour_info(callbacks) -> Callbacks.</pre>
+ <p>or by a <c>-callback</c> attribute for each callback
+ function:</p>
+ <pre>
+-callback Name(Arguments) -> Result.</pre>
+ <p>where <c>Arguments</c> is a list of zero or more arguments.
+ The <c>-callback</c> attribute is to be preferred since the
+ extra type information can be used by tools to produce
+ documentation or find discrepancies.</p>
+ <p>Read more about behaviours and callback modules in
+ <seealso marker="doc/design_principles:spec_proc#behaviours">
+ OTP Design Principles</seealso>.</p>
</section>
<section>
diff --git a/xcomp/erl-xcomp-powerpc-ose5.conf b/xcomp/erl-xcomp-powerpc-ose5.conf
index 60b75b36c1..bf49b32827 100644
--- a/xcomp/erl-xcomp-powerpc-ose5.conf
+++ b/xcomp/erl-xcomp-powerpc-ose5.conf
@@ -338,8 +338,14 @@ erl_xcomp_ose_LM_ELF_SIZE="${OSEROOT}/bin/${HOST}/lm_elf_size"
# * `erl_xcomp_ose_LM_LCF` - OSE load module linker configuration file
erl_xcomp_ose_LM_LCF="${ERL_TOP}/erts/emulator/sys/ose/gcc_${GCCVERSION}_lm_ppc.lcf"
-# * `erl_xcomp_ose_LM_CONF` - OSE load module default configuration file
-erl_xcomp_ose_LM_CONF="${ERL_TOP}/erts/emulator/sys/ose/default.lmconf"
+# * `erl_xcomp_ose_BEAM_LM_CONF` - beam OSE load module configuration file
+erl_xcomp_ose_BEAM_LM_CONF="${ERL_TOP}/erts/emulator/sys/ose/beam.lmconf"
+
+# * `erl_xcomp_ose_RUN_ERL_LM_CONF` - run_erl_lm OSE load module configuration file
+erl_xcomp_ose_RUN_ERL_LM_CONF="${ERL_TOP}/erts/etc/ose/etc.lmconf"
+
+# * `erl_xcomp_ose_EPMD_LM_CONF` - epmd OSE load module configuration file
+erl_xcomp_ose_EPMD_LM_CONF="${ERL_TOP}/erts/etc/ose/etc.lmconf"
# * `erl_xcomp_ose_CONFD` - OSE confd source file
erl_xcomp_ose_CONFD="${OSEROOT}/src/ose_confd.c"
diff --git a/xcomp/erl-xcomp-vars.sh b/xcomp/erl-xcomp-vars.sh
index c5e245b4b6..5e55c3af1b 100644
--- a/xcomp/erl-xcomp-vars.sh
+++ b/xcomp/erl-xcomp-vars.sh
@@ -26,4 +26,4 @@
# and precious variables in $ERL_TOP/erts/aclocal.m4.
#
-erl_xcomp_vars="erl_xcomp_sysroot erl_xcomp_isysroot erl_xcomp_bigendian erl_xcomp_double_middle_endian erl_xcomp_linux_clock_gettime_correction erl_xcomp_linux_nptl erl_xcomp_linux_usable_sigusrx erl_xcomp_linux_usable_sigaltstack erl_xcomp_poll erl_xcomp_kqueue erl_xcomp_putenv_copy erl_xcomp_reliable_fpe erl_xcomp_getaddrinfo erl_xcomp_gethrvtime_procfs_ioctl erl_xcomp_clock_gettime_cpu_time erl_xcomp_after_morecore_hook erl_xcomp_dlsym_brk_wrappers erl_xcomp_posix_memalign erl_xcomp_ose_ldflags_pass1 erl_xcomp_ose_ldflags_pass2 erl_xcomp_ose_OSEROOT erl_xcomp_ose_STRIP erl_xcomp_ose_LM_POST_LINK erl_xcomp_ose_LM_SET_CONF erl_xcomp_ose_LM_GET_CONF erl_xcomp_ose_LM_ELF_SIZE erl_xcomp_ose_LM_LCF erl_xcomp_ose_LM_CONF erl_xcomp_ose_CONFD erl_xcomp_ose_CRT0_LM"
+erl_xcomp_vars="erl_xcomp_sysroot erl_xcomp_isysroot erl_xcomp_bigendian erl_xcomp_double_middle_endian erl_xcomp_linux_clock_gettime_correction erl_xcomp_linux_nptl erl_xcomp_linux_usable_sigusrx erl_xcomp_linux_usable_sigaltstack erl_xcomp_poll erl_xcomp_kqueue erl_xcomp_putenv_copy erl_xcomp_reliable_fpe erl_xcomp_getaddrinfo erl_xcomp_gethrvtime_procfs_ioctl erl_xcomp_clock_gettime_cpu_time erl_xcomp_after_morecore_hook erl_xcomp_dlsym_brk_wrappers erl_xcomp_posix_memalign erl_xcomp_ose_ldflags_pass1 erl_xcomp_ose_ldflags_pass2 erl_xcomp_ose_OSEROOT erl_xcomp_ose_STRIP erl_xcomp_ose_LM_POST_LINK erl_xcomp_ose_LM_SET_CONF erl_xcomp_ose_LM_GET_CONF erl_xcomp_ose_LM_ELF_SIZE erl_xcomp_ose_LM_LCF erl_xcomp_ose_BEAM_LM_CONF erl_xcomp_ose_EPMD_LM_CONF erl_xcomp_ose_RUN_ERL_LM_CONF erl_xcomp_ose_CONFD erl_xcomp_ose_CRT0_LM"