aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--erts/doc/src/Makefile39
-rw-r--r--erts/doc/src/alt_disco.xml2
-rw-r--r--erts/doc/src/book.xml3
-rw-r--r--erts/doc/src/communication.xml2
-rw-r--r--erts/doc/src/crash_dump.xml2
-rw-r--r--erts/doc/src/erl_dist_protocol.xml28
-rw-r--r--erts/doc/src/erl_driver.xml24
-rw-r--r--erts/doc/src/erl_ext_dist.xml6
-rw-r--r--erts/doc/src/erl_ext_fig.gifbin3834 -> 3840 bytes
-rw-r--r--erts/doc/src/erl_nif.xml4
-rw-r--r--erts/doc/src/erlang.xml6
-rw-r--r--erts/doc/src/internal.xml44
-rw-r--r--erts/doc/src/notes.xml32
-rw-r--r--erts/doc/src/tty.xml4
-rw-r--r--erts/emulator/beam/arith_instrs.tab83
-rw-r--r--erts/emulator/beam/beam_emu.c54
-rw-r--r--erts/emulator/beam/dist.c30
-rw-r--r--erts/emulator/beam/erl_bif_info.c2
-rw-r--r--erts/emulator/beam/erl_node_tables.h1
-rw-r--r--erts/emulator/beam/erl_posix_str.c3
-rw-r--r--erts/emulator/beam/erl_proc_sig_queue.c2
-rw-r--r--erts/emulator/beam/erl_process.c6
-rw-r--r--erts/emulator/beam/erl_utils.h1
-rw-r--r--erts/emulator/beam/external.c6
-rw-r--r--erts/emulator/beam/external.h8
-rw-r--r--erts/emulator/beam/global.h9
-rw-r--r--erts/emulator/beam/msg_instrs.tab1
-rw-r--r--erts/emulator/beam/ops.tab11
-rw-r--r--erts/emulator/beam/sys.h8
-rw-r--r--erts/emulator/beam/utils.c8
-rw-r--r--erts/emulator/internal_doc/CarrierMigration.md27
-rw-r--r--erts/emulator/internal_doc/CodeLoading.md6
-rw-r--r--erts/emulator/internal_doc/GarbageCollection.md53
-rw-r--r--erts/emulator/internal_doc/PTables.md4
-rw-r--r--erts/emulator/internal_doc/SuperCarrier.md10
-rw-r--r--erts/emulator/internal_doc/Tracing.md6
-rw-r--r--erts/emulator/internal_doc/beam_makeops.md7
-rw-r--r--erts/emulator/sys/common/erl_check_io.c6
-rw-r--r--erts/emulator/sys/unix/sys_drivers.c4
-rw-r--r--erts/emulator/test/Makefile1
-rw-r--r--erts/emulator/test/distribution_SUITE.erl44
-rw-r--r--erts/emulator/test/driver_SUITE.erl4
-rw-r--r--erts/emulator/test/efile_SUITE.erl45
-rw-r--r--erts/emulator/test/lcnt_SUITE.erl3
-rw-r--r--erts/emulator/test/map_SUITE.erl92
-rw-r--r--erts/emulator/test/process_SUITE.erl42
-rw-r--r--erts/emulator/test/small_SUITE.erl115
-rw-r--r--erts/emulator/test/statistics_SUITE.erl43
-rw-r--r--erts/include/internal/ethr_internal.h2
-rw-r--r--erts/include/internal/ethread_inline.h3
-rw-r--r--erts/vsn.mk2
-rw-r--r--lib/common_test/doc/src/ct_master.xml2
-rw-r--r--lib/common_test/doc/src/event_handler_chapter.xml2
-rw-r--r--lib/common_test/src/test_server_node.erl103
-rw-r--r--lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl2
-rw-r--r--lib/compiler/doc/src/Makefile11
-rw-r--r--lib/compiler/doc/src/book.xml3
-rw-r--r--lib/compiler/doc/src/compile.xml16
-rw-r--r--lib/compiler/doc/src/internal.xml38
-rw-r--r--lib/compiler/src/cerl.erl16
-rw-r--r--lib/compiler/src/cerl_clauses.erl4
-rw-r--r--lib/compiler/src/core_parse.hrl107
-rw-r--r--lib/crypto/c_src/aead.c248
-rw-r--r--lib/crypto/c_src/aead.h3
-rw-r--r--lib/crypto/c_src/api_ng.c26
-rw-r--r--lib/crypto/c_src/api_ng.h2
-rw-r--r--lib/crypto/c_src/cipher.c40
-rw-r--r--lib/crypto/c_src/cipher.h2
-rw-r--r--lib/crypto/c_src/common.h5
-rw-r--r--lib/crypto/c_src/crypto.c5
-rw-r--r--lib/crypto/c_src/otp_test_engine.c4
-rw-r--r--lib/crypto/doc/src/Makefile3
-rw-r--r--lib/crypto/doc/src/crypto.xml501
-rw-r--r--lib/crypto/doc/src/new_api.xml209
-rw-r--r--lib/crypto/doc/src/usersguide.xml1
-rw-r--r--lib/crypto/src/crypto.erl313
-rw-r--r--lib/crypto/test/crypto_SUITE.erl693
-rw-r--r--lib/dialyzer/src/dialyzer_utils.erl65
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/results/simple4
-rw-r--r--lib/dialyzer/test/r9c_SUITE_data/results/asn14
-rw-r--r--lib/dialyzer/test/r9c_SUITE_data/src/inets/mod_responsecontrol.erl2
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/bs_fail_constr6
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/pretty_bitstring2
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/tuple_set_crash10
-rw-r--r--lib/edoc/src/edoc_data.erl2
-rw-r--r--lib/erl_docgen/priv/dtd/book.dtd3
-rw-r--r--lib/erl_docgen/priv/dtd/common.dtd2
-rw-r--r--lib/erl_docgen/priv/xsl/db_html.xsl113
-rw-r--r--lib/erl_docgen/src/docgen_edoc_xml_cb.erl14
-rw-r--r--lib/erl_docgen/src/docgen_xmerl_xml_cb.erl1
-rw-r--r--lib/erl_interface/src/Makefile.in34
-rw-r--r--lib/erl_interface/src/connect/ei_connect.c4
-rw-r--r--lib/erl_interface/src/depend.mk1133
-rw-r--r--lib/erl_interface/src/epmd/ei_epmd.h5
-rw-r--r--lib/erl_interface/src/epmd/epmd_publish.c28
-rw-r--r--lib/erl_interface/src/prog/erl_call.c3
-rw-r--r--lib/inets/src/http_server/mod_responsecontrol.erl2
-rw-r--r--lib/jinterface/doc/src/jinterface_users_guide.xml8
-rw-r--r--lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangPid.java6
-rw-r--r--lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangPort.java6
-rw-r--r--lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangRef.java7
-rw-r--r--lib/jinterface/java_src/com/ericsson/otp/erlang/OtpOutputStream.java50
-rw-r--r--lib/kernel/doc/src/application.xml2
-rw-r--r--lib/kernel/doc/src/auth.xml6
-rw-r--r--lib/kernel/doc/src/erl_ddll.xml4
-rw-r--r--lib/kernel/doc/src/gen_sctp.xml2
-rw-r--r--lib/kernel/doc/src/logger_chapter.xml2
-rw-r--r--lib/kernel/doc/src/notes.xml15
-rw-r--r--lib/kernel/src/kernel.appup.src8
-rw-r--r--lib/kernel/src/kernel.erl2
-rw-r--r--lib/kernel/src/raw_file_io_inflate.erl2
-rw-r--r--lib/kernel/test/file_SUITE.erl73
-rw-r--r--lib/kernel/test/file_name_SUITE.erl11
-rw-r--r--lib/kernel/vsn.mk2
-rw-r--r--lib/public_key/doc/src/public_key.xml3
-rw-r--r--lib/ssh/src/ssh_transport.erl16
-rw-r--r--lib/ssl/src/dtls_connection.erl10
-rw-r--r--lib/ssl/src/dtls_packet_demux.erl4
-rw-r--r--lib/ssl/src/inet_tls_dist.erl10
-rw-r--r--lib/ssl/src/ssl.erl4
-rw-r--r--lib/ssl/src/ssl_cipher.erl91
-rw-r--r--lib/ssl/src/ssl_cipher.hrl80
-rw-r--r--lib/ssl/src/ssl_cipher_format.erl187
-rw-r--r--lib/ssl/src/ssl_handshake.erl2
-rw-r--r--lib/ssl/src/ssl_record.erl37
-rw-r--r--lib/ssl/src/ssl_record.hrl5
-rw-r--r--lib/ssl/src/tls_connection.erl4
-rw-r--r--lib/ssl/src/tls_record_1_3.erl2
-rw-r--r--lib/ssl/test/Makefile5
-rw-r--r--lib/ssl/test/inet_crypto_dist.erl1323
-rw-r--r--lib/ssl/test/ssl.spec2
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl367
-rw-r--r--lib/ssl/test/ssl_cipher_suite_SUITE.erl169
-rw-r--r--lib/ssl/test/ssl_dist_bench_SUITE.erl134
-rw-r--r--lib/ssl/test/ssl_session_cache_SUITE.erl2
-rw-r--r--lib/ssl/test/ssl_test_lib.erl194
-rw-r--r--lib/ssl/test/ssl_to_openssl_SUITE.erl177
-rw-r--r--lib/ssl/test/ssl_upgrade_SUITE.erl13
-rw-r--r--lib/stdlib/doc/src/calendar.xml2
-rw-r--r--lib/stdlib/doc/src/dets.xml4
-rw-r--r--lib/stdlib/doc/src/digraph_utils.xml2
-rw-r--r--lib/stdlib/doc/src/notes.xml15
-rw-r--r--lib/stdlib/doc/src/proc_lib.xml2
-rw-r--r--lib/stdlib/doc/src/slave.xml4
-rw-r--r--lib/stdlib/src/erl_lint.erl46
-rw-r--r--lib/stdlib/src/erl_pp.erl6
-rw-r--r--lib/stdlib/src/erl_tar.erl4
-rw-r--r--lib/stdlib/src/otp_internal.erl147
-rw-r--r--lib/stdlib/src/stdlib.appup.src8
-rw-r--r--lib/stdlib/test/erl_lint_SUITE.erl27
-rw-r--r--lib/stdlib/test/erl_pp_SUITE.erl37
-rw-r--r--lib/stdlib/test/stdlib_bench_SUITE_data/generic_fsm.erl2
-rw-r--r--lib/stdlib/vsn.mk2
-rw-r--r--lib/syntax_tools/test/syntax_tools_SUITE.erl12
-rw-r--r--lib/tools/emacs/erlang-test.el11
-rw-r--r--lib/tools/emacs/erlang.el560
-rw-r--r--lib/tools/test/emacs_SUITE.erl23
-rw-r--r--lib/wx/examples/simple/hello2.erl2
-rwxr-xr-xmake/emd2exml.in85
-rw-r--r--make/otp_release_targets.mk2
-rw-r--r--otp_versions.table1
-rw-r--r--system/doc/efficiency_guide/commoncaveats.xml5
-rw-r--r--system/doc/installation_guide/Makefile2
-rw-r--r--system/doc/tutorial/overview.xml6
165 files changed, 5352 insertions, 3459 deletions
diff --git a/.gitignore b/.gitignore
index bd0e9615f7..789d08fdb0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,6 +7,9 @@ TAGS
# vim
.*.sw[a-z]
+# vscode
+.vscode
+
autom4te.cache
*.beam
*.asn1db
diff --git a/erts/doc/src/Makefile b/erts/doc/src/Makefile
index 06a8691c0e..bc01919da1 100644
--- a/erts/doc/src/Makefile
+++ b/erts/doc/src/Makefile
@@ -67,7 +67,22 @@ XML_REF3_FILES = \
erts_alloc.xml
XML_PART_FILES = \
- part.xml
+ part.xml internal.xml
+
+XML_INTERNAL_FILES = \
+ CarrierMigration.xml \
+ ThreadProgress.xml \
+ CodeLoading.xml \
+ Tracing.xml \
+ DelayedDealloc.xml \
+ beam_makeops.xml \
+ GarbageCollection.xml \
+ PTables.xml \
+ PortSignals.xml \
+ ProcessManagementOptimizations.xml \
+ SuperCarrier.xml \
+ CountingInstructions.xml
+
XML_CHAPTER_FILES = \
introduction.xml \
@@ -97,6 +112,8 @@ XML_FILES = \
$(BOOK_FILES) $(XML_CHAPTER_FILES) \
$(XML_PART_FILES) $(XML_REF3_FILES) $(XML_REF1_FILES) $(XML_APPLICATION_FILES)
+XML_GEN_FILES = $(XML_INTERNAL_FILES:%=$(XMLDIR)/%)
+
# ----------------------------------------------------
HTML_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \
@@ -116,6 +133,12 @@ SPECS_FILES = $(XML_REF3_EFILES:%.xml=$(SPECDIR)/specs_%.xml)
TOP_SPECS_FILE = specs.xml
+XML_FIGURE_DIR = $(XMLDIR)/figures
+
+INTERNAL_DOC_PNG_FILES = $(wildcard ../../emulator/internal_doc/figures/*.png)
+PNG_FILES = $(notdir $(INTERNAL_DOC_PNG_FILES))
+XMLDIR_PNG_FILES = $(PNG_FILES:%=$(XML_FIGURE_DIR)/%)
+
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
@@ -128,10 +151,15 @@ SPECS_FLAGS = -I$(KERNEL_SRC) -I$(KERNEL_INCLUDE)
# ----------------------------------------------------
# Targets
# ----------------------------------------------------
+_create_dirs := $(shell mkdir -p $(XML_FIGURE_DIR))
+
$(HTMLDIR)/%.gif: %.gif
$(INSTALL_DATA) $< $@
-docs: man pdf html $(INFO_FILE)
+$(XML_FIGURE_DIR)/%.png: ../../emulator/internal_doc/figures/%.png
+ $(INSTALL_DATA) $< $@
+
+docs: figures man pdf html $(INFO_FILE)
$(TOP_PDF_FILE): $(XML_FILES)
@@ -146,6 +174,7 @@ gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
$(INFO_FILE): $(INFO_FILE_SRC) $(ERL_TOP)/make/$(TARGET)/otp.mk
sed -e 's;%RELEASE%;$(SYSTEM_VSN);' $(INFO_FILE_SRC) > $(INFO_FILE)
+figures: $(XMLDIR_PNG_FILES)
debug opt:
@@ -164,6 +193,9 @@ $(SPECDIR)/specs_%.xml:
$(gen_verbose)escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \
-o$(dir $@) -module $(patsubst $(SPECDIR)/specs_%.xml,%,$@)
+$(XMLDIR)/%.xml: ../../emulator/internal_doc/%.md $(ERL_TOP)/make/emd2exml
+ $(ERL_TOP)/make/emd2exml $< $@
+
# ----------------------------------------------------
# Release Target
# ----------------------------------------------------
@@ -173,8 +205,11 @@ release_docs_spec: docs
$(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
$(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
$(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html/figures"
$(INSTALL_DATA) $(HTMLDIR)/* \
"$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(XMLDIR)/figures/* \
+ "$(RELSYSDIR)/doc/html/figures"
$(INSTALL_DATA) $(ERL_TOP)/erts/example/time_compat.erl \
"$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(ERL_TOP)/lib/kernel/examples/gen_tcp_dist/src/gen_tcp_dist.erl \
diff --git a/erts/doc/src/alt_disco.xml b/erts/doc/src/alt_disco.xml
index d04221b9b3..148d6f549e 100644
--- a/erts/doc/src/alt_disco.xml
+++ b/erts/doc/src/alt_disco.xml
@@ -63,7 +63,7 @@
<seealso marker="kernel:erl_epmd">EPMD module</seealso>. However, instead of
communicating with EPMD you can connect to any service to find out
connection details of other nodes. A discovery module is enabled
- by setting <seealso marker="erts:erl#epmd_module">-epmd_module</seealso>
+ by setting <seealso marker="erts:erl">-epmd_module</seealso>
when starting erlang. The discovery module must implement the following
callbacks:</p>
diff --git a/erts/doc/src/book.xml b/erts/doc/src/book.xml
index a0780c91d9..d79da1e4f7 100644
--- a/erts/doc/src/book.xml
+++ b/erts/doc/src/book.xml
@@ -41,6 +41,9 @@
<applications>
<xi:include href="ref_man.xml"/>
</applications>
+ <internals>
+ <xi:include href="internal.xml"/>
+ </internals>
<releasenotes>
<xi:include href="notes.xml"/>
</releasenotes>
diff --git a/erts/doc/src/communication.xml b/erts/doc/src/communication.xml
index 7e18a73aa8..251b52dc65 100644
--- a/erts/doc/src/communication.xml
+++ b/erts/doc/src/communication.xml
@@ -64,7 +64,7 @@
a synchronous communication operation consists of two asynchronous
signals; one request signal and one reply signal. An example of
such a synchronous communication is a call to
- <seealso marker="erlang:process_info/2">
+ <seealso marker="erlang#process_info/2">
<c>erlang:process_info/2</c></seealso>
when the first argument is not <c>self()</c>. The caller sends
an asynchronous signal requesting information, and then
diff --git a/erts/doc/src/crash_dump.xml b/erts/doc/src/crash_dump.xml
index a9aeb1888c..33d0903622 100644
--- a/erts/doc/src/crash_dump.xml
+++ b/erts/doc/src/crash_dump.xml
@@ -290,7 +290,7 @@ Slogan: &lt;reason&gt;</pre>
<title>Memory Information</title>
<p>Under the tag <em>=memory</em> is shown information similar
to what can be obtainted on a living node with
- <seealso marker="erts:erlang#erlang:memory/0">
+ <seealso marker="erts:erlang#memory/0">
<c>erlang:memory()</c></seealso>.</p>
</section>
diff --git a/erts/doc/src/erl_dist_protocol.xml b/erts/doc/src/erl_dist_protocol.xml
index 185c75fe84..1951d498cd 100644
--- a/erts/doc/src/erl_dist_protocol.xml
+++ b/erts/doc/src/erl_dist_protocol.xml
@@ -109,7 +109,8 @@
<title>Register a Node in EPMD</title>
<p>When a distributed node is started it registers itself in the EPMD.
The message <c>ALIVE2_REQ</c> described below is sent from the node to
- the EPMD. The response from the EPMD is <c>ALIVE2_RESP</c>.</p>
+ the EPMD. The response from the EPMD is <c>ALIVE2_X_RESP</c> (or
+ <c>ALIVE2_RESP</c>).</p>
<table align="left">
<row>
@@ -155,12 +156,12 @@
<tag><c>HighestVersion</c></tag>
<item>
<p>The highest distribution version that this node can handle.
- The value in Erlang/OTP R6B and later is 5.</p>
+ The value in OTP 22 and later is 6.</p>
</item>
<tag><c>LowestVersion</c></tag>
<item>
<p>The lowest distribution version that this node can handle.
- The value in Erlang/OTP R6B and later is 5.</p>
+ The value in OTP 22 and later is 5.</p>
</item>
<tag><c>Nlen</c></tag>
<item>
@@ -184,7 +185,24 @@
node is a distributed node. When the connection is closed,
the node is automatically unregistered from the EPMD.</p>
- <p>The response message <c>ALIVE2_RESP</c> is as follows:</p>
+ <p>The response message is either <c>ALIVE2_X_RESP</c> or
+ <c>ALIVE2_RESP</c> depending on distribution version. If both the node
+ and EPMD support distribution version 6 then response is
+ <c>ALIVE2_X_RESP</c> otherwise it is the older <c>ALIVE2_RESP</c>:</p>
+
+ <table align="left">
+ <row>
+ <cell align="center">1</cell>
+ <cell align="center">1</cell>
+ <cell align="center">4</cell>
+ </row>
+ <row>
+ <cell align="center"><c>118</c></cell>
+ <cell align="center"><c>Result</c></cell>
+ <cell align="center"><c>Creation</c></cell>
+ </row>
+ <tcaption>ALIVE2_X_RESP (118) with 32 bit creation</tcaption>
+ </table>
<table align="left">
<row>
@@ -197,7 +215,7 @@
<cell align="center"><c>Result</c></cell>
<cell align="center"><c>Creation</c></cell>
</row>
- <tcaption>ALIVE2_RESP (121)</tcaption>
+ <tcaption>ALIVE2_RESP (121) with 16-bit creation</tcaption>
</table>
<p>Result = 0 -> ok, result &gt; 0 -> error.</p>
diff --git a/erts/doc/src/erl_driver.xml b/erts/doc/src/erl_driver.xml
index 58678f2393..3e2d3bb447 100644
--- a/erts/doc/src/erl_driver.xml
+++ b/erts/doc/src/erl_driver.xml
@@ -230,7 +230,7 @@
<item>
<p>With these functions, the driver sends data back to the emulator.
The data is received as messages by the port owner process, see
- <seealso marker="erlang:open_port/2">
+ <seealso marker="erlang#open_port/2">
<c>erlang:open_port/2</c></seealso>. The vector function and the
function taking a driver binary are faster, as they avoid
copying the data buffer. There is also a fast way of sending
@@ -1154,27 +1154,27 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code>
<taglist>
<tag><seealso marker="driver_entry#start">
<c>start</c></seealso></tag>
- <item>Called from <seealso marker="erlang:open_port/2">
+ <item>Called from <seealso marker="erlang#open_port/2">
<c>erlang:open_port/2</c></seealso>.</item>
<tag><seealso marker="driver_entry#output">
<c>output</c></seealso></tag>
- <item>Called from <seealso marker="erlang:send/2">
+ <item>Called from <seealso marker="erlang#send/2">
<c>erlang:send/2</c></seealso> and
- <seealso marker="erlang:port_command/2">
+ <seealso marker="erlang#port_command/2">
<c>erlang:port_command/2</c></seealso>.</item>
<tag><seealso marker="driver_entry#outputv">
<c>outputv</c></seealso></tag>
- <item>Called from <seealso marker="erlang:send/2">
+ <item>Called from <seealso marker="erlang#send/2">
<c>erlang:send/2</c></seealso> and
- <seealso marker="erlang:port_command/2">
+ <seealso marker="erlang#port_command/2">
<c>erlang:port_command/2</c></seealso>.</item>
<tag><seealso marker="driver_entry#control">
<c>control</c></seealso></tag>
- <item>Called from <seealso marker="erlang:port_control/3">
+ <item>Called from <seealso marker="erlang#port_control/3">
<c>erlang:port_control/3</c></seealso>.</item>
<tag><seealso marker="driver_entry#call">
<c>call</c></seealso></tag>
- <item>Called from <seealso marker="erlang:port_call/3">
+ <item>Called from <seealso marker="erlang#port_call/3">
<c>erlang:port_call/3</c></seealso>.</item>
</taglist>
<p>Notice that this function is <em>not</em> thread-safe, not
@@ -2305,7 +2305,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code>
<c>*value_size</c> has been set to the buffer size needed.</p>
<warning>
<p>This function reads the emulated environment used by
- <seealso marker="os:getenv/1"><c>os:getenv/1</c></seealso> and not
+ <seealso marker="kernel:os#getenv/1"><c>os:getenv/1</c></seealso> and not
the environment used by libc's <c>getenv(3)</c> or similar. Drivers
that <em>require</em> that these are in sync will need to do so
themselves, but keep in mind that they are segregated for a reason;
@@ -2656,7 +2656,7 @@ erl_drv_output_term(driver_mk_port(drvport), spec, sizeof(spec) / sizeof(spec[0]
</note>
<warning>
<p>This function modifies the emulated environment used by
- <seealso marker="os:putenv/2"><c>os:putenv/2</c></seealso> and not
+ <seealso marker="kernel:os#putenv/2"><c>os:putenv/2</c></seealso> and not
the environment used by libc's <c>putenv(3)</c> or similar. Drivers
that <em>require</em> that these are in sync will need to do so
themselves, but keep in mind that they are segregated for a reason;
@@ -2849,7 +2849,7 @@ erl_drv_output_term(driver_mk_port(drvport), spec, sizeof(spec) / sizeof(spec[0]
<desc>
<marker id="erl_drv_set_os_pid"></marker>
<p>Sets the <c>os_pid</c> seen when doing
- <seealso marker="erlang:port_info/2">
+ <seealso marker="erlang#port_info/2">
<c>erlang:port_info/2</c></seealso> on this port.</p>
<p><c>port</c> is the port handle of the port (driver instance) to set
the pid on. <c>pid</c>is the pid to set.</p>
@@ -3204,7 +3204,7 @@ erl_drv_output_term(driver_mk_port(drvport), spec, sizeof(spec) / sizeof(spec[0]
<c>control</c></seealso> driver entry
function will return data to the port owner process.
(The <c>control</c> function is called from
- <seealso marker="erlang:port_control/3">
+ <seealso marker="erlang#port_control/3">
<c>erlang:port_control/3</c></seealso>.)</p>
<p>Currently there are only two meaningful values for
<c>flags</c>: <c>0</c> means that data is returned in a list,
diff --git a/erts/doc/src/erl_ext_dist.xml b/erts/doc/src/erl_ext_dist.xml
index 4721747097..6b7a6db943 100644
--- a/erts/doc/src/erl_ext_dist.xml
+++ b/erts/doc/src/erl_ext_dist.xml
@@ -399,7 +399,7 @@
<tcaption>REFERENCE_EXT</tcaption></table>
<p>
Encodes a reference object (an object generated with
- <seealso marker="erlang:make_ref/0">erlang:make_ref/0</seealso>).
+ <seealso marker="erlang#make_ref/0">erlang:make_ref/0</seealso>).
The <c>Node</c> term is an encoded atom, that is,
<seealso marker="#ATOM_UTF8_EXT"><c>ATOM_UTF8_EXT</c></seealso>,
<seealso marker="#SMALL_ATOM_UTF8_EXT"><c>SMALL_ATOM_UTF8_EXT</c></seealso>, or
@@ -437,7 +437,7 @@
<tcaption>PORT_EXT</tcaption></table>
<p>
Encodes a port object (obtained from
- <seealso marker="erlang:open_port/2">
+ <seealso marker="erlang#open_port/2">
<c>erlang:open_port/2</c></seealso>).
The <c>ID</c> is a node-specific identifier for a local port.
Port operations are not allowed across node boundaries.
@@ -467,7 +467,7 @@
<tcaption>PID_EXT</tcaption></table>
<p>
Encodes a process identifier object (obtained from
- <seealso marker="erlang:spawn/3"><c>erlang:spawn/3</c></seealso> or
+ <seealso marker="erlang#spawn/3"><c>erlang:spawn/3</c></seealso> or
friends). The <c>ID</c> and <c>Creation</c> fields works just like in
<seealso marker="#REFERENCE_EXT"><c>REFERENCE_EXT</c></seealso>, while
the <c>Serial</c> field is used to improve safety.
diff --git a/erts/doc/src/erl_ext_fig.gif b/erts/doc/src/erl_ext_fig.gif
index 14d6bbc871..40dd17bd5e 100644
--- a/erts/doc/src/erl_ext_fig.gif
+++ b/erts/doc/src/erl_ext_fig.gif
Binary files differ
diff --git a/erts/doc/src/erl_nif.xml b/erts/doc/src/erl_nif.xml
index cf1994887a..c0be715678 100644
--- a/erts/doc/src/erl_nif.xml
+++ b/erts/doc/src/erl_nif.xml
@@ -546,8 +546,8 @@ int writeiovec(ErlNifEnv *env, ERL_NIF_TERM term, ERL_NIF_TERM *tail,
<p>Many operations communicating with a process executing a
dirty NIF can, however, complete while it executes the
dirty NIF. For example, retrieving information about it through
- <seealso marker="erlang:process_info/1">
- <c>erlang:process_info</c></seealso>, setting its group leader,
+ <seealso marker="erlang#process_info/1">
+ <c>process_info</c></seealso>, setting its group leader,
register/unregister its name, and so on.</p>
<p>Termination of a process executing a dirty NIF can only be
completed up to a certain point while it executes the dirty NIF.
diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml
index 0d94f83493..2b444ccf01 100644
--- a/erts/doc/src/erlang.xml
+++ b/erts/doc/src/erlang.xml
@@ -126,7 +126,7 @@
instance.</p>
<p>One can get an approximation of the <c>native</c>
time unit by calling
- <seealso marker="erlang:convert_time_unit/3">
+ <seealso marker="#convert_time_unit/3">
<c>erlang:convert_time_unit(1, second, native)</c></seealso>.
The result equals the number
of whole <c>native</c> time units per second. If
@@ -4663,6 +4663,7 @@ RealSystem = system + MissedSystem</code>
<name name="port_info" arity="2" clause_i="6" since="OTP R16B"/>
<fsummary>Information about the memory size of a port.</fsummary>
<desc>
+ <marker id="port_info_memory"/>
<p><c><anno>Bytes</anno></c> is the total number of
bytes allocated for this port by the runtime system. The
port itself can have allocated memory that is not
@@ -5387,6 +5388,7 @@ RealSystem = system + MissedSystem</code>
</item>
<tag><c>{memory, <anno>Size</anno>}</c></tag>
<item>
+ <marker id="process_info_memory"/>
<p><c><anno>Size</anno></c> is the size in bytes of the process.
This includes call stack, heap, and internal structures.</p>
</item>
@@ -6676,7 +6678,7 @@ lists:map(
<tag><c>async</c></tag>
<item>Async threads are used by various linked-in drivers (mainly the
file drivers) do offload non-CPU intensive work. See
- <seealso marker="erts:erl#+async_thread_pool_size">erl +A</seealso> for more details.</item>
+ <seealso marker="erts:erl#async_thread_pool_size">erl +A</seealso> for more details.</item>
<tag><c>aux</c></tag>
<item>Takes care of any work that is not
specifically assigned to a scheduler.</item>
diff --git a/erts/doc/src/internal.xml b/erts/doc/src/internal.xml
new file mode 100644
index 0000000000..88609d492a
--- /dev/null
+++ b/erts/doc/src/internal.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE part SYSTEM "part.dtd">
+
+<internal xmlns:xi="http://www.w3.org/2001/XInclude">
+ <header>
+ <copyright>
+ <year>2018</year><year>2018</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ </legalnotice>
+
+ <title>ERTS Internal Documentation</title>
+ <prepared>Lukas Larsson</prepared>
+ <docno></docno>
+ <date>2018-07-07</date>
+ <rev>4.5.2</rev>
+ <file>internal.xml</file>
+ </header>
+ <xi:include href="CarrierMigration.xml"/>
+ <xi:include href="ThreadProgress.xml"/>
+ <xi:include href="CodeLoading.xml"/>
+ <xi:include href="Tracing.xml"/>
+ <xi:include href="DelayedDealloc.xml"/>
+ <xi:include href="beam_makeops.xml"/>
+ <xi:include href="CountingInstructions.xml"/>
+ <xi:include href="GarbageCollection.xml"/>
+ <xi:include href="PTables.xml"/>
+ <xi:include href="PortSignals.xml"/>
+ <xi:include href="ProcessManagementOptimizations.xml"/>
+ <xi:include href="SuperCarrier.xml"/>
+</internal>
diff --git a/erts/doc/src/notes.xml b/erts/doc/src/notes.xml
index 248b871ca0..13cd4129ac 100644
--- a/erts/doc/src/notes.xml
+++ b/erts/doc/src/notes.xml
@@ -31,6 +31,28 @@
</header>
<p>This document describes the changes made to the ERTS application.</p>
+<section><title>Erts 10.3.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fixed a bug in <c>seq_trace:reset_trace/0</c> that
+ could crash the emulator.</p>
+ <p>
+ Own Id: OTP-15704</p>
+ </item>
+ <item>
+ <p>
+ Fixed bug in <c>process_info(reductions)</c> causing it
+ to sometimes return invalid results.</p>
+ <p>
+ Own Id: OTP-15709 Aux Id: ERIERL-337 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Erts 10.3.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -8341,8 +8363,7 @@
Erlang/OTP has been ported to the realtime operating
system OSE. The port supports both smp and non-smp
emulator. For details around the port and how to started
- see the User's Guide in the <seealso
- marker="ose:ose_intro">ose</seealso> application. </p>
+ see the User's Guide in the <em>ose</em> application.</p>
<p>
Note that not all parts of Erlang/OTP has been ported. </p>
<p>
@@ -9448,9 +9469,9 @@
<c>fix_alloc</c> allocator, a different strategy for
management of fix blocks will be used.</item> <item>The
information returned from <seealso
- marker="erlang:system_info_allocator_tuple"><c>erlang:system_info({allocator,
+ marker="erlang#system_info_allocator_tuple"><c>erlang:system_info({allocator,
A})</c></seealso>, and <seealso
- marker="erlang:system_info_allocator_sizes"><c>erlang:system_info({allocator_sizes,
+ marker="erlang#system_info_allocator_sizes"><c>erlang:system_info({allocator_sizes,
A})</c></seealso> will be slightly different when this
feature has been enabled. An <c>mbcs_pool</c> tuple will
be present giving information about abandoned carriers,
@@ -10259,8 +10280,7 @@
information about signal ordering guarantees, see the
chapter on <seealso
marker="erts:communication">communication</seealso> in
- the ERTS user's guide. The <seealso
- marker="erts:erl#+n">+n</seealso> command line flag of
+ the ERTS user's guide. The <c>+n</c> command line flag of
<seealso marker="erts:erl">erl(1)</seealso> can be
helpful when trying to find signaling order bugs in
Erlang code that have been exposed by these
diff --git a/erts/doc/src/tty.xml b/erts/doc/src/tty.xml
index 51db1ba8e2..c33e082f4f 100644
--- a/erts/doc/src/tty.xml
+++ b/erts/doc/src/tty.xml
@@ -165,6 +165,10 @@ erl</pre>
<cell align="left" valign="middle">C-y</cell>
<cell align="left" valign="middle">Insert previously killed text</cell>
</row>
+ <row>
+ <cell align="left" valign="middle">C-]</cell>
+ <cell align="left" valign="middle">Insert matching closing bracket</cell>
+ </row>
<tcaption>tty Text Editing</tcaption>
</table>
</section>
diff --git a/erts/emulator/beam/arith_instrs.tab b/erts/emulator/beam/arith_instrs.tab
index 5f23b2c168..f14b376419 100644
--- a/erts/emulator/beam/arith_instrs.tab
+++ b/erts/emulator/beam/arith_instrs.tab
@@ -51,11 +51,50 @@ plus.fetch(Op1, Op2) {
plus.execute(Fail, Dst) {
if (ERTS_LIKELY(is_both_small(PlusOp1, PlusOp2))) {
+#ifdef HAVE_OVERFLOW_CHECK_BUILTINS
+ Sint lhs_tagged, rhs_untagged, res;
+
+ /* The value part of immediate integers start right after the tag and
+ * occupy the rest of the word, so if you squint a bit they look like
+ * fixed-point integers; as long as you mask the tag away you will get
+ * correct results from addition/subtraction since they share the same
+ * notion of zero. It's fairly easy to see that the following holds
+ * when (a + b) is in range:
+ *
+ * (a >> s) + (b >> s) == ((a & ~m) + (b & ~m)) >> s
+ *
+ * Where 's' is the tag size and 'm' is the tag mask.
+ *
+ * The left-hand side is our fallback in the #else clause and is the
+ * fastest way to do this safely in plain C. The actual addition will
+ * never overflow since `Sint` has a much greater range than our
+ * smalls, so we can use the IS_SSMALL macro to see if the result is
+ * within range.
+ *
+ * What we're doing below is an extension of the right-hand side. By
+ * treating `a` and `b` as fixed-point integers, all additions whose
+ * result is out of range will also overflow `Sint` and we can use the
+ * compiler's overflow intrinsics to check for this condition.
+ *
+ * In addition, since the tag lives in the lowest bits we can further
+ * optimize this by only stripping the tag from either side. The higher
+ * bits can't influence the tag bits since we bail on overflow, so the
+ * tag bits from the tagged side will simply appear in the result. */
+ lhs_tagged = PlusOp1;
+ rhs_untagged = PlusOp2 & ~_TAG_IMMED1_MASK;
+
+ if (ERTS_LIKELY(!__builtin_add_overflow(lhs_tagged, rhs_untagged, &res))) {
+ ASSERT(is_small(res));
+ $Dst = res;
+ $NEXT0();
+ }
+#else
Sint i = signed_val(PlusOp1) + signed_val(PlusOp2);
if (ERTS_LIKELY(IS_SSMALL(i))) {
$Dst = make_small(i);
$NEXT0();
}
+#endif
}
$OUTLINED_ARITH_2($Fail, mixed_plus, BIF_splus_2, PlusOp1, PlusOp2, $Dst);
}
@@ -73,11 +112,26 @@ minus.fetch(Op1, Op2) {
minus.execute(Fail, Dst) {
if (ERTS_LIKELY(is_both_small(MinusOp1, MinusOp2))) {
+#ifdef HAVE_OVERFLOW_CHECK_BUILTINS
+ Sint lhs_tagged, rhs_untagged, res;
+
+ /* See plus.execute */
+ lhs_tagged = MinusOp1;
+ rhs_untagged = MinusOp2 & ~_TAG_IMMED1_MASK;
+
+ if (ERTS_LIKELY(!__builtin_sub_overflow(lhs_tagged, rhs_untagged, &res))) {
+ ASSERT(is_small(res));
+ $Dst = res;
+ $NEXT0();
+ }
+#else
Sint i = signed_val(MinusOp1) - signed_val(MinusOp2);
+
if (ERTS_LIKELY(IS_SSMALL(i))) {
$Dst = make_small(i);
$NEXT0();
}
+#endif
}
$OUTLINED_ARITH_2($Fail, mixed_minus, BIF_sminus_2, MinusOp1, MinusOp2, $Dst);
}
@@ -97,12 +151,27 @@ increment.execute(IncrementVal, Dst) {
Eterm result;
if (ERTS_LIKELY(is_small(increment_reg_val))) {
+#ifdef HAVE_OVERFLOW_CHECK_BUILTINS
+ Sint lhs_tagged, rhs_untagged, res;
+
+ /* See plus.execute */
+ lhs_tagged = increment_reg_val;
+ rhs_untagged = (Sint)increment_val << _TAG_IMMED1_SIZE;
+
+ if (ERTS_LIKELY(!__builtin_add_overflow(lhs_tagged, rhs_untagged, &res))) {
+ ASSERT(is_small(res));
+ $Dst = res;
+ $NEXT0();
+ }
+#else
Sint i = signed_val(increment_reg_val) + increment_val;
if (ERTS_LIKELY(IS_SSMALL(i))) {
$Dst = make_small(i);
$NEXT0();
}
+#endif
}
+
result = erts_mixed_plus(c_p, increment_reg_val, make_small(increment_val));
ERTS_HOLE_CHECK(c_p);
if (ERTS_LIKELY(is_value(result))) {
@@ -118,11 +187,15 @@ i_times(Fail, Op1, Op2, Dst) {
Eterm op2 = $Op2;
#ifdef HAVE_OVERFLOW_CHECK_BUILTINS
if (ERTS_LIKELY(is_both_small(op1, op2))) {
- Sint a = signed_val(op1);
- Sint b = signed_val(op2);
- Sint res;
- if (ERTS_LIKELY(!__builtin_mul_overflow(a, b, &res) && IS_SSMALL(res))) {
- $Dst = make_small(res);
+ /* See plus.execute */
+ Sint lhs_untagged, rhs_actual, res;
+
+ lhs_untagged = op1 & ~_TAG_IMMED1_MASK;
+ rhs_actual = signed_val(op2);
+
+ if (ERTS_LIKELY(!__builtin_mul_overflow(lhs_untagged, rhs_actual, &res))) {
+ ASSERT(!(res & _TAG_IMMED1_MASK));
+ $Dst = res | _TAG_IMMED1_SMALL;
$NEXT0();
}
}
diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c
index f1d8609066..8e93e53003 100644
--- a/erts/emulator/beam/beam_emu.c
+++ b/erts/emulator/beam/beam_emu.c
@@ -375,44 +375,33 @@ do { \
/*
* process_main() is already huge, so we want to avoid inlining
- * into it. Especially functions that are seldom used.
+ * seldom used functions into it.
*/
-#ifdef __GNUC__
-# define NOINLINE __attribute__((__noinline__))
-#else
-# define NOINLINE
-#endif
-
-
-/*
- * The following functions are called directly by process_main().
- * Don't inline them.
- */
-static void init_emulator_finish(void) NOINLINE;
-static ErtsCodeMFA *ubif2mfa(void* uf) NOINLINE;
+static void init_emulator_finish(void) ERTS_NOINLINE;
+static ErtsCodeMFA *ubif2mfa(void* uf) ERTS_NOINLINE;
static BeamInstr* handle_error(Process* c_p, BeamInstr* pc,
- Eterm* reg, ErtsCodeMFA* bif_mfa) NOINLINE;
+ Eterm* reg, ErtsCodeMFA* bif_mfa) ERTS_NOINLINE;
static BeamInstr* call_error_handler(Process* p, ErtsCodeMFA* mfa,
- Eterm* reg, Eterm func) NOINLINE;
+ Eterm* reg, Eterm func) ERTS_NOINLINE;
static BeamInstr* fixed_apply(Process* p, Eterm* reg, Uint arity,
- BeamInstr *I, Uint offs) NOINLINE;
+ BeamInstr *I, Uint offs) ERTS_NOINLINE;
static BeamInstr* apply(Process* p, Eterm* reg,
- BeamInstr *I, Uint offs) NOINLINE;
+ BeamInstr *I, Uint offs) ERTS_NOINLINE;
static BeamInstr* call_fun(Process* p, int arity,
- Eterm* reg, Eterm args) NOINLINE;
+ Eterm* reg, Eterm args) ERTS_NOINLINE;
static BeamInstr* apply_fun(Process* p, Eterm fun,
- Eterm args, Eterm* reg) NOINLINE;
+ Eterm args, Eterm* reg) ERTS_NOINLINE;
static Eterm new_fun(Process* p, Eterm* reg,
- ErlFunEntry* fe, int num_free) NOINLINE;
+ ErlFunEntry* fe, int num_free) ERTS_NOINLINE;
static int is_function2(Eterm Term, Uint arity);
static Eterm erts_gc_new_map(Process* p, Eterm* reg, Uint live,
- Uint n, BeamInstr* ptr) NOINLINE;
+ Uint n, BeamInstr* ptr) ERTS_NOINLINE;
static Eterm erts_gc_new_small_map_lit(Process* p, Eterm* reg, Eterm keys_literal,
- Uint live, BeamInstr* ptr) NOINLINE;
+ Uint live, BeamInstr* ptr) ERTS_NOINLINE;
static Eterm erts_gc_update_map_assoc(Process* p, Eterm* reg, Uint live,
- Uint n, BeamInstr* new_p) NOINLINE;
+ Uint n, BeamInstr* new_p) ERTS_NOINLINE;
static Eterm erts_gc_update_map_exact(Process* p, Eterm* reg, Uint live,
- Uint n, Eterm* new_p) NOINLINE;
+ Uint n, Eterm* new_p) ERTS_NOINLINE;
static Eterm get_map_element(Eterm map, Eterm key);
static Eterm get_map_element_hash(Eterm map, Eterm key, Uint32 hx);
@@ -3267,20 +3256,23 @@ erts_is_builtin(Eterm Mod, Eterm Name, int arity)
/*
- * Return the current number of reductions for the given process.
+ * Return the current number of reductions consumed by the given process.
* To get the total number of reductions, p->reds must be added.
*/
Uint
-erts_current_reductions(Process *current, Process *p)
+erts_current_reductions(Process *c_p, Process *p)
{
- if (current != p) {
+ Sint reds_left;
+ if (c_p != p || !(erts_atomic32_read_nob(&c_p->state)
+ & ERTS_PSFLG_RUNNING)) {
return 0;
- } else if (current->fcalls < 0 && ERTS_PROC_GET_SAVED_CALLS_BUF(current)) {
- return current->fcalls + CONTEXT_REDS;
+ } else if (c_p->fcalls < 0 && ERTS_PROC_GET_SAVED_CALLS_BUF(c_p)) {
+ reds_left = c_p->fcalls + CONTEXT_REDS;
} else {
- return REDS_IN(current) - current->fcalls;
+ reds_left = c_p->fcalls;
}
+ return REDS_IN(c_p) - reds_left;
}
int
diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c
index 8bbe6450eb..456b6fdac0 100644
--- a/erts/emulator/beam/dist.c
+++ b/erts/emulator/beam/dist.c
@@ -775,19 +775,25 @@ void init_dist(void)
static ERTS_INLINE ErtsDistOutputBuf *
alloc_dist_obuf(Uint size, Uint headers)
{
- int i;
+ Uint obuf_size = sizeof(ErtsDistOutputBuf)*(headers);
ErtsDistOutputBuf *obuf;
- Uint obuf_size = sizeof(ErtsDistOutputBuf)*(headers) +
- sizeof(byte)*size;
- Binary *bin = erts_bin_drv_alloc(obuf_size);
- obuf = (ErtsDistOutputBuf *) &bin->orig_bytes[size];
+ Binary *bin;
+ byte *extp;
+ int i;
+
+ bin = erts_bin_drv_alloc(obuf_size + size);
erts_refc_add(&bin->intern.refc, headers - 1, 1);
+
+ obuf = (ErtsDistOutputBuf *)&bin->orig_bytes[0];
+ extp = (byte *)&bin->orig_bytes[obuf_size];
+
for (i = 0; i < headers; i++) {
obuf[i].bin = bin;
- obuf[i].extp = (byte *)&bin->orig_bytes[0];
+ obuf[i].extp = extp;
#ifdef DEBUG
obuf[i].dbg_pattern = ERTS_DIST_OUTPUT_BUF_DBG_PATTERN;
- obuf[i].alloc_endp = obuf->extp + size;
+ obuf[i].ext_startp = extp;
+ obuf[i].alloc_endp = &extp[size];
ASSERT(bin == ErtsDistOutputBuf2Binary(obuf));
#endif
}
@@ -1360,7 +1366,7 @@ erts_dist_seq_tree_foreach_delete_yielding(DistSeqNode **root,
limit);
if (res > 0) {
if (ysp != &ys)
- erts_free(ERTS_ALC_T_ML_YIELD_STATE, ysp);
+ erts_free(ERTS_ALC_T_SEQ_YIELD_STATE, ysp);
*vyspp = NULL;
}
else {
@@ -2341,7 +2347,8 @@ erts_dsig_send(ErtsDSigSendContext *ctx)
(ctx->fragments-1) * ERTS_DIST_FRAGMENT_HEADER_SIZE,
ctx->fragments);
ctx->obuf->ext_start = &ctx->obuf->extp[0];
- ctx->obuf->ext_endp = &ctx->obuf->extp[0] + ctx->max_finalize_prepend + ctx->dhdr_ext_size;
+ ctx->obuf->ext_endp = &ctx->obuf->extp[0] + ctx->max_finalize_prepend
+ + ctx->dhdr_ext_size;
/* Encode internal version of dist header */
ctx->obuf->extp = erts_encode_ext_dist_header_setup(
@@ -2380,8 +2387,8 @@ erts_dsig_send(ErtsDSigSendContext *ctx)
case ERTS_DSIG_SEND_PHASE_FIN: {
ASSERT(ctx->obuf->extp < ctx->obuf->ext_endp);
- ASSERT(((byte*)&ctx->obuf->bin->orig_bytes[0]) <= ctx->obuf->extp - ctx->max_finalize_prepend);
- ASSERT(ctx->obuf->ext_endp <= ((byte*)ctx->obuf->bin->orig_bytes) + ctx->data_size + ctx->dhdr_ext_size);
+ ASSERT(ctx->obuf->ext_startp <= ctx->obuf->extp - ctx->max_finalize_prepend);
+ ASSERT(ctx->obuf->ext_endp <= (byte*)ctx->obuf->ext_startp + ctx->data_size + ctx->dhdr_ext_size);
ctx->data_size = ctx->obuf->ext_endp - ctx->obuf->extp;
@@ -3457,6 +3464,7 @@ dist_ctrl_get_data_1(BIF_ALIST_1)
pb->bytes = (byte*) obuf->extp;
pb->flags = 0;
res = make_binary(pb);
+ hp += PROC_BIN_SIZE;
} else {
hp = HAlloc(BIF_P, PROC_BIN_SIZE * 2 + 4 + hsz);
pb = (ProcBin *) (char *) hp;
diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c
index a7424bbcb8..39d42d9757 100644
--- a/erts/emulator/beam/erl_bif_info.c
+++ b/erts/emulator/beam/erl_bif_info.c
@@ -2579,6 +2579,7 @@ BIF_RETTYPE system_info_1(BIF_ALIST_1)
/* Need to be the only thread running... */
erts_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN);
+ BIF_P->scheduler_data->current_process = NULL;
erts_thr_progress_block();
if (BIF_ARG_1 == am_info)
@@ -2592,6 +2593,7 @@ BIF_RETTYPE system_info_1(BIF_ALIST_1)
erts_thr_progress_unblock();
erts_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);
+ BIF_P->scheduler_data->current_process = BIF_P;
ASSERT(dsbufp && dsbufp->str);
res = new_binary(BIF_P, (byte *) dsbufp->str, dsbufp->str_len);
diff --git a/erts/emulator/beam/erl_node_tables.h b/erts/emulator/beam/erl_node_tables.h
index c434926142..fc3e117463 100644
--- a/erts/emulator/beam/erl_node_tables.h
+++ b/erts/emulator/beam/erl_node_tables.h
@@ -95,6 +95,7 @@ enum dist_entry_state {
struct ErtsDistOutputBuf_ {
#ifdef DEBUG
Uint dbg_pattern;
+ byte *ext_startp;
byte *alloc_endp;
#endif
ErtsDistOutputBuf *next;
diff --git a/erts/emulator/beam/erl_posix_str.c b/erts/emulator/beam/erl_posix_str.c
index 7b3e640d3f..5b515d6e78 100644
--- a/erts/emulator/beam/erl_posix_str.c
+++ b/erts/emulator/beam/erl_posix_str.c
@@ -171,6 +171,9 @@ erl_errno_id(error)
#if defined(EIDRM) && (!defined(EINPROGRESS) || (EIDRM != EINPROGRESS))
case EIDRM: return "eidrm";
#endif
+#ifdef EILSEQ
+ case EILSEQ: return "eilseq";
+#endif
#ifdef EINIT
case EINIT: return "einit";
#endif
diff --git a/erts/emulator/beam/erl_proc_sig_queue.c b/erts/emulator/beam/erl_proc_sig_queue.c
index 4e9f177e51..f58a606d57 100644
--- a/erts/emulator/beam/erl_proc_sig_queue.c
+++ b/erts/emulator/beam/erl_proc_sig_queue.c
@@ -1019,6 +1019,8 @@ send_gen_exit_signal(Process *c_p, Eterm from_tag,
ref_sz = size_object(ref);
hsz += ref_sz;
+ reason_sz = 0; /* Set to silence gcc warning */
+
/* The reason was part of the control message,
just use copy it into the xsigd */
if (is_value(reason)) {
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index 9e662632b4..2b45d2d353 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -12141,10 +12141,9 @@ erts_proc_exit_handle_dist_monitor(ErtsMonitor *mon, void *vctxt, Sint reds)
reason);
switch (code) {
case ERTS_DSIG_SEND_CONTINUE:
+ case ERTS_DSIG_SEND_YIELD:
erts_set_gc_state(c_p, 0);
ctxt->dist_state = erts_dsend_export_trap_context(c_p, &ctx);
- /* fall-through */
- case ERTS_DSIG_SEND_YIELD:
break;
case ERTS_DSIG_SEND_OK:
break;
@@ -12388,11 +12387,10 @@ erts_proc_exit_handle_dist_link(ErtsLink *lnk, void *vctxt, Sint reds)
reason,
SEQ_TRACE_TOKEN(c_p));
switch (code) {
+ case ERTS_DSIG_SEND_YIELD:
case ERTS_DSIG_SEND_CONTINUE:
erts_set_gc_state(c_p, 0);
ctxt->dist_state = erts_dsend_export_trap_context(c_p, &ctx);
- /* fall-through */
- case ERTS_DSIG_SEND_YIELD:
break;
case ERTS_DSIG_SEND_OK:
break;
diff --git a/erts/emulator/beam/erl_utils.h b/erts/emulator/beam/erl_utils.h
index 880febba8b..430ac305c5 100644
--- a/erts/emulator/beam/erl_utils.h
+++ b/erts/emulator/beam/erl_utils.h
@@ -69,7 +69,6 @@ int erts_fit_in_bits_int32(Sint32);
int erts_fit_in_bits_uint(Uint);
Sint erts_list_length(Eterm);
int erts_is_builtin(Eterm, Eterm, int);
-Uint32 block_hash(byte *, unsigned, Uint32);
Uint32 make_hash2(Eterm);
Uint32 make_hash(Eterm);
Uint32 make_internal_hash(Eterm, Uint32 salt);
diff --git a/erts/emulator/beam/external.c b/erts/emulator/beam/external.c
index 471c1c3938..fa8314c115 100644
--- a/erts/emulator/beam/external.c
+++ b/erts/emulator/beam/external.c
@@ -699,6 +699,7 @@ dist_ext_size(ErtsDistExternal *edep)
} else {
sz -= sizeof(ErtsAtomTranslationTable);
}
+ ASSERT(sz % 4 == 0);
return sz;
}
@@ -706,8 +707,9 @@ Uint
erts_dist_ext_size(ErtsDistExternal *edep)
{
Uint sz = dist_ext_size(edep);
+ sz += 4; /* may need to pad to 8-byte-align ErtsDistExternalData */
sz += edep->data[0].frag_id * sizeof(ErtsDistExternalData);
- return sz + ERTS_EXTRA_DATA_ALIGN_SZ(sz);
+ return sz;
}
Uint
@@ -749,6 +751,8 @@ erts_make_dist_ext_copy(ErtsDistExternal *edep, ErtsDistExternal *new_edep)
erts_ref_dist_entry(new_edep->dep);
ep += dist_ext_sz;
+ ep += (UWord)ep & 4; /* 8-byte alignment for ErtsDistExternalData */
+ ASSERT((UWord)ep % 8 == 0);
new_edep->data = (ErtsDistExternalData*)ep;
sys_memzero(new_edep->data, sizeof(ErtsDistExternalData) * edep->data->frag_id);
diff --git a/erts/emulator/beam/external.h b/erts/emulator/beam/external.h
index 396cd9f802..f2cc9bf98f 100644
--- a/erts/emulator/beam/external.h
+++ b/erts/emulator/beam/external.h
@@ -144,14 +144,6 @@ typedef struct erl_dist_external {
ErtsAtomTranslationTable attab;
} ErtsDistExternal;
-#define ERTS_DIST_EXT_SIZE(EDEP) \
- (sizeof(ErtsDistExternal) \
- - (((EDEP)->flags & ERTS_DIST_EXT_ATOM_TRANS_TAB) \
- ? (ASSERT(0 <= (EDEP)->attab.size \
- && (EDEP)->attab.size <= ERTS_ATOM_CACHE_SIZE), \
- sizeof(Eterm)*(ERTS_ATOM_CACHE_SIZE - (EDEP)->attab.size)) \
- : sizeof(ErtsAtomTranslationTable)))
-
typedef struct {
byte *extp;
int exttmp;
diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h
index f9bbe4167f..4c8d3d3dbe 100644
--- a/erts/emulator/beam/global.h
+++ b/erts/emulator/beam/global.h
@@ -1216,10 +1216,11 @@ Uint64 erts_timestamp_millis(void);
Export* erts_find_function(Eterm, Eterm, unsigned int, ErtsCodeIndex);
-void *erts_calc_stacklimit(char *prev_c, UWord stacksize);
-int erts_check_below_limit(char *ptr, char *limit);
-int erts_check_above_limit(char *ptr, char *limit);
-void *erts_ptr_id(void *ptr);
+/* ERTS_NOINLINE prevents link-time optimization across modules */
+void *erts_calc_stacklimit(char *prev_c, UWord stacksize) ERTS_NOINLINE;
+int erts_check_below_limit(char *ptr, char *limit) ERTS_NOINLINE;
+int erts_check_above_limit(char *ptr, char *limit) ERTS_NOINLINE;
+void *erts_ptr_id(void *ptr) ERTS_NOINLINE;
Eterm store_external_or_ref_in_proc_(Process *, Eterm);
Eterm store_external_or_ref_(Uint **, ErlOffHeap*, Eterm);
diff --git a/erts/emulator/beam/msg_instrs.tab b/erts/emulator/beam/msg_instrs.tab
index 6f8d1469ef..b08466c830 100644
--- a/erts/emulator/beam/msg_instrs.tab
+++ b/erts/emulator/beam/msg_instrs.tab
@@ -105,6 +105,7 @@ i_loop_rec(Dest) {
$SET_CP_I_ABS(I);
c_p->arity = 0;
c_p->current = NULL;
+ c_p->fcalls = FCALLS;
FCALLS -= erts_proc_sig_receive_helper(c_p, FCALLS, neg_o_reds,
&msgp, &get_out);
SWAPIN;
diff --git a/erts/emulator/beam/ops.tab b/erts/emulator/beam/ops.tab
index 7a125b0f67..10ca74cd60 100644
--- a/erts/emulator/beam/ops.tab
+++ b/erts/emulator/beam/ops.tab
@@ -1690,9 +1690,14 @@ i_plus S1=c S2=c Fail Dst => move S1 x | i_plus x S2 Fail Dst
i_plus xy xyc j? d
-i_minus x x j? d
-i_minus c x j? d
-i_minus s s j? d
+# A minus instruction with a constant right operand will be
+# converted to an i_increment instruction, except in guards or
+# when the negated value of the constant won't fit in a guard.
+# Therefore, it very rare.
+i_minus S1 S2=c Fail Dst => move S2 x | i_minus S1 x Fail Dst
+
+i_minus xy xy j? d
+i_minus c xy j? d
i_times j? s s d
diff --git a/erts/emulator/beam/sys.h b/erts/emulator/beam/sys.h
index a6312293cc..c261c8e117 100644
--- a/erts/emulator/beam/sys.h
+++ b/erts/emulator/beam/sys.h
@@ -63,6 +63,14 @@
# endif
#endif
+#ifndef ERTS_NOINLINE
+# if ERTS_AT_LEAST_GCC_VSN__(3,1,1)
+# define ERTS_NOINLINE __attribute__((__noinline__))
+# else
+# define ERTS_NOINLINE
+# endif
+#endif
+
#if defined(DEBUG) || defined(ERTS_ENABLE_LOCK_CHECK)
# undef ERTS_CAN_INLINE
# define ERTS_CAN_INLINE 0
diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c
index 36cfe0548e..0bbae65e28 100644
--- a/erts/emulator/beam/utils.c
+++ b/erts/emulator/beam/utils.c
@@ -1069,11 +1069,11 @@ do { \
#define HCONST 0x9e3779b9UL /* the golden ratio; an arbitrary value */
-Uint32
-block_hash(byte *k, unsigned length, Uint32 initval)
+static Uint32
+block_hash(byte *k, Uint length, Uint32 initval)
{
Uint32 a,b,c;
- unsigned len;
+ Uint len;
/* Set up the internal state */
len = length;
@@ -1749,7 +1749,7 @@ make_internal_hash(Eterm term, Uint32 salt)
case SUB_BINARY_SUBTAG:
{
byte* bptr;
- unsigned sz = binary_size(term);
+ Uint sz = binary_size(term);
Uint32 con = HCONST_13 + hash;
Uint bitoffs;
Uint bitsize;
diff --git a/erts/emulator/internal_doc/CarrierMigration.md b/erts/emulator/internal_doc/CarrierMigration.md
index bb3d8aac28..40f6031ca8 100644
--- a/erts/emulator/internal_doc/CarrierMigration.md
+++ b/erts/emulator/internal_doc/CarrierMigration.md
@@ -1,6 +1,9 @@
Carrier Migration
=================
+Introduction
+------------
+
The ERTS memory allocators manage memory blocks in two types of raw
memory chunks. We call these chunks of raw memory
*carriers*. Single-block carriers which only contain one large block,
@@ -141,11 +144,11 @@ Since the carrier has been unlinked from the data structure of
available free blocks, no more allocations will be made in the
carrier.
-The allocator instance that created a carrier is called its **owner**.
+The allocator instance that created a carrier is called its *owner*.
Ownership never changes.
The allocator instance that has the responsibility to perform deallocations in a
-carrier is called its **employer**. The employer may also perform allocations if
+carrier is called its *employer*. The employer may also perform allocations if
the carrier is not in the pool. Employment may change when a carrier is fetched from
or inserted into the pool.
@@ -153,14 +156,14 @@ Deallocations in a carrier, while it remains in the pool, is always performed
the owner. That is, all pooled carriers are employed by their owners.
Each carrier has an atomic word containing a pointer to the employing allocator
-instance and three bit flags; IN_POOL, BUSY and HOMECOMING.
+instance and three bit flags; IN\_POOL, BUSY and HOMECOMING.
When fetching a carrier from the pool, employment may change and further
deallocations in the carrier will be redirected to the new
employer using the delayed dealloc functionality.
When a foreign allocator instance abandons a carrier back into the pool, it will
-also pass it back to its **owner** using the delayed dealloc queue. When doing
+also pass it back to its *owner* using the delayed dealloc queue. When doing
this it will set the HOMECOMING bit flag to mark it as "enqueued". The owner
will later clear the HOMECOMING bit when the carrier is dequeued. This mechanism
prevents a carrier from being enqueued again before it has been dequeued.
@@ -180,14 +183,14 @@ back to the owner for deallocation using the delayed dealloc functionality.
In short:
-* The allocator instance that created a carrier **owns** it.
-* An empty carrier is always deallocated by its **owner**.
-* **Ownership** never changes.
-* The allocator instance that uses a carrier **employs** it.
-* An **employer** can abandon a carrier into the pool.
+* The allocator instance that created a carrier *owns* it.
+* An empty carrier is always deallocated by its *owner*.
+* *Ownership* never changes.
+* The allocator instance that uses a carrier *employs* it.
+* An *employer* can abandon a carrier into the pool.
* Pooled carriers are not allocated from.
-* Pooled carriers are always **employed** by their **owner**.
-* **Employment** can only change from **owner** to a foreign allocator
+* Pooled carriers are always *employed* by their *owner*.
+* *Employment* can only change from *owner* to a foreign allocator
when a carrier is fetched from the pool.
@@ -229,7 +232,7 @@ carrier. When the cluster gets to the same size as the search limit,
all searches will essentially fail.
To counter the "bad cluster" problem and also ease the contention, the
-search will now always start by first looking at the allocators **own**
+search will now always start by first looking at the allocators *own*
carriers. That is, carriers that were initially created by the
allocator itself and later had been abandoned to the pool. If none of
our own abandoned carrier would do, then the search continues into the
diff --git a/erts/emulator/internal_doc/CodeLoading.md b/erts/emulator/internal_doc/CodeLoading.md
index 151b9cd57c..0b2e3070e7 100644
--- a/erts/emulator/internal_doc/CodeLoading.md
+++ b/erts/emulator/internal_doc/CodeLoading.md
@@ -45,7 +45,7 @@ free to schedule other work while the second loader is waiting. (See
`erts_release_code_write_permission`).
The ability to prepare several modules in parallel is not currently
-used as almost all code loading is serialized by the code_server
+used as almost all code loading is serialized by the code\_server
process. The BIF interface is however prepared for this.
erlang:prepare_loading(Module, Code) -> LoaderState
@@ -71,8 +71,8 @@ structures. These *code access structures* are
* Export table. One entry for every exported function.
* Module table. One entry for each loaded module.
-* "beam_catches". Identifies jump destinations for catch instructions.
-* "beam_ranges". Map code address to function and line in source file.
+* "beam\_catches". Identifies jump destinations for catch instructions.
+* "beam\_ranges". Map code address to function and line in source file.
The most frequently used of these structures is the export table that
is accessed in run time for every executed external function call to
diff --git a/erts/emulator/internal_doc/GarbageCollection.md b/erts/emulator/internal_doc/GarbageCollection.md
index 1d9e3f4160..a1627b3233 100644
--- a/erts/emulator/internal_doc/GarbageCollection.md
+++ b/erts/emulator/internal_doc/GarbageCollection.md
@@ -1,6 +1,6 @@
# Erlang Garbage Collector
-Erlang manages dynamic memory with a [tracing garbage collector](https://en.wikipedia.org/wiki/Tracing_garbage_collection). More precisely a per process generational semi-space copying collector using [Cheney's](#cheney) copy collection algorithm together with a global large object space.
+Erlang manages dynamic memory with a [tracing garbage collector](https://en.wikipedia.org/wiki/Tracing_garbage_collection). More precisely a per process generational semi-space copying collector using Cheney's copy collection algorithm together with a global large object space. (See C. J. Cheney in [References](#references).)
## Overview
@@ -12,12 +12,11 @@ Terms are created on the heap by evaluating expressions. There are two major typ
Let's look at an example that returns a tuple with the newly created data.
-```erlang
-data(Foo) ->
- Cons = [42|Foo],
- Literal = {text, "hello world!"},
- {tag, Cons, Literal}.
-```
+
+ data(Foo) ->
+ Cons = [42|Foo],
+ Literal = {text, "hello world!"},
+ {tag, Cons, Literal}.
In this example we first create a new cons cell with an integer and a tuple with some text. Then a tuple of size three wrapping the other values with an atom tag is created and returned.
@@ -25,7 +24,6 @@ On the heap tuples require a word size for each of its elements as well as for t
Compiling this code to beam assembly (`erlc -S`) shows exactly what is happening.
-```erlang
...
{test_heap,6,1}.
{put_list,{integer,42},{x,0},{x,1}}.
@@ -34,9 +32,8 @@ Compiling this code to beam assembly (`erlc -S`) shows exactly what is happening
{put,{x,1}}.
{put,{literal,{text,"hello world!"}}}.
return.
-```
-Looking at the assembler code we can see three things; The heap requirement in this function turns out to be only six words, as seen by the `{test_heap,6,1}` instruction. All the allocations are combined to a single instruction. The bulk of the data `{text, "hello world!"}` is a *literal*. Literals, sometimes referred to as constants, are not allocated in the function since they are a part of the module and allocated at load time.
+Looking at the assembler code we can see three things: The heap requirement in this function turns out to be only six words, as seen by the `{test_heap,6,1}` instruction. All the allocations are combined to a single instruction. The bulk of the data `{text, "hello world!"}` is a *literal*. Literals, sometimes referred to as constants, are not allocated in the function since they are a part of the module and allocated at load time.
If there is not enough space available on the heap to satisfy the `test_heap` instructions request for memory, then a garbage collection is initiated. It may happen immediately in the `test_heap` instruction, or it can be delayed until a later time depending on what state the process is in. If the garbage collection is delayed, any memory needed will be allocated in heap fragments. Heap fragments are extra memory blocks that are a part of the young heap, but are not allocated in the contigious area where terms normally reside. See [The young heap](#the-young-heap) for more details.
@@ -50,11 +47,9 @@ It follows all the pointers from the root-set to the heap and copies each term w
After the header word has been copied a [*move marker*](https://github.com/erlang/otp/blob/OTP-18.0/erts/emulator/beam/erl_gc.h#L45-L46) is destructively placed in it pointing to the term in the *to space*. Any other term that points to the already moved term will [see this move marker](https://github.com/erlang/otp/blob/OTP-18.0/erts/emulator/beam/erl_gc.c#L1125) and copy the referring pointer instead. For example, if the have the following Erlang code:
-```erlang
-foo(Arg) ->
- T = {test, Arg},
- {wrapper, T, T, T}.
-```
+ foo(Arg) ->
+ T = {test, Arg},
+ {wrapper, T, T, T}.
Only one copy of T exists on the heap and during the garbage collection only the first time T is encountered will it be copied.
@@ -86,15 +81,15 @@ In the next garbage collection, any pointers to the old heap will be ignored and
Generational garbage collection aims to increase performance at the expense of memory. This is achieved because only the young, smaller, heap is considered in most garbage collections.
-The generational [hypothesis](#ungar) predicts that most terms tend to die young, and for an immutable language such as Erlang, young terms die even faster than in other languages. So for most usage patterns the data in the new heap will die very soon after it is allocated. This is good because it limits the amount of data copied to the old heap and also because the garbage collection algorithm used is proportional to the amount of live data on the heap.
+The generational hypothesis predicts that most terms tend to die young (see D. Ungar in [References](#references)), and for an immutable language such as Erlang, young terms die even faster than in other languages. So for most usage patterns the data in the new heap will die very soon after it is allocated. This is good because it limits the amount of data copied to the old heap and also because the garbage collection algorithm used is proportional to the amount of live data on the heap.
One critical issue to note here is that any term on the young heap can reference terms on the old heap but *no* term on the old heap may refer to a term on the young heap. This is due to the nature of the copy algorithm. Anything referenced by an old heap term is not included in the reference tree, root-set and its followers, and hence is not copied. If it was, the data would be lost, fire and brimstone would rise to cover the earth. Fortunately, this comes naturally for Erlang because the terms are immutable and thus there can be no pointers modified on the old heap to point to the young heap.
-To reclaim data from the old heap, both young and old heaps are included during the collection and copied to a common *to space*. Both the *from space* of the young and old heap are then deallocated and the procedure will start over from the beginning. This type of garbage collection is called a full sweep and is triggered when the size of the area under the high-watermark is larger than the size of the free area of the old heap. It can also be triggered by doing a manual call to [erlang:garbage_collect()](http://erlang.org/doc/man/erlang.html#garbage_collect-0), or by running into the young garbage collection limit set by [spawn_opt(fun(),[{fullsweep_after, N}])](http://erlang.org/doc/man/erlang.html#spawn_opt-4) where N is the number of young garbage collections to do before forcing a garbage collection of both young and old heap.
+To reclaim data from the old heap, both young and old heaps are included during the collection and copied to a common *to space*. Both the *from space* of the young and old heap are then deallocated and the procedure will start over from the beginning. This type of garbage collection is called a full sweep and is triggered when the size of the area under the high-watermark is larger than the size of the free area of the old heap. It can also be triggered by doing a manual call to [erlang:garbage_collect()](http://erlang.org/doc/man/erlang.html#garbage_collect-0), or by running into the young garbage collection limit set by [spawn\_opt(fun(),[{fullsweep\_after, N}\])](http://erlang.org/doc/man/erlang.html#spawn_opt-4) where N is the number of young garbage collections to do before forcing a garbage collection of both young and old heap.
## The young heap
-The young heap, or the allocation heap, consists of the stack and heap as described in the Overview. However, it also includes any heap fragments that are attached to the heap. All of the heap fragments are considered to be above the high-watermark and part of the young generation. Heap fragments contain terms that either did not fit on the heap, or were created by another process and then attached to the heap. For instance if the bif binary_to_term created a term which does not fit on the current heap without doing a garbage collection, it will create a heap-fragment for the term and then schedule a garbage collection for later. Also if a message is sent to the process, the payload may be placed in a heap-fragment and that fragment is added to young heap when the message is matched in a receive clause.
+The young heap, or the allocation heap, consists of the stack and heap as described in the Overview. However, it also includes any heap fragments that are attached to the heap. All of the heap fragments are considered to be above the high-watermark and part of the young generation. Heap fragments contain terms that either did not fit on the heap, or were created by another process and then attached to the heap. For instance if the bif `binary_to_term/1` created a term which does not fit on the current heap without doing a garbage collection, it will create a heap-fragment for the term and then schedule a garbage collection for later. Also if a message is sent to the process, the payload may be placed in a heap-fragment and that fragment is added to young heap when the message is matched in a receive clause.
This procedure differs from how it worked prior to Erlang/OTP 19.0. Before 19.0, only a contiguous memory block where the young heap and stack resided was considered to be part of the young heap. Heap fragments and messages were immediately copied into the young heap before they could be inspected by the Erlang program. The behaviour introduced in 19.0 is superior in many ways - most significantly it reduces the number of necessary copy operations and the root set for garbage collection.
@@ -118,21 +113,19 @@ The old heap is always one step ahead in the heap growth stages than the young h
When garbage collecting a heap (young or old) all literals are left in place and not copied. To figure out if a term should be copied or not when doing a garbage collection the following pseudo code is used:
-```c
-if (erts_is_literal(ptr) || (on_old_heap(ptr) && !fullsweep)) {
- /* literal or non fullsweep - do not copy */
-} else {
- copy(ptr);
-}
-```
+ if (erts_is_literal(ptr) || (on_old_heap(ptr) && !fullsweep)) {
+ /* literal or non fullsweep - do not copy */
+ } else {
+ copy(ptr);
+ }
The [`erts_is_literal`](https://github.com/erlang/otp/blob/OTP-19.0/erts/emulator/beam/global.h#L1452-L1465) check works differently on different architectures and operating systems.
-On 64 bit systems that allow mapping of unreserved virtual memory areas (most operating systems except Windows), an area of size 1 GB (by default) is mapped and then all literals are placed within that area. Then all that has to be done to determine if something is a literal or not is [two quick pointer checks](https://github.com/erlang/otp/blob/OTP-19.0/erts/emulator/beam/erl_alloc.h#L322-L324). This system relies on the fact that a memory page that has not been touched yet does not take any actual space. So even if 1 GB of virtual memory is mapped, only the memory which is actually needed for literals is allocated in ram. The size of the literal area is configurable through the +MIscs erts_alloc option.
+On 64 bit systems that allow mapping of unreserved virtual memory areas (most operating systems except Windows), an area of size 1 GB (by default) is mapped and then all literals are placed within that area. Then all that has to be done to determine if something is a literal or not is [two quick pointer checks](https://github.com/erlang/otp/blob/OTP-19.0/erts/emulator/beam/erl_alloc.h#L322-L324). This system relies on the fact that a memory page that has not been touched yet does not take any actual space. So even if 1 GB of virtual memory is mapped, only the memory which is actually needed for literals is allocated in ram. The size of the literal area is configurable through the +MIscs erts\_alloc option.
On 32 bit systems, there is not enough virtual memory space to allocate 1 GB for just literals, so instead small 256 KB sized literal regions are created on demand and a card mark bit-array of the entire 32 bit memory space is then used to determine if a term is a literal or not. Since the total memory space is only 32 bits, the card mark bit-array is only 256 words large. On a 64 bit system the same bit-array would have to be 1 tera words large, so this technique is only viable on 32 bit systems. Doing [lookups in the array](https://github.com/erlang/otp/blob/OTP-19.0/erts/emulator/beam/erl_alloc.h#L316-L319) is a little more expensive then just doing the pointer checks that can be done in 64 bit systems, but not extremely so.
-On 64 bit windows, on which erts_alloc cannot do unreserved virtual memory mappings, a [special tag](https://github.com/erlang/otp/blob/OTP-19.0/erts/emulator/beam/erl_term.h#L59) within the Erlang term object is used to determine if something [is a literal or not](https://github.com/erlang/otp/blob/OTP-19.0/erts/emulator/beam/erl_term.h#L248-L252). This is very cheap, however, the tag is only available on 64 bit machines, and it is possible to do a great deal of other nice optimizations with this tag in the future (like for instance a more compact list implementation) so it is not used on operating systems where it is not needed.
+On 64 bit windows, on which erts\_alloc cannot do unreserved virtual memory mappings, a [special tag](https://github.com/erlang/otp/blob/OTP-19.0/erts/emulator/beam/erl_term.h#L59) within the Erlang term object is used to determine if something [is a literal or not](https://github.com/erlang/otp/blob/OTP-19.0/erts/emulator/beam/erl_term.h#L248-L252). This is very cheap, however, the tag is only available on 64 bit machines, and it is possible to do a great deal of other nice optimizations with this tag in the future (like for instance a more compact list implementation) so it is not used on operating systems where it is not needed.
This behaviour is different from how it worked prior to Erlang/OTP 19.0. Before 19.0 the literal check was done by checking if the pointer pointed to the young or old heap block. If it did not, then it was considered a literal. This lead to considerable overhead and strange memory usage scenarios, so it was removed in 19.0.
@@ -182,6 +175,8 @@ Using `on_heap` will force all messages to be part of on the young heap which wi
Which one of these strategies is best depends a lot on what the process is doing and how it interacts with other processes. So, as always, profile the application and see how it behaves with the different options.
- <a name="cheney">[1]</a>: C. J. Cheney. A nonrecursive list compacting algorithm. Commun. ACM, 13(11):677–678, Nov. 1970.
+## References
+
+C. J. Cheney. A nonrecursive list compacting algorithm. Commun. ACM, 13(11):677–678, Nov. 1970.
- <a name="ungar">[2]</a>: D. Ungar. Generation scavenging: A non-disruptive high performance storage reclamation algorithm. SIGSOFT Softw. Eng. Notes, 9(3):157–167, Apr. 1984.
+D. Ungar. Generation scavenging: A non-disruptive high performance storage reclamation algorithm. SIGSOFT Softw. Eng. Notes, 9(3):157–167, Apr. 1984.
diff --git a/erts/emulator/internal_doc/PTables.md b/erts/emulator/internal_doc/PTables.md
index 6fe0e7665d..ef61963a40 100644
--- a/erts/emulator/internal_doc/PTables.md
+++ b/erts/emulator/internal_doc/PTables.md
@@ -85,13 +85,13 @@ following:
3. Depending on use, issue appropriate memory barrier.
A common barrier used is a barrier with acquire semantics. On
- x86/x86_64 this maps to a compiler barrier preventing the compiler
+ x86/x86\_64 this maps to a compiler barrier preventing the compiler
to reorder instructions, but on other hardware often some kind of
light weight hardware memory barrier is also needed.
When comparing with a locked approach, at least one heavy weight
memory barrier will be issued when locking the lock on most, if
- not all, hardware architectures (including x86/x86_64), and often
+ not all, hardware architectures (including x86/x86\_64), and often
some kind of light weight memory barrier will be issued when
unlocking the lock.
diff --git a/erts/emulator/internal_doc/SuperCarrier.md b/erts/emulator/internal_doc/SuperCarrier.md
index acf722ea37..f52c6613d5 100644
--- a/erts/emulator/internal_doc/SuperCarrier.md
+++ b/erts/emulator/internal_doc/SuperCarrier.md
@@ -5,7 +5,7 @@ A super carrier is large memory area, allocated at VM start, which can
be used during runtime to allocate normal carriers from.
The super carrier feature was introduced in OTP R16B03. It is
-enabled with command line option +MMscs <size in Mb>
+enabled with command line option +MMscs &lt;size in Mb&gt;
and can be configured with other options.
Problem
@@ -65,7 +65,7 @@ carrier is full.
### Implementation ###
-The entire super carrier implementation is kept in erl_mmap.c. The
+The entire super carrier implementation is kept in erl\_mmap.c. The
name suggest that it can be viewed as our own mmap implementation.
A super carrier needs to satisfy two slightly different kinds of
@@ -98,8 +98,8 @@ other.
### Data structures ###
-The MBC area is called **sa** as in super aligned and the SBC area is
-called **sua** as in super un-aligned.
+The MBC area is called *sa* as in super aligned and the SBC area is
+called *sua* as in super un-aligned.
Note that the "super" in super alignment and the "super" in super
carrier has nothing to do with each other. We could have choosen
@@ -128,7 +128,7 @@ down or up.
We need to keep track of all the free segments in order to reuse them
for new carrier allocations. One initial idea was to use the same
mechanism that is used to keep track of free blocks within MBCs
-(alloc_util and the different strategies). However, that would not be
+(alloc\_util and the different strategies). However, that would not be
as straight forward as one can think and can also waste quite a lot of
memory as it uses prepended block headers. The granularity of the
super carrier is one memory page (usually 4kb). We want to allocate
diff --git a/erts/emulator/internal_doc/Tracing.md b/erts/emulator/internal_doc/Tracing.md
index 7f97f64765..196ae0dd4e 100644
--- a/erts/emulator/internal_doc/Tracing.md
+++ b/erts/emulator/internal_doc/Tracing.md
@@ -37,6 +37,7 @@ what different type of break actions that are enabled.
Same Same but Different
-----------------------
+
Even though `trace_pattern` use the same technique as the non-blocking
code loading with replicated generations of data structures and an
atomic switch, the implementations are quite separate from each
@@ -72,6 +73,7 @@ aligned write operation on all hardware architectures we use.
Adding a new Breakpoint
-----------------------
+
This is a simplified sequence describing what `trace_pattern` goes
through when adding a new breakpoint.
@@ -82,7 +84,7 @@ through when adding a new breakpoint.
instruction word in the breakpoint.
3. Write a pointer to the breakpoint at offset -4 from the first
- instruction "func_info" header.
+ instruction "func\_info" header.
4. Set the staging part of the breakpoint as enabled with specified
breakpoint data.
@@ -139,7 +141,7 @@ and removing breakpoints.
2. Allocate new breakpoint structures with a disabled active part and
the original beam instruction. Write a pointer to the breakpoint in
- "func_info" header at offset -4.
+ "func\_info" header at offset -4.
3. Update the staging part of all affected breakpoints. Disable
breakpoints that are to be removed.
diff --git a/erts/emulator/internal_doc/beam_makeops.md b/erts/emulator/internal_doc/beam_makeops.md
index 1da8d2ab05..2880099b70 100644
--- a/erts/emulator/internal_doc/beam_makeops.md
+++ b/erts/emulator/internal_doc/beam_makeops.md
@@ -403,7 +403,7 @@ A line with `//` is also a comment. It is recommended to only
use this style of comments in files that define implementations of
instructions.
-A long line can be broken into shorter lines by a placing a`\` before
+A long line can be broken into shorter lines by a placing a `\` before
the newline.
### Variable definitions ###
@@ -1159,7 +1159,6 @@ implementation of `gen_element()`:
return op;
}
-}
### Defining the implementation ###
@@ -1452,7 +1451,7 @@ optionally additional heap space.
##### The NEXT_INSTRUCTION pre-bound variable #####
-The NEXT_INSTRUCTION is a pre-bound variable that is available in
+The NEXT\_INSTRUCTION is a pre-bound variable that is available in
all instructions. It expands to the address of the next instruction.
Here is an example:
@@ -1545,7 +1544,7 @@ register, the pointer will no longer be valid. (Y registers are
stored on the stack.)
In those circumstances, `$REFRESH_GEN_DEST()` must be invoked
-to set up the pointer again. **beam\_makeops** will notice
+to set up the pointer again. **beam\_makeops** will notice
if there is a call to a function that does a garbage collection and
`$REFRESH_GEN_DEST()` is not called.
diff --git a/erts/emulator/sys/common/erl_check_io.c b/erts/emulator/sys/common/erl_check_io.c
index 80e8030d74..98be50815c 100644
--- a/erts/emulator/sys/common/erl_check_io.c
+++ b/erts/emulator/sys/common/erl_check_io.c
@@ -842,6 +842,8 @@ driver_select(ErlDrvPort ix, ErlDrvEvent e, int mode, int on)
ret = 0;
goto done_unknown;
}
+ /* For some reason (don't know why), we do not clean all
+ events when doing ERL_DRV_USE_NO_CALLBACK. */
else if ((mode&ERL_DRV_USE_NO_CALLBACK) == ERL_DRV_USE) {
mode |= (ERL_DRV_READ | ERL_DRV_WRITE);
}
@@ -2491,6 +2493,10 @@ drvmode2str(int mode) {
case ERL_DRV_WRITE|ERL_DRV_USE: return "WRITE|USE";
case ERL_DRV_READ|ERL_DRV_WRITE|ERL_DRV_USE: return "READ|WRITE|USE";
case ERL_DRV_USE: return "USE";
+ case ERL_DRV_READ|ERL_DRV_USE_NO_CALLBACK: return "READ|USE_NO_CB";
+ case ERL_DRV_WRITE|ERL_DRV_USE_NO_CALLBACK: return "WRITE|USE_NO_CB";
+ case ERL_DRV_READ|ERL_DRV_WRITE|ERL_DRV_USE_NO_CALLBACK: return "READ|WRITE|USE_NO_CB";
+ case ERL_DRV_USE_NO_CALLBACK: return "USE_NO_CB";
case ERL_DRV_READ: return "READ";
case ERL_DRV_WRITE: return "WRITE";
case ERL_DRV_READ|ERL_DRV_WRITE: return "READ|WRITE";
diff --git a/erts/emulator/sys/unix/sys_drivers.c b/erts/emulator/sys/unix/sys_drivers.c
index 042a091db1..664d677ebd 100644
--- a/erts/emulator/sys/unix/sys_drivers.c
+++ b/erts/emulator/sys/unix/sys_drivers.c
@@ -1006,10 +1006,8 @@ static void clear_fd_data(ErtsSysFdData *fdd)
static void nbio_stop_fd(ErlDrvPort prt, ErtsSysFdData *fdd, int use)
{
- driver_select(prt, abs(fdd->fd), use ? ERL_DRV_USE_NO_CALLBACK : 0|DO_READ|DO_WRITE, 0);
clear_fd_data(fdd);
SET_BLOCKING(abs(fdd->fd));
-
}
static void fd_stop(ErlDrvData ev) /* Does not close the fds */
@@ -1026,10 +1024,12 @@ static void fd_stop(ErlDrvData ev) /* Does not close the fds */
if (dd->ifd) {
sz += sizeof(ErtsSysFdData);
+ driver_select(prt, abs(dd->ifd->fd), ERL_DRV_USE_NO_CALLBACK|DO_READ|DO_WRITE, 0);
nbio_stop_fd(prt, dd->ifd, 1);
}
if (dd->ofd && dd->ofd != dd->ifd) {
sz += sizeof(ErtsSysFdData);
+ driver_select(prt, abs(dd->ofd->fd), ERL_DRV_USE_NO_CALLBACK|DO_WRITE, 0);
nbio_stop_fd(prt, dd->ofd, 1);
}
diff --git a/erts/emulator/test/Makefile b/erts/emulator/test/Makefile
index 8c2054cb51..28775b6f02 100644
--- a/erts/emulator/test/Makefile
+++ b/erts/emulator/test/Makefile
@@ -124,6 +124,7 @@ MODULES= \
send_term_SUITE \
sensitive_SUITE \
signal_SUITE \
+ small_SUITE \
smoke_test_SUITE \
$(SOCKET_MODULES) \
statistics_SUITE \
diff --git a/erts/emulator/test/distribution_SUITE.erl b/erts/emulator/test/distribution_SUITE.erl
index 449821e5ad..58194cf167 100644
--- a/erts/emulator/test/distribution_SUITE.erl
+++ b/erts/emulator/test/distribution_SUITE.erl
@@ -39,6 +39,8 @@
-define(Line,).
-export([all/0, suite/0, groups/0,
+ init_per_suite/1, end_per_suite/1,
+ init_per_group/2, end_per_group/2,
ping/1, bulk_send_small/1,
group_leader/1,
optimistic_dflags/1,
@@ -119,6 +121,28 @@ groups() ->
message_latency_large_exit2]}
].
+init_per_suite(Config) ->
+ {ok, Apps} = application:ensure_all_started(os_mon),
+ [{started_apps, Apps} | Config].
+
+end_per_suite(Config) ->
+ Apps = proplists:get_value(started_apps, Config),
+ [application:stop(App) || App <- lists:reverse(Apps)],
+ Config.
+
+init_per_group(message_latency, Config) ->
+ Free = free_memory(),
+ if Free < 2048 ->
+ {skip, "Not enough memory"};
+ true ->
+ Config
+ end;
+init_per_group(_, Config) ->
+ Config.
+
+end_per_group(_, Config) ->
+ Config.
+
%% Tests pinging a node in different ways.
ping(Config) when is_list(Config) ->
Times = 1024,
@@ -2845,3 +2869,23 @@ uint8(Uint) when is_integer(Uint), 0 =< Uint, Uint < 1 bsl 8 ->
Uint band 16#ff;
uint8(Uint) ->
exit({badarg, uint8, [Uint]}).
+
+free_memory() ->
+ %% Free memory in MB.
+ try
+ SMD = memsup:get_system_memory_data(),
+ {value, {free_memory, Free}} = lists:keysearch(free_memory, 1, SMD),
+ TotFree = (Free +
+ case lists:keysearch(cached_memory, 1, SMD) of
+ {value, {cached_memory, Cached}} -> Cached;
+ false -> 0
+ end +
+ case lists:keysearch(buffered_memory, 1, SMD) of
+ {value, {buffered_memory, Buffed}} -> Buffed;
+ false -> 0
+ end),
+ TotFree div (1024*1024)
+ catch
+ error : undef ->
+ ct:fail({"os_mon not built"})
+ end.
diff --git a/erts/emulator/test/driver_SUITE.erl b/erts/emulator/test/driver_SUITE.erl
index bb0f3498ab..cbed71cedd 100644
--- a/erts/emulator/test/driver_SUITE.erl
+++ b/erts/emulator/test/driver_SUITE.erl
@@ -998,7 +998,9 @@ chkio_test({erts_poll_info, Before},
During = get_check_io_total(erlang:system_info(check_io)),
erlang:display(During),
- 0 = element(1, erts_debug:get_internal_state(check_io_debug)),
+ [0 = element(1, erts_debug:get_internal_state(check_io_debug)) ||
+ %% The pollset is not stable when running the fallback testcase
+ Test /= ?CHKIO_USE_FALLBACK_POLLSET],
io:format("During test: ~p~n", [During]),
chk_chkio_port(Port),
case erlang:port_control(Port, ?CHKIO_STOP, "") of
diff --git a/erts/emulator/test/efile_SUITE.erl b/erts/emulator/test/efile_SUITE.erl
index 55c5343739..045b351e02 100644
--- a/erts/emulator/test/efile_SUITE.erl
+++ b/erts/emulator/test/efile_SUITE.erl
@@ -105,34 +105,27 @@ open_files(Name) ->
%% a /proc directory), let's read some zero sized files 500 times each, while
%% ensuring that response isn't empty << >>
proc_zero_sized_files(Config) when is_list(Config) ->
- {Type, Flavor} = os:type(),
- %% Some files which exist on Linux but might be missing on other systems
- Inputs = ["/proc/cpuinfo",
- "/proc/meminfo",
- "/proc/partitions",
- "/proc/swaps",
- "/proc/version",
- "/proc/uptime",
- %% curproc is present on freebsd
- "/proc/curproc/cmdline"],
- case filelib:is_dir("/proc") of
- false -> {skip, "/proc not found"}; % skip the test if no /proc
- _ when Type =:= unix andalso Flavor =:= sunos ->
- %% SunOS has a /proc, but no zero sized special files
- {skip, "sunos does not have any zero sized special files"};
- true ->
- %% Take away files which do not exist in proc
- Inputs1 = lists:filter(fun filelib:is_file/1, Inputs),
-
- %% Fail if none of mentioned files exist in /proc, did we just get
- %% a normal /proc directory without any special files?
- ?assertNotEqual([], Inputs1),
-
+ TestFiles0 = [%% Some files which exist on Linux but might be missing on
+ %% other systems
+ "/proc/cpuinfo",
+ "/proc/meminfo",
+ "/proc/partitions",
+ "/proc/swaps",
+ "/proc/version",
+ "/proc/uptime",
+ %% curproc is present on FreeBSD
+ "/proc/curproc/cmdline"],
+
+ TestFiles = [F || F <- TestFiles0, filelib:is_file(F)],
+
+ case TestFiles of
+ [_|_] ->
%% For 6 inputs and 500 attempts each this do run anywhere
%% between 500 and 3000 function calls.
- lists:foreach(
- fun(Filename) -> do_proc_zero_sized(Filename, 500) end,
- Inputs1)
+ [do_proc_zero_sized(F, 500) || F <- TestFiles],
+ ok;
+ [] ->
+ {skip, "Failed to find any known zero-sized files"}
end.
%% @doc Test one file N times to also trigger possible leaking fds and memory
diff --git a/erts/emulator/test/lcnt_SUITE.erl b/erts/emulator/test/lcnt_SUITE.erl
index 87b97037d6..2dbaec9942 100644
--- a/erts/emulator/test/lcnt_SUITE.erl
+++ b/erts/emulator/test/lcnt_SUITE.erl
@@ -187,5 +187,8 @@ remove_untoggleable_locks([]) ->
[];
remove_untoggleable_locks([{resource_monitors, _, _, _} | T]) ->
remove_untoggleable_locks(T);
+remove_untoggleable_locks([{'socket[gcnt]', _, _, _} | T]) ->
+ %% Global lock used by socket NIF
+ remove_untoggleable_locks(T);
remove_untoggleable_locks([H | T]) ->
[H | remove_untoggleable_locks(T)].
diff --git a/erts/emulator/test/map_SUITE.erl b/erts/emulator/test/map_SUITE.erl
index d0a6763fe5..9ea59e1084 100644
--- a/erts/emulator/test/map_SUITE.erl
+++ b/erts/emulator/test/map_SUITE.erl
@@ -17,7 +17,7 @@
%% %CopyrightEnd%
%%
-module(map_SUITE).
--export([all/0, suite/0]).
+-export([all/0, suite/0, init_per_suite/1, end_per_suite/1]).
-export([t_build_and_match_literals/1, t_build_and_match_literals_large/1,
t_update_literals/1, t_update_literals_large/1,
@@ -84,7 +84,10 @@
%% instruction-level tests
t_has_map_fields/1,
y_regs/1,
- badmap_17/1]).
+ badmap_17/1,
+
+ %%Bugs
+ t_large_unequal_bins_same_hash_bug/1]).
-include_lib("stdlib/include/ms_transform.hrl").
@@ -149,7 +152,26 @@ all() -> [t_build_and_match_literals, t_build_and_match_literals_large,
%% instruction-level tests
t_has_map_fields,
y_regs,
- badmap_17].
+ badmap_17,
+
+ %% Bugs
+ t_large_unequal_bins_same_hash_bug].
+
+init_per_suite(Config) ->
+ A0 = case application:start(sasl) of
+ ok -> [sasl];
+ _ -> []
+ end,
+ A = case application:start(os_mon) of
+ ok -> [os_mon|A0];
+ _ -> A0
+ end,
+ [{started_apps, A}|Config].
+
+end_per_suite(Config) ->
+ As = proplists:get_value(started_apps, Config),
+ lists:foreach(fun (A) -> application:stop(A) end, As),
+ Config.
%% tests
@@ -3374,3 +3396,67 @@ fannerl() ->
104,2,97,9,97,16,70,63,184,100,97,32,0,0,0,104,2,97,10,97,16,70,63,169,174,
254,64,0,0,0,104,2,97,11,97,16,70,191,119,121,234,0,0,0,0,104,2,97,12,97,
16,70,63,149,12,170,128,0,0,0,104,2,97,13,97,16,70,191,144,193,191,0,0,0,0>>.
+
+%% This test case checks that the bug with ticket number OTP-15707 is
+%% fixed. The bug could cause a crash or memory usage to grow until
+%% the machine ran out of memory.
+t_large_unequal_bins_same_hash_bug(Config) when is_list(Config) ->
+ run_when_enough_resources(
+ fun() ->
+ K1 = get_4GB_bin(1),
+ K2 = get_4GB_bin(2),
+ Map = make_map(500),
+ Map2 = maps:put(K1, 42, Map),
+ %% The map needed to contain at least 32 key-value pairs
+ %% at this point to get the crash or out of memory
+ %% problem on the next line
+ Map3 = maps:put(K2, 43, Map2),
+ %% The following line should avoid that the compiler
+ %% optimizes away the above
+ io:format("~p ~p~n", [erlang:phash2(Map3), maps:size(Map3)])
+ end).
+
+make_map(0) ->
+ #{};
+make_map(Size) ->
+ maps:put(Size, Size, make_map(Size-1)).
+
+get_4GB_bin(Value) ->
+ List = lists:duplicate(65536, Value),
+ Bin = erlang:iolist_to_binary(List),
+ IOList4GB = duplicate_iolist(Bin, 16),
+ Bin4GB = erlang:iolist_to_binary(IOList4GB),
+ 4294967296 = size(Bin4GB),
+ Bin4GB.
+
+duplicate_iolist(IOList, 0) ->
+ IOList;
+duplicate_iolist(IOList, NrOfTimes) ->
+ duplicate_iolist([IOList, IOList], NrOfTimes - 1).
+
+run_when_enough_resources(Fun) ->
+ case {total_memory(), erlang:system_info(wordsize)} of
+ {Mem, 8} when is_integer(Mem) andalso Mem >= 31 ->
+ Fun();
+ {Mem, WordSize} ->
+ {skipped,
+ io_lib:format("Not enough resources (System Memory >= ~p, Word Size = ~p)",
+ [Mem, WordSize])}
+ end.
+
+total_memory() ->
+ %% Total memory in GB.
+ try
+ MemoryData = memsup:get_system_memory_data(),
+ case lists:keysearch(total_memory, 1, MemoryData) of
+ {value, {total_memory, TM}} ->
+ TM div (1024*1024*1024);
+ false ->
+ {value, {system_total_memory, STM}} =
+ lists:keysearch(system_total_memory, 1, MemoryData),
+ STM div (1024*1024*1024)
+ end
+ catch
+ _ : _ ->
+ undefined
+ end.
diff --git a/erts/emulator/test/process_SUITE.erl b/erts/emulator/test/process_SUITE.erl
index c698220013..b530ced566 100644
--- a/erts/emulator/test/process_SUITE.erl
+++ b/erts/emulator/test/process_SUITE.erl
@@ -44,6 +44,7 @@
process_info_garbage_collection/1,
process_info_smoke_all/1,
process_info_status_handled_signal/1,
+ process_info_reductions/1,
bump_reductions/1, low_prio/1, binary_owner/1, yield/1, yield2/1,
otp_4725/1, bad_register/1, garbage_collect/1, otp_6237/1,
process_info_messages/1, process_flag_badarg/1, process_flag_heap_size/1,
@@ -84,6 +85,7 @@ all() ->
process_info_garbage_collection,
process_info_smoke_all,
process_info_status_handled_signal,
+ process_info_reductions,
bump_reductions, low_prio, yield, yield2, otp_4725,
bad_register, garbage_collect, process_info_messages,
process_flag_badarg, process_flag_heap_size,
@@ -1093,6 +1095,46 @@ process_info_status_handled_signal(Config) when is_list(Config) ->
false = erlang:is_process_alive(P),
ok.
+%% OTP-15709
+%% Provoke a bug where process_info(reductions) returned wrong result
+%% because REDS_IN (def_arg_reg[5]) is read when the process in not running.
+process_info_reductions(Config) when is_list(Config) ->
+ pi_reductions_tester(spawn_link(fun() -> pi_reductions_spinnloop() end)),
+ pi_reductions_tester(spawn_link(fun() -> pi_reductions_recvloop() end)),
+ ok.
+
+pi_reductions_tester(Pid) ->
+ {_, DiffList} =
+ lists:foldl(fun(_, {Prev, Acc}) ->
+ %% Add another item that force sending the request
+ %% as a signal, like 'current_function'.
+ PI = process_info(Pid, [reductions, current_function]),
+ [{reductions,Reds}, {current_function,_}] = PI,
+ Diff = Reds - Prev,
+ {Diff, true} = {Diff, (Diff >= 0)},
+ {Diff, true} = {Diff, (Diff =< 1000*1000)},
+ {Reds, [Diff | Acc]}
+ end,
+ {0, []},
+ lists:seq(1,10)),
+ unlink(Pid),
+ exit(Pid,kill),
+ io:format("Reduction diffs: ~p\n", [DiffList]),
+ ok.
+
+pi_reductions_spinnloop() ->
+ %% 6 args to make use of def_arg_reg[5] which is also used as REDS_IN
+ pi_reductions_spinnloop(1, atom, "hej", self(), make_ref(), 3.14).
+
+pi_reductions_spinnloop(A,B,C,D,E,F) ->
+ pi_reductions_spinnloop(B,C,D,E,F,A).
+
+pi_reductions_recvloop() ->
+ receive
+ "a free lunch" -> false
+ end.
+
+
%% Tests erlang:bump_reductions/1.
bump_reductions(Config) when is_list(Config) ->
erlang:garbage_collect(),
diff --git a/erts/emulator/test/small_SUITE.erl b/erts/emulator/test/small_SUITE.erl
new file mode 100644
index 0000000000..00a02e5560
--- /dev/null
+++ b/erts/emulator/test/small_SUITE.erl
@@ -0,0 +1,115 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(small_SUITE).
+
+-export([all/0, suite/0]).
+-export([edge_cases/1]).
+
+-include_lib("common_test/include/ct.hrl").
+
+suite() ->
+ [{ct_hooks,[ts_install_cth]},
+ {timetrap, {minutes, 1}}].
+
+all() ->
+ [edge_cases].
+
+edge_cases(Config) when is_list(Config) ->
+ {MinSmall, MaxSmall} = Limits = determine_small_limits(0),
+ ct:pal("Limits = ~p", [Limits]),
+
+ true = (MaxSmall + 1) =:= MaxSmall + id(1),
+ true = (MinSmall - 1) =:= MinSmall - id(1),
+ true = (MaxSmall + 1) > id(MaxSmall),
+ true = (MinSmall - 1) < id(MinSmall),
+ -1 = MinSmall + id(MaxSmall),
+ -1 = MaxSmall + id(MinSmall),
+
+ false = is_small(MinSmall * -1),
+ false = is_small(MinSmall - id(1)),
+ false = is_small(MinSmall - 1),
+ false = is_small(MaxSmall + id(1)),
+
+ Lower = lists:seq(MinSmall, MinSmall + 128),
+ Upper = lists:seq(MaxSmall, MaxSmall - 128, -1),
+ Pow2 = seq_pow2(MinSmall, MaxSmall),
+ NearZero = lists:seq(-128, 128),
+
+ ok = test_combinations([Lower, Upper, Pow2, NearZero], MinSmall, MaxSmall),
+
+ ok.
+
+test_combinations([As | Rest]=TestVectors, MinS, MaxS) ->
+ [begin
+ _ = [arith_test(A, B, MinS, MaxS) || B <- Bs]
+ end || A <- As, Bs <- TestVectors],
+ test_combinations(Rest, MinS, MaxS);
+test_combinations([], _MinS, _MaxS) ->
+ ok.
+
+%% Builds a sequence of all powers of 2 between MinSmall and MaxSmall
+seq_pow2(MinSmall, MaxSmall) ->
+ sp2_1(MinSmall, MinSmall, MaxSmall).
+
+sp2_1(N, _MinS, MaxS) when N >= MaxS ->
+ [];
+sp2_1(-1, MinS, MaxS) ->
+ [-1 | sp2_1(1, MinS, MaxS)];
+sp2_1(N, MinS, MaxS) when N < 0 ->
+ [N | sp2_1(N bsr 1, MinS, MaxS)];
+sp2_1(N, MinS, MaxS) when N > 0 ->
+ [N | sp2_1(N bsl 1, MinS, MaxS)].
+
+arith_test(A, B, MinS, MaxS) ->
+ verify_kind(A + B, MinS, MaxS),
+ verify_kind(B + A, MinS, MaxS),
+ verify_kind(A - B, MinS, MaxS),
+ verify_kind(B - A, MinS, MaxS),
+ verify_kind(A * B, MinS, MaxS),
+ verify_kind(B * A, MinS, MaxS),
+
+ true = A + B =:= apply(erlang, id('+'), [A, B]),
+ true = A - B =:= apply(erlang, id('-'), [A, B]),
+ true = A * B =:= apply(erlang, id('*'), [A, B]),
+
+ true = A + B =:= B + id(A),
+ true = A - B =:= A + id(-B),
+ true = B - A =:= B + id(-A),
+ true = A * B =:= B * id(A),
+
+ true = B =:= 0 orelse ((A * B) div id(B) =:= A),
+ true = A =:= 0 orelse ((B * A) div id(A) =:= B),
+
+ ok.
+
+%% Verifies that N is a small when it should be
+verify_kind(N, MinS, MaxS) ->
+ true = is_small(N) =:= (N >= MinS andalso N =< MaxS).
+
+is_small(N) when is_integer(N) ->
+ 0 =:= erts_debug:flat_size(N).
+
+determine_small_limits(N) ->
+ case is_small(-1 bsl N) of
+ true -> determine_small_limits(N + 1);
+ false -> {-1 bsl (N - 1), (1 bsl (N - 1)) - 1}
+ end.
+
+id(I) -> I.
diff --git a/erts/emulator/test/statistics_SUITE.erl b/erts/emulator/test/statistics_SUITE.erl
index ae3099633a..d278ac86c7 100644
--- a/erts/emulator/test/statistics_SUITE.erl
+++ b/erts/emulator/test/statistics_SUITE.erl
@@ -93,25 +93,34 @@ wall_clock_zero_diff1(0) ->
%% statistics(wall_clock) are compatible, and are within a small number
%% of ms of the amount of real time we waited for.
wall_clock_update(Config) when is_list(Config) ->
- wall_clock_update1(6).
+ N = 10,
+ Inc = 200,
+ TotalTime = wall_clock_update1(N, Inc, 0),
+ Overhead = TotalTime - N * Inc,
+ IsDebug = test_server:is_debug(),
-wall_clock_update1(N) when N > 0 ->
- {T1_wc_time, _} = statistics(wall_clock),
- receive after 1000 -> ok end,
- {T2_wc_time, Wc_Diff} = statistics(wall_clock),
-
- Wc_Diff = T2_wc_time - T1_wc_time,
- io:format("Wall clock diff = ~p; should be = 1000..1040~n", [Wc_Diff]),
- case test_server:is_debug() of
- false ->
- true = Wc_Diff =< 1040;
+ %% Check that the average overhead is reasonable.
+ if
+ Overhead < N * 100 ->
+ ok;
+ IsDebug, Overhead < N * 1000 ->
+ ok;
true ->
- true = Wc_Diff =< 2000 %Be more tolerant in debug-compiled emulator.
- end,
- true = Wc_Diff >= 1000,
- wall_clock_update1(N-1);
-wall_clock_update1(0) ->
- ok.
+ io:format("There was an overhead of ~p ms during ~p rounds.",
+ [Overhead,N]),
+ ct:fail(too_much_overhead)
+ end.
+
+wall_clock_update1(N, Inc, Total) when N > 0 ->
+ {Time1, _} = statistics(wall_clock),
+ receive after Inc -> ok end,
+ {Time2, WcDiff} = statistics(wall_clock),
+ WcDiff = Time2 - Time1,
+ io:format("Wall clock diff = ~p (expected at least ~p)\n", [WcDiff,Inc]),
+ true = WcDiff >= Inc,
+ wall_clock_update1(N-1, Inc, Total + WcDiff);
+wall_clock_update1(0, _, Total) ->
+ Total.
%%% Test statistics(runtime).
diff --git a/erts/include/internal/ethr_internal.h b/erts/include/internal/ethr_internal.h
index ac27ff2ed0..17ec84c52b 100644
--- a/erts/include/internal/ethr_internal.h
+++ b/erts/include/internal/ethr_internal.h
@@ -90,7 +90,7 @@ int ethr_init_common__(ethr_init_data *id);
int ethr_late_init_common__(ethr_late_init_data *lid);
void ethr_run_exit_handlers__(void);
void ethr_ts_event_destructor__(void *vtsep);
-void ethr_set_stacklimit__(char *prev_c, size_t stacksize);
+void ethr_set_stacklimit__(char *prev_c, size_t stacksize) ETHR_NOINLINE;
#if defined(ETHR_X86_RUNTIME_CONF__)
void ethr_x86_cpuid__(int *eax, int *ebx, int *ecx, int *edx);
diff --git a/erts/include/internal/ethread_inline.h b/erts/include/internal/ethread_inline.h
index 8e6bcfc4a8..791d7fa0ff 100644
--- a/erts/include/internal/ethread_inline.h
+++ b/erts/include/internal/ethread_inline.h
@@ -62,12 +62,15 @@
# define ETHR_INLINE __inline__
# if ETHR_AT_LEAST_GCC_VSN__(3, 1, 1)
# define ETHR_FORCE_INLINE __inline__ __attribute__((__always_inline__))
+# define ETHR_NOINLINE __attribute__((__noinline__))
# else
# define ETHR_FORCE_INLINE __inline__
+# define ETHR_NOINLINE
# endif
#elif defined(__WIN32__)
# define ETHR_INLINE __forceinline
# define ETHR_FORCE_INLINE __forceinline
+# define ETHR_NOINLINE
#endif
#endif /* #ifndef ETHREAD_INLINE_H__ */
diff --git a/erts/vsn.mk b/erts/vsn.mk
index 3942af7f78..bce5ce4167 100644
--- a/erts/vsn.mk
+++ b/erts/vsn.mk
@@ -18,7 +18,7 @@
# %CopyrightEnd%
#
-VSN = 10.3.1
+VSN = 10.3.2
# Port number 4365 in 4.2
# Port number 4366 in 4.3
diff --git a/lib/common_test/doc/src/ct_master.xml b/lib/common_test/doc/src/ct_master.xml
index 2ab421fe9e..f003b7de11 100644
--- a/lib/common_test/doc/src/ct_master.xml
+++ b/lib/common_test/doc/src/ct_master.xml
@@ -210,7 +210,7 @@
</type>
<desc><marker id="run_test-2"/>
<p>Tests are spawned on <c>Node</c> using
- <seealso marker="ct:run_test-1"><c>ct:run_test/1</c></seealso></p>
+ <seealso marker="ct#run_test-1"><c>ct:run_test/1</c></seealso></p>
</desc>
</func>
</funcs>
diff --git a/lib/common_test/doc/src/event_handler_chapter.xml b/lib/common_test/doc/src/event_handler_chapter.xml
index bd9ed21cb4..182abba7ca 100644
--- a/lib/common_test/doc/src/event_handler_chapter.xml
+++ b/lib/common_test/doc/src/event_handler_chapter.xml
@@ -378,7 +378,7 @@
<note><p>To ensure that printouts to <c>stdout</c> (or printouts made with
<seealso marker="ct#log-2"><c>ct:log/2,3</c></seealso> or
- <seealso marker="ct:pal-2"><c>ct:pal,2,3</c></seealso>) get written to the test case log
+ <seealso marker="ct#pal-2"><c>ct:pal,2,3</c></seealso>) get written to the test case log
file, and not to the <c>Common Test</c> framework log, you can synchronize
with the <c>Common Test</c> server by matching on evvents <c>tc_start</c> and <c>tc_done</c>.
In the period between these events, all I/O is directed to the
diff --git a/lib/common_test/src/test_server_node.erl b/lib/common_test/src/test_server_node.erl
index ea7ad8538e..3ae4a047d8 100644
--- a/lib/common_test/src/test_server_node.erl
+++ b/lib/common_test/src/test_server_node.erl
@@ -656,9 +656,19 @@ find_release({unix,linux}, Rel) ->
find_release(_, _) -> none.
find_rel_linux(Rel) ->
- case suse_release() of
- none -> [];
- SuseRel -> find_rel_suse(Rel, SuseRel)
+ try
+ case ubuntu_release() of
+ none -> none;
+ [UbuntuRel |_] -> throw(find_rel_ubuntu(Rel, UbuntuRel))
+ end,
+ case suse_release() of
+ none -> none;
+ SuseRel -> throw(find_rel_suse(Rel, SuseRel))
+ end,
+ []
+ catch
+ throw:Result ->
+ Result
end.
find_rel_suse(Rel, SuseRel) ->
@@ -735,6 +745,93 @@ suse_release(Fd) ->
end
end.
+find_rel_ubuntu(_Rel, UbuntuRel) when is_integer(UbuntuRel), UbuntuRel < 16 ->
+ [];
+find_rel_ubuntu(Rel, UbuntuRel) when is_integer(UbuntuRel) ->
+ Root = "/usr/local/otp/releases/ubuntu",
+ lists:foldl(fun (ChkUbuntuRel, Acc) ->
+ find_rel_ubuntu_aux1(Rel, Root++integer_to_list(ChkUbuntuRel))
+ ++ Acc
+ end,
+ [],
+ lists:seq(16, UbuntuRel)).
+
+find_rel_ubuntu_aux1(Rel, RootWc) ->
+ case erlang:system_info(wordsize) of
+ 4 ->
+ find_rel_ubuntu_aux2(Rel, RootWc++"_32");
+ 8 ->
+ find_rel_ubuntu_aux2(Rel, RootWc++"_64") ++
+ find_rel_ubuntu_aux2(Rel, RootWc++"_32")
+ end.
+
+find_rel_ubuntu_aux2(Rel, RootWc) ->
+ RelDir = filename:dirname(RootWc),
+ Pat = filename:basename(RootWc ++ "_" ++ Rel) ++ ".*",
+ case file:list_dir(RelDir) of
+ {ok,Dirs} ->
+ case lists:filter(fun(Dir) ->
+ case re:run(Dir, Pat, [unicode]) of
+ nomatch -> false;
+ _ -> true
+ end
+ end, Dirs) of
+ [] ->
+ [];
+ [R|_] ->
+ [filename:join([RelDir,R,"bin","erl"])]
+ end;
+ _ ->
+ []
+ end.
+
+ubuntu_release() ->
+ case file:open("/etc/lsb-release", [read]) of
+ {ok,Fd} ->
+ try
+ ubuntu_release(Fd, undefined, undefined)
+ after
+ file:close(Fd)
+ end;
+ {error,_} -> none
+ end.
+
+ubuntu_release(_Fd, DistrId, Rel) when DistrId /= undefined,
+ Rel /= undefined ->
+ Ubuntu = case DistrId of
+ "Ubuntu" -> true;
+ "ubuntu" -> true;
+ _ -> false
+ end,
+ case Ubuntu of
+ false -> none;
+ true -> Rel
+ end;
+ubuntu_release(Fd, DistroId, Rel) ->
+ case io:get_line(Fd, '') of
+ eof ->
+ none;
+ Line when is_list(Line) ->
+ case re:run(Line, "^DISTRIB_ID=(\\w+)$",
+ [{capture,all_but_first,list}]) of
+ {match,[NewDistroId]} ->
+ ubuntu_release(Fd, NewDistroId, Rel);
+ nomatch ->
+ case re:run(Line, "^DISTRIB_RELEASE=(\\d+(?:\\.\\d+)*)$",
+ [{capture,all_but_first,list}]) of
+ {match,[RelList]} ->
+ NewRel = lists:map(fun (N) ->
+ list_to_integer(N)
+ end,
+ string:lexemes(RelList, ".")),
+ ubuntu_release(Fd, DistroId, NewRel);
+ nomatch ->
+ ubuntu_release(Fd, DistroId, Rel)
+ end
+ end
+ end.
+
+
unpack(Bin) ->
{One,Term} = split_binary(Bin, 1),
case binary_to_list(One) of
diff --git a/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl b/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl
index 7aaf33839f..69a7de1431 100644
--- a/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl
+++ b/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl
@@ -271,7 +271,7 @@ no_client_hello(Config) ->
%% Tell server to receive a get request and then die without
%% replying since no hello has been received. (is this correct
- %% behavoiur??)
+ %% behaviour??)
?NS:expect_do(get,close),
{error,closed} = ct_netconfc:get(Client,whatever),
ok.
diff --git a/lib/compiler/doc/src/Makefile b/lib/compiler/doc/src/Makefile
index 32f150eef8..2fb163b9e7 100644
--- a/lib/compiler/doc/src/Makefile
+++ b/lib/compiler/doc/src/Makefile
@@ -31,6 +31,7 @@ APPLICATION=compiler
# Release directory specification
# ----------------------------------------------------
RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
+COMPILER_DIR = $(ERL_TOP)/lib/compiler/src
# ----------------------------------------------------
# Target Specs
@@ -38,7 +39,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
XML_APPLICATION_FILES = ref_man.xml
XML_REF3_FILES = compile.xml
-XML_PART_FILES =
+XML_PART_FILES = internal.xml
XML_CHAPTER_FILES = notes.xml
BOOK_FILES = book.xml
@@ -49,6 +50,9 @@ XML_FILES = \
$(BOOK_FILES) $(XML_CHAPTER_FILES) \
$(XML_PART_FILES) $(XML_REF3_FILES) $(XML_APPLICATION_FILES)
+XML_INTERNAL_FILES = \
+ cerl.xml cerl_trees.xml cerl_clauses.xml
+
# ----------------------------------------------------
HTML_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \
@@ -62,6 +66,8 @@ HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
+XML_GEN_FILES = $(XML_INTERNAL_FILES:%=$(XMLDIR)/%)
+
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
@@ -85,6 +91,9 @@ man: $(MAN3_FILES)
gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
+$(XML_INTERNAL_FILES:%=$(XMLDIR)/%): $(COMPILER_DIR)/$(@:$(XMLDIR)/%.xml=%.erl)
+ $(gen_verbose)escript $(DOCGEN)/priv/bin/xml_from_edoc.escript -def vsn $(COMPILER_VSN) -dir $(XMLDIR) $(COMPILER_DIR)/$(@:$(XMLDIR)/%.xml=%.erl)
+
debug opt:
clean clean_docs:
diff --git a/lib/compiler/doc/src/book.xml b/lib/compiler/doc/src/book.xml
index af6b4cf47a..d101d40cb4 100644
--- a/lib/compiler/doc/src/book.xml
+++ b/lib/compiler/doc/src/book.xml
@@ -38,6 +38,9 @@
<applications>
<xi:include href="ref_man.xml"/>
</applications>
+ <internals>
+ <xi:include href="internal.xml"/>
+ </internals>
<releasenotes>
<xi:include href="notes.xml"/>
</releasenotes>
diff --git a/lib/compiler/doc/src/compile.xml b/lib/compiler/doc/src/compile.xml
index 5219ba0f5d..549b1049d8 100644
--- a/lib/compiler/doc/src/compile.xml
+++ b/lib/compiler/doc/src/compile.xml
@@ -632,6 +632,22 @@ module.beam: module.erl \
to be deprecated.</p>
</item>
+ <tag><c>nowarn_removed</c></tag>
+ <item>
+ <p>Turns off warnings for calls to functions that have
+ been removed. Default is to emit warnings for every call
+ to a function known by the compiler to have been recently
+ removed from Erlang/OTP.</p>
+ </item>
+
+ <tag><c>{nowarn_removed, ModulesOrMFAs}</c></tag>
+ <item>
+ <p>Turns off warnings for calls to modules or functions
+ that have been removed. Default is to emit warnings for
+ every call to a function known by the compiler to have
+ been recently removed from Erlang/OTP.</p>
+ </item>
+
<tag><c>nowarn_obsolete_guard</c></tag>
<item>
<p>Turns off warnings for calls to old type testing BIFs,
diff --git a/lib/compiler/doc/src/internal.xml b/lib/compiler/doc/src/internal.xml
new file mode 100644
index 0000000000..f24b363c1c
--- /dev/null
+++ b/lib/compiler/doc/src/internal.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE part SYSTEM "part.dtd">
+
+<internal xmlns:xi="http://www.w3.org/2001/XInclude">
+ <header>
+ <copyright>
+ <year>2018</year><year>2018</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ </legalnotice>
+
+ <title>Compiler Internal Documentation</title>
+ <prepared>Lukas Larsson</prepared>
+ <docno></docno>
+ <date>2018-07-07</date>
+ <rev>1.0.0</rev>
+ <file>internal.xml</file>
+ </header>
+ <description>
+ </description>
+ <xi:include href="cerl.xml"/>
+ <xi:include href="cerl_trees.xml"/>
+ <xi:include href="cerl_clauses.xml"/>
+</internal>
+
diff --git a/lib/compiler/src/cerl.erl b/lib/compiler/src/cerl.erl
index fce23bfd68..62cd5b5120 100644
--- a/lib/compiler/src/cerl.erl
+++ b/lib/compiler/src/cerl.erl
@@ -2157,12 +2157,16 @@ values_arity(Node) ->
%% @spec c_binary(Segments::[cerl()]) -> cerl()
%%
-%% @doc Creates an abstract binary-template. A binary object is a
-%% sequence of 8-bit bytes. It is specified by zero or more bit-string
-%% template <em>segments</em> of arbitrary lengths (in number of bits),
-%% such that the sum of the lengths is evenly divisible by 8. If
-%% <code>Segments</code> is <code>[S1, ..., Sn]</code>, the result
-%% represents "<code>#{<em>S1</em>, ..., <em>Sn</em>}#</code>". All the
+
+%% @doc Creates an abstract binary-template. A binary object is in
+%% this context a sequence of an arbitrary number of bits. (The number
+%% of bits used to be evenly divisible by 8, but after the
+%% introduction of bit strings in the Erlang language, the choice was
+%% made to use the binary template for all bit strings.) It is
+%% specified by zero or more bit-string template <em>segments</em> of
+%% arbitrary lengths (in number of bits). If <code>Segments</code> is
+%% <code>[S1, ..., Sn]</code>, the result represents
+%% "<code>#{<em>S1</em>, ..., <em>Sn</em>}#</code>". All the
%% <code>Si</code> must have type <code>bitstr</code>.
%%
%% @see ann_c_binary/2
diff --git a/lib/compiler/src/cerl_clauses.erl b/lib/compiler/src/cerl_clauses.erl
index fa5104c01b..3fd7ddd181 100644
--- a/lib/compiler/src/cerl_clauses.erl
+++ b/lib/compiler/src/cerl_clauses.erl
@@ -14,8 +14,8 @@
%% @author Richard Carlsson <[email protected]>
%% @doc Utility functions for Core Erlang case/receive clauses.
%%
-%% <p>Syntax trees are defined in the module <a
-%% href=""><code>cerl</code></a>.</p>
+%% <p>Syntax trees are defined in the module
+%% <a href="cerl"><code>cerl</code></a>.</p>
%%
%% @type cerl() = cerl:cerl()
diff --git a/lib/compiler/src/core_parse.hrl b/lib/compiler/src/core_parse.hrl
index 83a6f0179c..90c796d3d9 100644
--- a/lib/compiler/src/core_parse.hrl
+++ b/lib/compiler/src/core_parse.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -29,81 +29,82 @@
%% The record definitions appear alphabetically
--record(c_alias, {anno=[], var, % var :: Tree,
- pat}). % pat :: Tree
+-record(c_alias, {anno=[] :: list(), var :: cerl:cerl(),
+ pat :: cerl:cerl()}).
--record(c_apply, {anno=[], op, % op :: Tree,
- args}). % args :: [Tree]
+-record(c_apply, {anno=[] :: list(), op :: cerl:cerl(),
+ args :: [cerl:cerl()]}).
--record(c_binary, {anno=[], segments :: [cerl:c_bitstr()]}).
+-record(c_binary, {anno=[] :: list(), segments :: [cerl:c_bitstr()]}).
--record(c_bitstr, {anno=[], val, % val :: Tree,
- size, % size :: Tree,
- unit, % unit :: Tree,
- type, % type :: Tree,
- flags}). % flags :: Tree
+-record(c_bitstr, {anno=[] :: list(), val :: cerl:cerl(),
+ size :: cerl:cerl(),
+ unit :: cerl:cerl(),
+ type :: cerl:cerl(),
+ flags :: cerl:cerl()}).
--record(c_call, {anno=[], module, % module :: Tree,
- name, % name :: Tree,
- args}). % args :: [Tree]
+-record(c_call, {anno=[] :: list(), module :: cerl:cerl(),
+ name :: cerl:cerl(),
+ args :: [cerl:cerl()]}).
--record(c_case, {anno=[], arg, % arg :: Tree,
- clauses}). % clauses :: [Tree]
+-record(c_case, {anno=[] :: list(), arg :: cerl:cerl(),
+ clauses :: [cerl:cerl()]}).
--record(c_catch, {anno=[], body}). % body :: Tree
+-record(c_catch, {anno=[] :: list(), body :: cerl:cerl()}).
--record(c_clause, {anno=[], pats, % pats :: [Tree],
- guard, % guard :: Tree,
- body}). % body :: Tree
+-record(c_clause, {anno=[] :: list(), pats :: [cerl:cerl()],
+ guard :: cerl:cerl(),
+ body :: cerl:cerl() | any()}). % TODO
--record(c_cons, {anno=[], hd, % hd :: Tree,
- tl}). % tl :: Tree
+-record(c_cons, {anno=[] :: list(), hd :: cerl:cerl(),
+ tl :: cerl:cerl()}).
--record(c_fun, {anno=[], vars, % vars :: [Tree],
- body}). % body :: Tree
+-record(c_fun, {anno=[] :: list(), vars :: [cerl:cerl()],
+ body :: cerl:cerl()}).
--record(c_let, {anno=[], vars, % vars :: [Tree],
- arg, % arg :: Tree,
- body}). % body :: Tree
+-record(c_let, {anno=[] :: list(), vars :: [cerl:cerl()],
+ arg :: cerl:cerl(),
+ body :: cerl:cerl()}).
--record(c_letrec, {anno=[], defs, % defs :: [#c_def{}],
- body}). % body :: Tree
+-record(c_letrec, {anno=[] :: list(),
+ defs :: [{cerl:cerl(), cerl:cerl()}],
+ body :: cerl:cerl()}).
--record(c_literal, {anno=[], val}). % val :: literal()
+-record(c_literal, {anno=[] :: list(), val :: any()}).
--record(c_map, {anno=[],
+-record(c_map, {anno=[] :: list(),
arg=#c_literal{val=#{}} :: cerl:c_var() | cerl:c_literal(),
es :: [cerl:c_map_pair()],
is_pat=false :: boolean()}).
--record(c_map_pair, {anno=[],
+-record(c_map_pair, {anno=[] :: list(),
op :: #c_literal{val::'assoc'} | #c_literal{val::'exact'},
- key,
- val}).
+ key :: any(), % TODO
+ val :: any()}). % TODO
--record(c_module, {anno=[], name, % name :: Tree,
- exports, % exports :: [Tree],
- attrs, % attrs :: [#c_def{}],
- defs}). % defs :: [#c_def{}]
+-record(c_module, {anno=[] :: list(), name :: cerl:cerl(),
+ exports :: [cerl:cerl()],
+ attrs :: [{cerl:cerl(), cerl:cerl()}],
+ defs :: [{cerl:cerl(), cerl:cerl()}]}).
--record(c_primop, {anno=[], name, % name :: Tree,
- args}). % args :: [Tree]
+-record(c_primop, {anno=[] :: list(), name :: cerl:cerl(),
+ args :: [cerl:cerl()]}).
--record(c_receive, {anno=[], clauses, % clauses :: [Tree],
- timeout, % timeout :: Tree,
- action}). % action :: Tree
+-record(c_receive, {anno=[] :: list(), clauses :: [cerl:cerl()],
+ timeout :: cerl:cerl(),
+ action :: cerl:cerl()}).
--record(c_seq, {anno=[], arg, % arg :: Tree,
- body}). % body :: Tree
+-record(c_seq, {anno=[] :: list(), arg :: cerl:cerl() | any(), % TODO
+ body :: cerl:cerl()}).
--record(c_try, {anno=[], arg, % arg :: Tree,
- vars, % vars :: [Tree],
- body, % body :: Tree
- evars, % evars :: [Tree],
- handler}). % handler :: Tree
+-record(c_try, {anno=[] :: list(), arg :: cerl:cerl(),
+ vars :: [cerl:cerl()],
+ body :: cerl:cerl(),
+ evars :: [cerl:cerl()],
+ handler :: cerl:cerl()}).
--record(c_tuple, {anno=[], es}). % es :: [Tree]
+-record(c_tuple, {anno=[] :: list(), es :: [cerl:cerl()]}).
--record(c_values, {anno=[], es}). % es :: [Tree]
+-record(c_values, {anno=[] :: list(), es :: [cerl:cerl()]}).
--record(c_var, {anno=[], name :: cerl:var_name()}).
+-record(c_var, {anno=[] :: list(), name :: cerl:var_name()}).
diff --git a/lib/crypto/c_src/aead.c b/lib/crypto/c_src/aead.c
index 4ed16615a5..ab0e609130 100644
--- a/lib/crypto/c_src/aead.c
+++ b/lib/crypto/c_src/aead.c
@@ -22,36 +22,65 @@
#include "aes.h"
#include "cipher.h"
-ERL_NIF_TERM aead_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Type,Key,Iv,AAD,In) */
+
+
+ERL_NIF_TERM aead_cipher(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/*
+ (Type,Key,Iv,AAD,In,TagLen,true)
+ (Type,Key,Iv,AAD,In,Tag,false)
+ */
#if defined(HAVE_AEAD)
const struct cipher_type_t *cipherp;
EVP_CIPHER_CTX *ctx = NULL;
const EVP_CIPHER *cipher = NULL;
- ErlNifBinary key, iv, aad, in;
+ ErlNifBinary key, iv, aad, in, tag;
unsigned int tag_len;
- unsigned char *outp, *tagp;
- ERL_NIF_TERM type, out, out_tag, ret;
- int len, ctx_ctrl_set_ivlen, ctx_ctrl_get_tag, ctx_ctrl_set_tag;
+ unsigned char *outp, *tagp, *tag_data;
+ ERL_NIF_TERM type, out, out_tag, ret, encflg_arg;
+ int len, encflg;
+
+ encflg_arg = argv[6];
+
+ /* Fetch the flag telling if we are going to encrypt (=true) or decrypt (=false) */
+ if (encflg_arg == atom_true)
+ encflg = 1;
+ else if (encflg_arg == atom_false)
+ encflg = 0;
+ else if (encflg_arg == atom_undefined)
+ /* For compat funcs in crypto.erl */
+ encflg = -1;
+ else
+ {
+ ret = EXCP_BADARG(env, "Bad enc flag");
+ goto done;
+ }
type = argv[0];
- ASSERT(argc == 6);
-
if (!enif_is_atom(env, type))
{ret = EXCP_BADARG(env, "non-atom cipher type"); goto done;}
if (!enif_inspect_iolist_as_binary(env, argv[1], &key))
{ret = EXCP_BADARG(env, "non-binary key"); goto done;}
- if (!enif_inspect_binary(env, argv[2], &iv))
+ if (!enif_inspect_iolist_as_binary(env, argv[2], &iv))
{ret = EXCP_BADARG(env, "non-binary iv"); goto done;}
- if (!enif_inspect_iolist_as_binary(env, argv[3], &aad))
- {ret = EXCP_BADARG(env, "non-binary AAD"); goto done;}
- if (!enif_inspect_iolist_as_binary(env, argv[4], &in))
+ if (!enif_inspect_iolist_as_binary(env, argv[3], &in))
{ret = EXCP_BADARG(env, "non-binary text"); goto done;}
- if (!enif_get_uint(env, argv[5], &tag_len))
- {ret = EXCP_BADARG(env, ""); goto done;}
+ if (!enif_inspect_iolist_as_binary(env, argv[4], &aad))
+ {ret = EXCP_BADARG(env, "non-binary AAD"); goto done;}
+
+ if (encflg) {
+ if (!enif_get_uint(env, argv[5], &tag_len))
+ {ret = EXCP_BADARG(env, "Bad Tag length"); goto done;}
+ tag_data = NULL;
+ } else {
+ if (!enif_inspect_iolist_as_binary(env, argv[5], &tag))
+ {ret = EXCP_BADARG(env, "non-binary Tag"); goto done;}
+ tag_len = tag.size;
+ tag_data = tag.data;
+ }
if (tag_len > INT_MAX
+ || key.size > INT_MAX
|| iv.size > INT_MAX
|| in.size > INT_MAX
|| aad.size > INT_MAX)
@@ -66,167 +95,88 @@ ERL_NIF_TERM aead_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
if ((cipher = cipherp->cipher.p) == NULL)
{ret = EXCP_NOTSUP(env, "Cipher not supported in this libcrypto version"); goto done;}
- ctx_ctrl_set_ivlen = cipherp->extra.aead.ctx_ctrl_set_ivlen;
- ctx_ctrl_get_tag = cipherp->extra.aead.ctx_ctrl_get_tag;
- ctx_ctrl_set_tag = cipherp->extra.aead.ctx_ctrl_set_tag;
-
+#if defined(HAVE_GCM_EVP_DECRYPT_BUG)
+ if ( !encflg && (cipherp->flags & GCM_MODE))
+ return aes_gcm_decrypt_NO_EVP(env, argc, argv);
+#endif
+
if ((ctx = EVP_CIPHER_CTX_new()) == NULL)
- {ret = EXCP_ERROR(env, ""); goto done;}
+ {ret = EXCP_ERROR(env, "Can't allocate ctx"); goto done;}
- if (EVP_EncryptInit_ex(ctx, cipher, NULL, NULL, NULL) != 1)
- {ret = EXCP_ERROR(env, ""); goto done;}
- if (EVP_CIPHER_CTX_ctrl(ctx, ctx_ctrl_set_ivlen, (int)iv.size, NULL) != 1)
- {ret = EXCP_ERROR(env, ""); goto done;}
+ if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, encflg) != 1)
+ {ret = EXCP_ERROR(env, "CipherInit failed"); goto done;}
+ if (EVP_CIPHER_CTX_ctrl(ctx, cipherp->extra.aead.ctx_ctrl_set_ivlen, (int)iv.size, NULL) != 1)
+ {ret = EXCP_BADARG(env, "Bad IV length"); goto done;}
#if defined(HAVE_CCM)
- if (type == atom_aes_ccm) {
- if (EVP_CIPHER_CTX_ctrl(ctx, ctx_ctrl_set_tag, (int)tag_len, NULL) != 1)
- {ret = EXCP_ERROR(env, ""); goto done;}
- if (EVP_EncryptInit_ex(ctx, NULL, NULL, key.data, iv.data) != 1)
- {ret = EXCP_ERROR(env, ""); goto done;}
- if (EVP_EncryptUpdate(ctx, NULL, &len, NULL, (int)in.size) != 1)
- {ret = EXCP_ERROR(env, ""); goto done;}
+ if (cipherp->flags & CCM_MODE) {
+ if (EVP_CIPHER_CTX_ctrl(ctx, cipherp->extra.aead.ctx_ctrl_set_tag, (int)tag_len, tag_data) != 1)
+ {ret = EXCP_BADARG(env, "Can't set tag"); goto done;}
+ if (EVP_CipherInit_ex(ctx, NULL, NULL, key.data, iv.data, -1) != 1)
+ {ret = EXCP_BADARG(env, "Can't set key or iv"); goto done;}
+ if (EVP_CipherUpdate(ctx, NULL, &len, NULL, (int)in.size) != 1)
+ {ret = EXCP_BADARG(env, "Can't set text size"); goto done;}
} else
#endif
{
- if (EVP_EncryptInit_ex(ctx, NULL, NULL, key.data, iv.data) != 1)
- {ret = EXCP_ERROR(env, ""); goto done;}
+ if (EVP_CipherInit_ex(ctx, NULL, NULL, key.data, iv.data, -1) != 1)
+ {ret = EXCP_BADARG(env, "Can't set key or iv"); goto done;}
}
- if (EVP_EncryptUpdate(ctx, NULL, &len, aad.data, (int)aad.size) != 1)
- {ret = EXCP_ERROR(env, ""); goto done;}
+ if (EVP_CipherUpdate(ctx, NULL, &len, aad.data, (int)aad.size) != 1)
+ {ret = EXCP_BADARG(env, "Can't set AAD"); goto done;}
if ((outp = enif_make_new_binary(env, in.size, &out)) == NULL)
- {ret = EXCP_ERROR(env, ""); goto done;}
-
- if (EVP_EncryptUpdate(ctx, outp, &len, in.data, (int)in.size) != 1)
- {ret = EXCP_ERROR(env, ""); goto done;}
- if (EVP_EncryptFinal_ex(ctx, outp/*+len*/, &len) != 1)
- {ret = EXCP_ERROR(env, ""); goto done;}
-
- if ((tagp = enif_make_new_binary(env, tag_len, &out_tag)) == NULL)
- {ret = EXCP_ERROR(env, ""); goto done;}
+ {ret = EXCP_ERROR(env, "Can't make 'Out' binary"); goto done;}
- if (EVP_CIPHER_CTX_ctrl(ctx, ctx_ctrl_get_tag, (int)tag_len, tagp) != 1)
- {ret = EXCP_ERROR(env, ""); goto done;}
-
- CONSUME_REDS(env, in);
- ret = enif_make_tuple2(env, out, out_tag);
-
- done:
- if (ctx)
- EVP_CIPHER_CTX_free(ctx);
- return ret;
-
-#else
- return EXCP_NOTSUP(env, "");
-#endif
-}
-
-ERL_NIF_TERM aead_decrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Type,Key,Iv,AAD,In,Tag) */
-#if defined(HAVE_AEAD)
- const struct cipher_type_t *cipherp;
- EVP_CIPHER_CTX *ctx = NULL;
- const EVP_CIPHER *cipher = NULL;
- ErlNifBinary key, iv, aad, in, tag;
- unsigned char *outp;
- ERL_NIF_TERM type, out, ret;
- int len, ctx_ctrl_set_ivlen, ctx_ctrl_set_tag;
-
- ASSERT(argc == 6);
-
- type = argv[0];
-#if defined(HAVE_GCM_EVP_DECRYPT_BUG)
- if (type == atom_aes_gcm)
- return aes_gcm_decrypt_NO_EVP(env, argc, argv);
-#endif
-
- if (!enif_is_atom(env, type))
- {ret = EXCP_BADARG(env, "non-atom cipher type"); goto done;}
- if (!enif_inspect_iolist_as_binary(env, argv[1], &key))
- {ret = EXCP_BADARG(env, "non-binary key"); goto done;}
- if (!enif_inspect_binary(env, argv[2], &iv))
- {ret = EXCP_BADARG(env, "non-binary iv"); goto done;}
- if (!enif_inspect_iolist_as_binary(env, argv[3], &aad))
- {ret = EXCP_BADARG(env, "non-binary AAD"); goto done;}
- if (!enif_inspect_iolist_as_binary(env, argv[4], &in))
- {ret = EXCP_BADARG(env, ""); goto done;}
- if (!enif_inspect_iolist_as_binary(env, argv[5], &tag))
- {ret = EXCP_BADARG(env, "non-binary text"); goto done;}
-
- if (tag.size > INT_MAX
- || key.size > INT_MAX
- || iv.size > INT_MAX
- || in.size > INT_MAX
- || aad.size > INT_MAX)
- {ret = EXCP_BADARG(env, "binary too long"); goto done;}
-
- if ((cipherp = get_cipher_type(type, key.size)) == NULL)
- {ret = EXCP_BADARG(env, "Unknown cipher"); goto done;}
- if (cipherp->flags & NON_EVP_CIPHER)
- {ret = EXCP_BADARG(env, "Bad cipher"); goto done;}
- if ( !(cipherp->flags & AEAD_CIPHER) )
- {ret = EXCP_BADARG(env, "Not aead cipher"); goto done;}
- if ((cipher = cipherp->cipher.p) == NULL)
- {ret = EXCP_NOTSUP(env, "Cipher not supported in this libcrypto version"); goto done;}
+ if (EVP_CipherUpdate(ctx, outp, &len, in.data, (int)in.size) != 1)
+ {
+ if (encflg)
+ ret = EXCP_BADARG(env, "Can't set in-text");
+ else
+ /* Decrypt error */
+ ret = atom_error;
+ goto done;
+ }
- ctx_ctrl_set_ivlen = cipherp->extra.aead.ctx_ctrl_set_ivlen;
- ctx_ctrl_set_tag = cipherp->extra.aead.ctx_ctrl_set_tag;
+ if (encflg)
+ {
+ if (EVP_CipherFinal_ex(ctx, outp/*+len*/, &len) != 1)
+ {ret = EXCP_ERROR(env, "Encrypt error"); goto done;}
- if ((outp = enif_make_new_binary(env, in.size, &out)) == NULL)
- {ret = EXCP_ERROR(env, ""); goto done;}
+ if ((tagp = enif_make_new_binary(env, tag_len, &out_tag)) == NULL)
+ {ret = EXCP_ERROR(env, "Can't make 'Out' binary"); goto done;}
- if ((ctx = EVP_CIPHER_CTX_new()) == NULL)
- {ret = EXCP_ERROR(env, ""); goto done;}
- if (EVP_DecryptInit_ex(ctx, cipher, NULL, NULL, NULL) != 1)
- {ret = EXCP_ERROR(env, ""); goto done;}
- if (EVP_CIPHER_CTX_ctrl(ctx, ctx_ctrl_set_ivlen, (int)iv.size, NULL) != 1)
- {ret = EXCP_ERROR(env, ""); goto done;}
+ if (EVP_CIPHER_CTX_ctrl(ctx, cipherp->extra.aead.ctx_ctrl_get_tag, (int)tag_len, tagp) != 1)
+ {ret = EXCP_ERROR(env, "Can't get Tag"); goto done;}
-#if defined(HAVE_CCM)
- if (type == atom_aes_ccm) {
- if (EVP_CIPHER_CTX_ctrl(ctx, ctx_ctrl_set_tag, (int)tag.size, tag.data) != 1)
- {ret = EXCP_ERROR(env, ""); goto done;}
- if (EVP_DecryptInit_ex(ctx, NULL, NULL, key.data, iv.data) != 1)
- {ret = EXCP_ERROR(env, ""); goto done;}
- if (EVP_DecryptUpdate(ctx, NULL, &len, NULL, (int)in.size) != 1)
- {ret = EXCP_ERROR(env, ""); goto done;}
- }
+ ret = enif_make_tuple2(env, out, out_tag);
+ }
else
-#endif
{
- if (EVP_DecryptInit_ex(ctx, NULL, NULL, key.data, iv.data) != 1)
- {ret = EXCP_ERROR(env, ""); goto done;}
- }
-
- if (EVP_DecryptUpdate(ctx, NULL, &len, aad.data, (int)aad.size) != 1)
- {ret = EXCP_ERROR(env, ""); goto done;}
- if (EVP_DecryptUpdate(ctx, outp, &len, in.data, (int)in.size) != 1)
- {ret = EXCP_ERROR(env, ""); goto done;}
-
#if defined(HAVE_GCM)
- if (type == atom_aes_gcm) {
- if (EVP_CIPHER_CTX_ctrl(ctx, ctx_ctrl_set_tag, (int)tag.size, tag.data) != 1)
- goto err;
- if (EVP_DecryptFinal_ex(ctx, outp+len, &len) != 1)
- goto err;
- }
+ if (cipherp->flags & GCM_MODE) {
+ if (EVP_CIPHER_CTX_ctrl(ctx, cipherp->extra.aead.ctx_ctrl_set_tag, (int)tag_len, tag.data) != 1)
+ /* Decrypt error */
+ {ret = atom_error; goto done;}
+ if (EVP_DecryptFinal_ex(ctx, outp+len, &len) != 1)
+ /* Decrypt error */
+ {ret = atom_error; goto done;}
+ }
#endif
- CONSUME_REDS(env, in);
- ret = out;
- goto done;
+ ret = out;
+ }
- err:
- /* Decrypt failed, that is, wrong tag */
- ret = atom_error;
+ CONSUME_REDS(env, in);
- done:
+done:
if (ctx)
EVP_CIPHER_CTX_free(ctx);
return ret;
#else
- return EXCP_NOTSUP(env, "");
+ return EXCP_NOTSUP(env, "Unsupported Cipher");
#endif
}
+
+
diff --git a/lib/crypto/c_src/aead.h b/lib/crypto/c_src/aead.h
index 54c0711535..2ec7a8a930 100644
--- a/lib/crypto/c_src/aead.h
+++ b/lib/crypto/c_src/aead.h
@@ -23,7 +23,6 @@
#include "common.h"
-ERL_NIF_TERM aead_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-ERL_NIF_TERM aead_decrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM aead_cipher(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
#endif /* E_AEAD_H__ */
diff --git a/lib/crypto/c_src/api_ng.c b/lib/crypto/c_src/api_ng.c
index 5d063c3ae4..107723d2cb 100644
--- a/lib/crypto/c_src/api_ng.c
+++ b/lib/crypto/c_src/api_ng.c
@@ -27,7 +27,7 @@
*
*/
ERL_NIF_TERM ng_crypto_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-ERL_NIF_TERM ng_crypto_one_shot(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM ng_crypto_one_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
#ifdef HAVE_ECB_IVEC_BUG
/* <= 0.9.8l returns faulty ivec length */
@@ -93,6 +93,13 @@ static int get_init_args(ErlNifEnv* env,
goto err;
}
+ if ((*cipherp)->flags & AEAD_CIPHER)
+ {
+ *return_term = EXCP_BADARG(env, "Missing arguments for this cipher");
+ goto err;
+ }
+
+
if (FORBIDDEN_IN_FIPS(*cipherp))
{
*return_term = EXCP_NOTSUP(env, "Forbidden in FIPS");
@@ -413,13 +420,15 @@ int EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, const EVP_CIPHER_CTX *in)
ERL_NIF_TERM ng_crypto_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Context, Data [, IV]) */
struct evp_cipher_ctx *ctx_res;
+ struct evp_cipher_ctx ctx_res_copy;
ERL_NIF_TERM ret;
+ ctx_res_copy.ctx = NULL;
+
if (!enif_get_resource(env, argv[0], (ErlNifResourceType*)evp_cipher_ctx_rtype, (void**)&ctx_res))
return EXCP_BADARG(env, "Bad 1:st arg");
if (argc == 3) {
- struct evp_cipher_ctx ctx_res_copy;
ErlNifBinary ivec_bin;
memcpy(&ctx_res_copy, ctx_res, sizeof ctx_res_copy);
@@ -474,6 +483,9 @@ ERL_NIF_TERM ng_crypto_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
get_update_args(env, ctx_res, argv[1], &ret);
err:
+ if (ctx_res_copy.ctx)
+ EVP_CIPHER_CTX_free(ctx_res_copy.ctx);
+
return ret; /* Both success and error */
}
@@ -504,7 +516,7 @@ ERL_NIF_TERM ng_crypto_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM a
/* One shot */
/*************************************************************************/
-ERL_NIF_TERM ng_crypto_one_shot(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+ERL_NIF_TERM ng_crypto_one_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Cipher, Key, IVec, Data, Encrypt) */
struct evp_cipher_ctx ctx_res;
const struct cipher_type_t *cipherp;
@@ -521,7 +533,7 @@ ERL_NIF_TERM ng_crypto_one_shot(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg
return ret;
}
-ERL_NIF_TERM ng_crypto_one_shot_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+ERL_NIF_TERM ng_crypto_one_time_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Cipher, Key, IVec, Data, Encrypt) % if no IV for the Cipher, set IVec = <<>>
*/
ErlNifBinary data_bin;
@@ -536,10 +548,10 @@ ERL_NIF_TERM ng_crypto_one_shot_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
/* Run long jobs on a dirty scheduler to not block the current emulator thread */
if (data_bin.size > MAX_BYTES_TO_NIF) {
- return enif_schedule_nif(env, "ng_crypto_one_shot",
+ return enif_schedule_nif(env, "ng_crypto_one_time",
ERL_NIF_DIRTY_JOB_CPU_BOUND,
- ng_crypto_one_shot, argc, argv);
+ ng_crypto_one_time, argc, argv);
}
- return ng_crypto_one_shot(env, argc, argv);
+ return ng_crypto_one_time(env, argc, argv);
}
diff --git a/lib/crypto/c_src/api_ng.h b/lib/crypto/c_src/api_ng.h
index 5c7d9af3c5..aaf67524ae 100644
--- a/lib/crypto/c_src/api_ng.h
+++ b/lib/crypto/c_src/api_ng.h
@@ -25,6 +25,6 @@
ERL_NIF_TERM ng_crypto_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM ng_crypto_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-ERL_NIF_TERM ng_crypto_one_shot_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM ng_crypto_one_time_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
#endif /* E_AES_H__ */
diff --git a/lib/crypto/c_src/cipher.c b/lib/crypto/c_src/cipher.c
index 2652e1db4e..13de3562e8 100644
--- a/lib/crypto/c_src/cipher.c
+++ b/lib/crypto/c_src/cipher.c
@@ -117,31 +117,31 @@ static struct cipher_type_t cipher_types[] =
#endif
#if defined(HAVE_GCM)
- {{"aes_gcm"}, {&EVP_aes_128_gcm}, 16, AEAD_CIPHER, {{EVP_CTRL_GCM_SET_IVLEN,EVP_CTRL_GCM_GET_TAG,EVP_CTRL_GCM_SET_TAG}}},
- {{"aes_gcm"}, {&EVP_aes_192_gcm}, 24, AEAD_CIPHER, {{EVP_CTRL_GCM_SET_IVLEN,EVP_CTRL_GCM_GET_TAG,EVP_CTRL_GCM_SET_TAG}}},
- {{"aes_gcm"}, {&EVP_aes_256_gcm}, 32, AEAD_CIPHER, {{EVP_CTRL_GCM_SET_IVLEN,EVP_CTRL_GCM_GET_TAG,EVP_CTRL_GCM_SET_TAG}}},
- {{"aes_128_gcm"}, {&EVP_aes_128_gcm}, 16, AEAD_CIPHER, {{EVP_CTRL_GCM_SET_IVLEN,EVP_CTRL_GCM_GET_TAG,EVP_CTRL_GCM_SET_TAG}}},
- {{"aes_192_gcm"}, {&EVP_aes_192_gcm}, 24, AEAD_CIPHER, {{EVP_CTRL_GCM_SET_IVLEN,EVP_CTRL_GCM_GET_TAG,EVP_CTRL_GCM_SET_TAG}}},
- {{"aes_256_gcm"}, {&EVP_aes_256_gcm}, 32, AEAD_CIPHER, {{EVP_CTRL_GCM_SET_IVLEN,EVP_CTRL_GCM_GET_TAG,EVP_CTRL_GCM_SET_TAG}}},
+ {{"aes_gcm"}, {&EVP_aes_128_gcm}, 16, AEAD_CIPHER|GCM_MODE, {{EVP_CTRL_GCM_SET_IVLEN,EVP_CTRL_GCM_GET_TAG,EVP_CTRL_GCM_SET_TAG}}},
+ {{"aes_gcm"}, {&EVP_aes_192_gcm}, 24, AEAD_CIPHER|GCM_MODE, {{EVP_CTRL_GCM_SET_IVLEN,EVP_CTRL_GCM_GET_TAG,EVP_CTRL_GCM_SET_TAG}}},
+ {{"aes_gcm"}, {&EVP_aes_256_gcm}, 32, AEAD_CIPHER|GCM_MODE, {{EVP_CTRL_GCM_SET_IVLEN,EVP_CTRL_GCM_GET_TAG,EVP_CTRL_GCM_SET_TAG}}},
+ {{"aes_128_gcm"}, {&EVP_aes_128_gcm}, 16, AEAD_CIPHER|GCM_MODE, {{EVP_CTRL_GCM_SET_IVLEN,EVP_CTRL_GCM_GET_TAG,EVP_CTRL_GCM_SET_TAG}}},
+ {{"aes_192_gcm"}, {&EVP_aes_192_gcm}, 24, AEAD_CIPHER|GCM_MODE, {{EVP_CTRL_GCM_SET_IVLEN,EVP_CTRL_GCM_GET_TAG,EVP_CTRL_GCM_SET_TAG}}},
+ {{"aes_256_gcm"}, {&EVP_aes_256_gcm}, 32, AEAD_CIPHER|GCM_MODE, {{EVP_CTRL_GCM_SET_IVLEN,EVP_CTRL_GCM_GET_TAG,EVP_CTRL_GCM_SET_TAG}}},
#else
- {{"aes_gcm"}, {NULL}, 0, AEAD_CIPHER, {{0,0,0}}},
- {{"aes_128_gcm"}, {NULL}, 16, AEAD_CIPHER, {{0,0,0}}},
- {{"aes_192_gcm"}, {NULL}, 24, AEAD_CIPHER, {{0,0,0}}},
- {{"aes_256_gcm"}, {NULL}, 32, AEAD_CIPHER, {{0,0,0}}},
+ {{"aes_gcm"}, {NULL}, 0, AEAD_CIPHER|GCM_MODE, {{0,0,0}}},
+ {{"aes_128_gcm"}, {NULL}, 16, AEAD_CIPHER|GCM_MODE, {{0,0,0}}},
+ {{"aes_192_gcm"}, {NULL}, 24, AEAD_CIPHER|GCM_MODE, {{0,0,0}}},
+ {{"aes_256_gcm"}, {NULL}, 32, AEAD_CIPHER|GCM_MODE, {{0,0,0}}},
#endif
#if defined(HAVE_CCM)
- {{"aes_ccm"}, {&EVP_aes_128_ccm}, 16, AEAD_CIPHER, {{EVP_CTRL_CCM_SET_IVLEN,EVP_CTRL_CCM_GET_TAG,EVP_CTRL_CCM_SET_TAG}}},
- {{"aes_ccm"}, {&EVP_aes_192_ccm}, 24, AEAD_CIPHER, {{EVP_CTRL_CCM_SET_IVLEN,EVP_CTRL_CCM_GET_TAG,EVP_CTRL_CCM_SET_TAG}}},
- {{"aes_ccm"}, {&EVP_aes_256_ccm}, 32, AEAD_CIPHER, {{EVP_CTRL_CCM_SET_IVLEN,EVP_CTRL_CCM_GET_TAG,EVP_CTRL_CCM_SET_TAG}}},
- {{"aes_128_ccm"}, {&EVP_aes_128_ccm}, 16, AEAD_CIPHER, {{EVP_CTRL_CCM_SET_IVLEN,EVP_CTRL_CCM_GET_TAG,EVP_CTRL_CCM_SET_TAG}}},
- {{"aes_192_ccm"}, {&EVP_aes_192_ccm}, 24, AEAD_CIPHER, {{EVP_CTRL_CCM_SET_IVLEN,EVP_CTRL_CCM_GET_TAG,EVP_CTRL_CCM_SET_TAG}}},
- {{"aes_256_ccm"}, {&EVP_aes_256_ccm}, 32, AEAD_CIPHER, {{EVP_CTRL_CCM_SET_IVLEN,EVP_CTRL_CCM_GET_TAG,EVP_CTRL_CCM_SET_TAG}}},
+ {{"aes_ccm"}, {&EVP_aes_128_ccm}, 16, AEAD_CIPHER|CCM_MODE, {{EVP_CTRL_CCM_SET_IVLEN,EVP_CTRL_CCM_GET_TAG,EVP_CTRL_CCM_SET_TAG}}},
+ {{"aes_ccm"}, {&EVP_aes_192_ccm}, 24, AEAD_CIPHER|CCM_MODE, {{EVP_CTRL_CCM_SET_IVLEN,EVP_CTRL_CCM_GET_TAG,EVP_CTRL_CCM_SET_TAG}}},
+ {{"aes_ccm"}, {&EVP_aes_256_ccm}, 32, AEAD_CIPHER|CCM_MODE, {{EVP_CTRL_CCM_SET_IVLEN,EVP_CTRL_CCM_GET_TAG,EVP_CTRL_CCM_SET_TAG}}},
+ {{"aes_128_ccm"}, {&EVP_aes_128_ccm}, 16, AEAD_CIPHER|CCM_MODE, {{EVP_CTRL_CCM_SET_IVLEN,EVP_CTRL_CCM_GET_TAG,EVP_CTRL_CCM_SET_TAG}}},
+ {{"aes_192_ccm"}, {&EVP_aes_192_ccm}, 24, AEAD_CIPHER|CCM_MODE, {{EVP_CTRL_CCM_SET_IVLEN,EVP_CTRL_CCM_GET_TAG,EVP_CTRL_CCM_SET_TAG}}},
+ {{"aes_256_ccm"}, {&EVP_aes_256_ccm}, 32, AEAD_CIPHER|CCM_MODE, {{EVP_CTRL_CCM_SET_IVLEN,EVP_CTRL_CCM_GET_TAG,EVP_CTRL_CCM_SET_TAG}}},
#else
- {{"aes_ccm"}, {NULL}, 0, AEAD_CIPHER, {{0,0,0}}},
- {{"aes_128_ccm"}, {NULL}, 16, AEAD_CIPHER, {{0,0,0}}},
- {{"aes_192_ccm"}, {NULL}, 24, AEAD_CIPHER, {{0,0,0}}},
- {{"aes_256_ccm"}, {NULL}, 32, AEAD_CIPHER, {{0,0,0}}},
+ {{"aes_ccm"}, {NULL}, 0, AEAD_CIPHER|CCM_MODE, {{0,0,0}}},
+ {{"aes_128_ccm"}, {NULL}, 16, AEAD_CIPHER|CCM_MODE, {{0,0,0}}},
+ {{"aes_192_ccm"}, {NULL}, 24, AEAD_CIPHER|CCM_MODE, {{0,0,0}}},
+ {{"aes_256_ccm"}, {NULL}, 32, AEAD_CIPHER|CCM_MODE, {{0,0,0}}},
#endif
/*==== Specialy handled ciphers, only for inclusion in algorithm's list ====*/
diff --git a/lib/crypto/c_src/cipher.h b/lib/crypto/c_src/cipher.h
index b94873940f..0e51c410eb 100644
--- a/lib/crypto/c_src/cipher.h
+++ b/lib/crypto/c_src/cipher.h
@@ -46,6 +46,8 @@ struct cipher_type_t {
#define AEAD_CIPHER 8
#define NON_EVP_CIPHER 16
#define AES_CTR_COMPAT 32
+#define CCM_MODE 64
+#define GCM_MODE 128
#ifdef FIPS_SUPPORT
diff --git a/lib/crypto/c_src/common.h b/lib/crypto/c_src/common.h
index 0bf7f09f4f..a7e59d5d01 100644
--- a/lib/crypto/c_src/common.h
+++ b/lib/crypto/c_src/common.h
@@ -38,8 +38,11 @@
/* All nif functions return a valid value or throws an exception */
#define EXCP(Env, Id, Str) enif_raise_exception((Env), \
- enif_make_tuple2((Env), \
+ enif_make_tuple3((Env), \
(Id), \
+ enif_make_tuple2((Env), \
+ enif_make_string((Env),__FILE__,(ERL_NIF_LATIN1)), \
+ enif_make_int((Env), __LINE__)), \
enif_make_string((Env),(Str),(ERL_NIF_LATIN1)) ))
#define EXCP_NOTSUP(Env, Str) EXCP((Env), atom_notsup, (Str))
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index 4aed06a489..a8014745c8 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -81,7 +81,7 @@ static ErlNifFunc nif_funcs[] = {
{"ng_crypto_init_nif", 4, ng_crypto_init_nif, 0},
{"ng_crypto_update_nif", 2, ng_crypto_update_nif, 0},
{"ng_crypto_update_nif", 3, ng_crypto_update_nif, 0},
- {"ng_crypto_one_shot_nif", 5, ng_crypto_one_shot_nif, 0},
+ {"ng_crypto_one_time_nif", 5, ng_crypto_one_time_nif, 0},
{"strong_rand_bytes_nif", 1, strong_rand_bytes_nif, 0},
{"strong_rand_range_nif", 1, strong_rand_range_nif, 0},
{"rand_uniform_nif", 2, rand_uniform_nif, 0},
@@ -105,8 +105,7 @@ static ErlNifFunc nif_funcs[] = {
{"rand_seed_nif", 1, rand_seed_nif, 0},
- {"aead_encrypt", 6, aead_encrypt, 0},
- {"aead_decrypt", 6, aead_decrypt, 0},
+ {"aead_cipher", 7, aead_cipher, 0},
{"poly1305_nif", 2, poly1305_nif, 0},
diff --git a/lib/crypto/c_src/otp_test_engine.c b/lib/crypto/c_src/otp_test_engine.c
index fd26b7cb5d..4a155becf8 100644
--- a/lib/crypto/c_src/otp_test_engine.c
+++ b/lib/crypto/c_src/otp_test_engine.c
@@ -404,7 +404,7 @@ int test_rsa_sign(int dtype,
} */
if ((sizeof(fake_flag) == m_len)
- && bcmp(m,fake_flag,m_len) == 0) {
+ && memcmp(m,fake_flag,m_len) == 0) {
int slen;
printf("To be faked\r\n");
@@ -432,7 +432,7 @@ int test_rsa_verify(int dtype,
printf("test_rsa_verify (dtype=%i) called m_len=%u siglen=%u\r\n", dtype, m_len, siglen);
if ((sizeof(fake_flag) == m_len)
- && bcmp(m,fake_flag,m_len) == 0) {
+ && memcmp(m,fake_flag,m_len) == 0) {
int size;
if ((size = RSA_size(rsa)) < 0)
diff --git a/lib/crypto/doc/src/Makefile b/lib/crypto/doc/src/Makefile
index cbcafb7375..8da494dad6 100644
--- a/lib/crypto/doc/src/Makefile
+++ b/lib/crypto/doc/src/Makefile
@@ -39,7 +39,8 @@ XML_REF3_FILES = crypto.xml
XML_REF6_FILES = crypto_app.xml
XML_PART_FILES = usersguide.xml
-XML_CHAPTER_FILES = notes.xml licenses.xml fips.xml engine_load.xml engine_keys.xml algorithm_details.xml
+XML_CHAPTER_FILES = notes.xml licenses.xml fips.xml engine_load.xml engine_keys.xml \
+ algorithm_details.xml new_api.xml
BOOK_FILES = book.xml
diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml
index 8a4fad67de..14efc5c6f6 100644
--- a/lib/crypto/doc/src/crypto.xml
+++ b/lib/crypto/doc/src/crypto.xml
@@ -42,7 +42,7 @@
<item>
<url href="https://www.nist.gov/publications/sha-3-standard-permutation-based-hash-and-extendable-output-functions?pub_id=919061">
SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions [FIPS PUB 202]
- </url>
+ </url>
</item>
<tag>BLAKE2</tag>
<item>
@@ -190,70 +190,101 @@
</description>
<datatypes>
- <datatype_title>Ciphers</datatype_title>
+ <datatype_title>Ciphers, new API</datatype_title>
<datatype>
<name name="cipher"/>
- <name name="stream_cipher"/>
- <name name="block_cipher"/>
<desc>
- <p>Ciphers known byt the CRYPTO application. Note that this list might be reduced if the
- underlying libcrypto does not support all of them.</p>
</desc>
</datatype>
-
<datatype>
- <name name="stream_cipher_iv"/>
- <name name="stream_cipher_no_iv"/>
+ <name name="cipher_no_iv"/>
<desc>
- <p>Stream ciphers for
- <seealso marker="#stream_init-3">stream_init/3</seealso> and
- <seealso marker="#stream_init-2">stream_init/2</seealso> .
- </p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="cipher_iv"/>
+ <desc>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="cipher_aead"/>
+ <desc>
+ <p>Ciphers known by the CRYPTO application when using the
+ <seealso marker="crypto:new_api#the-new-api">new API</seealso>.</p>
+ <p>Note that this list might be reduced if the underlying libcrypto does not support all of them.</p>
</desc>
</datatype>
+ <datatype_title>Ciphers, old API</datatype_title>
+ <datatype>
+ <name name="block_cipher_with_iv"/>
+ <desc>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="block_cipher_without_iv"/>
+ <desc>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="stream_cipher"/>
+ <desc>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="aead_cipher"/>
+ <desc>
+ </desc>
+ </datatype>
<datatype>
- <name name="block_cipher_iv"/>
<name name="cbc_cipher"/>
+ <desc>
+ </desc>
+ </datatype>
+ <datatype>
<name name="cfb_cipher"/>
<desc>
- <p>Block ciphers with initialization vector for
- <seealso marker="#block_encrypt-4">block_encrypt/4</seealso> and
- <seealso marker="#block_decrypt-4">block_decrypt/4</seealso> .
- </p>
</desc>
</datatype>
-
<datatype>
- <name name="alias_cfb"/>
- <name name="alias_cbc"/>
+ <name name="ctr_cipher"/>
<desc>
- <p>Names that are replaced by more common names. They may deprecated in futer releases.</p>
- <p><c>des3_cbc</c> and <c>des_ede3</c> should be replaced by <c>des_ede3_cbc</c></p>
- <p><c>des_ede3_cbf</c>, <c>des3_cbf</c> and <c>des3_cfb</c> should be replaced by <c>des_ede3_cfb</c>.</p>
- <p><c>aes_cbc128</c> should be replaced by <c>aes_128_cbc</c>.</p>
- <p><c>aes_cbc256</c> should be replaced by <c>aes_256_cbc</c>.</p>
</desc>
</datatype>
-
<datatype>
- <name name="block_cipher_no_iv"/>
<name name="ecb_cipher"/>
<desc>
- <p>Block ciphers without initialization vector for
- <seealso marker="#block_encrypt-3">block_encrypt/3</seealso> and
- <seealso marker="#block_decrypt-3">block_decrypt/3</seealso> .
- </p>
+ <p>Ciphers known by the CRYPTO application when using the
+ <seealso marker="crypto:new_api#the-old-api">old API</seealso>.</p>
+ <p>Note that this list might be reduced if the underlying libcrypto does not support all of them.</p>
</desc>
</datatype>
<datatype>
- <name name="aead_cipher"/>
+ <name name="retired_cbc_cipher_aliases"/>
+ <desc>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="retired_cfb_cipher_aliases"/>
<desc>
- <p>Ciphers with simultaneous MAC-calculation or MAC-checking.
- <seealso marker="#block_encrypt-4">block_encrypt/4</seealso> and
- <seealso marker="#block_decrypt-4">block_decrypt/4</seealso> .
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="retired_ctr_cipher_aliases"/>
+ <desc>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="retired_ecb_cipher_aliases"/>
+ <desc>
+ <p>Alternative, old names of ciphers known by the CRYPTO application when using the
+ <seealso marker="crypto:new_api#the-old-api">old API</seealso>.
+ See <seealso marker="crypto:new_api#retired-cipher-names">Retired cipher names</seealso> for names to
+ use instead to be prepared for an easy convertion to the
+ <seealso marker="crypto:new_api#the-new-api">new API</seealso>.
</p>
+ <p>Note that this list might be reduced if the underlying libcrypto does not support all of them.</p>
</desc>
</datatype>
@@ -547,6 +578,7 @@
<name name="stream_state"/>
<name name="hmac_state"/>
<name name="hash_state"/>
+ <name name="crypto_state"/>
<desc>
<p>Contexts with an internal state that should not be manipulated but passed between function calls.
</p>
@@ -575,117 +607,171 @@
<p>This is a more developed variant of the older
<seealso marker="#type-run_time_error">run_time_error()</seealso>.
</p>
+ <p>The exception is:</p>
+ <pre>
+ {Tag, {C_FileName,LineNumber}, Description}
+
+ Tag = badarg | notsup | error
+ C_FileName = string()
+ LineNumber = integer()
+ Description = string()
+ </pre>
+
<p>It is like the older type an exception of the <c>error</c> class. In addition they contain
a descriptive text in English. That text is targeted to a developer. Examples are "Bad key size"
or "Cipher id is not an atom".
</p>
- <p>The exceptions are:</p>
+ <p>The exception tags are:</p>
<taglist>
- <tag><c>{badarg, Description::string()}</c></tag>
+ <tag><c>badarg</c></tag>
<item><p>Signifies that one or more arguments are of wrong data type or are otherwise badly formed.</p>
</item>
- <tag><c>{notsup, Description::string()}</c></tag>
+ <tag><c>notsup</c></tag>
<item><p>Signifies that the algorithm is known but is not supported by current underlying libcrypto
or explicitly disabled when building that one.</p>
</item>
- <tag><c>{error, Description::string()}</c></tag>
+ <tag><c>error</c></tag>
<item><p>An error condition that should not occur, for example a memory allocation failed or
the underlying cryptolib returned an error code, for example "Can't initialize context, step 1".
Thoose text usually needs searching the C-code to be understood.</p>
</item>
</taglist>
+ <p>To catch the exception, use for example:</p>
+ <code>
+ try crypto:crypto_init(Ciph, Key, IV, true)
+ catch
+ error:{Tag, {C_FileName,LineNumber}, Description} ->
+ do_something(......)
+ .....
+ end
+ </code>
</desc>
</datatype>
</datatypes>
<!--================ FUNCTIONS ================-->
+ <section>
+ <title>New API</title>
+ </section>
+
<funcs>
<func>
- <name name="block_encrypt" arity="3" since="OTP 18.0"/>
- <fsummary>Encrypt <c>PlainText</c> according to <c>Type</c> block cipher</fsummary>
+ <name name="crypto_init" arity="3" since="OTP 22.0"/>
+ <fsummary>Initializes a series of encryptions or decryptions</fsummary>
<desc>
- <p>Encrypt <c>PlainText</c> according to <c>Type</c> block cipher.</p>
- <p>May raise exception <c>error:notsup</c> in case the chosen <c>Type</c>
- is not supported by the underlying libcrypto implementation.</p>
- <p>For keylengths and blocksizes see the
- <seealso marker="crypto:algorithm_details#ciphers">User's Guide</seealso>.
+ <p>As <seealso marker="#crypto_init/4">crypto_init/4</seealso> but for ciphers without IVs.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="crypto_init" arity="4" since="OTP 22.0"/>
+ <fsummary>Initializes a series of encryptions or decryptions</fsummary>
+ <desc>
+ <p>Part of the <seealso marker="crypto:new_api#the-new-api">new API</seealso>.
+ Initializes a series of encryptions or decryptions.
+ The actual encryption or decryption is done by
+ <seealso marker="crypto#crypto_update/2">crypto_update/2</seealso>.
+ </p>
+ <p>For encryption, set the <c>EncryptFlag</c> to <c>true</c>.
+ </p>
+ <p>See <seealso marker="crypto:new_api#the-new-api">examples in the User's Guide.</seealso>
</p>
</desc>
</func>
<func>
- <name name="block_decrypt" arity="3" since="OTP 18.0"/>
- <fsummary>Decrypt <c>CipherText</c> according to <c>Type</c> block cipher</fsummary>
+ <name name="crypto_init_dyn_iv" arity="3" since="OTP 22.0"/>
+ <fsummary>Initializes a series of encryptions or decryptions where the IV is provided later</fsummary>
<desc>
- <p>Decrypt <c>CipherText</c> according to <c>Type</c> block cipher.</p>
- <p>May raise exception <c>error:notsup</c> in case the chosen <c>Type</c>
- is not supported by the underlying libcrypto implementation.</p>
- <p>For keylengths and blocksizes see the
- <seealso marker="crypto:algorithm_details#ciphers">User's Guide</seealso>.
+ <p>Part of the <seealso marker="crypto:new_api#the-new-api">new API</seealso>.
+ Initializes a series of encryptions or decryptions where the IV is provided later.
+ The actual encryption or decryption is done by
+ <seealso marker="crypto#crypto_update_dyn_iv/3">crypto_update_dyn_iv/3</seealso>.
+ </p>
+ <p>For encryption, set the <c>EncryptFlag</c> to <c>true</c>.
+ </p>
+ <p>See <seealso marker="crypto:new_api#the-new-api">examples in the User's Guide.</seealso>
</p>
</desc>
</func>
<func>
- <name since="OTP R16B01">block_encrypt(Type, Key, Ivec, PlainText) -> CipherText | Error</name>
- <name since="OTP R16B01">block_encrypt(AeadType, Key, Ivec, {AAD, PlainText}) -> {CipherText, CipherTag} | Error</name>
- <name since="OTP R16B01">block_encrypt(aes_gcm | aes_ccm, Key, Ivec, {AAD, PlainText, TagLength}) -> {CipherText, CipherTag} | Error </name>
- <fsummary>Encrypt <c>PlainText</c> according to <c>Type</c> block cipher</fsummary>
- <type>
- <v>Type = <seealso marker="#type-block_cipher_iv">block_cipher_iv()</seealso></v>
- <v>AeadType = <seealso marker="#type-aead_cipher">aead_cipher()</seealso></v>
- <v>Key = <seealso marker="#type-key">key()</seealso> | <seealso marker="#type-des3_key">des3_key()</seealso></v>
- <v>PlainText = iodata()</v>
- <v>AAD = IVec = CipherText = CipherTag = binary()</v>
- <v>TagLength = 1..16</v>
- <v>Error = <seealso marker="#type-run_time_error">run_time_error()</seealso></v>
- </type>
+ <name name="crypto_update" arity="2" since="OTP 22.0"/>
+ <fsummary>Do an actual crypto operation on a part of the full text</fsummary>
<desc>
- <p>Encrypt <c>PlainText</c> according to <c>Type</c> block cipher.
- <c>IVec</c> is an arbitrary initializing vector.</p>
- <p>In AEAD (Authenticated Encryption with Associated Data) mode, encrypt
- <c>PlainText</c>according to <c>Type</c> block cipher and calculate
- <c>CipherTag</c> that also authenticates the <c>AAD</c> (Associated Authenticated Data).</p>
- <p>May raise exception <c>error:notsup</c> in case the chosen <c>Type</c>
- is not supported by the underlying libcrypto implementation.</p>
- <p>For keylengths, iv-sizes and blocksizes see the
- <seealso marker="crypto:algorithm_details#ciphers">User's Guide</seealso>.
+ <p>Part of the <seealso marker="crypto:new_api#the-new-api">new API</seealso>.
+ Do an actual crypto operation on a part of the full text.
+ The <c>State</c> should be created with
+ <seealso marker="crypto#crypto_init/3">crypto_init/3</seealso>
+ or
+ <seealso marker="crypto#crypto_init/4">crypto_init/4</seealso>.
+ </p>
+ <p>See <seealso marker="crypto:new_api#the-new-api">examples in the User's Guide.</seealso>
</p>
</desc>
</func>
<func>
- <name since="OTP R16B01">block_decrypt(Type, Key, Ivec, CipherText) -> PlainText | Error</name>
- <name since="OTP R16B01">block_decrypt(AeadType, Key, Ivec, {AAD, CipherText, CipherTag}) -> PlainText | Error</name>
- <fsummary>Decrypt <c>CipherText</c> according to <c>Type</c> block cipher</fsummary>
- <type>
- <v>Type = <seealso marker="#type-block_cipher_iv">block_cipher_iv()</seealso></v>
- <v>AeadType = <seealso marker="#type-aead_cipher">aead_cipher()</seealso></v>
- <v>Key = <seealso marker="#type-key">key()</seealso> | <seealso marker="#type-des3_key">des3_key()</seealso></v>
- <v>PlainText = iodata()</v>
- <v>AAD = IVec = CipherText = CipherTag = binary()</v>
- <v>Error = BadTag | <seealso marker="#type-run_time_error">run_time_error()</seealso></v>
- <v>BadTag = error</v>
- </type>
+ <name name="crypto_update_dyn_iv" arity="3" since="OTP 22.0"/>
+ <fsummary>Do an actual crypto operation on a part of the full text and the IV is supplied for each part</fsummary>
<desc>
- <p>Decrypt <c>CipherText</c> according to <c>Type</c> block cipher.
- <c>IVec</c> is an arbitrary initializing vector.</p>
- <p>In AEAD (Authenticated Encryption with Associated Data) mode, decrypt
- <c>CipherText</c>according to <c>Type</c> block cipher and check the authenticity
- the <c>PlainText</c> and <c>AAD</c> (Associated Authenticated Data) using the
- <c>CipherTag</c>. May return <c>error</c> if the decryption or validation fail's</p>
- <p>May raise exception <c>error:notsup</c> in case the chosen <c>Type</c>
- is not supported by the underlying libcrypto implementation.</p>
- <p>For keylengths, iv-sizes and blocksizes see the
- <seealso marker="crypto:algorithm_details#ciphers">User's Guide</seealso>.
+ <p>Part of the <seealso marker="crypto:new_api#the-new-api">new API</seealso>.
+ Do an actual crypto operation on a part of the full text and the IV is supplied for each part.
+ The <c>State</c> should be created with
+ <seealso marker="crypto#crypto_init_dyn_iv/3">crypto_init_dyn_iv/3</seealso>.
+ </p>
+ <p>See <seealso marker="crypto:new_api#the-new-api">examples in the User's Guide.</seealso>
</p>
</desc>
</func>
- <func>
+ <func>
+ <name name="crypto_one_time" arity="4" since="OTP 22.0"/>
+ <fsummary>Do a complete encrypt or decrypt of the full text</fsummary>
+ <desc>
+ <p>As <seealso marker="#crypto_one_time/5">crypto_one_time/5</seealso> but for ciphers without IVs.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="crypto_one_time" arity="5" since="OTP 22.0"/>
+ <fsummary>Do a complete encrypt or decrypt of the full text</fsummary>
+ <desc>
+ <p>Part of the <seealso marker="crypto:new_api#the-new-api">new API</seealso>.
+ Do a complete encrypt or decrypt of the full text.
+ </p>
+ <p>For encryption, set the <c>EncryptFlag</c> to <c>true</c>.
+ </p>
+ <p>See <seealso marker="crypto:new_api#the-new-api">examples in the User's Guide.</seealso>
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="crypto_aead" arity="6" since="OTP 22.0"/>
+ <name name="crypto_aead" arity="7" since="OTP 22.0"/>
+ <fsummary>Do a complete encrypt or decrypt with an AEAD cipher of the full text</fsummary>
+ <desc>
+ <p>Part of the <seealso marker="crypto:new_api#the-new-api">new API</seealso>.
+ Do a complete encrypt or decrypt with an AEAD cipher of the full text.
+ </p>
+ <p>For encryption, set the <c>EncryptFlag</c> to <c>true</c>.
+ </p>
+ <p>See <seealso marker="crypto:new_api#the-new-api">examples in the User's Guide.</seealso>
+ </p>
+ </desc>
+ </func>
+ </funcs>
+
+ <section>
+ <title>API kept from previous versions</title>
+ </section>
+
+ <funcs>
+ <func>
<name name="bytes_to_integer" arity="1" since="OTP R16B01"/>
<fsummary>Convert binary representation, of an integer, to an Erlang integer.</fsummary>
<desc>
@@ -928,7 +1014,7 @@
cipher algorithm in question.
</p>
<note>
- <p>The ciphers <c>aes_cbc</c>, <c>aes_cfb8</c>, <c>aes_cfb128</c>, <c>aes_ctr</c>,
+ <p>The ciphers <c>aes_cbc</c>, <c>aes_cfb8</c>, <c>aes_cfb128</c>, <c>aes_ctr</c>,
<c>aes_ecb</c>, <c>aes_gcm</c> and <c>aes_ccm</c>
has no keylength in the <c>Type</c> as opposed to for example <c>aes_128_ctr</c>. They adapt to the length of
the key provided in the encrypt and decrypt function. Therefor it is impossible to return a valid keylength
@@ -1094,7 +1180,7 @@
<seealso marker="#rand_seed_s-0">rand_seed_s/0</seealso>.
</p>
<p>
- When using the state object from this function the
+ When using the state object from this function the
<seealso marker="stdlib:rand">rand</seealso> functions using it
may raise exception <c>error:low_entropy</c> in case the random generator
failed due to lack of secure "randomness".
@@ -1120,7 +1206,7 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre>
<seealso marker="stdlib:rand#seed_s-1">rand:seed_s/1</seealso>.
</p>
<p>
- When using the state object from this function the
+ When using the state object from this function the
<seealso marker="stdlib:rand">rand</seealso> functions using it
may raise exception <c>error:low_entropy</c> in case the random generator
failed due to lack of secure "randomness".
@@ -1129,7 +1215,7 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre>
<p>
The state returned from this function cannot be used
to get a reproducable random sequence as from
- the other
+ the other
<seealso marker="stdlib:rand">rand</seealso>
functions,
since reproducability does not match cryptographically safe.
@@ -1160,7 +1246,7 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre>
<seealso marker="#rand_seed_alg_s-1">rand_seed_alg_s/1</seealso>.
</p>
<p>
- When using the state object from this function the
+ When using the state object from this function the
<seealso marker="stdlib:rand">rand</seealso> functions using it
may raise exception <c>error:low_entropy</c> in case the random generator
failed due to lack of secure "randomness".
@@ -1227,7 +1313,7 @@ FloatValue = rand:uniform(). % again
of 56 bits that makes calculations fast on 64 bit machines.
</p>
<p>
- When using the state object from this function the
+ When using the state object from this function the
<seealso marker="stdlib:rand">rand</seealso> functions using it
may raise exception <c>error:low_entropy</c> in case the random generator
failed due to lack of secure "randomness".
@@ -1248,7 +1334,7 @@ FloatValue = rand:uniform(). % again
<p>
The state returned from this function cannot be used
to get a reproducable random sequence as from
- the other
+ the other
<seealso marker="stdlib:rand">rand</seealso>
functions,
since reproducability does not match cryptographically safe.
@@ -1331,56 +1417,6 @@ FloatValue = rand:uniform(). % again
</desc>
</func>
- <func>
- <name name="stream_init" arity="2" since="OTP R16B01"/>
- <fsummary></fsummary>
- <desc>
- <p>Initializes the state for use in RC4 stream encryption
- <seealso marker="#stream_encrypt-2">stream_encrypt</seealso> and
- <seealso marker="#stream_decrypt-2">stream_decrypt</seealso></p>
- <p>For keylengths see the
- <seealso marker="crypto:algorithm_details#stream-ciphers">User's Guide</seealso>.
- </p>
- </desc>
- </func>
-
- <func>
- <name name="stream_init" arity="3" since="OTP R16B01"/>
- <fsummary></fsummary>
- <desc>
- <p>Initializes the state for use in streaming AES encryption using Counter mode (CTR).
- <c>Key</c> is the AES key and must be either 128, 192, or 256 bits long. <c>IVec</c> is
- an arbitrary initializing vector of 128 bits (16 bytes). This state is for use with
- <seealso marker="#stream_encrypt-2">stream_encrypt</seealso> and
- <seealso marker="#stream_decrypt-2">stream_decrypt</seealso>.</p>
- <p>For keylengths and iv-sizes see the
- <seealso marker="crypto:algorithm_details#stream-ciphers">User's Guide</seealso>.
- </p>
- </desc>
- </func>
-
- <func>
- <name name="stream_encrypt" arity="2" since="OTP R16B01"/>
- <fsummary></fsummary>
- <desc>
- <p>Encrypts <c>PlainText</c> according to the stream cipher <c>Type</c> specified in stream_init/3.
- <c>Text</c> can be any number of bytes. The initial <c>State</c> is created using
- <seealso marker="#stream_init-2">stream_init</seealso>.
- <c>NewState</c> must be passed into the next call to <c>stream_encrypt</c>.</p>
- </desc>
- </func>
-
- <func>
- <name name="stream_decrypt" arity="2" since="OTP R16B01"/>
- <fsummary></fsummary>
- <desc>
- <p>Decrypts <c>CipherText</c> according to the stream cipher <c>Type</c> specified in stream_init/3.
- <c>PlainText</c> can be any number of bytes. The initial <c>State</c> is created using
- <seealso marker="#stream_init-2">stream_init</seealso>.
- <c>NewState</c> must be passed into the next call to <c>stream_decrypt</c>.</p>
- </desc>
- </func>
-
<func>
<name name="supports" arity="0" since="OTP R16B01"/>
<fsummary>Provide a list of available crypto algorithms.</fsummary>
@@ -1440,6 +1476,12 @@ FloatValue = rand:uniform(). % again
</desc>
</func>
+ </funcs>
+ <section>
+ <title>Engine API</title>
+ </section>
+
+ <funcs>
<!-- Engine functions -->
<func>
<name name="privkey_to_pubkey" arity="2" since="OTP 20.2"/>
@@ -1752,5 +1794,152 @@ FloatValue = rand:uniform(). % again
</funcs>
+<section>
+ <title>Old API</title>
+</section>
+
+ <funcs>
+ <func>
+ <name name="block_encrypt" arity="3" since="OTP 18.0"/>
+ <fsummary>Encrypt <c>PlainText</c> according to <c>Type</c> block cipher</fsummary>
+ <desc>
+ <dont><p>Don't use this function for new programs! Use <seealso marker="crypto:new_api">the-new-api</seealso>.</p></dont>
+ <p>Encrypt <c>PlainText</c> according to <c>Type</c> block cipher.</p>
+ <p>May raise exception <c>error:notsup</c> in case the chosen <c>Type</c>
+ is not supported by the underlying libcrypto implementation.</p>
+ <p>For keylengths and blocksizes see the
+ <seealso marker="crypto:algorithm_details#ciphers">User's Guide</seealso>.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="block_decrypt" arity="3" since="OTP 18.0"/>
+ <fsummary>Decrypt <c>CipherText</c> according to <c>Type</c> block cipher</fsummary>
+ <desc>
+ <dont><p>Don't use this function for new programs! Use <seealso marker="crypto:new_api">the new api</seealso>.</p></dont>
+ <p>Decrypt <c>CipherText</c> according to <c>Type</c> block cipher.</p>
+ <p>May raise exception <c>error:notsup</c> in case the chosen <c>Type</c>
+ is not supported by the underlying libcrypto implementation.</p>
+ <p>For keylengths and blocksizes see the
+ <seealso marker="crypto:algorithm_details#ciphers">User's Guide</seealso>.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP R16B01">block_encrypt(Type, Key, Ivec, PlainText) -> CipherText | Error</name>
+ <name since="OTP R16B01">block_encrypt(AeadType, Key, Ivec, {AAD, PlainText}) -> {CipherText, CipherTag} | Error</name>
+ <name since="OTP R16B01">block_encrypt(aes_gcm | aes_ccm, Key, Ivec, {AAD, PlainText, TagLength}) -> {CipherText, CipherTag} | Error </name>
+ <fsummary>Encrypt <c>PlainText</c> according to <c>Type</c> block cipher</fsummary>
+ <type>
+ <v>Type = <seealso marker="#type-block_cipher_with_iv">block_cipher_with_iv()</seealso></v>
+ <v>AeadType = <seealso marker="#type-aead_cipher">aead_cipher()</seealso></v>
+ <v>Key = <seealso marker="#type-key">key()</seealso> | <seealso marker="#type-des3_key">des3_key()</seealso></v>
+ <v>PlainText = iodata()</v>
+ <v>AAD = IVec = CipherText = CipherTag = binary()</v>
+ <v>TagLength = 1..16</v>
+ <v>Error = <seealso marker="#type-run_time_error">run_time_error()</seealso></v>
+ </type>
+ <desc>
+ <dont><p>Don't use this function for new programs! Use <seealso marker="crypto:new_api">the new api</seealso>.</p></dont>
+ <p>Encrypt <c>PlainText</c> according to <c>Type</c> block cipher.
+ <c>IVec</c> is an arbitrary initializing vector.</p>
+ <p>In AEAD (Authenticated Encryption with Associated Data) mode, encrypt
+ <c>PlainText</c>according to <c>Type</c> block cipher and calculate
+ <c>CipherTag</c> that also authenticates the <c>AAD</c> (Associated Authenticated Data).</p>
+ <p>May raise exception <c>error:notsup</c> in case the chosen <c>Type</c>
+ is not supported by the underlying libcrypto implementation.</p>
+ <p>For keylengths, iv-sizes and blocksizes see the
+ <seealso marker="crypto:algorithm_details#ciphers">User's Guide</seealso>.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP R16B01">block_decrypt(Type, Key, Ivec, CipherText) -> PlainText | Error</name>
+ <name since="OTP R16B01">block_decrypt(AeadType, Key, Ivec, {AAD, CipherText, CipherTag}) -> PlainText | Error</name>
+ <fsummary>Decrypt <c>CipherText</c> according to <c>Type</c> block cipher</fsummary>
+ <type>
+ <v>Type = <seealso marker="#type-block_cipher_with_iv">block_cipher_with_iv()</seealso></v>
+ <v>AeadType = <seealso marker="#type-aead_cipher">aead_cipher()</seealso></v>
+ <v>Key = <seealso marker="#type-key">key()</seealso> | <seealso marker="#type-des3_key">des3_key()</seealso></v>
+ <v>PlainText = iodata()</v>
+ <v>AAD = IVec = CipherText = CipherTag = binary()</v>
+ <v>Error = BadTag | <seealso marker="#type-run_time_error">run_time_error()</seealso></v>
+ <v>BadTag = error</v>
+ </type>
+ <desc>
+ <dont><p>Don't use this function for new programs! Use <seealso marker="crypto:new_api">the new api</seealso>.</p></dont>
+ <p>Decrypt <c>CipherText</c> according to <c>Type</c> block cipher.
+ <c>IVec</c> is an arbitrary initializing vector.</p>
+ <p>In AEAD (Authenticated Encryption with Associated Data) mode, decrypt
+ <c>CipherText</c>according to <c>Type</c> block cipher and check the authenticity
+ the <c>PlainText</c> and <c>AAD</c> (Associated Authenticated Data) using the
+ <c>CipherTag</c>. May return <c>error</c> if the decryption or validation fail's</p>
+ <p>May raise exception <c>error:notsup</c> in case the chosen <c>Type</c>
+ is not supported by the underlying libcrypto implementation.</p>
+ <p>For keylengths, iv-sizes and blocksizes see the
+ <seealso marker="crypto:algorithm_details#ciphers">User's Guide</seealso>.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="stream_init" arity="2" since="OTP R16B01"/>
+ <fsummary></fsummary>
+ <desc>
+ <dont><p>Don't use this function for new programs! Use <seealso marker="crypto:new_api">the new api</seealso>.</p></dont>
+ <p>Initializes the state for use in RC4 stream encryption
+ <seealso marker="#stream_encrypt-2">stream_encrypt</seealso> and
+ <seealso marker="#stream_decrypt-2">stream_decrypt</seealso></p>
+ <p>For keylengths see the
+ <seealso marker="crypto:algorithm_details#stream-ciphers">User's Guide</seealso>.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="stream_init" arity="3" since="OTP R16B01"/>
+ <fsummary></fsummary>
+ <desc>
+ <dont><p>Don't use this function for new programs! Use <seealso marker="crypto:new_api">the new api</seealso>.</p></dont>
+ <p>Initializes the state for use in streaming AES encryption using Counter mode (CTR).
+ <c>Key</c> is the AES key and must be either 128, 192, or 256 bits long. <c>IVec</c> is
+ an arbitrary initializing vector of 128 bits (16 bytes). This state is for use with
+ <seealso marker="#stream_encrypt-2">stream_encrypt</seealso> and
+ <seealso marker="#stream_decrypt-2">stream_decrypt</seealso>.</p>
+ <p>For keylengths and iv-sizes see the
+ <seealso marker="crypto:algorithm_details#stream-ciphers">User's Guide</seealso>.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="stream_encrypt" arity="2" since="OTP R16B01"/>
+ <fsummary></fsummary>
+ <desc>
+ <dont><p>Don't use this function for new programs! Use <seealso marker="crypto:new_api">the new api</seealso>.</p></dont>
+ <p>Encrypts <c>PlainText</c> according to the stream cipher <c>Type</c> specified in stream_init/3.
+ <c>Text</c> can be any number of bytes. The initial <c>State</c> is created using
+ <seealso marker="#stream_init-2">stream_init</seealso>.
+ <c>NewState</c> must be passed into the next call to <c>stream_encrypt</c>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="stream_decrypt" arity="2" since="OTP R16B01"/>
+ <fsummary></fsummary>
+ <desc>
+ <dont><p>Don't use this function for new programs! Use <seealso marker="crypto:new_api">the new api</seealso>.</p></dont>
+ <p>Decrypts <c>CipherText</c> according to the stream cipher <c>Type</c> specified in stream_init/3.
+ <c>PlainText</c> can be any number of bytes. The initial <c>State</c> is created using
+ <seealso marker="#stream_init-2">stream_init</seealso>.
+ <c>NewState</c> must be passed into the next call to <c>stream_decrypt</c>.</p>
+ </desc>
+ </func>
+
+ </funcs>
+
</erlref>
diff --git a/lib/crypto/doc/src/new_api.xml b/lib/crypto/doc/src/new_api.xml
new file mode 100644
index 0000000000..66eeefb692
--- /dev/null
+++ b/lib/crypto/doc/src/new_api.xml
@@ -0,0 +1,209 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2014</year><year>2019</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>New and Old API</title>
+ <prepared>Hans Nilsson</prepared>
+ <docno></docno>
+ <date>2019-08-22</date>
+ <rev>A</rev>
+ <file>new_api.xml</file>
+ </header>
+ <p>
+ This chapter describes the new api to encryption and decryption.
+ </p>
+
+ <section>
+ <title>Background</title>
+ <p>The CRYPTO app has evolved during its lifetime. Since also the OpenSSL cryptolib has changed the
+ API several times, there are parts of the CRYPTO app that uses a very old one internally and
+ other parts that uses the latest one. The internal definitions of e.g cipher names was a bit hard
+ to maintain.
+ </p>
+ <p>It turned out that using the old api in the new way (more about that later), and still keep it
+ backwards compatible was not possible. Specially as more precision in the error messages was wanted
+ it could not be combined with the old standard.
+ </p>
+ <p>Therefore the old api (see next section) is kept for now but internally implemented with new primitives.
+ </p>
+ </section>
+
+ <section>
+ <title>The old API</title>
+ <p>The old functions - not recommended for new programs - are:</p>
+ <list>
+ <item><seealso marker="crypto#block_encrypt-3">block_encrypt/3</seealso></item>
+ <item><seealso marker="crypto#block_encrypt-4">block_encrypt/4</seealso></item>
+ <item><seealso marker="crypto#block_decrypt-3">block_decrypt/3</seealso></item>
+ <item><seealso marker="crypto#block_decrypt-4">block_decrypt/4</seealso></item>
+ <item><seealso marker="crypto#stream_init-2">stream_init/2</seealso></item>
+ <item><seealso marker="crypto#stream_init-2">stream_init/3</seealso></item>
+ <item><seealso marker="crypto#stream_encrypt-2">stream_encrypt/2</seealso></item>
+ <item><seealso marker="crypto#stream_decrypt-2">stream_decrypt/2</seealso></item>
+ </list>
+ <p>They are not deprecated for now, but may be in a future.
+ </p>
+ </section>
+
+ <section>
+ <title>The new API</title>
+ <p>The new functions for encrypting or decrypting one single text in one binary are:
+ </p>
+ <list>
+ <item><seealso marker="crypto#crypto_one_time/4">crypto_one_time/4</seealso></item>
+ <item><seealso marker="crypto#crypto_one_time/5">crypto_one_time/5</seealso></item>
+ <item><seealso marker="crypto#crypto_aead/6">crypto_aead/6</seealso></item>
+ <item><seealso marker="crypto#crypto_aead/7">crypto_aead/7</seealso></item>
+ </list>
+ <p>The <c>crypto_aead</c> functions are for the ciphers of mode <c>ccm</c> or
+ <c>gcm</c>, and for the cipher <c>chacha20-poly1305</c>.
+ </p>
+ <p>For repeated encryption or decryption of a text divided in parts, where the parts are handled
+ one by one but in sequence, the functions are:
+ </p>
+ <list>
+ <item><seealso marker="crypto#crypto_init/4">crypto_init/4</seealso></item>
+ <item><seealso marker="crypto#crypto_init/3">crypto_init/3</seealso></item>
+ <item><seealso marker="crypto#crypto_update/2">crypto_update/2</seealso></item>
+ </list>
+ <p>The <c>crypto_init</c> initialies a cipher operation and one or more calls of
+ <c>crypto_update</c> does the acual encryption or decryption. Note that AEAD ciphers
+ can't be handled this way due to their nature.
+ </p>
+ <p>Finally, for repeated encryption or decryption of a text divided in parts where the
+ same cipher and same key is used, but a new initialization vector (nounce) should be applied
+ for each part, the functions are:
+ </p>
+ <list>
+ <item><seealso marker="crypto#crypto_init_dyn_iv/3">crypto_init_dyn_iv/3</seealso></item>
+ <item><seealso marker="crypto#crypto_update_dyn_iv/3">crypto_update_dyn_iv/3</seealso></item>
+ </list>
+ <p>An example of where those functions are needed, is when handling the TLS protocol.</p>
+
+ <section>
+ <title>Examples of crypto_init/4 and crypto_update/2</title>
+ <p>Encrypting two blocks:</p>
+ <code type="erl">
+ 1> crypto:start().
+ ok
+ 2> Key = &lt;&lt;1:128>>,
+ 2> IV = &lt;&lt;0:128>>,
+ 2> StateEnc = crypto:crypto_init(aes_128_ctr, Key, IV, true). % encrypt -> true
+ #Ref&lt;0.3768901617.1128660993.124047>
+ 3> crypto:crypto_update(StateEnc, &lt;&lt;"First bytes">>).
+ &lt;&lt;67,44,216,166,25,130,203,5,66,6,162>>
+ 4> crypto:crypto_update(StateEnc, &lt;&lt;"Second bytes">>).
+ &lt;&lt;16,79,94,115,234,197,94,253,16,144,151,41>>
+ 5>
+ 5> StateDec = crypto:crypto_init(aes_128_ctr, Key, IV, false). % decrypt -> false
+ #Ref&lt;0.3768901617.1128660994.124255>
+ 6> crypto:crypto_update(StateDec, &lt;&lt;67,44,216,166,25,130,203>>).
+ &lt;&lt;"First b">>
+ 7> crypto:crypto_update(StateDec, &lt;&lt;5,66,6,162,16,79,94,115,234,197,
+ 94,253,16,144,151>>).
+ &lt;&lt;"ytesSecond byte">>
+ 8> crypto:crypto_update(StateDec, &lt;&lt;41>>).
+ &lt;&lt;"s">>
+ 9>
+ </code>
+ <p>Note that the data that the <c>StateEnc</c> and <c>StateDec</c> references are destructivly
+ updated by the calls to <seealso marker="crypto#crypto_update/2">crypto_update/2</seealso>.
+ This is to gain time in the calls of the nifs interfacing the cryptolib. In a loop where the
+ state is saved in the loop's state, it also saves one update of the loop state per crypto operation.
+ </p>
+ <p>For example, a simple server receiving text parts to encrypt and send the result back to the
+ one who sent them (the <c>Requester</c>):
+ </p>
+ <code type="erl">
+ encode(Crypto, Key, IV) ->
+ crypto_loop(crypto:crypto_init(Crypto, Key, IV, true)).
+
+ crypto_loop(State) ->
+ receive
+ {Text, Requester} ->
+ Requester ! crypto:crypto_update(State, Text),
+ loop(State)
+ end.
+ </code>
+ <p>Note that the <c>State</c> is not updated. Such updates could be costly if the loop state
+ is a tuple or record with many elements.
+ </p>
+ </section>
+
+ <section>
+ <title>Example of crypto_one_time/5</title>
+ <p>The same eample as in the
+ <seealso marker="#examples-of-crypto_init-4-and-crypto_update-2">previous section</seealso>,
+ but now with one call to <c>crypto_one_time/5</c>:
+ </p>
+ <code>
+ 2> Key = &lt;&lt;1:128>>,
+ 2> IV = &lt;&lt;0:128>>,
+ 2> Txt = [&lt;&lt;"First bytes">>,&lt;&lt;"Second bytes">>],
+ 2> crypto:crypto_one_time(aes_128_ctr, Key, IV, Txt, true).
+ &lt;&lt;67,44,216,166,25,130,203,5,66,6,162,16,79,94,115,234,
+ 197,94,253,16,144,151,41>>
+ 3>
+ </code>
+ <p>The <c>[&lt;&lt;"First bytes">>,&lt;&lt;"Second bytes">>]</c> could of course have been one
+ single binary: <c>&lt;&lt;"First bytesSecond bytes">></c>.
+ </p>
+ </section>
+ </section>
+
+ <section>
+ <title>Retired cipher names</title>
+ <p>This table lists the retired cipher names in the first column and suggests names to replace them with
+ in the second column.
+ </p>
+ <p>The new names follows the OpenSSL libcrypto names. The format is ALGORITM_KEYSIZE_MODE.
+ </p>
+ <p>Examples of algorithms are aes, chacha20 and des. The keysize is the number of bits
+ and examples of the mode are cbc, ctr and gcm. The mode may be followed by a number depending
+ on the mode. An example is the ccm mode which has a variant called ccm8 where the so called tag
+ has a length of eight bits.
+ </p>
+ <p>The old names had by time lost any common naming which the new names now introduces. The new names include
+ the key length which improves the error checking in the lower levels of the crypto application.
+ </p>
+
+ <table>
+ <row><cell><strong>Instead of:</strong></cell> <cell><strong>Use:</strong> </cell></row>
+
+ <row><cell><c>aes_cbc128</c> </cell> <cell> <c>aes_128_cbc</c> </cell></row>
+ <row><cell><c>aes_cbc256</c> </cell> <cell> <c>aes_256_cbc</c> </cell></row>
+ <row><cell><c>aes_cbc</c> </cell> <cell> <c>aes_128_cbc, aes_192_cbc, aes_256_cbc</c></cell></row>
+ <row><cell><c>aes_ccm</c> </cell> <cell> <c>aes_128_ccm, aes_192_ccm, aes_256_ccm</c></cell></row>
+ <row><cell><c>aes_cfb128</c> </cell> <cell> <c>aes_128_cfb128, aes_192_cfb128, aes_256_cfb128</c></cell></row>
+ <row><cell><c>aes_cfb8</c> </cell> <cell> <c>aes_128_cfb8, aes_192_cfb8, aes_256_cfb8</c></cell></row>
+ <row><cell><c>aes_ctr</c> </cell> <cell> <c>aes_128_ctr, aes_192_ctr, aes_256_ctr</c></cell></row>
+ <row><cell><c>aes_gcm</c> </cell> <cell> <c>aes_128_gcm, aes_192_gcm, aes_256_gcm</c></cell></row>
+ <row><cell><c>des3_cbc</c> </cell> <cell> <c>des_ede3_cbc</c></cell></row>
+ <row><cell><c>des3_cbf</c> </cell> <cell> <c>des_ede3_cfb</c></cell></row>
+ <row><cell><c>des3_cfb</c> </cell> <cell> <c>des_ede3_cfb</c></cell></row>
+ <row><cell><c>des_ede3</c> </cell> <cell> <c>des_ede3_cbc</c></cell></row>
+ <row><cell><c>des_ede3_cbf</c> </cell> <cell> <c>des_ede3_cfb</c></cell></row>
+ <tcaption></tcaption>
+ </table>
+ </section>
+
+</chapter>
diff --git a/lib/crypto/doc/src/usersguide.xml b/lib/crypto/doc/src/usersguide.xml
index 2dfc966609..134f900d4c 100644
--- a/lib/crypto/doc/src/usersguide.xml
+++ b/lib/crypto/doc/src/usersguide.xml
@@ -51,4 +51,5 @@
<xi:include href="engine_load.xml"/>
<xi:include href="engine_keys.xml"/>
<xi:include href="algorithm_details.xml"/>
+ <xi:include href="new_api.xml"/>
</part>
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index fd13481951..04b2f62266 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -58,7 +58,8 @@
%% New interface
-export([crypto_init/4, crypto_init/3,
crypto_update/2,
- crypto_one_shot/5,
+ crypto_one_time/4, crypto_one_time/5,
+ crypto_aead/6, crypto_aead/7,
crypto_init_dyn_iv/3,
crypto_update_dyn_iv/3
]).
@@ -276,48 +277,153 @@
-type edwards_curve_ed() :: ed25519 | ed448 .
-%%%
--type cipher() :: block_cipher()
- | stream_cipher()
- | aead_cipher() .
+%%%----------------------------------------------------------------
+%%% New cipher schema
+%%%
+-type cipher() :: cipher_no_iv()
+ | cipher_iv()
+ | cipher_aead() .
--type block_cipher() :: block_cipher_iv() | block_cipher_no_iv() .
+-type cipher_no_iv() :: aes_128_ecb
+ | aes_192_ecb
+ | aes_256_ecb
--type block_cipher_iv() :: cbc_cipher()
- | cfb_cipher()
- | aes_ige256
- | blowfish_ofb64
- | rc2_cbc .
+ | blowfish_ecb
+ | des_ecb
+ | rc4 .
--type cbc_cipher() :: des_cbc | des_ede3_cbc
- | blowfish_cbc
- | aes_cbc | aes_128_cbc | aes_192_cbc | aes_256_cbc
- | alias_cbc() .
--type alias_cbc() :: des3_cbc | des_ede3
- | aes_cbc128 | aes_cbc256 .
+-type cipher_iv() :: aes_128_cbc
+ | aes_192_cbc
+ | aes_256_cbc
+
+ | aes_128_cfb128
+ | aes_192_cfb128
+ | aes_256_cfb128
+
+ | aes_128_cfb8
+ | aes_192_cfb8
+ | aes_256_cfb8
--type aead_cipher() :: aes_gcm
+ | aes_128_ctr
+ | aes_192_ctr
+ | aes_256_ctr
+
+ | aes_ige256
+
+ | blowfish_cbc
+ | blowfish_cfb64
+ | blowfish_ofb64
+ | chacha20
+ | des_ede3_cbc
+ | des_ede3_cfb
+
+ | des_cbc
+ | des_cfb
+ | rc2_cbc .
+
+
+-type cipher_aead() :: aes_128_ccm
+ | aes_192_ccm
+ | aes_256_ccm
+
| aes_128_gcm
| aes_192_gcm
| aes_256_gcm
- | aes_ccm
- | aes_128_ccm
- | aes_192_ccm
- | aes_256_ccm
+
| chacha20_poly1305 .
--type cfb_cipher() :: aes_cfb8
- | aes_cfb128
- | blowfish_cfb64
- | des_cfb
- | des_ede3_cfb
- | alias_cfb() .
--type alias_cfb() :: des_ede3_cbf | des3_cbf
- | des3_cfb .
+%% -type retired_cipher_no_iv_aliases() :: aes_ecb .
+
+%% -type retired_cipher_iv_aliases() :: aes_cbc
+%% | aes_cbc128 % aes_128_cbc
+%% | aes_cbc256 % aes_256_cbc
+%% | aes_cfb128
+%% | aes_cfb8
+%% | aes_ctr
+%% | des3_cbc % des_ede3_cbc
+%% | des_ede3 % des_ede3_cbc
+%% | des_ede3_cbf % des_ede3_cfb
+%% | des3_cbf % des_ede3_cfb
+%% | des3_cfb . % des_ede3_cfb
+
+%% -type retired_cipher_aead_aliases() :: aes_ccm
+%% | aes_gcm .
--type block_cipher_no_iv() :: ecb_cipher() .
--type ecb_cipher() :: des_ecb | blowfish_ecb | aes_ecb .
+%%%----------------------------------------------------------------
+%%% Old cipher scheme
+%%%
+%%%
+-type block_cipher_without_iv() :: ecb_cipher() .
+
+-type block_cipher_with_iv() :: cbc_cipher()
+ | cfb_cipher()
+ | blowfish_ofb64
+ | aes_ige256 .
+
+-type stream_cipher() :: ctr_cipher()
+ | chacha20
+ | rc4 .
+
+
+%%%----
+-type cbc_cipher() :: aes_128_cbc
+ | aes_192_cbc
+ | aes_256_cbc
+ | blowfish_cbc
+ | des_cbc
+ | des_ede3_cbc
+ | rc2_cbc
+ | retired_cbc_cipher_aliases() .
+
+-type retired_cbc_cipher_aliases() :: aes_cbc % aes_*_cbc
+ | aes_cbc128 % aes_128_cbc
+ | aes_cbc256 % aes_256_cbc
+ | des3_cbc % des_ede3_cbc
+ | des_ede3 . % des_ede3_cbc
+
+%%%----
+-type cfb_cipher() :: aes_128_cfb128
+ | aes_192_cfb128
+ | aes_256_cfb128
+ | aes_128_cfb8
+ | aes_192_cfb8
+ | aes_256_cfb8
+ | blowfish_cfb64
+ | des_cfb
+ | des_ede3_cfb
+ | retired_cfb_cipher_aliases() .
+
+-type retired_cfb_cipher_aliases() :: aes_cfb8 % aes_*_cfb8
+ | aes_cfb128 % aes_*_cfb128
+ | des3_cbf % des_ede3_cfb, cfb misspelled
+ | des3_cfb % des_ede3_cfb
+ | des_ede3_cbf .% cfb misspelled
+
+
+%%%----
+-type ctr_cipher() :: aes_128_ctr
+ | aes_192_ctr
+ | aes_256_ctr
+ | retired_ctr_cipher_aliases() .
+
+-type retired_ctr_cipher_aliases() :: aes_ctr . % aes_*_ctr
+
+%%%----
+-type ecb_cipher() :: aes_128_ecb
+ | aes_192_ecb
+ | aes_256_ecb
+ | blowfish_ecb
+ | retired_ecb_cipher_aliases() .
+
+-type retired_ecb_cipher_aliases() :: aes_ecb .
+
+%%%----
+-type aead_cipher() :: aes_gcm | aes_ccm | chacha20_poly1305 .
+
+
+%%%----- end old cipher schema ------------------------------------
+%%%----------------------------------------------------------------
-type key() :: iodata().
-type des3_key() :: [key()].
@@ -564,9 +670,9 @@ poly1305(Key, Data) ->
-define(COMPAT(CALL),
try begin CALL end
catch
- error:{error,_} ->
+ error:{error, {_File,_Line}, _Reason} ->
error(badarg);
- error:{E,_Reason} when E==notsup ; E==badarg ->
+ error:{E, {_File,_Line}, _Reason} when E==notsup ; E==badarg ->
error(E)
end).
@@ -611,7 +717,7 @@ cipher_info(Type) ->
%%%---- Block ciphers
%%%----------------------------------------------------------------
--spec block_encrypt(Type::block_cipher_iv(), Key::key()|des3_key(), Ivec::binary(), PlainText::iodata()) ->
+-spec block_encrypt(Type::block_cipher_with_iv(), Key::key()|des3_key(), Ivec::binary(), PlainText::iodata()) ->
binary() | run_time_error();
(Type::aead_cipher(), Key::iodata(), Ivec::binary(), {AAD::binary(), PlainText::iodata()}) ->
{binary(), binary()} | run_time_error();
@@ -627,34 +733,24 @@ block_encrypt(Type, Key0, Ivec, Data) ->
?COMPAT(
case Data of
{AAD, PlainText} ->
- aead_encrypt(alias(Type,Key), Key, Ivec, AAD, PlainText, aead_tag_len(Type));
+ crypto_aead(alias(Type,Key), Key, Ivec, PlainText, AAD, true);
{AAD, PlainText, TagLength} ->
- aead_encrypt(alias(Type,Key), Key, Ivec, AAD, PlainText, TagLength);
+ crypto_aead(alias(Type,Key), Key, Ivec, PlainText, AAD, TagLength, true);
PlainText ->
- crypto_one_shot(alias(Type,Key), Key, Ivec, PlainText, true)
+ crypto_one_time(alias(Type,Key), Key, Ivec, PlainText, true)
end).
--spec block_encrypt(Type::block_cipher_no_iv(), Key::key(), PlainText::iodata()) ->
+-spec block_encrypt(Type::block_cipher_without_iv(), Key::key(), PlainText::iodata()) ->
binary() | run_time_error().
block_encrypt(Type, Key0, PlainText) ->
Key = iolist_to_binary(Key0),
- ?COMPAT(crypto_one_shot(alias(Type,Key), Key, <<>>, PlainText, true)).
+ ?COMPAT(crypto_one_time(alias(Type,Key), Key, PlainText, true)).
-aead_tag_len(chacha20_poly1305) -> 16;
-aead_tag_len(aes_ccm) -> 12;
-aead_tag_len(aes_128_ccm) -> 12;
-aead_tag_len(aes_192_ccm) -> 12;
-aead_tag_len(aes_256_ccm) -> 12;
-aead_tag_len(aes_gcm) -> 16;
-aead_tag_len(aes_128_gcm) -> 16;
-aead_tag_len(aes_192_gcm) -> 16;
-aead_tag_len(aes_256_gcm) -> 16.
-
%%%----------------------------------------------------------------
%%%----------------------------------------------------------------
--spec block_decrypt(Type::block_cipher_iv(), Key::key()|des3_key(), Ivec::binary(), Data::iodata()) ->
+-spec block_decrypt(Type::block_cipher_with_iv(), Key::key()|des3_key(), Ivec::binary(), Data::iodata()) ->
binary() | run_time_error();
(Type::aead_cipher(), Key::iodata(), Ivec::binary(),
{AAD::binary(), Data::iodata(), Tag::binary()}) ->
@@ -668,18 +764,18 @@ block_decrypt(Type, Key0, Ivec, Data) ->
?COMPAT(
case Data of
{AAD, CryptoText, Tag} ->
- aead_decrypt(alias(Type,Key), Key, Ivec, AAD, CryptoText, Tag);
+ crypto_aead(alias(Type,Key), Key, Ivec, CryptoText, AAD, Tag, false);
CryptoText ->
- crypto_one_shot(alias(Type,Key), Key, Ivec, CryptoText, false)
+ crypto_one_time(alias(Type,Key), Key, Ivec, CryptoText, false)
end).
--spec block_decrypt(Type::block_cipher_no_iv(), Key::key(), Data::iodata()) ->
+-spec block_decrypt(Type::block_cipher_without_iv(), Key::key(), Data::iodata()) ->
binary() | run_time_error().
block_decrypt(Type, Key0, CryptoText) ->
Key = iolist_to_binary(Key0),
- ?COMPAT(crypto_one_shot(alias(Type,Key), Key, <<>>, CryptoText, false)).
+ ?COMPAT(crypto_one_time(alias(Type,Key), Key, CryptoText, false)).
%%%-------- Stream ciphers API
@@ -687,17 +783,9 @@ block_decrypt(Type, Key0, CryptoText) ->
crypto_state() | {crypto_state(),flg_undefined}
}.
--type stream_cipher() :: stream_cipher_iv() | stream_cipher_no_iv() .
--type stream_cipher_no_iv() :: rc4 .
--type stream_cipher_iv() :: aes_ctr
- | aes_128_ctr
- | aes_192_ctr
- | aes_256_ctr
- | chacha20 .
-
%%%---- stream_init
-spec stream_init(Type, Key, IVec) -> State | run_time_error()
- when Type :: stream_cipher_iv(),
+ when Type :: stream_cipher(),
Key :: iodata(),
IVec ::binary(),
State :: stream_state() .
@@ -711,7 +799,7 @@ stream_init(Type, Key0, IVec) when is_binary(IVec) ->
-spec stream_init(Type, Key) -> State | run_time_error()
- when Type :: stream_cipher_no_iv(),
+ when Type :: rc4,
Key :: iodata(),
State :: stream_state() .
stream_init(rc4 = Type, Key0) ->
@@ -792,38 +880,35 @@ next_iv(Type, Data, _Ivec) ->
%%%
-spec crypto_init(Cipher, Key, EncryptFlag) -> State | descriptive_error()
- when Cipher :: block_cipher_no_iv()
- | stream_cipher_no_iv(),
+ when Cipher :: cipher_no_iv(),
Key :: iodata(),
EncryptFlag :: boolean(),
State :: crypto_state() .
crypto_init(Cipher, Key, EncryptFlag) ->
%% The IV is supposed to be supplied by calling crypto_update/3
- ng_crypto_init_nif(alias(Cipher), iolist_to_binary(Key), <<>>, EncryptFlag).
+ ng_crypto_init_nif(Cipher, iolist_to_binary(Key), <<>>, EncryptFlag).
-spec crypto_init(Cipher, Key, IV, EncryptFlag) -> State | descriptive_error()
- when Cipher :: stream_cipher_iv()
- | block_cipher_iv(),
+ when Cipher :: cipher_iv(),
Key :: iodata(),
IV :: iodata(),
EncryptFlag :: boolean(),
State :: crypto_state() .
crypto_init(Cipher, Key, IV, EncryptFlag) ->
- ng_crypto_init_nif(alias(Cipher), iolist_to_binary(Key), iolist_to_binary(IV), EncryptFlag).
+ ng_crypto_init_nif(Cipher, iolist_to_binary(Key), iolist_to_binary(IV), EncryptFlag).
%%%----------------------------------------------------------------
-spec crypto_init_dyn_iv(Cipher, Key, EncryptFlag) -> State | descriptive_error()
- when Cipher :: stream_cipher_iv()
- | block_cipher_iv(),
+ when Cipher :: cipher_iv(),
Key :: iodata(),
EncryptFlag :: boolean(),
State :: crypto_state() .
crypto_init_dyn_iv(Cipher, Key, EncryptFlag) ->
%% The IV is supposed to be supplied by calling crypto_update/3
- ng_crypto_init_nif(alias(Cipher), iolist_to_binary(Key), undefined, EncryptFlag).
+ ng_crypto_init_nif(Cipher, iolist_to_binary(Key), undefined, EncryptFlag).
%%%----------------------------------------------------------------
%%%
@@ -866,29 +951,86 @@ crypto_update_dyn_iv(State, Data0, IV) ->
%%% The size must be an integer multiple of the crypto's blocksize.
%%%
--spec crypto_one_shot(Cipher, Key, IV, Data, EncryptFlag) ->
+-spec crypto_one_time(Cipher, Key, Data, EncryptFlag) ->
Result | descriptive_error()
- when Cipher :: stream_cipher()
- | block_cipher(),
+ when Cipher :: cipher_no_iv(),
Key :: iodata(),
- IV :: iodata() | undefined,
Data :: iodata(),
EncryptFlag :: boolean(),
Result :: binary() .
-crypto_one_shot(Cipher, Key, undefined, Data, EncryptFlag) ->
- crypto_one_shot(Cipher, Key, <<>>, Data, EncryptFlag);
+crypto_one_time(Cipher, Key, Data, EncryptFlag) ->
+ crypto_one_time(Cipher, Key, <<>>, Data, EncryptFlag).
-crypto_one_shot(Cipher, Key, IV, Data0, EncryptFlag) ->
+-spec crypto_one_time(Cipher, Key, IV, Data, EncryptFlag) ->
+ Result | descriptive_error()
+ when Cipher :: cipher_iv(),
+ Key :: iodata(),
+ IV :: iodata(),
+ Data :: iodata(),
+ EncryptFlag :: boolean(),
+ Result :: binary() .
+
+crypto_one_time(Cipher, Key, IV, Data0, EncryptFlag) ->
case iolist_to_binary(Data0) of
<<>> ->
<<>>; % Known to fail on OpenSSL 0.9.8h
Data ->
- ng_crypto_one_shot_nif(alias(Cipher),
+ ng_crypto_one_time_nif(Cipher,
iolist_to_binary(Key), iolist_to_binary(IV), Data,
EncryptFlag)
end.
+
+-spec crypto_aead(Cipher, Key, IV, InText, AAD, EncFlag::true) ->
+ Result | descriptive_error()
+ when Cipher :: cipher_aead(),
+ Key :: iodata(),
+ IV :: iodata(),
+ InText :: iodata(),
+ AAD :: iodata(),
+ Result :: EncryptResult,
+ EncryptResult :: {OutCryptoText, OutTag},
+ OutCryptoText :: binary(),
+ OutTag :: binary().
+
+crypto_aead(Cipher, Key, IV, PlainText, AAD, true) ->
+ crypto_aead(Cipher, Key, IV, PlainText, AAD, aead_tag_len(Cipher), true).
+
+
+-spec crypto_aead(Cipher, Key, IV, InText, AAD, TagOrTagLength, EncFlag) ->
+ Result | descriptive_error()
+ when Cipher :: cipher_aead(),
+ Key :: iodata(),
+ IV :: iodata(),
+ InText :: iodata(),
+ AAD :: iodata(),
+ TagOrTagLength :: EncryptTagLength | DecryptTag,
+ EncryptTagLength :: non_neg_integer(), % or pos_integer() 1..
+ DecryptTag :: iodata(),
+ EncFlag :: boolean(),
+ Result :: EncryptResult | DecryptResult,
+ EncryptResult :: {OutCryptoText, OutTag},
+ DecryptResult :: OutPlainText | error,
+ OutCryptoText :: binary(),
+ OutTag :: binary(),
+ OutPlainText :: binary().
+
+crypto_aead(Cipher, Key, IV, TextIn, AAD, TagOrTagLength, EncFlg) ->
+ aead_cipher(Cipher, Key, IV, TextIn, AAD, TagOrTagLength, EncFlg).
+
+
+aead_tag_len(chacha20_poly1305) -> 16;
+aead_tag_len(aes_ccm ) -> 12;
+aead_tag_len(aes_128_ccm) -> 12;
+aead_tag_len(aes_192_ccm) -> 12;
+aead_tag_len(aes_256_ccm) -> 12;
+aead_tag_len(aes_gcm ) -> 16;
+aead_tag_len(aes_128_gcm) -> 16;
+aead_tag_len(aes_192_gcm) -> 16;
+aead_tag_len(aes_256_gcm) -> 16;
+aead_tag_len(_) -> error({badarg, "Not an AEAD cipher"}).
+
%%%----------------------------------------------------------------
%%% NIFs
@@ -909,9 +1051,9 @@ ng_crypto_update_nif(_State, _Data) -> ?nif_stub.
ng_crypto_update_nif(_State, _Data, _IV) -> ?nif_stub.
--spec ng_crypto_one_shot_nif(atom(), binary(), binary(), binary(), boolean() ) ->
+-spec ng_crypto_one_time_nif(atom(), binary(), binary(), binary(), boolean() ) ->
binary() | descriptive_error().
-ng_crypto_one_shot_nif(_Cipher, _Key, _IVec, _Data, _EncryptFlg) -> ?nif_stub.
+ng_crypto_one_time_nif(_Cipher, _Key, _IVec, _Data, _EncryptFlg) -> ?nif_stub.
%%%----------------------------------------------------------------
%%% Cipher aliases
@@ -2060,8 +2202,7 @@ cipher_info_nif(_Type) -> ?nif_stub.
%% AES - in Galois/Counter Mode (GCM)
%%
%% The default tag length is EVP_GCM_TLS_TAG_LEN(16),
-aead_encrypt(_Type, _Key, _Ivec, _AAD, _In, _TagLength) -> ?nif_stub.
-aead_decrypt(_Type, _Key, _Ivec, _AAD, _In, _Tag) -> ?nif_stub.
+aead_cipher(_Type, _Key, _Ivec, _AAD, _In, _TagOrTagLength, _EncFlg) -> ?nif_stub.
%%
%% AES - with 256 bit key in infinite garble extension mode (IGE)
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index ce5097de47..6a2727a622 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -45,6 +45,42 @@ all() ->
hash_info
].
+-define(NEW_CIPHER_TYPE_SCHEMA,
+ {group, des_ede3_cbc},
+ {group, des_ede3_cfb},
+ {group, aes_128_cbc},
+ {group, aes_192_cbc},
+ {group, aes_256_cbc},
+ {group, aes_128_ctr},
+ {group, aes_192_ctr},
+ {group, aes_256_ctr},
+ {group, aes_128_ccm},
+ {group, aes_192_ccm},
+ {group, aes_256_ccm},
+ {group, aes_128_ecb},
+ {group, aes_192_ecb},
+ {group, aes_256_ecb},
+ {group, aes_128_gcm},
+ {group, aes_192_gcm},
+ {group, aes_256_gcm},
+ {group, des_ede3_cbc},
+ {group, des_ede3_cfb}
+ ).
+
+-define(RETIRED_TYPE_ALIASES,
+ {group, aes_cbc},
+ {group, aes_cbc128},
+ {group, aes_cbc256},
+ {group, aes_ccm},
+ {group, aes_ctr},
+ {group, aes_gcm},
+ {group, aes_ecb},
+ {group, des3_cfb},
+ {group, des3_cbc},
+ {group, des3_cbf},
+ {group, des_ede3}
+ ).
+
groups() ->
[{non_fips, [], [
{group, blake2b},
@@ -67,35 +103,29 @@ groups() ->
{group, sha3_512},
{group, sha512},
{group, sha},
+ {group, poly1305},
{group, dh},
{group, ecdh},
{group, srp},
- {group, aes_cbc},
- {group, aes_ccm},
- {group, aes_gcm},
{group, chacha20_poly1305},
{group, chacha20},
- {group, des3_cfb},
- {group, aes_cbc128},
- {group, aes_cbc256},
- {group, aes_cfb128},
- {group, aes_cfb8},
- {group, aes_ctr},
- {group, aes_ige256},
{group, blowfish_cbc},
{group, blowfish_cfb64},
{group, blowfish_ecb},
{group, blowfish_ofb64},
- {group, des3_cbc},
- {group, des3_cbf},
+
+ {group, aes_cfb128},
+ {group, aes_cfb8},
+ {group, aes_ige256},
{group, des_cbc},
{group, des_cfb},
- {group, des_ede3},
- {group, poly1305},
{group, rc2_cbc},
- {group, rc4}
+ {group, rc4},
+
+ ?NEW_CIPHER_TYPE_SCHEMA,
+ ?RETIRED_TYPE_ALIASES
]},
{fips, [], [
{group, no_blake2b},
@@ -114,123 +144,142 @@ groups() ->
{group, sha256},
{group, sha384},
{group, sha512},
+ {group, no_poly1305},
{group, dh},
{group, ecdh},
{group, no_srp},
- {group, aes_cbc},
- {group, aes_ccm},
- {group, aes_gcm},
{group, no_chacha20_poly1305},
{group, no_chacha20},
- {group, des3_cfb},
- {group, aes_cbc128},
- {group, aes_cbc256},
- {group, no_aes_cfb128},
- {group, no_aes_cfb8},
- {group, aes_ctr},
- {group, no_aes_ige256},
{group, no_blowfish_cbc},
{group, no_blowfish_cfb64},
{group, no_blowfish_ecb},
{group, no_blowfish_ofb64},
- {group, des3_cbc},
- {group, des3_cbf},
+
+ {group, no_aes_cfb128},
+ {group, no_aes_cfb8},
+ {group, no_aes_ige256},
{group, no_des_cbc},
{group, no_des_cfb},
- {group, des_ede3},
- {group, no_poly1305},
{group, no_rc2_cbc},
- {group, no_rc4}
+ {group, no_rc4},
+
+ ?NEW_CIPHER_TYPE_SCHEMA,
+ ?RETIRED_TYPE_ALIASES
]},
- {md4, [], [hash]},
- {md5, [], [hash, hmac]},
- {ripemd160, [], [hash]},
- {sha, [], [hash, hmac]},
- {sha224, [], [hash, hmac]},
- {sha256, [], [hash, hmac]},
- {sha384, [], [hash, hmac]},
- {sha512, [], [hash, hmac]},
- {sha3_224, [], [hash, hmac]},
- {sha3_256, [], [hash, hmac]},
- {sha3_384, [], [hash, hmac]},
- {sha3_512, [], [hash, hmac]},
- {blake2b, [], [hash, hmac]},
- {blake2s, [], [hash, hmac]},
- {no_blake2b, [], [no_hash, no_hmac]},
- {no_blake2s, [], [no_hash, no_hmac]},
- {rsa, [], [sign_verify,
- public_encrypt,
- private_encrypt,
- generate
- ]},
- {dss, [], [sign_verify
- %% Does not work yet: ,public_encrypt, private_encrypt
- ]},
- {ecdsa, [], [sign_verify
- %% Does not work yet: ,public_encrypt, private_encrypt
- ]},
- {ed25519, [], [sign_verify
- %% Does not work yet: ,public_encrypt, private_encrypt
- ]},
- {ed448, [], [sign_verify
- %% Does not work yet: ,public_encrypt, private_encrypt
- ]},
- {dh, [], [generate_compute,
- compute_bug]},
- {ecdh, [], [use_all_elliptic_curves, compute, generate]},
- {srp, [], [generate_compute]},
- {des_cbc, [], [block, api_ng, api_ng_one_shot, api_ng_tls]},
- {des_cfb, [], [block, api_ng, api_ng_one_shot, api_ng_tls]},
- {des3_cbc,[], [block, api_ng, api_ng_one_shot, api_ng_tls]},
- {des_ede3,[], [block, api_ng, api_ng_one_shot, api_ng_tls]},
- {des3_cbf,[], [block, api_ng, api_ng_one_shot, api_ng_tls]},
- {des3_cfb,[], [block, api_ng, api_ng_one_shot, api_ng_tls]},
- {rc2_cbc,[], [block, api_ng, api_ng_one_shot, api_ng_tls]},
- {aes_cbc128,[], [block, api_ng, api_ng_one_shot, api_ng_tls, cmac]},
- {aes_cfb8,[], [block, api_ng, api_ng_one_shot, api_ng_tls]},
- {aes_cfb128,[], [block, api_ng, api_ng_one_shot, api_ng_tls]},
- {aes_cbc256,[], [block, api_ng, api_ng_one_shot, api_ng_tls, cmac]},
- {aes_ecb,[], [block, api_ng, api_ng_one_shot, api_ng_tls]},
- {aes_ige256,[], [block]},
- {blowfish_cbc, [], [block, api_ng, api_ng_one_shot, api_ng_tls]},
- {blowfish_ecb, [], [block, api_ng, api_ng_one_shot, api_ng_tls]},
- {blowfish_cfb64, [], [block, api_ng, api_ng_one_shot, api_ng_tls]},
- {blowfish_ofb64,[], [block, api_ng, api_ng_one_shot, api_ng_tls]},
- {rc4, [], [stream, api_ng, api_ng_one_shot, api_ng_tls]},
- {aes_ctr, [], [stream, api_ng, api_ng_one_shot, api_ng_tls]},
- {aes_ccm, [], [aead]},
- {aes_gcm, [], [aead]},
- {chacha20_poly1305, [], [aead]},
- {chacha20, [], [stream, api_ng, api_ng_one_shot, api_ng_tls]},
- {poly1305, [], [poly1305]},
- {no_poly1305, [], [no_poly1305]},
- {aes_cbc, [], [block, api_ng, api_ng_one_shot, api_ng_tls]},
- {no_aes_cfb8,[], [no_support, no_block]},
- {no_aes_cfb128,[], [no_support, no_block]},
- {no_md4, [], [no_support, no_hash]},
- {no_md5, [], [no_support, no_hash, no_hmac]},
- {no_ed25519, [], [no_support, no_sign_verify
- %% Does not work yet: ,public_encrypt, private_encrypt
- ]},
- {no_ed448, [], [no_support, no_sign_verify
- %% Does not work yet: ,public_encrypt, private_encrypt
- ]},
- {no_ripemd160, [], [no_support, no_hash]},
- {no_srp, [], [no_support, no_generate_compute]},
- {no_des_cbc, [], [no_support, no_block]},
- {no_des_cfb, [], [no_support, no_block]},
- {no_blowfish_cbc, [], [no_support, no_block]},
- {no_blowfish_ecb, [], [no_support, no_block]},
- {no_blowfish_cfb64, [], [no_support, no_block]},
- {no_blowfish_ofb64, [], [no_support, no_block]},
- {no_aes_ige256, [], [no_support, no_block]},
+
+ {md4, [], [hash]},
+ {md5, [], [hash, hmac]},
+ {ripemd160, [], [hash]},
+ {sha, [], [hash, hmac]},
+ {sha224, [], [hash, hmac]},
+ {sha256, [], [hash, hmac]},
+ {sha384, [], [hash, hmac]},
+ {sha512, [], [hash, hmac]},
+ {sha3_224, [], [hash, hmac]},
+ {sha3_256, [], [hash, hmac]},
+ {sha3_384, [], [hash, hmac]},
+ {sha3_512, [], [hash, hmac]},
+ {blake2b, [], [hash, hmac]},
+ {blake2s, [], [hash, hmac]},
+ {no_blake2b, [], [no_hash, no_hmac]},
+ {no_blake2s, [], [no_hash, no_hmac]},
+ {rsa, [], [sign_verify,
+ public_encrypt,
+ private_encrypt,
+ generate
+ ]},
+ {dss, [], [sign_verify
+ %% Does not work yet: ,public_encrypt, private_encrypt
+ ]},
+ {ecdsa, [], [sign_verify
+ %% Does not work yet: ,public_encrypt, private_encrypt
+ ]},
+ {ed25519, [], [sign_verify
+ %% Does not work yet: ,public_encrypt, private_encrypt
+ ]},
+ {ed448, [], [sign_verify
+ %% Does not work yet: ,public_encrypt, private_encrypt
+ ]},
+ {dh, [], [generate_compute, compute_bug]},
+ {ecdh, [], [use_all_elliptic_curves, compute, generate]},
+ {srp, [], [generate_compute]},
+ {des_cbc, [], [block, api_ng, api_ng_one_shot, api_ng_tls]},
+ {des_cfb, [], [block, api_ng, api_ng_one_shot, api_ng_tls]},
+ {des_ede3_cbc, [], [block, api_ng, api_ng_one_shot, api_ng_tls]},
+ {des_ede3_cfb, [], [block, api_ng, api_ng_one_shot, api_ng_tls]},
+ {rc2_cbc, [], [block, api_ng, api_ng_one_shot, api_ng_tls]},
+ {aes_cfb8, [], [block, api_ng, api_ng_one_shot, api_ng_tls]},
+ {no_aes_cfb8, [], [no_support, no_block]},
+ {aes_cfb128, [], [block, api_ng, api_ng_one_shot, api_ng_tls]},
+ {no_aes_cfb128, [], [no_support, no_block]},
+ {aes_ige256, [], [block]},
+ {no_aes_ige256, [], [no_support, no_block]},
+ {blowfish_cbc, [], [block, api_ng, api_ng_one_shot, api_ng_tls]},
+ {blowfish_ecb, [], [block, api_ng, api_ng_one_shot]},
+ {blowfish_cfb64, [], [block, api_ng, api_ng_one_shot, api_ng_tls]},
+ {blowfish_ofb64, [], [block, api_ng, api_ng_one_shot, api_ng_tls]},
+ {rc4, [], [stream, api_ng, api_ng_one_shot, api_ng_tls]},
+ {aes_ctr, [], [stream]},
+ {chacha20_poly1305, [], [aead]},
+ {chacha20, [], [stream, api_ng, api_ng_one_shot, api_ng_tls]},
+ {poly1305, [], [poly1305]},
+ {no_poly1305, [], [no_poly1305]},
+ {no_aes_cfb128, [], [no_support, no_block]},
+ {no_md4, [], [no_support, no_hash]},
+ {no_md5, [], [no_support, no_hash, no_hmac]},
+ {no_ed25519, [], [no_support, no_sign_verify
+ %% Does not work yet: ,public_encrypt, private_encrypt
+ ]},
+ {no_ed448, [], [no_support, no_sign_verify
+ %% Does not work yet: ,public_encrypt, private_encrypt
+ ]},
+ {no_ripemd160, [], [no_support, no_hash]},
+ {no_srp, [], [no_support, no_generate_compute]},
+ {no_des_cbc, [], [no_support, no_block]},
+ {no_des_cfb, [], [no_support, no_block]},
+ {no_blowfish_cbc, [], [no_support, no_block]},
+ {no_blowfish_ecb, [], [no_support, no_block]},
+ {no_blowfish_cfb64, [], [no_support, no_block]},
+ {no_blowfish_ofb64, [], [no_support, no_block]},
+ {no_aes_ige256, [], [no_support, no_block]},
{no_chacha20_poly1305, [], [no_support, no_aead]},
- {no_chacha20, [], [no_support, no_stream_ivec]},
- {no_rc2_cbc, [], [no_support, no_block]},
- {no_rc4, [], [no_support, no_stream]},
- {api_errors, [], [api_errors_ecdh]}
+ {no_chacha20, [], [no_support, no_stream_ivec]},
+ {no_rc2_cbc, [], [no_support, no_block]},
+ {no_rc4, [], [no_support, no_stream]},
+ {api_errors, [], [api_errors_ecdh]},
+
+ %% New cipher nameing schema
+ {des_ede3_cbc, [], [api_ng, api_ng_one_shot, api_ng_tls]},
+ {des_ede3_cfb, [], [api_ng, api_ng_one_shot, api_ng_tls]},
+ {aes_128_cbc, [], [api_ng, api_ng_one_shot, api_ng_tls]},
+ {aes_192_cbc, [], [api_ng, api_ng_one_shot, api_ng_tls]},
+ {aes_256_cbc, [], [api_ng, api_ng_one_shot, api_ng_tls]},
+ {aes_128_ctr, [], [api_ng, api_ng_one_shot, api_ng_tls]},
+ {aes_192_ctr, [], [api_ng, api_ng_one_shot, api_ng_tls]},
+ {aes_256_ctr, [], [api_ng, api_ng_one_shot, api_ng_tls]},
+ {aes_128_ccm, [], [aead]},
+ {aes_192_ccm, [], [aead]},
+ {aes_256_ccm, [], [aead]},
+ {aes_128_ecb, [], [api_ng, api_ng_one_shot]},
+ {aes_192_ecb, [], [api_ng, api_ng_one_shot]},
+ {aes_256_ecb, [], [api_ng, api_ng_one_shot]},
+ {aes_128_gcm, [], [aead]},
+ {aes_192_gcm, [], [aead]},
+ {aes_256_gcm, [], [aead]},
+
+ %% Retired aliases
+ {aes_cbc, [], [block]},
+ {aes_cbc128, [], [block]},
+ {aes_cbc256, [], [block]},
+ {aes_ccm, [], [aead]},
+ {aes_ecb, [], [block]},
+ {aes_gcm, [], [aead]},
+ {des3_cbc, [], [block]},
+ {des_ede3, [], [block]},
+ {des3_cbf, [], [block]},
+ {des3_cfb, [], [block]}
].
%%-------------------------------------------------------------------
@@ -430,7 +479,6 @@ poly1305(Config) ->
no_poly1305() ->
[{doc, "Test disabled poly1305 function"}].
no_poly1305(Config) ->
- Type = ?config(type, Config),
Key = <<133,214,190,120,87,85,109,51,127,68,82,254,66,213,6,168,1,
3,128,138,251,13,178,253,74,191,246,175,65,73,245,27>>,
Txt = <<"Cryptographic Forum Research Group">>,
@@ -440,7 +488,7 @@ no_poly1305(Config) ->
block() ->
[{doc, "Test block ciphers"}].
block(Config) when is_list(Config) ->
- Blocks = lazy_eval(proplists:get_value(block, Config)),
+ [_|_] = Blocks = lazy_eval(proplists:get_value(cipher, Config)),
lists:foreach(fun block_cipher/1, Blocks),
lists:foreach(fun block_cipher/1, block_iolistify(Blocks)),
lists:foreach(fun block_cipher_increment/1, block_iolistify(Blocks)).
@@ -449,7 +497,7 @@ block(Config) when is_list(Config) ->
no_block() ->
[{doc, "Test disabled block ciphers"}].
no_block(Config) when is_list(Config) ->
- Blocks = lazy_eval(proplists:get_value(block, Config)),
+ [_|_] = Blocks = lazy_eval(proplists:get_value(cipher, Config)),
Args = case Blocks of
[{_Type, _Key, _PlainText} = A | _] ->
tuple_to_list(A);
@@ -466,10 +514,8 @@ api_ng() ->
[{doc, "Test new api"}].
api_ng(Config) when is_list(Config) ->
- Blocks = lazy_eval(proplists:get_value(block, Config, [])),
- Streams = lazy_eval(proplists:get_value(stream, Config, [])),
- lists:foreach(fun api_ng_cipher_increment/1, Blocks++Streams).
-
+ [_|_] = Ciphers = lazy_eval(proplists:get_value(cipher, Config, [])),
+ lists:foreach(fun api_ng_cipher_increment/1, Ciphers).
api_ng_cipher_increment({Type, Key, PlainTexts}=_X) ->
ct:log("~p",[_X]),
@@ -523,9 +569,8 @@ api_ng_one_shot() ->
[{doc, "Test new api"}].
api_ng_one_shot(Config) when is_list(Config) ->
- Blocks = lazy_eval(proplists:get_value(block, Config, [])),
- Streams = lazy_eval(proplists:get_value(stream, Config, [])),
- lists:foreach(fun do_api_ng_one_shot/1, Blocks++Streams).
+ [_|_] = Ciphers = lazy_eval(proplists:get_value(cipher, Config, [])),
+ lists:foreach(fun do_api_ng_one_shot/1, Ciphers).
do_api_ng_one_shot({Type, Key, PlainTexts}=_X) ->
ct:log("~p",[_X]),
@@ -537,8 +582,8 @@ do_api_ng_one_shot({Type, Key, IV, PlainTexts}=_X) ->
do_api_ng_one_shot({Type, Key, IV, PlainText0, ExpectedEncText}=_X) ->
ct:log("~p",[_X]),
- PlainText = iolist_to_binary(PlainText0),
- EncTxt = crypto:crypto_one_shot(Type, Key, IV, PlainText, true),
+ PlainText = iolist_to_binary(lazy_eval(PlainText0)),
+ EncTxt = crypto:crypto_one_time(Type, Key, IV, PlainText, true),
case ExpectedEncText of
undefined ->
ok;
@@ -546,14 +591,14 @@ do_api_ng_one_shot({Type, Key, IV, PlainText0, ExpectedEncText}=_X) ->
ok;
_ ->
ct:log("encode~nIn: ~p~nExpected: ~p~nEnc: ~p~n", [{Type,Key,IV,PlainText}, ExpectedEncText, EncTxt]),
- ct:fail("api_ng_one_shot (encode)",[])
+ ct:fail("api_ng_one_time (encode)",[])
end,
- case crypto:crypto_one_shot(Type, Key, IV, EncTxt, false) of
+ case crypto:crypto_one_time(Type, Key, IV, EncTxt, false) of
PlainText ->
ok;
OtherPT ->
ct:log("decode~nIn: ~p~nExpected: ~p~nDec: ~p~n", [{Type,Key,IV,EncTxt}, PlainText, OtherPT]),
- ct:fail("api_ng_one_shot (decode)",[])
+ ct:fail("api_ng_one_time (decode)",[])
end.
%%--------------------------------------------------------------------
@@ -561,9 +606,8 @@ api_ng_tls() ->
[{doc, "Test special tls api"}].
api_ng_tls(Config) when is_list(Config) ->
- Blocks = lazy_eval(proplists:get_value(block, Config, [])),
- Streams = lazy_eval(proplists:get_value(stream, Config, [])),
- lists:foreach(fun do_api_ng_tls/1, Blocks++Streams).
+ [_|_] = Ciphers = lazy_eval(proplists:get_value(cipher, Config, [])),
+ lists:foreach(fun do_api_ng_tls/1, Ciphers).
do_api_ng_tls({Type, Key, PlainTexts}=_X) ->
@@ -576,7 +620,7 @@ do_api_ng_tls({Type, Key, IV, PlainTexts}=_X) ->
do_api_ng_tls({Type, Key, IV, PlainText0, ExpectedEncText}=_X) ->
ct:log("~p",[_X]),
- PlainText = iolist_to_binary(PlainText0),
+ PlainText = iolist_to_binary(lazy_eval(PlainText0)),
Renc = crypto:crypto_init_dyn_iv(Type, Key, true),
Rdec = crypto:crypto_init_dyn_iv(Type, Key, false),
EncTxt = crypto:crypto_update_dyn_iv(Renc, PlainText, IV),
@@ -616,7 +660,7 @@ no_aead() ->
[{doc, "Test disabled aead ciphers"}].
no_aead(Config) when is_list(Config) ->
EncArg4 =
- case lazy_eval(proplists:get_value(aead, Config)) of
+ case lazy_eval(proplists:get_value(cipher, Config)) of
[{Type, Key, PlainText, Nonce, AAD, CipherText, CipherTag, TagLen, _Info} | _] ->
{AAD, PlainText, TagLen};
[{Type, Key, PlainText, Nonce, AAD, CipherText, CipherTag, _Info} | _] ->
@@ -631,7 +675,7 @@ no_aead(Config) when is_list(Config) ->
stream() ->
[{doc, "Test stream ciphers"}].
stream(Config) when is_list(Config) ->
- Streams = lazy_eval(proplists:get_value(stream, Config)),
+ [_|_] = Streams = lazy_eval(proplists:get_value(cipher, Config)),
lists:foreach(fun stream_cipher/1, Streams),
lists:foreach(fun stream_cipher/1, stream_iolistify(Streams)),
@@ -654,8 +698,7 @@ no_stream_ivec(Config) when is_list(Config) ->
aead() ->
[{doc, "Test AEAD ciphers"}].
aead(Config) when is_list(Config) ->
- AEADs = lazy_eval(proplists:get_value(aead, Config)),
-
+ [_|_] = AEADs = lazy_eval(proplists:get_value(cipher, Config)),
FilteredAEADs =
case proplists:get_bool(fips, Config) of
false ->
@@ -668,7 +711,6 @@ aead(Config) when is_list(Config) ->
IVLen >= 12
end, AEADs)
end,
-
lists:foreach(fun aead_cipher/1, FilteredAEADs).
%%--------------------------------------------------------------------
@@ -985,13 +1027,27 @@ block_cipher({Type, Key, IV, PlainText, CipherText}) ->
ct:fail({{crypto, block_decrypt, [Type, Key, IV, CipherText]}, {expected, Plain}, {got, Other1}})
end.
-block_cipher_increment({Type, Key, IV, PlainTexts})
- when Type == des_cbc; Type == aes_cbc; Type == des3_cbc ->
+block_cipher_increment({Type, Key, IV, PlainTexts}) when Type == des_cbc ;
+ Type == des3_cbc ;
+ Type == aes_128_cbc ;
+ Type == aes_192_cbc ;
+ Type == aes_256_cbc
+ ->
block_cipher_increment(Type, Key, IV, IV, PlainTexts, iolist_to_binary(PlainTexts), []);
-block_cipher_increment({Type, Key, IV, PlainTexts, CipherText})
- when Type == des_cbc; Type == des3_cbc ->
+block_cipher_increment({Type, Key, IV, PlainTexts, CipherText}) when Type == des_cbc;
+ Type == des_ede3_cbc ;
+ Type == des3_cbc ;
+ Type == des_ede3 ;
+ Type == des_ede3_cfb ;
+ Type == des_ede3_cbf ;
+ Type == des3_cbf ;
+ Type == des3_cfb
+ ->
block_cipher_increment(Type, Key, IV, IV, PlainTexts, iolist_to_binary(PlainTexts), CipherText, []);
-block_cipher_increment({Type, Key, IV, PlainTexts, _CipherText}) when Type == aes_cbc ->
+block_cipher_increment({Type, Key, IV, PlainTexts, _CipherText}) when Type == aes_128_cbc ;
+ Type == aes_192_cbc ;
+ Type == aes_256_cbc
+ ->
Plain = iolist_to_binary(PlainTexts),
Blocks = [iolistify(Block) || << Block:128/bitstring >> <= Plain],
block_cipher_increment(Type, Key, IV, IV, Blocks, Plain, []);
@@ -1025,8 +1081,9 @@ block_cipher_increment(Type, Key, IV0, IV, [PlainText | PlainTexts], Plain, Ciph
NextIV = crypto:next_iv(Type, CT),
block_cipher_increment(Type, Key, IV0, NextIV, PlainTexts, Plain, CipherText, [CT | Acc]).
-stream_cipher({Type, Key, PlainText}) ->
- Plain = iolist_to_binary(PlainText),
+stream_cipher({Type, Key, PlainText0}) ->
+ PlainText = lazy_eval(PlainText0),
+ Plain = iolist_to_binary(lazy_eval(PlainText)),
StateE = crypto:stream_init(Type, Key),
StateD = crypto:stream_init(Type, Key),
{_, CipherText} = crypto:stream_encrypt(StateE, PlainText),
@@ -1036,7 +1093,8 @@ stream_cipher({Type, Key, PlainText}) ->
Other ->
ct:fail({{crypto, stream_decrypt, [StateD, CipherText]}, {expected, PlainText}, {got, Other}})
end;
-stream_cipher({Type, Key, IV, PlainText}) ->
+stream_cipher({Type, Key, IV, PlainText0}) ->
+ PlainText = lazy_eval(PlainText0),
Plain = iolist_to_binary(PlainText),
StateE = crypto:stream_init(Type, Key, IV),
StateD = crypto:stream_init(Type, Key, IV),
@@ -1047,7 +1105,8 @@ stream_cipher({Type, Key, IV, PlainText}) ->
Other ->
ct:fail({{crypto, stream_decrypt, [StateD, CipherText]}, {expected, PlainText}, {got, Other}})
end;
-stream_cipher({Type, Key, IV, PlainText, CipherText}) ->
+stream_cipher({Type, Key, IV, PlainText0, CipherText}) ->
+ PlainText = lazy_eval(PlainText0),
Plain = iolist_to_binary(PlainText),
StateE = crypto:stream_init(Type, Key, IV),
StateD = crypto:stream_init(Type, Key, IV),
@@ -1112,7 +1171,7 @@ aead_cipher({Type, Key, PlainText, IV, AAD, CipherText, CipherTag, Info}) ->
aead_cipher({Type, Key, PlainText, IV, AAD, CipherText, CipherTag, TagLen, Info}) ->
<<TruncatedCipherTag:TagLen/binary, _/binary>> = CipherTag,
Plain = iolist_to_binary(PlainText),
- case crypto:block_encrypt(Type, Key, IV, {AAD, Plain, TagLen}) of
+ try crypto:block_encrypt(Type, Key, IV, {AAD, Plain, TagLen}) of
{CipherText, TruncatedCipherTag} ->
ok;
Other0 ->
@@ -1121,6 +1180,18 @@ aead_cipher({Type, Key, PlainText, IV, AAD, CipherText, CipherTag, TagLen, Info}
[{info,Info}, {key,Key}, {pt,PlainText}, {iv,IV}, {aad,AAD}, {ct,CipherText}, {tag,CipherTag}, {taglen,TagLen}]},
{expected, {CipherText, TruncatedCipherTag}},
{got, Other0}})
+ catch
+ error:E ->
+ ct:log("~p",[{Type, Key, PlainText, IV, AAD, CipherText, CipherTag, TagLen, Info}]),
+ try crypto:crypto_aead(Type, Key, IV, PlainText, AAD, TagLen, true)
+ of
+ RR ->
+ ct:log("Works: ~p",[RR])
+ catch
+ CC:EE ->
+ ct:log("~p:~p", [CC,EE])
+ end,
+ ct:fail("~p",[E])
end,
case crypto:block_decrypt(Type, Key, IV, {AAD, CipherText, TruncatedCipherTag}) of
Plain ->
@@ -1369,16 +1440,15 @@ do_stream_iolistify({Type, Key, IV, PlainText}) ->
{Type, iolistify(Key), IV, iolistify(PlainText)};
do_stream_iolistify({Type, Key, IV, PlainText, CipherText}) ->
{Type, iolistify(Key), IV, iolistify(PlainText), CipherText}.
-
-do_block_iolistify({des_cbc = Type, Key, IV, PlainText}) ->
- {Type, Key, IV, des_iolistify(PlainText)};
-do_block_iolistify({des3_cbc = Type, Key, IV, PlainText}) ->
- {Type, Key, IV, des_iolistify(PlainText)};
-do_block_iolistify({des3_cbf = Type, Key, IV, PlainText}) ->
- {Type, Key, IV, des_iolistify(PlainText)};
-do_block_iolistify({des3_cfb = Type, Key, IV, PlainText}) ->
- {Type, Key, IV, des_iolistify(PlainText)};
-do_block_iolistify({des_ede3 = Type, Key, IV, PlainText}) ->
+do_block_iolistify({Type, Key, IV, PlainText}) when Type == des_cbc ;
+ Type == des_ede3_cbc ;
+ Type == des3_cbc ;
+ Type == des_ede3 ;
+ Type == des_ede3_cfb ;
+ Type == des_ede3_cbf ;
+ Type == des3_cbf ;
+ Type == des3_cfb
+ ->
{Type, Key, IV, des_iolistify(PlainText)};
do_block_iolistify({Type, Key, PlainText}) ->
{Type, iolistify(Key), iolistify(PlainText)};
@@ -1387,10 +1457,13 @@ do_block_iolistify({Type, Key, IV, PlainText}) ->
do_block_iolistify({Type, Key, IV, PlainText, CipherText}) ->
{Type, iolistify(Key), IV, iolistify(PlainText), CipherText}.
-iolistify(<<"Test With Truncation">>)->
+iolistify(X) ->
+ iolistify1(lazy_eval(X)).
+
+iolistify1(<<"Test With Truncation">>)->
%% Do not iolistify as it spoils this special case
<<"Test With Truncation">>;
-iolistify(Msg) when is_binary(Msg) ->
+iolistify1(Msg) when is_binary(Msg) ->
Length = erlang:byte_size(Msg),
Split = Length div 2,
List0 = binary_to_list(Msg),
@@ -1400,8 +1473,8 @@ iolistify(Msg) when is_binary(Msg) ->
{List1, List2}->
[List1, List2]
end;
-iolistify(Msg) ->
- iolistify(list_to_binary(Msg)).
+iolistify1(Msg) when is_list(Msg) ->
+ iolistify1(list_to_binary(Msg)).
des_iolistify(Msg) ->
des_iolist(erlang:byte_size(Msg) div 8, Msg, []).
@@ -1710,7 +1783,6 @@ group_config(dss = Type, Config) ->
MsgPubEnc = <<"7896345786348 Asldi">>,
PubPrivEnc = [{dss, Public, Private, MsgPubEnc, []}],
[{sign_verify, SignVerify}, {pub_priv_encrypt, PubPrivEnc} | Config];
-
group_config(ecdsa = Type, Config) ->
{Private, Public} = ec_key_named(),
Msg = ec_msg(),
@@ -1722,15 +1794,13 @@ group_config(ecdsa = Type, Config) ->
MsgPubEnc = <<"7896345786348 Asldi">>,
PubPrivEnc = [{ecdsa, Public, Private, MsgPubEnc, []}],
[{sign_verify, SignVerify}, {pub_priv_encrypt, PubPrivEnc} | Config];
-
group_config(Type, Config) when Type == ed25519 ; Type == ed448 ->
TestVectors = eddsa(Type),
[{sign_verify,TestVectors} | Config];
-
-
group_config(srp, Config) ->
GenerateCompute = [srp3(), srp6(), srp6a(), srp6a_smaller_prime()],
[{generate_compute, GenerateCompute} | Config];
+
group_config(ecdh, Config) ->
Compute = ecdh(),
Generate = ecc(),
@@ -1738,77 +1808,19 @@ group_config(ecdh, Config) ->
group_config(dh, Config) ->
GenerateCompute = [dh()],
[{generate_compute, GenerateCompute} | Config];
-group_config(des_cbc, Config) ->
- Block = des_cbc(),
- [{block, Block} | Config];
-group_config(des_cfb, Config) ->
- Block = des_cfb(),
- [{block, Block} | Config];
-group_config(des3_cbc, Config) ->
- Block = des3_cbc(),
- [{block, Block} | Config];
-group_config(des3_cbf, Config) ->
- Block = des3_cbf(),
- [{block, Block} | Config];
-group_config(des3_cfb, Config) ->
- Block = des3_cfb(),
- [{block, Block} | Config];
-group_config(des_ede3, Config) ->
- Block = des_ede3(),
- [{block, Block} | Config];
-group_config(rc2_cbc, Config) ->
- Block = rc2_cbc(),
- [{block, Block} | Config];
+
group_config(aes_cbc128 = Type, Config) ->
Block = fun() -> aes_cbc128(Config) end,
Pairs = fun() -> cmac_nist(Config, Type) end,
- [{block, Block}, {cmac, Pairs} | Config];
+ [{cipher, Block}, {cmac, Pairs} | Config];
group_config(aes_cbc256 = Type, Config) ->
Block = fun() -> aes_cbc256(Config) end,
Pairs = fun() -> cmac_nist(Config, Type) end,
- [{block, Block}, {cmac, Pairs} | Config];
-group_config(aes_ecb, Config) ->
- Block = fun() -> aes_ecb(Config) end,
- [{block, Block} | Config];
-group_config(aes_ige256, Config) ->
- Block = aes_ige256(),
- [{block, Block} | Config];
-group_config(aes_cfb8, Config) ->
- Block = fun() -> aes_cfb8(Config) end,
- [{block, Block} | Config];
-group_config(aes_cfb128, Config) ->
- Block = fun() -> aes_cfb128(Config) end,
- [{block, Block} | Config];
-group_config(blowfish_cbc, Config) ->
- Block = blowfish_cbc(),
- [{block, Block} | Config];
-group_config(blowfish_ecb, Config) ->
- Block = blowfish_ecb(),
- [{block, Block} | Config];
-group_config(blowfish_cfb64, Config) ->
- Block = blowfish_cfb64(),
- [{block, Block} | Config];
-group_config(blowfish_ofb64, Config) ->
- Block = blowfish_ofb64(),
- [{block, Block} | Config];
-group_config(rc4, Config) ->
- Stream = rc4(),
- [{stream, Stream} | Config];
-group_config(aes_ctr, Config) ->
- Stream = aes_ctr(),
- [{stream, Stream} | Config];
-group_config(aes_ccm, Config) ->
- AEAD = fun() -> aes_ccm(Config) end,
- [{aead, AEAD} | Config];
-group_config(aes_gcm, Config) ->
- AEAD = fun() -> aes_gcm(Config) end,
- [{aead, AEAD} | Config];
+ [{cipher, Block}, {cmac, Pairs} | Config];
group_config(chacha20_poly1305, Config) ->
- AEAD = chacha20_poly1305(),
- [{aead, AEAD} | Config];
-group_config(chacha20, Config) ->
- Stream = chacha20(),
- [{stream, Stream} | Config];
+ AEAD = chacha20_poly1305(Config),
+ [{cipher, AEAD} | Config];
+
group_config(poly1305, Config) ->
V = [%% {Key, Txt, Expect}
{%% RFC7539 2.5.2
@@ -1818,11 +1830,12 @@ group_config(poly1305, Config) ->
}
],
[{poly1305,V} | Config];
-group_config(aes_cbc, Config) ->
- Block = aes_cbc(Config),
- [{block, Block} | Config];
-group_config(_, Config) ->
- Config.
+
+group_config(F, Config) ->
+ TestVectors = fun() -> ?MODULE:F(Config) end,
+ [{cipher, TestVectors} | Config].
+
+
rsa_sign_verify_tests(Config, Msg, Public, Private, PublicS, PrivateS, OptsToTry) ->
case ?config(fips, Config) of
@@ -2413,19 +2426,19 @@ rfc4231_hmac_sha512() ->
"debd71f8867289865df5a32d20cdc944"
"b6022cac3c4982b10d5eeb55c3e4de15"
"134676fb6de0446065c97440fa8c6a58")].
-des_cbc() ->
+des_cbc(_) ->
[{des_cbc,
hexstr2bin("0123456789abcdef"),
hexstr2bin("1234567890abcdef"),
<<"Now is the time for all ">> }].
-des_cfb() ->
+des_cfb(_) ->
[{des_cfb,
hexstr2bin("0123456789abcdef"),
hexstr2bin("1234567890abcdef"),
<<"Now is the">>}].
-des3_cbc() ->
+des3_cbc(_) ->
[{des3_cbc,
[hexstr2bin("0123456789abcdef"),
hexstr2bin("fedcba9876543210"),
@@ -2434,7 +2447,7 @@ des3_cbc() ->
<<"Now is the time for all ">>
}].
-des_ede3() ->
+des_ede3(_) ->
[{des_ede3,
[hexstr2bin("8000000000000000"),
hexstr2bin("4000000000000000"),
@@ -2443,7 +2456,23 @@ des_ede3() ->
hexstr2bin("0000000000000000")
}].
-des3_cbf() ->
+des_ede3_cbc(_) ->
+ [{des_ede3_cbc,
+ [hexstr2bin("0123456789abcdef"),
+ hexstr2bin("fedcba9876543210"),
+ hexstr2bin("0f2d4b6987a5c3e1")],
+ hexstr2bin("1234567890abcdef"),
+ <<"Now is the time for all ">>
+ },
+ {des_ede3_cbc,
+ [hexstr2bin("8000000000000000"),
+ hexstr2bin("4000000000000000"),
+ hexstr2bin("2000000000000000")],
+ hexstr2bin("7AD16FFB79C45926"),
+ hexstr2bin("0000000000000000")
+ }].
+
+des3_cbf(_) ->
[{des3_cbf,
[hexstr2bin("0123456789abcdef"),
hexstr2bin("fedcba9876543210"),
@@ -2452,7 +2481,7 @@ des3_cbf() ->
<<"Now is the time for all ">>
}].
-des3_cfb() ->
+des3_cfb(_) ->
[{des3_cfb,
[hexstr2bin("0123456789abcdef"),
hexstr2bin("fedcba9876543210"),
@@ -2461,7 +2490,16 @@ des3_cfb() ->
<<"Now is the time for all ">>
}].
-rc2_cbc() ->
+des_ede3_cfb(_) ->
+ [{des_ede3_cfb,
+ [hexstr2bin("0123456789abcdef"),
+ hexstr2bin("fedcba9876543210"),
+ hexstr2bin("0f2d4b6987a5c3e1")],
+ hexstr2bin("1234567890abcdef"),
+ <<"Now is the time for all ">>
+ }].
+
+rc2_cbc(_) ->
[{rc2_cbc,
<<146,210,160,124,215,227,153,239,227,17,222,140,3,93,27,191>>,
<<72,91,135,182,25,42,35,210>>,
@@ -2470,7 +2508,8 @@ rc2_cbc() ->
%% AES CBC test vectors from http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
aes_cbc(Config) ->
- read_rsp(Config, aes_cbc,
+ %% RETIRED aes_*_cbc
+ read_rsp(Config, aes_cbc,
["CBCVarTxt128.rsp", "CBCVarKey128.rsp", "CBCGFSbox128.rsp", "CBCKeySbox128.rsp",
"CBCVarTxt192.rsp", "CBCVarKey192.rsp", "CBCGFSbox192.rsp", "CBCKeySbox192.rsp",
"CBCVarTxt256.rsp", "CBCVarKey256.rsp", "CBCGFSbox256.rsp", "CBCKeySbox256.rsp",
@@ -2478,15 +2517,32 @@ aes_cbc(Config) ->
]).
aes_cbc128(Config) ->
+ %% RETIRED aes_128_cbc
read_rsp(Config, aes_cbc128,
["CBCVarTxt128.rsp", "CBCVarKey128.rsp", "CBCGFSbox128.rsp", "CBCKeySbox128.rsp",
"CBCMMT128.rsp"]).
aes_cbc256(Config) ->
+ %% RETIRED aes_256_cbc
read_rsp(Config, aes_cbc256,
["CBCVarTxt256.rsp", "CBCVarKey256.rsp", "CBCGFSbox256.rsp", "CBCKeySbox256.rsp",
"CBCMMT256.rsp"]).
+aes_128_cbc(Config) ->
+ read_rsp(Config, aes_128_cbc,
+ ["CBCVarTxt128.rsp", "CBCVarKey128.rsp", "CBCGFSbox128.rsp", "CBCKeySbox128.rsp",
+ "CBCMMT128.rsp"]).
+
+aes_192_cbc(Config) ->
+ read_rsp(Config, aes_192_cbc,
+ ["CBCVarTxt192.rsp", "CBCVarKey192.rsp", "CBCGFSbox192.rsp", "CBCKeySbox192.rsp",
+ "CBCMMT192.rsp"]).
+
+aes_256_cbc(Config) ->
+ read_rsp(Config, aes_256_cbc,
+ ["CBCVarTxt256.rsp", "CBCVarKey256.rsp", "CBCGFSbox256.rsp", "CBCKeySbox256.rsp",
+ "CBCMMT256.rsp"]).
+
aes_ecb(Config) ->
read_rsp(Config, aes_ecb,
["ECBVarTxt128.rsp", "ECBVarKey128.rsp", "ECBGFSbox128.rsp", "ECBKeySbox128.rsp",
@@ -2494,7 +2550,22 @@ aes_ecb(Config) ->
"ECBVarTxt256.rsp", "ECBVarKey256.rsp", "ECBGFSbox256.rsp", "ECBKeySbox256.rsp",
"ECBMMT128.rsp", "ECBMMT192.rsp", "ECBMMT256.rsp"]).
-aes_ige256() ->
+aes_128_ecb(Config) ->
+ read_rsp(Config, aes_128_ecb,
+ ["ECBVarTxt128.rsp", "ECBVarKey128.rsp", "ECBGFSbox128.rsp", "ECBKeySbox128.rsp",
+ "ECBMMT128.rsp"]).
+
+aes_192_ecb(Config) ->
+ read_rsp(Config, aes_192_ecb,
+ ["ECBVarTxt192.rsp", "ECBVarKey192.rsp", "ECBGFSbox192.rsp", "ECBKeySbox192.rsp",
+ "ECBMMT192.rsp"]).
+
+aes_256_ecb(Config) ->
+ read_rsp(Config, aes_256_ecb,
+ ["ECBVarTxt256.rsp", "ECBVarKey256.rsp", "ECBGFSbox256.rsp", "ECBKeySbox256.rsp",
+ "ECBMMT256.rsp"]).
+
+aes_ige256(_) ->
[{aes_ige256,
hexstr2bin("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"),
hexstr2bin("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"),
@@ -2527,14 +2598,14 @@ aes_cfb128(Config) ->
"CFB128VarTxt256.rsp", "CFB128VarKey256.rsp", "CFB128GFSbox256.rsp", "CFB128KeySbox256.rsp",
"CFB128MMT128.rsp", "CFB128MMT192.rsp", "CFB128MMT256.rsp"]).
-blowfish_cbc() ->
+blowfish_cbc(_) ->
[{blowfish_cbc,
hexstr2bin("0123456789ABCDEFF0E1D2C3B4A59687"),
hexstr2bin("FEDCBA9876543210"),
hexstr2bin("37363534333231204E6F77206973207468652074696D6520666F722000000000")
}].
-blowfish_ecb() ->
+blowfish_ecb(_) ->
[
{blowfish_ecb,
hexstr2bin("0000000000000000"),
@@ -2631,26 +2702,26 @@ blowfish_ecb() ->
hexstr2bin("FFFFFFFFFFFFFFFF")}
].
-blowfish_cfb64() ->
+blowfish_cfb64(_) ->
[{blowfish_cfb64,
hexstr2bin("0123456789ABCDEFF0E1D2C3B4A59687"),
hexstr2bin("FEDCBA9876543210"),
hexstr2bin("37363534333231204E6F77206973207468652074696D6520666F722000")
}].
-blowfish_ofb64() ->
+blowfish_ofb64(_) ->
[{blowfish_ofb64,
hexstr2bin("0123456789ABCDEFF0E1D2C3B4A59687"),
hexstr2bin("FEDCBA9876543210"),
hexstr2bin("37363534333231204E6F77206973207468652074696D6520666F722000")
}].
-rc4() ->
+rc4(_) ->
[{rc4, <<"apaapa">>, <<"Yo baby yo">>},
{rc4, <<"apaapa">>, list_to_binary(lists:seq(0, 255))},
{rc4, <<"apaapa">>, long_msg()}
].
-aes_ctr() ->
+aes_ctr(_) ->
[ %% F.5.3 CTR-AES192.Encrypt
{aes_ctr, hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"),
@@ -2699,24 +2770,109 @@ aes_ctr() ->
].
+aes_128_ctr(_) ->
+ [ %% F.5.3 CTR-AES192.Encrypt
+ {aes_128_ctr, hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"),
+ hexstr2bin("6bc1bee22e409f96e93d7e117393172a")},
+ {aes_128_ctr, hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdff00"),
+ hexstr2bin("ae2d8a571e03ac9c9eb76fac45af8e51")},
+ {aes_128_ctr, hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdff01"),
+ hexstr2bin("30c81c46a35ce411e5fbc1191a0a52ef") },
+ {aes_128_ctr, hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdff02"),
+ hexstr2bin("f69f2445df4f9b17ad2b417be66c3710")}
+ ].
+
+aes_192_ctr(_) ->
+ [ %% F.5.3 CTR-AES192.Encrypt
+ {aes_192_ctr, hexstr2bin("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"),
+ hexstr2bin("6bc1bee22e409f96e93d7e117393172a")},
+ {aes_192_ctr, hexstr2bin("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdff00"),
+ hexstr2bin("ae2d8a571e03ac9c9eb76fac45af8e51")},
+ {aes_192_ctr, hexstr2bin("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdff01"),
+ hexstr2bin("30c81c46a35ce411e5fbc1191a0a52ef")},
+ {aes_192_ctr, hexstr2bin("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdff02"),
+ hexstr2bin("f69f2445df4f9b17ad2b417be66c3710")}
+ ].
+
+aes_256_ctr(_) ->
+ [ %% F.5.5 CTR-AES256.Encrypt
+ {aes_256_ctr, hexstr2bin("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"),
+ hexstr2bin("6bc1bee22e409f96e93d7e117393172a")},
+ {aes_256_ctr, hexstr2bin("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdff00"),
+ hexstr2bin("ae2d8a571e03ac9c9eb76fac45af8e51")},
+ {aes_256_ctr, hexstr2bin("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdff01"),
+ hexstr2bin("30c81c46a35ce411e5fbc1191a0a52ef")},
+ {aes_256_ctr, hexstr2bin("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdff02"),
+ hexstr2bin("f69f2445df4f9b17ad2b417be66c3710")},
+
+ {aes_256_ctr, hexstr2bin("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"),
+ long_msg()}
+ ].
+
+
aes_gcm(Config) ->
- read_rsp(Config, aes_gcm,
+ %% RETIRED aes_*_gcm
+ read_rsp(Config, aes_gcm,
+ ["gcmDecrypt128.rsp",
+ "gcmDecrypt192.rsp",
+ "gcmDecrypt256.rsp",
+ "gcmEncryptExtIV128.rsp",
+ "gcmEncryptExtIV192.rsp",
+ "gcmEncryptExtIV256.rsp"]).
+
+aes_128_gcm(Config) ->
+ read_rsp(Config, aes_128_gcm,
["gcmDecrypt128.rsp",
- "gcmDecrypt192.rsp",
- "gcmDecrypt256.rsp",
- "gcmEncryptExtIV128.rsp",
- "gcmEncryptExtIV192.rsp",
+ "gcmEncryptExtIV128.rsp"]).
+
+aes_192_gcm(Config) ->
+ read_rsp(Config, aes_192_gcm,
+ ["gcmDecrypt192.rsp",
+ "gcmEncryptExtIV192.rsp"]).
+
+aes_256_gcm(Config) ->
+ read_rsp(Config, aes_256_gcm,
+ ["gcmDecrypt256.rsp",
"gcmEncryptExtIV256.rsp"]).
+
aes_ccm(Config) ->
- read_rsp(Config, aes_ccm,
- ["VADT128.rsp", "VADT192.rsp", "VADT256.rsp",
- "VNT128.rsp", "VNT192.rsp", "VNT256.rsp",
- "VPT128.rsp", "VPT192.rsp", "VPT256.rsp"
- ]).
+ %% RETIRED aes_*_ccm
+ read_rsp(Config, aes_ccm,
+ ["VADT128.rsp", "VADT192.rsp", "VADT256.rsp",
+ "VNT128.rsp", "VNT192.rsp", "VNT256.rsp",
+ "VPT128.rsp", "VPT192.rsp", "VPT256.rsp"
+ ]).
+
+aes_128_ccm(Config) ->
+ read_rsp(Config, aes_128_ccm,
+ ["VADT128.rsp", "VNT128.rsp", "VPT128.rsp"]).
+
+aes_192_ccm(Config) ->
+ read_rsp(Config, aes_192_ccm,
+ ["VADT192.rsp", "VNT192.rsp", "VPT192.rsp"]).
+
+aes_256_ccm(Config) ->
+ read_rsp(Config, aes_256_ccm,
+ ["VADT256.rsp", "VNT256.rsp", "VPT256.rsp"]).
+
+
%% https://tools.ietf.org/html/rfc7539#appendix-A.5
-chacha20_poly1305() ->
+chacha20_poly1305(_) ->
[
{chacha20_poly1305,
hexstr2bin("1c9240a5eb55d38af333888604f6b5f0" %% Key
@@ -2763,7 +2919,7 @@ chacha20_poly1305() ->
].
-chacha20() ->
+chacha20(_) ->
%%% chacha20 (no mode) test vectors from RFC 7539 A.2
[
%% Test Vector #1:
@@ -3697,9 +3853,18 @@ parse_rsp(_Type, [], _State, Acc) ->
Acc;
parse_rsp(_Type, [<<"DECRYPT">>|_], _State, Acc) ->
Acc;
+parse_rsp(_Type, [<<"ENCRYPT">>|_], _State, Acc) ->
+ Acc;
%% AES format
parse_rsp(Type, [<<"COUNT = ", _/binary>>,
<<"KEY = ", Key/binary>>,
+ <<"PLAINTEXT = ", PlainText/binary>>,
+ <<"CIPHERTEXT = ", CipherText/binary>>|Next], State, Acc) ->
+ parse_rsp(Type, Next, State,
+ [{Type, hexstr2bin(Key),
+ hexstr2bin(PlainText), hexstr2bin(CipherText)}|Acc]);
+parse_rsp(Type, [<<"COUNT = ", _/binary>>,
+ <<"KEY = ", Key/binary>>,
<<"IV = ", IV/binary>>,
<<"PLAINTEXT = ", PlainText/binary>>,
<<"CIPHERTEXT = ", CipherText/binary>>|Next], State, Acc) ->
diff --git a/lib/dialyzer/src/dialyzer_utils.erl b/lib/dialyzer/src/dialyzer_utils.erl
index 3fe026b096..245c099fef 100644
--- a/lib/dialyzer/src/dialyzer_utils.erl
+++ b/lib/dialyzer/src/dialyzer_utils.erl
@@ -46,6 +46,7 @@
]).
-include("dialyzer.hrl").
+-include("../../compiler/src/core_parse.hrl").
%%-define(DEBUG, true).
@@ -751,9 +752,13 @@ pp_hook(Node, Ctxt, Cont) ->
map ->
pp_map(Node, Ctxt, Cont);
literal ->
- case is_map(cerl:concrete(Node)) of
- true -> pp_map(Node, Ctxt, Cont);
- false -> Cont(Node, Ctxt)
+ case cerl:concrete(Node) of
+ Map when is_map(Map) ->
+ pp_map(Node, Ctxt, Cont);
+ Bitstr when is_bitstring(Bitstr) ->
+ pp_binary(Node, Ctxt, Cont);
+ _ ->
+ Cont(Node, Ctxt)
end;
_ ->
Cont(Node, Ctxt)
@@ -761,7 +766,7 @@ pp_hook(Node, Ctxt, Cont) ->
pp_binary(Node, Ctxt, Cont) ->
prettypr:beside(prettypr:text("<<"),
- prettypr:beside(pp_segments(cerl:binary_segments(Node),
+ prettypr:beside(pp_segments(cerl_binary_segments(Node),
Ctxt, Cont),
prettypr:text(">>"))).
@@ -780,10 +785,29 @@ pp_segment(Node, Ctxt, Cont) ->
Unit = cerl:bitstr_unit(Node),
Type = cerl:bitstr_type(Node),
Flags = cerl:bitstr_flags(Node),
- prettypr:beside(Cont(Val, Ctxt),
- prettypr:beside(pp_size(Size, Ctxt, Cont),
- prettypr:beside(pp_opts(Type, Flags),
- pp_unit(Unit, Ctxt, Cont)))).
+ RestPP =
+ case {concrete(Unit), concrete(Type), concrete(Flags)} of
+ {1, integer, [unsigned, big]} -> % Simplify common cases.
+ case concrete(Size) of
+ 8 -> prettypr:text("");
+ _ -> pp_size(Size, Ctxt, Cont)
+ end;
+ {8, binary, [unsigned, big]} ->
+ SizePP = pp_size(Size, Ctxt, Cont),
+ prettypr:beside(SizePP,
+ prettypr:beside(prettypr:text("/"), pp_atom(Type)));
+ _What ->
+ SizePP = pp_size(Size, Ctxt, Cont),
+ UnitPP = pp_unit(Unit, Ctxt, Cont),
+ OptsPP = pp_opts(Type, Flags),
+ prettypr:beside(SizePP, prettypr:beside(OptsPP, UnitPP))
+ end,
+ prettypr:beside(Cont(Val, Ctxt), RestPP).
+
+concrete(Cerl) ->
+ try cerl:concrete(Cerl)
+ catch _:_ -> anything_unexpected
+ end.
pp_size(Size, Ctxt, Cont) ->
case cerl:is_c_atom(Size) of
@@ -859,6 +883,31 @@ seq([H | T], Separator, Ctxt, Fun) ->
seq([], _, _, _) ->
[prettypr:empty()].
+cerl_binary_segments(#c_literal{val = B}) when is_bitstring(B) ->
+ segs_from_bitstring(B);
+cerl_binary_segments(CBinary) ->
+ cerl:binary_segments(CBinary).
+
+%% Copied from core_pp. The function cerl:binary_segments/2 should/could
+%% be extended to handle literals, but then the cerl module cannot be
+%% HiPE-compiled as of Erlang/OTP 22.0 (due to <<I:N>>).
+segs_from_bitstring(<<H,T/bitstring>>) ->
+ [#c_bitstr{val=#c_literal{val=H},
+ size=#c_literal{val=8},
+ unit=#c_literal{val=1},
+ type=#c_literal{val=integer},
+ flags=#c_literal{val=[unsigned,big]}}|segs_from_bitstring(T)];
+segs_from_bitstring(<<>>) ->
+ [];
+segs_from_bitstring(Bitstring) ->
+ N = bit_size(Bitstring),
+ <<I:N>> = Bitstring,
+ [#c_bitstr{val=#c_literal{val=I},
+ size=#c_literal{val=N},
+ unit=#c_literal{val=1},
+ type=#c_literal{val=integer},
+ flags=#c_literal{val=[unsigned,big]}}].
+
%%------------------------------------------------------------------------------
-spec refold_pattern(cerl:cerl()) -> cerl:cerl().
diff --git a/lib/dialyzer/test/opaque_SUITE_data/results/simple b/lib/dialyzer/test/opaque_SUITE_data/results/simple
index 5cd8916aee..0e1bb934e9 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/results/simple
+++ b/lib/dialyzer/test/opaque_SUITE_data/results/simple
@@ -63,9 +63,9 @@ simple1_api.erl:381: Invalid type specification for function simple1_api:bool_ad
simple1_api.erl:407: The size simple1_adt:i1() breaks the opacity of A
simple1_api.erl:418: The attempt to match a term of type non_neg_integer() against the variable A breaks the opacity of simple1_adt:i1()
simple1_api.erl:425: The attempt to match a term of type non_neg_integer() against the variable B breaks the opacity of simple1_adt:i1()
-simple1_api.erl:432: The pattern <<_:B/integer-unit:1>> can never match the type any()
+simple1_api.erl:432: The pattern <<_:B>> can never match the type any()
simple1_api.erl:448: The attempt to match a term of type non_neg_integer() against the variable Sz breaks the opacity of simple1_adt:i1()
-simple1_api.erl:460: The attempt to match a term of type simple1_adt:bit1() against the pattern <<_/binary-unit:8>> breaks the opacity of the term
+simple1_api.erl:460: The attempt to match a term of type simple1_adt:bit1() against the pattern <<_/binary>> breaks the opacity of the term
simple1_api.erl:478: The call 'foo':A(A::simple1_adt:a()) breaks the opacity of the term A :: simple1_adt:a()
simple1_api.erl:486: The call A:'foo'(A::simple1_adt:a()) breaks the opacity of the term A :: simple1_adt:a()
simple1_api.erl:499: The call 'foo':A(A::simple1_api:i()) requires that A is of type atom() not simple1_api:i()
diff --git a/lib/dialyzer/test/r9c_SUITE_data/results/asn1 b/lib/dialyzer/test/r9c_SUITE_data/results/asn1
index 1cf03346ee..6e51b972af 100644
--- a/lib/dialyzer/test/r9c_SUITE_data/results/asn1
+++ b/lib/dialyzer/test/r9c_SUITE_data/results/asn1
@@ -87,7 +87,7 @@ asn1rt_per_bin.erl:2127: Cons will produce an improper list since its 2nd argume
asn1rt_per_bin.erl:2129: Cons will produce an improper list since its 2nd argument is integer()
asn1rt_per_bin.erl:446: The variable _ can never match since previous clauses completely covered the type integer()
asn1rt_per_bin.erl:467: The variable _ can never match since previous clauses completely covered the type integer()
-asn1rt_per_bin.erl:474: The pattern <{_N, <<_:8/integer-unit:1,Bs/binary-unit:8>>}, C> can never match since previous clauses completely covered the type <{0,_},integer()>
+asn1rt_per_bin.erl:474: The pattern <{_N, <<_,Bs/binary>>}, C> can never match since previous clauses completely covered the type <{0,_},integer()>
asn1rt_per_bin.erl:487: The variable _ can never match since previous clauses completely covered the type integer()
asn1rt_per_bin.erl:498: The variable _ can never match since previous clauses completely covered the type integer()
asn1rt_per_bin_rt2ct.erl:152: The call asn1rt_per_bin_rt2ct:getbit({0,maybe_improper_list()}) will never return since it differs in the 1st argument from the success typing arguments: (<<_:8,_:_*8>> | {non_neg_integer(),<<_:1,_:_*1>>})
@@ -95,7 +95,7 @@ asn1rt_per_bin_rt2ct.erl:1533: The pattern {'BMPString', {'octets', Ol}} can nev
asn1rt_per_bin_rt2ct.erl:1875: The pattern {Name, Val} can never match since previous clauses completely covered the type any()
asn1rt_per_bin_rt2ct.erl:443: The variable _ can never match since previous clauses completely covered the type integer()
asn1rt_per_bin_rt2ct.erl:464: The variable _ can never match since previous clauses completely covered the type integer()
-asn1rt_per_bin_rt2ct.erl:471: The pattern <{_N, <<_B:8/integer-unit:1,Bs/binary-unit:8>>}, C> can never match since previous clauses completely covered the type <{0,_},integer()>
+asn1rt_per_bin_rt2ct.erl:471: The pattern <{_N, <<_B,Bs/binary>>}, C> can never match since previous clauses completely covered the type <{0,_},integer()>
asn1rt_per_bin_rt2ct.erl:484: The variable _ can never match since previous clauses completely covered the type integer()
asn1rt_per_bin_rt2ct.erl:495: The variable _ can never match since previous clauses completely covered the type integer()
asn1rt_per_v1.erl:1209: The pattern <_, 'true', _> can never match the type <_,'false',_>
diff --git a/lib/dialyzer/test/r9c_SUITE_data/src/inets/mod_responsecontrol.erl b/lib/dialyzer/test/r9c_SUITE_data/src/inets/mod_responsecontrol.erl
index a997db6880..53eeedc29f 100644
--- a/lib/dialyzer/test/r9c_SUITE_data/src/inets/mod_responsecontrol.erl
+++ b/lib/dialyzer/test/r9c_SUITE_data/src/inets/mod_responsecontrol.erl
@@ -71,7 +71,7 @@ do_responsecontrol(Info) ->
%% If a client sends more then one of the if-XXXX fields in a request
-%% The standard says it does not specify the behaviuor so I specified it :-)
+%% The standard says it does not specify the behaviour so I specified it :-)
%% The priority between the fields is
%% 1.If-modified
%% 2.If-Unmodified
diff --git a/lib/dialyzer/test/small_SUITE_data/results/bs_fail_constr b/lib/dialyzer/test/small_SUITE_data/results/bs_fail_constr
index dbc8241971..797f83956d 100644
--- a/lib/dialyzer/test/small_SUITE_data/results/bs_fail_constr
+++ b/lib/dialyzer/test/small_SUITE_data/results/bs_fail_constr
@@ -1,9 +1,9 @@
bs_fail_constr.erl:11: Function w3/1 has no local return
-bs_fail_constr.erl:12: Binary construction will fail since the size field S in segment 42:S/integer-unit:1 has type neg_integer()
+bs_fail_constr.erl:12: Binary construction will fail since the size field S in segment 42:S has type neg_integer()
bs_fail_constr.erl:14: Function w4/1 has no local return
bs_fail_constr.erl:15: Binary construction will fail since the value field V in segment V/utf32 has type float()
bs_fail_constr.erl:5: Function w1/1 has no local return
-bs_fail_constr.erl:6: Binary construction will fail since the value field V in segment V:8/integer-unit:1 has type float()
+bs_fail_constr.erl:6: Binary construction will fail since the value field V in segment V has type float()
bs_fail_constr.erl:8: Function w2/1 has no local return
-bs_fail_constr.erl:9: Binary construction will fail since the value field V in segment V/binary-unit:8 has type atom()
+bs_fail_constr.erl:9: Binary construction will fail since the value field V in segment V/binary has type atom()
diff --git a/lib/dialyzer/test/small_SUITE_data/results/pretty_bitstring b/lib/dialyzer/test/small_SUITE_data/results/pretty_bitstring
index e148e5cf22..dc3620fcf0 100644
--- a/lib/dialyzer/test/small_SUITE_data/results/pretty_bitstring
+++ b/lib/dialyzer/test/small_SUITE_data/results/pretty_bitstring
@@ -1,3 +1,3 @@
pretty_bitstring.erl:7: Function t/0 has no local return
-pretty_bitstring.erl:8: The call binary:copy(#{#<1>(8, 1, 'integer', ['unsigned', 'big']), #<2>(8, 1, 'integer', ['unsigned', 'big']), #<3>(3, 1, 'integer', ['unsigned', 'big'])}#,2) breaks the contract (Subject,N) -> binary() when Subject :: binary(), N :: non_neg_integer()
+pretty_bitstring.erl:8: The call binary:copy(<<1,2,3:3>>,2) breaks the contract (Subject,N) -> binary() when Subject :: binary(), N :: non_neg_integer()
diff --git a/lib/dialyzer/test/small_SUITE_data/results/tuple_set_crash b/lib/dialyzer/test/small_SUITE_data/results/tuple_set_crash
index 8c9df56a4b..7fd1f304cb 100644
--- a/lib/dialyzer/test/small_SUITE_data/results/tuple_set_crash
+++ b/lib/dialyzer/test/small_SUITE_data/results/tuple_set_crash
@@ -3,12 +3,12 @@ tuple_set_crash.erl:103: Invalid type specification for function tuple_set_crash
tuple_set_crash.erl:123: Invalid type specification for function tuple_set_crash:parse_video_target_info/1. The success typing is (<<_:48>>) -> [{'status',byte()} | {'target_id',non_neg_integer()},...]
tuple_set_crash.erl:127: Invalid type specification for function tuple_set_crash:parse_audio_target_info/1. The success typing is (<<_:48>>) -> [{'master_volume',char()} | {'status',byte()} | {'target_id',non_neg_integer()},...]
tuple_set_crash.erl:138: Invalid type specification for function tuple_set_crash:parse_av_device_info/1. The success typing is (<<_:48>>) -> [{'address',byte()} | {'device_id',non_neg_integer()} | {'model',binary()} | {'status',byte()},...]
-tuple_set_crash.erl:143: The pattern <<TargetId:32/integer-little-unit:1,Rest1/binary-unit:8>> can never match the type <<_:8>>
+tuple_set_crash.erl:143: The pattern <<TargetId:32/integer-little-unit:1,Rest1/binary>> can never match the type <<_:8>>
tuple_set_crash.erl:155: Invalid type specification for function tuple_set_crash:parse_video_output_info/1. The success typing is (<<_:48>>) -> [{'audio_volume',char()} | {'display_type',binary()} | {'output_id',non_neg_integer()},...]
-tuple_set_crash.erl:160: The pattern <<DeviceId:32/integer-little-unit:1,Rest1/binary-unit:8>> can never match the type <<_:8>>
+tuple_set_crash.erl:160: The pattern <<DeviceId:32/integer-little-unit:1,Rest1/binary>> can never match the type <<_:8>>
tuple_set_crash.erl:171: Invalid type specification for function tuple_set_crash:parse_audio_output_info/1. The success typing is (<<_:48>>) -> [{'output_id',non_neg_integer()},...]
-tuple_set_crash.erl:176: The pattern <<DeviceId:32/integer-little-unit:1,Rest1/binary-unit:8>> can never match the type <<_:8>>
-tuple_set_crash.erl:179: The pattern <<AudioVolume:16/integer-little-unit:1,Rest2/binary-unit:8>> can never match the type <<_:8>>
-tuple_set_crash.erl:182: The pattern <<Delay:16/integer-little-unit:1,_Padding/binary-unit:8>> can never match the type <<_:8>>
+tuple_set_crash.erl:176: The pattern <<DeviceId:32/integer-little-unit:1,Rest1/binary>> can never match the type <<_:8>>
+tuple_set_crash.erl:179: The pattern <<AudioVolume:16/integer-little-unit:1,Rest2/binary>> can never match the type <<_:8>>
+tuple_set_crash.erl:182: The pattern <<Delay:16/integer-little-unit:1,_Padding/binary>> can never match the type <<_:8>>
tuple_set_crash.erl:62: The pattern {'play_list', _Playlist} can never match the type 'ok' | {'device_properties',[{atom(),_}]} | {'error',[{atom(),_}]}
tuple_set_crash.erl:64: The pattern {'error', 17} can never match the type 'ok' | {'device_properties',[{atom(),_}]} | {'error',[{atom(),_}]}
diff --git a/lib/edoc/src/edoc_data.erl b/lib/edoc/src/edoc_data.erl
index 7c077d3acd..a8373d6536 100644
--- a/lib/edoc/src/edoc_data.erl
+++ b/lib/edoc/src/edoc_data.erl
@@ -345,6 +345,8 @@ deprecated(Repl, Env) ->
deprecated(Desc) ->
[{deprecated, description(Desc)}].
+-dialyzer({no_match, replacement_function/2}).
+
replacement_function(M0, {M,F,A}) when is_list(A) ->
%% refer to the largest listed arity - the most general version
replacement_function(M0, {M,F,lists:last(lists:sort(A))});
diff --git a/lib/erl_docgen/priv/dtd/book.dtd b/lib/erl_docgen/priv/dtd/book.dtd
index aa07d38658..326bf3369a 100644
--- a/lib/erl_docgen/priv/dtd/book.dtd
+++ b/lib/erl_docgen/priv/dtd/book.dtd
@@ -30,7 +30,7 @@
insidecover?,
pagetext,
preamble,
- (applications|parts|headline|pagetext)+,
+ (applications|parts|internals|headline|pagetext)+,
(listoffigures?,
listoftables?,
listofterms?,
@@ -56,6 +56,7 @@
<!ELEMENT applications (include)* >
<!ELEMENT parts (title?,description?,(include|onepart)*) >
<!ATTLIST parts lift (yes|no) "no" >
+<!ELEMENT internals (include)* >
<!ELEMENT headline (#PCDATA) >
<!ELEMENT index EMPTY >
<!ELEMENT listoffigures EMPTY >
diff --git a/lib/erl_docgen/priv/dtd/common.dtd b/lib/erl_docgen/priv/dtd/common.dtd
index b1578ad9d4..0ccd52068b 100644
--- a/lib/erl_docgen/priv/dtd/common.dtd
+++ b/lib/erl_docgen/priv/dtd/common.dtd
@@ -25,7 +25,7 @@
<!ENTITY % block "p|pre|code|list|taglist|codeinclude|
erleval" >
<!ENTITY % inline "#PCDATA|c|i|em|strong|term|cite|br|path|seealso|
- url|marker|anno" >
+ url|marker|anno|image" >
<!-- XXX -->
<!ELEMENT p (%inline;)* >
<!ELEMENT pre (#PCDATA|seealso|url|input|anno)* >
diff --git a/lib/erl_docgen/priv/xsl/db_html.xsl b/lib/erl_docgen/priv/xsl/db_html.xsl
index c9be926e1e..18bc8cd1cf 100644
--- a/lib/erl_docgen/priv/xsl/db_html.xsl
+++ b/lib/erl_docgen/priv/xsl/db_html.xsl
@@ -836,6 +836,10 @@
<!-- .../part -->
<xsl:call-template name="part.content" />
</xsl:if>
+ <xsl:if test="$lname = 'internal'">
+ <!-- .../internals -->
+ <xsl:call-template name="internal.content" />
+ </xsl:if>
<xsl:if test="$lname = 'chapter'">
<!-- .../part/chapter -->
<xsl:call-template name="chapter.content">
@@ -859,12 +863,24 @@
<xsl:param name="chapnum"/>
<xsl:param name="curModule"/>
<xsl:if test="(local-name() = 'part') or ((local-name() = 'chapter') and ancestor::part)">
- <!-- .../part or.../part/chapter -->
+ <!-- .../part or .../part/chapter -->
<xsl:call-template name="menu.ug">
<xsl:with-param name="chapnum" select="$chapnum"/>
</xsl:call-template>
</xsl:if>
- <xsl:if test="(local-name() = 'application') or (local-name() = 'erlref')or (local-name() = 'comref')or (local-name() = 'cref')or (local-name() = 'fileref')or (local-name() = 'appref')">
+ <xsl:if test="(local-name() = 'internal' and descendant::chapter) or ((local-name() = 'chapter') and ancestor::internal)">
+ <!-- .../internal or .../internal/chapter -->
+ <xsl:call-template name="menu.internal.ug">
+ <xsl:with-param name="chapnum" select="$chapnum"/>
+ </xsl:call-template>
+ </xsl:if>
+ <xsl:if test="(local-name() = 'internal' and descendant::erlref) or (((local-name() = 'erlref') or (local-name() = 'comref') or (local-name() = 'cref') or (local-name() = 'fileref') or (local-name() = 'appref')) and ancestor::internal)">
+ <!-- .../internal,.../internal/erlref, .../internal/comref or .../internal/cref or .../internal/fileref or .../internal/appref -->
+ <xsl:call-template name="menu.internal.ref">
+ <xsl:with-param name="curModule" select="$curModule"/>
+ </xsl:call-template>
+ </xsl:if>
+ <xsl:if test="(local-name() = 'application') or (((local-name() = 'erlref') or (local-name() = 'comref') or (local-name() = 'cref') or (local-name() = 'fileref') or (local-name() = 'appref')) and ancestor::application)">
<!-- .../application,.../application/erlref, .../application/comref or .../application/cref or .../application/fileref or .../application/appref -->
<xsl:call-template name="menu.ref">
<xsl:with-param name="curModule" select="$curModule"/>
@@ -902,6 +918,9 @@
<xsl:if test="boolean(/book/applications)">
<li><a href="index.html">Reference Manual</a></li>
</xsl:if>
+ <xsl:if test="boolean(/book/internals)">
+ <li><a href="internal_docs.html">Internal Documentation</a></li>
+ </xsl:if>
<xsl:if test="boolean(/book/releasenotes)">
<li><a href="release_notes.html">Release Notes</a></li>
</xsl:if>
@@ -942,6 +961,7 @@
<xsl:template match="/book">
<xsl:apply-templates select="parts"/>
<xsl:apply-templates select="applications"/>
+ <xsl:apply-templates select="internals"/>
<xsl:apply-templates select="releasenotes"/>
</xsl:template>
@@ -955,6 +975,11 @@
<xsl:apply-templates select="application"/>
</xsl:template>
+ <!-- Internals -->
+ <xsl:template match="internals">
+ <xsl:apply-templates select="internal"/>
+ </xsl:template>
+
<!-- Header -->
<xsl:template match="header"/>
@@ -1311,6 +1336,90 @@
</xsl:template>
+ <!-- Internal Docs -->
+
+ <!-- Part -->
+ <xsl:template match="internal">
+
+ <xsl:document href="{$outdir}/internal_docs.html" method="html" encoding="UTF-8" indent="yes" doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN">
+ <xsl:call-template name="pagelayout"/>
+ </xsl:document>
+ </xsl:template>
+
+
+ <!-- Part content-->
+ <xsl:template name="internal.content">
+ <div class="frontpage"/>
+
+ <center><h1><xsl:value-of select="/book/header/title"/> Internal Docs</h1></center>
+
+ <center><h4>Version <xsl:value-of select="$appver"/></h4></center>
+ <center><h4><xsl:value-of select="$gendate"/></h4></center>
+ <div class="extrafrontpageinfo">
+ <center><xsl:value-of select="$extra_front_page_info"/></center>
+ </div>
+
+ <xsl:apply-templates select="chapter|erlref"/>
+
+ </xsl:template>
+
+ <!-- Menu.internal.chapter -->
+ <xsl:template name="menu.internal.ug">
+ <xsl:param name="chapnum"/>
+
+ <div id="leftnav">
+ <div class="innertube">
+
+ <xsl:call-template name="erlang_logo"/>
+
+ <p class="section-title"><xsl:value-of select="/book/header/title"/></p>
+ <p class="section-subtitle">Internal Documentation</p>
+ <p class="section-version">Version <xsl:value-of select="$appver"/></p>
+
+ <xsl:call-template name="menu_top"/>
+
+ <xsl:call-template name="menu_middle"/>
+
+ <h3>Chapters</h3>
+
+ <ul class="flipMenu" imagepath="{$topdocdir}/js/flipmenu">
+ <xsl:call-template name="menu.chapter">
+ <xsl:with-param name="entries" select="/book/internals/internal/chapter[header/title]"/>
+ <xsl:with-param name="chapnum" select="$chapnum"/>
+ </xsl:call-template>
+ </ul>
+ </div>
+ </div>
+ </xsl:template>
+
+ <!-- Menu.internal.ref -->
+ <xsl:template name="menu.internal.ref">
+ <xsl:param name="curModule"/>
+ <div id="leftnav">
+ <div class="innertube">
+
+ <xsl:call-template name="erlang_logo"/>
+
+ <p class="section-title"><xsl:value-of select="/book/header/title"/></p>
+ <p class="section-subtitle">Reference Manual</p>
+ <p class="section-version">Version <xsl:value-of select="$appver"/></p>
+
+ <xsl:call-template name="menu_top"/>
+
+ <xsl:call-template name="menu_middle"/>
+
+ <h3>Table of Contents</h3>
+
+ <ul class="flipMenu">
+ <xsl:call-template name="menu.ref2">
+ <xsl:with-param name="entries" select="/book/internals/internal/erlref[module]|/book/internals/internal/cref[lib]|/book/internals/internal/comref[com]|/book/internals/internal/fileref[file]|/book/internals/internal/appref[app]"/>
+ <!--xsl:with-param name="genFuncMenu" select="true"/-->
+ <xsl:with-param name="curModule" select="$curModule"/>
+ </xsl:call-template>
+ </ul>
+ </div>
+ </div>
+ </xsl:template>
<!--Users Guide -->
diff --git a/lib/erl_docgen/src/docgen_edoc_xml_cb.erl b/lib/erl_docgen/src/docgen_edoc_xml_cb.erl
index d562cfddcc..2c9aa2e3a3 100644
--- a/lib/erl_docgen/src/docgen_edoc_xml_cb.erl
+++ b/lib/erl_docgen/src/docgen_edoc_xml_cb.erl
@@ -1260,11 +1260,15 @@ get_text(#xmlElement{content=[E]}) ->
%% text_and_name_only(Es) -> {N, Ts}
text_and_a_name_only(Es) ->
- [Name|_] = [Name ||
- #xmlElement{
- name = a,
- attributes = [#xmlAttribute{name=name}]}=Name <- Es],
- {Name#xmlElement{content = []}, text_only(Es)}.
+ erlang:display(Es),
+ case [Name || #xmlElement{
+ name = a,
+ attributes = [#xmlAttribute{name=name}]}=Name <- Es] of
+ [Name|_] ->
+ {Name#xmlElement{content = []}, text_only(Es)};
+ [] ->
+ {"", text_only(Es)}
+ end.
%% text_only(Es) -> Ts
%% Takes a list of xmlElement and xmlText and return a lists of xmlText.
diff --git a/lib/erl_docgen/src/docgen_xmerl_xml_cb.erl b/lib/erl_docgen/src/docgen_xmerl_xml_cb.erl
index 59d4dccfb7..9d69143c3c 100644
--- a/lib/erl_docgen/src/docgen_xmerl_xml_cb.erl
+++ b/lib/erl_docgen/src/docgen_xmerl_xml_cb.erl
@@ -87,6 +87,7 @@ convert_tag(underline, Attrs) -> {em, Attrs};
convert_tag(Tag, Attrs) -> {Tag, Attrs}.
is_url("http:"++_) -> true;
+is_url("https:"++_) -> true;
is_url("../"++_) -> true;
is_url(FileRef) ->
case filename:extension(FileRef) of
diff --git a/lib/erl_interface/src/Makefile.in b/lib/erl_interface/src/Makefile.in
index b2600f0fab..6e0d3476c7 100644
--- a/lib/erl_interface/src/Makefile.in
+++ b/lib/erl_interface/src/Makefile.in
@@ -784,29 +784,31 @@ $(MDD_OBJDIR)/ei_fake_prog_mdd_cxx$(EXE): prog/ei_fake_prog.c $(MDD_EILIB)
# Create dependency file using gcc -MM
###########################################################################
-depend:
+depend: $(TARGET)/depend.mk
+
+$(TARGET)/depend.mk: $(TARGET)/config.h
$(gen_verbose)
- $(V_colon)@echo "Generating dependency file depend.mk..."
- @echo "# Generated dependency rules" > depend.mk; \
- $(V_CC) $(CFLAGS) -MM $(SOURCES) | \
+ $(V_colon)echo "Generating dependency file depend.mk..."
+ @echo "# Generated dependency rules" > $@
+ $(V_CC) $(CFLAGS) -MM $(SOURCES) | \
sed 's&$(TARGET)&\$$\(TARGET\)&g' | \
- sed 's/^.*:/\$$\(ST_OBJDIR\)\/&/' >> depend.mk; \
- echo >> depend.mk; \
- $(CC) $(CFLAGS) -MM $(SOURCES) | \
+ sed 's/^.*:/\$$\(ST_OBJDIR\)\/&/' >> $@
+ @echo >> $@
+ $(V_CC) $(CFLAGS) -MM $(SOURCES) | \
sed 's&$(TARGET)&\$$\(TARGET\)&g' | \
- sed 's/^.*:/\$$\(MT_OBJDIR\)\/&/' >> depend.mk; \
- echo >> depend.mk; \
- $(CC) $(CFLAGS) -MM $(SOURCES) | \
+ sed 's/^.*:/\$$\(MT_OBJDIR\)\/&/' >> $@
+ @echo >> $@
+ $(V_CC) $(CFLAGS) -MM $(SOURCES) | \
sed 's&$(TARGET)&\$$\(TARGET\)&g' | \
- sed 's/^.*:/\$$\(MD_OBJDIR\)\/&/' >> depend.mk; \
- echo >> depend.mk; \
- $(CC) $(CFLAGS) -MM $(SOURCES) | \
+ sed 's/^.*:/\$$\(MD_OBJDIR\)\/&/' >> $@
+ @echo >> $@
+ $(V_CC) $(CFLAGS) -MM $(SOURCES) | \
sed 's&$(TARGET)&\$$\(TARGET\)&g' | \
- sed 's/^.*:/\$$\(MDD_OBJDIR\)\/&/' >> depend.mk; \
- echo >> depend.mk
+ sed 's/^.*:/\$$\(MDD_OBJDIR\)\/&/' >> $@
+ @echo >> $@
# For some reason this has to be after 'opt' target
-include depend.mk
+-include $(TARGET)/depend.mk
# ----------------------------------------------------
# Release Target
diff --git a/lib/erl_interface/src/connect/ei_connect.c b/lib/erl_interface/src/connect/ei_connect.c
index 7a304e6d4f..be7a2a6b0e 100644
--- a/lib/erl_interface/src/connect/ei_connect.c
+++ b/lib/erl_interface/src/connect/ei_connect.c
@@ -659,7 +659,7 @@ int ei_connect_xinit_ussi(ei_cnode* ec, const char *thishostname,
return ERL_ERROR;
}
- ec->creation = creation & 0x3; /* 2 bits */
+ ec->creation = creation;
if (cookie) {
if (strlen(cookie) >= sizeof(ec->ei_connect_cookie)) {
@@ -698,7 +698,7 @@ int ei_connect_xinit_ussi(ei_cnode* ec, const char *thishostname,
strcpy(ec->self.node,thisnodename);
ec->self.num = 0;
ec->self.serial = 0;
- ec->self.creation = creation & 0x3; /* 2 bits */
+ ec->self.creation = creation;
ec->cbs = cbs;
ec->setup_context = setup_context;
diff --git a/lib/erl_interface/src/depend.mk b/lib/erl_interface/src/depend.mk
deleted file mode 100644
index af753046e5..0000000000
--- a/lib/erl_interface/src/depend.mk
+++ /dev/null
@@ -1,1133 +0,0 @@
-# Generated dependency rules
-$(ST_OBJDIR)/ei_connect.o: connect/ei_connect.c $(TARGET)/config.h \
- misc/eidef.h ../include/ei.h misc/eiext.h misc/ei_portio.h \
- misc/ei_internal.h connect/ei_connect_int.h misc/ei_locking.h \
- connect/eisend.h connect/eirecv.h misc/eimd5.h misc/putget.h \
- connect/ei_resolve.h epmd/ei_epmd.h
-$(ST_OBJDIR)/ei_resolve.o: connect/ei_resolve.c $(TARGET)/config.h \
- misc/eidef.h ../include/ei.h connect/ei_resolve.h misc/ei_locking.h
-$(ST_OBJDIR)/eirecv.o: connect/eirecv.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h connect/eirecv.h misc/ei_portio.h \
- misc/ei_internal.h misc/putget.h misc/ei_trace.h misc/show_msg.h
-$(ST_OBJDIR)/send.o: connect/send.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h connect/eisend.h misc/putget.h \
- connect/ei_connect_int.h misc/ei_internal.h misc/ei_trace.h \
- misc/show_msg.h
-$(ST_OBJDIR)/send_exit.o: connect/send_exit.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/ei_connect_int.h misc/ei_trace.h \
- misc/ei_internal.h misc/putget.h misc/show_msg.h
-$(ST_OBJDIR)/send_reg.o: connect/send_reg.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h connect/eisend.h misc/putget.h \
- connect/ei_connect_int.h misc/ei_internal.h misc/ei_trace.h \
- misc/show_msg.h
-$(ST_OBJDIR)/decode_atom.o: decode/decode_atom.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_big.o: decode/decode_big.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_bignum.o: decode/decode_bignum.c $(TARGET)/config.h
-$(ST_OBJDIR)/decode_binary.o: decode/decode_binary.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_boolean.o: decode/decode_boolean.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_char.o: decode/decode_char.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_double.o: decode/decode_double.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_fun.o: decode/decode_fun.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/ei_malloc.h decode/decode_skip.h misc/putget.h
-$(ST_OBJDIR)/decode_intlist.o: decode/decode_intlist.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_list_header.o: decode/decode_list_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_long.o: decode/decode_long.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_pid.o: decode/decode_pid.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_port.o: decode/decode_port.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_ref.o: decode/decode_ref.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_skip.o: decode/decode_skip.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- decode/decode_skip.h
-$(ST_OBJDIR)/decode_string.o: decode/decode_string.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_trace.o: decode/decode_trace.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/putget.h
-$(ST_OBJDIR)/decode_tuple_header.o: decode/decode_tuple_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_ulong.o: decode/decode_ulong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_version.o: decode/decode_version.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_longlong.o: decode/decode_longlong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_ulonglong.o: decode/decode_ulonglong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_atom.o: encode/encode_atom.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_bignum.o: encode/encode_bignum.c $(TARGET)/config.h
-$(ST_OBJDIR)/encode_binary.o: encode/encode_binary.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_boolean.o: encode/encode_boolean.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_char.o: encode/encode_char.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_double.o: encode/encode_double.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_fun.o: encode/encode_fun.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_list_header.o: encode/encode_list_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_long.o: encode/encode_long.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_pid.o: encode/encode_pid.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_port.o: encode/encode_port.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_ref.o: encode/encode_ref.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_string.o: encode/encode_string.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_trace.o: encode/encode_trace.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/putget.h
-$(ST_OBJDIR)/encode_tuple_header.o: encode/encode_tuple_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_ulong.o: encode/encode_ulong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_version.o: encode/encode_version.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_longlong.o: encode/encode_longlong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h misc/ei_x_encode.h
-$(ST_OBJDIR)/encode_ulonglong.o: encode/encode_ulonglong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h misc/ei_x_encode.h
-$(ST_OBJDIR)/epmd_port.o: epmd/epmd_port.c misc/ei_internal.h epmd/ei_epmd.h \
- misc/putget.h
-$(ST_OBJDIR)/epmd_publish.o: epmd/epmd_publish.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/ei_internal.h \
- misc/putget.h ../include/erl_interface.h epmd/ei_epmd.h
-$(ST_OBJDIR)/epmd_unpublish.o: epmd/epmd_unpublish.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/ei_internal.h \
- misc/putget.h ../include/erl_interface.h epmd/ei_epmd.h
-$(ST_OBJDIR)/ei_decode_term.o: misc/ei_decode_term.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/ei_decode_term.h misc/putget.h
-$(ST_OBJDIR)/ei_format.o: misc/ei_format.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/ei_malloc.h misc/ei_format.h
-$(ST_OBJDIR)/ei_locking.o: misc/ei_locking.c $(TARGET)/config.h \
- misc/ei_malloc.h misc/ei_locking.h
-$(ST_OBJDIR)/ei_malloc.o: misc/ei_malloc.c misc/ei_malloc.h
-$(ST_OBJDIR)/ei_portio.o: misc/ei_portio.c misc/ei_portio.h misc/ei_internal.h
-$(ST_OBJDIR)/ei_printterm.o: misc/ei_printterm.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/ei_printterm.h misc/ei_malloc.h
-$(ST_OBJDIR)/ei_pthreads.o: misc/ei_pthreads.c $(TARGET)/config.h \
- ../include/ei.h misc/ei_locking.h
-$(ST_OBJDIR)/ei_trace.o: misc/ei_trace.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/ei_trace.h
-$(ST_OBJDIR)/ei_x_encode.o: misc/ei_x_encode.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/ei_x_encode.h \
- misc/ei_malloc.h
-$(ST_OBJDIR)/eimd5.o: misc/eimd5.c misc/eimd5.h
-$(ST_OBJDIR)/get_type.o: misc/get_type.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h misc/putget.h
-$(ST_OBJDIR)/show_msg.o: misc/show_msg.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h misc/putget.h misc/ei_printterm.h \
- misc/ei_internal.h misc/show_msg.h
-$(ST_OBJDIR)/ei_compat.o: misc/ei_compat.c ../include/ei.h misc/ei_internal.h
-$(ST_OBJDIR)/hash_dohash.o: registry/hash_dohash.c registry/hash.h ../include/ei.h
-$(ST_OBJDIR)/hash_foreach.o: registry/hash_foreach.c registry/hash.h ../include/ei.h
-$(ST_OBJDIR)/hash_freetab.o: registry/hash_freetab.c registry/hash.h ../include/ei.h
-$(ST_OBJDIR)/hash_insert.o: registry/hash_insert.c registry/hash.h ../include/ei.h
-$(ST_OBJDIR)/hash_isprime.o: registry/hash_isprime.c registry/hash.h ../include/ei.h
-$(ST_OBJDIR)/hash_lookup.o: registry/hash_lookup.c registry/hash.h ../include/ei.h
-$(ST_OBJDIR)/hash_newtab.o: registry/hash_newtab.c registry/hash.h ../include/ei.h
-$(ST_OBJDIR)/hash_remove.o: registry/hash_remove.c registry/hash.h ../include/ei.h
-$(ST_OBJDIR)/hash_resize.o: registry/hash_resize.c registry/hash.h ../include/ei.h
-$(ST_OBJDIR)/hash_rlookup.o: registry/hash_rlookup.c registry/hash.h ../include/ei.h
-$(ST_OBJDIR)/reg_close.o: registry/reg_close.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_delete.o: registry/reg_delete.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_dirty.o: registry/reg_dirty.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_dump.o: registry/reg_dump.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- registry/reg.h registry/hash.h connect/eisend.h connect/eirecv.h \
- connect/ei_connect_int.h
-$(ST_OBJDIR)/reg_free.o: registry/reg_free.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_get.o: registry/reg_get.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_getf.o: registry/reg_getf.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_geti.o: registry/reg_geti.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_getp.o: registry/reg_getp.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_gets.o: registry/reg_gets.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_make.o: registry/reg_make.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_open.o: registry/reg_open.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_purge.o: registry/reg_purge.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_resize.o: registry/reg_resize.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_restore.o: registry/reg_restore.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- registry/reg.h registry/hash.h connect/eisend.h connect/eirecv.h \
- connect/ei_connect_int.h
-$(ST_OBJDIR)/reg_set.o: registry/reg_set.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_setf.o: registry/reg_setf.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_seti.o: registry/reg_seti.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_setp.o: registry/reg_setp.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_sets.o: registry/reg_sets.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_stat.o: registry/reg_stat.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_tabstat.o: registry/reg_tabstat.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/decode_term.o: legacy/decode_term.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h ../include/erl_interface.h
-$(ST_OBJDIR)/encode_term.o: legacy/encode_term.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h misc/ei_x_encode.h ../include/erl_interface.h \
- legacy/erl_marshal.h legacy/erl_eterm.h legacy/portability.h
-$(ST_OBJDIR)/erl_connect.o: legacy/erl_connect.c $(TARGET)/config.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_config.h \
- legacy/erl_connect.h legacy/erl_eterm.h legacy/portability.h \
- legacy/erl_malloc.h misc/putget.h connect/ei_connect_int.h \
- misc/ei_locking.h epmd/ei_epmd.h misc/ei_internal.h
-$(ST_OBJDIR)/erl_error.o: legacy/erl_error.c $(TARGET)/config.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_error.h
-$(ST_OBJDIR)/erl_eterm.o: legacy/erl_eterm.c misc/ei_locking.h \
- $(TARGET)/config.h connect/ei_resolve.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_eterm.h \
- legacy/portability.h legacy/erl_malloc.h legacy/erl_marshal.h \
- legacy/erl_error.h legacy/erl_internal.h misc/ei_internal.h
-$(ST_OBJDIR)/erl_fix_alloc.o: legacy/erl_fix_alloc.c $(TARGET)/config.h \
- misc/ei_locking.h ../include/erl_interface.h ../include/ei.h \
- legacy/erl_error.h legacy/erl_malloc.h legacy/erl_fix_alloc.h \
- legacy/erl_eterm.h legacy/portability.h
-$(ST_OBJDIR)/erl_format.o: legacy/erl_format.c ../include/erl_interface.h \
- ../include/ei.h legacy/erl_eterm.h legacy/portability.h \
- legacy/erl_malloc.h legacy/erl_error.h legacy/erl_internal.h
-$(ST_OBJDIR)/erl_malloc.o: legacy/erl_malloc.c ../include/erl_interface.h \
- ../include/ei.h legacy/erl_fix_alloc.h legacy/erl_malloc.h \
- legacy/erl_internal.h legacy/erl_eterm.h legacy/portability.h \
- misc/ei_malloc.h
-$(ST_OBJDIR)/erl_marshal.o: legacy/erl_marshal.c $(TARGET)/config.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_marshal.h \
- legacy/erl_eterm.h legacy/portability.h legacy/erl_malloc.h \
- legacy/erl_error.h legacy/erl_internal.h misc/eiext.h misc/putget.h
-$(ST_OBJDIR)/erl_timeout.o: legacy/erl_timeout.c $(TARGET)/config.h \
- legacy/erl_timeout.h
-$(ST_OBJDIR)/global_names.o: legacy/global_names.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
- ../include/erl_interface.h legacy/erl_connect.h
-$(ST_OBJDIR)/global_register.o: legacy/global_register.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h ../include/erl_interface.h
-$(ST_OBJDIR)/global_unregister.o: legacy/global_unregister.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
- ../include/erl_interface.h legacy/erl_connect.h
-$(ST_OBJDIR)/global_whereis.o: legacy/global_whereis.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
- ../include/erl_interface.h legacy/erl_connect.h
-
-$(MT_OBJDIR)/ei_connect.o: connect/ei_connect.c $(TARGET)/config.h \
- misc/eidef.h ../include/ei.h misc/eiext.h misc/ei_portio.h \
- misc/ei_internal.h connect/ei_connect_int.h misc/ei_locking.h \
- connect/eisend.h connect/eirecv.h misc/eimd5.h misc/putget.h \
- connect/ei_resolve.h epmd/ei_epmd.h
-$(MT_OBJDIR)/ei_resolve.o: connect/ei_resolve.c $(TARGET)/config.h \
- misc/eidef.h ../include/ei.h connect/ei_resolve.h misc/ei_locking.h
-$(MT_OBJDIR)/eirecv.o: connect/eirecv.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h connect/eirecv.h misc/ei_portio.h \
- misc/ei_internal.h misc/putget.h misc/ei_trace.h misc/show_msg.h
-$(MT_OBJDIR)/send.o: connect/send.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h connect/eisend.h misc/putget.h \
- connect/ei_connect_int.h misc/ei_internal.h misc/ei_trace.h \
- misc/show_msg.h
-$(MT_OBJDIR)/send_exit.o: connect/send_exit.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/ei_connect_int.h misc/ei_trace.h \
- misc/ei_internal.h misc/putget.h misc/show_msg.h
-$(MT_OBJDIR)/send_reg.o: connect/send_reg.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h connect/eisend.h misc/putget.h \
- connect/ei_connect_int.h misc/ei_internal.h misc/ei_trace.h \
- misc/show_msg.h
-$(MT_OBJDIR)/decode_atom.o: decode/decode_atom.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_big.o: decode/decode_big.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_bignum.o: decode/decode_bignum.c $(TARGET)/config.h
-$(MT_OBJDIR)/decode_binary.o: decode/decode_binary.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_boolean.o: decode/decode_boolean.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_char.o: decode/decode_char.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_double.o: decode/decode_double.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_fun.o: decode/decode_fun.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/ei_malloc.h decode/decode_skip.h misc/putget.h
-$(MT_OBJDIR)/decode_intlist.o: decode/decode_intlist.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_list_header.o: decode/decode_list_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_long.o: decode/decode_long.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_pid.o: decode/decode_pid.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_port.o: decode/decode_port.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_ref.o: decode/decode_ref.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_skip.o: decode/decode_skip.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- decode/decode_skip.h
-$(MT_OBJDIR)/decode_string.o: decode/decode_string.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_trace.o: decode/decode_trace.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/putget.h
-$(MT_OBJDIR)/decode_tuple_header.o: decode/decode_tuple_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_ulong.o: decode/decode_ulong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_version.o: decode/decode_version.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_longlong.o: decode/decode_longlong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_ulonglong.o: decode/decode_ulonglong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_atom.o: encode/encode_atom.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_bignum.o: encode/encode_bignum.c $(TARGET)/config.h
-$(MT_OBJDIR)/encode_binary.o: encode/encode_binary.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_boolean.o: encode/encode_boolean.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_char.o: encode/encode_char.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_double.o: encode/encode_double.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_fun.o: encode/encode_fun.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_list_header.o: encode/encode_list_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_long.o: encode/encode_long.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_pid.o: encode/encode_pid.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_port.o: encode/encode_port.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_ref.o: encode/encode_ref.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_string.o: encode/encode_string.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_trace.o: encode/encode_trace.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/putget.h
-$(MT_OBJDIR)/encode_tuple_header.o: encode/encode_tuple_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_ulong.o: encode/encode_ulong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_version.o: encode/encode_version.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_longlong.o: encode/encode_longlong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h misc/ei_x_encode.h
-$(MT_OBJDIR)/encode_ulonglong.o: encode/encode_ulonglong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h misc/ei_x_encode.h
-$(MT_OBJDIR)/epmd_port.o: epmd/epmd_port.c misc/ei_internal.h epmd/ei_epmd.h \
- misc/putget.h
-$(MT_OBJDIR)/epmd_publish.o: epmd/epmd_publish.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/ei_internal.h \
- misc/putget.h ../include/erl_interface.h epmd/ei_epmd.h
-$(MT_OBJDIR)/epmd_unpublish.o: epmd/epmd_unpublish.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/ei_internal.h \
- misc/putget.h ../include/erl_interface.h epmd/ei_epmd.h
-$(MT_OBJDIR)/ei_decode_term.o: misc/ei_decode_term.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/ei_decode_term.h misc/putget.h
-$(MT_OBJDIR)/ei_format.o: misc/ei_format.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/ei_malloc.h misc/ei_format.h
-$(MT_OBJDIR)/ei_locking.o: misc/ei_locking.c $(TARGET)/config.h \
- misc/ei_malloc.h misc/ei_locking.h
-$(MT_OBJDIR)/ei_malloc.o: misc/ei_malloc.c misc/ei_malloc.h
-$(MT_OBJDIR)/ei_portio.o: misc/ei_portio.c misc/ei_portio.h misc/ei_internal.h
-$(MT_OBJDIR)/ei_printterm.o: misc/ei_printterm.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/ei_printterm.h misc/ei_malloc.h
-$(MT_OBJDIR)/ei_pthreads.o: misc/ei_pthreads.c $(TARGET)/config.h \
- ../include/ei.h misc/ei_locking.h
-$(MT_OBJDIR)/ei_trace.o: misc/ei_trace.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/ei_trace.h
-$(MT_OBJDIR)/ei_x_encode.o: misc/ei_x_encode.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/ei_x_encode.h \
- misc/ei_malloc.h
-$(MT_OBJDIR)/eimd5.o: misc/eimd5.c misc/eimd5.h
-$(MT_OBJDIR)/get_type.o: misc/get_type.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h misc/putget.h
-$(MT_OBJDIR)/show_msg.o: misc/show_msg.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h misc/putget.h misc/ei_printterm.h \
- misc/ei_internal.h misc/show_msg.h
-$(MT_OBJDIR)/ei_compat.o: misc/ei_compat.c ../include/ei.h misc/ei_internal.h
-$(MT_OBJDIR)/hash_dohash.o: registry/hash_dohash.c registry/hash.h ../include/ei.h
-$(MT_OBJDIR)/hash_foreach.o: registry/hash_foreach.c registry/hash.h ../include/ei.h
-$(MT_OBJDIR)/hash_freetab.o: registry/hash_freetab.c registry/hash.h ../include/ei.h
-$(MT_OBJDIR)/hash_insert.o: registry/hash_insert.c registry/hash.h ../include/ei.h
-$(MT_OBJDIR)/hash_isprime.o: registry/hash_isprime.c registry/hash.h ../include/ei.h
-$(MT_OBJDIR)/hash_lookup.o: registry/hash_lookup.c registry/hash.h ../include/ei.h
-$(MT_OBJDIR)/hash_newtab.o: registry/hash_newtab.c registry/hash.h ../include/ei.h
-$(MT_OBJDIR)/hash_remove.o: registry/hash_remove.c registry/hash.h ../include/ei.h
-$(MT_OBJDIR)/hash_resize.o: registry/hash_resize.c registry/hash.h ../include/ei.h
-$(MT_OBJDIR)/hash_rlookup.o: registry/hash_rlookup.c registry/hash.h ../include/ei.h
-$(MT_OBJDIR)/reg_close.o: registry/reg_close.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_delete.o: registry/reg_delete.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_dirty.o: registry/reg_dirty.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_dump.o: registry/reg_dump.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- registry/reg.h registry/hash.h connect/eisend.h connect/eirecv.h \
- connect/ei_connect_int.h
-$(MT_OBJDIR)/reg_free.o: registry/reg_free.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_get.o: registry/reg_get.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_getf.o: registry/reg_getf.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_geti.o: registry/reg_geti.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_getp.o: registry/reg_getp.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_gets.o: registry/reg_gets.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_make.o: registry/reg_make.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_open.o: registry/reg_open.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_purge.o: registry/reg_purge.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_resize.o: registry/reg_resize.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_restore.o: registry/reg_restore.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- registry/reg.h registry/hash.h connect/eisend.h connect/eirecv.h \
- connect/ei_connect_int.h
-$(MT_OBJDIR)/reg_set.o: registry/reg_set.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_setf.o: registry/reg_setf.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_seti.o: registry/reg_seti.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_setp.o: registry/reg_setp.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_sets.o: registry/reg_sets.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_stat.o: registry/reg_stat.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_tabstat.o: registry/reg_tabstat.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/decode_term.o: legacy/decode_term.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h ../include/erl_interface.h
-$(MT_OBJDIR)/encode_term.o: legacy/encode_term.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h misc/ei_x_encode.h ../include/erl_interface.h \
- legacy/erl_marshal.h legacy/erl_eterm.h legacy/portability.h
-$(MT_OBJDIR)/erl_connect.o: legacy/erl_connect.c $(TARGET)/config.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_config.h \
- legacy/erl_connect.h legacy/erl_eterm.h legacy/portability.h \
- legacy/erl_malloc.h misc/putget.h connect/ei_connect_int.h \
- misc/ei_locking.h epmd/ei_epmd.h misc/ei_internal.h
-$(MT_OBJDIR)/erl_error.o: legacy/erl_error.c $(TARGET)/config.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_error.h
-$(MT_OBJDIR)/erl_eterm.o: legacy/erl_eterm.c misc/ei_locking.h \
- $(TARGET)/config.h connect/ei_resolve.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_eterm.h \
- legacy/portability.h legacy/erl_malloc.h legacy/erl_marshal.h \
- legacy/erl_error.h legacy/erl_internal.h misc/ei_internal.h
-$(MT_OBJDIR)/erl_fix_alloc.o: legacy/erl_fix_alloc.c $(TARGET)/config.h \
- misc/ei_locking.h ../include/erl_interface.h ../include/ei.h \
- legacy/erl_error.h legacy/erl_malloc.h legacy/erl_fix_alloc.h \
- legacy/erl_eterm.h legacy/portability.h
-$(MT_OBJDIR)/erl_format.o: legacy/erl_format.c ../include/erl_interface.h \
- ../include/ei.h legacy/erl_eterm.h legacy/portability.h \
- legacy/erl_malloc.h legacy/erl_error.h legacy/erl_internal.h
-$(MT_OBJDIR)/erl_malloc.o: legacy/erl_malloc.c ../include/erl_interface.h \
- ../include/ei.h legacy/erl_fix_alloc.h legacy/erl_malloc.h \
- legacy/erl_internal.h legacy/erl_eterm.h legacy/portability.h \
- misc/ei_malloc.h
-$(MT_OBJDIR)/erl_marshal.o: legacy/erl_marshal.c $(TARGET)/config.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_marshal.h \
- legacy/erl_eterm.h legacy/portability.h legacy/erl_malloc.h \
- legacy/erl_error.h legacy/erl_internal.h misc/eiext.h misc/putget.h
-$(MT_OBJDIR)/erl_timeout.o: legacy/erl_timeout.c $(TARGET)/config.h \
- legacy/erl_timeout.h
-$(MT_OBJDIR)/global_names.o: legacy/global_names.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
- ../include/erl_interface.h legacy/erl_connect.h
-$(MT_OBJDIR)/global_register.o: legacy/global_register.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h ../include/erl_interface.h
-$(MT_OBJDIR)/global_unregister.o: legacy/global_unregister.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
- ../include/erl_interface.h legacy/erl_connect.h
-$(MT_OBJDIR)/global_whereis.o: legacy/global_whereis.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
- ../include/erl_interface.h legacy/erl_connect.h
-
-$(MD_OBJDIR)/ei_connect.o: connect/ei_connect.c $(TARGET)/config.h \
- misc/eidef.h ../include/ei.h misc/eiext.h misc/ei_portio.h \
- misc/ei_internal.h connect/ei_connect_int.h misc/ei_locking.h \
- connect/eisend.h connect/eirecv.h misc/eimd5.h misc/putget.h \
- connect/ei_resolve.h epmd/ei_epmd.h
-$(MD_OBJDIR)/ei_resolve.o: connect/ei_resolve.c $(TARGET)/config.h \
- misc/eidef.h ../include/ei.h connect/ei_resolve.h misc/ei_locking.h
-$(MD_OBJDIR)/eirecv.o: connect/eirecv.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h connect/eirecv.h misc/ei_portio.h \
- misc/ei_internal.h misc/putget.h misc/ei_trace.h misc/show_msg.h
-$(MD_OBJDIR)/send.o: connect/send.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h connect/eisend.h misc/putget.h \
- connect/ei_connect_int.h misc/ei_internal.h misc/ei_trace.h \
- misc/show_msg.h
-$(MD_OBJDIR)/send_exit.o: connect/send_exit.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/ei_connect_int.h misc/ei_trace.h \
- misc/ei_internal.h misc/putget.h misc/show_msg.h
-$(MD_OBJDIR)/send_reg.o: connect/send_reg.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h connect/eisend.h misc/putget.h \
- connect/ei_connect_int.h misc/ei_internal.h misc/ei_trace.h \
- misc/show_msg.h
-$(MD_OBJDIR)/decode_atom.o: decode/decode_atom.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_big.o: decode/decode_big.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_bignum.o: decode/decode_bignum.c $(TARGET)/config.h
-$(MD_OBJDIR)/decode_binary.o: decode/decode_binary.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_boolean.o: decode/decode_boolean.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_char.o: decode/decode_char.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_double.o: decode/decode_double.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_fun.o: decode/decode_fun.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/ei_malloc.h decode/decode_skip.h misc/putget.h
-$(MD_OBJDIR)/decode_intlist.o: decode/decode_intlist.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_list_header.o: decode/decode_list_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_long.o: decode/decode_long.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_pid.o: decode/decode_pid.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_port.o: decode/decode_port.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_ref.o: decode/decode_ref.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_skip.o: decode/decode_skip.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- decode/decode_skip.h
-$(MD_OBJDIR)/decode_string.o: decode/decode_string.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_trace.o: decode/decode_trace.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/putget.h
-$(MD_OBJDIR)/decode_tuple_header.o: decode/decode_tuple_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_ulong.o: decode/decode_ulong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_version.o: decode/decode_version.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_longlong.o: decode/decode_longlong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_ulonglong.o: decode/decode_ulonglong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_atom.o: encode/encode_atom.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_bignum.o: encode/encode_bignum.c $(TARGET)/config.h
-$(MD_OBJDIR)/encode_binary.o: encode/encode_binary.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_boolean.o: encode/encode_boolean.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_char.o: encode/encode_char.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_double.o: encode/encode_double.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_fun.o: encode/encode_fun.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_list_header.o: encode/encode_list_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_long.o: encode/encode_long.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_pid.o: encode/encode_pid.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_port.o: encode/encode_port.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_ref.o: encode/encode_ref.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_string.o: encode/encode_string.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_trace.o: encode/encode_trace.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/putget.h
-$(MD_OBJDIR)/encode_tuple_header.o: encode/encode_tuple_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_ulong.o: encode/encode_ulong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_version.o: encode/encode_version.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_longlong.o: encode/encode_longlong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h misc/ei_x_encode.h
-$(MD_OBJDIR)/encode_ulonglong.o: encode/encode_ulonglong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h misc/ei_x_encode.h
-$(MD_OBJDIR)/epmd_port.o: epmd/epmd_port.c misc/ei_internal.h epmd/ei_epmd.h \
- misc/putget.h
-$(MD_OBJDIR)/epmd_publish.o: epmd/epmd_publish.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/ei_internal.h \
- misc/putget.h ../include/erl_interface.h epmd/ei_epmd.h
-$(MD_OBJDIR)/epmd_unpublish.o: epmd/epmd_unpublish.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/ei_internal.h \
- misc/putget.h ../include/erl_interface.h epmd/ei_epmd.h
-$(MD_OBJDIR)/ei_decode_term.o: misc/ei_decode_term.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/ei_decode_term.h misc/putget.h
-$(MD_OBJDIR)/ei_format.o: misc/ei_format.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/ei_malloc.h misc/ei_format.h
-$(MD_OBJDIR)/ei_locking.o: misc/ei_locking.c $(TARGET)/config.h \
- misc/ei_malloc.h misc/ei_locking.h
-$(MD_OBJDIR)/ei_malloc.o: misc/ei_malloc.c misc/ei_malloc.h
-$(MD_OBJDIR)/ei_portio.o: misc/ei_portio.c misc/ei_portio.h misc/ei_internal.h
-$(MD_OBJDIR)/ei_printterm.o: misc/ei_printterm.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/ei_printterm.h misc/ei_malloc.h
-$(MD_OBJDIR)/ei_pthreads.o: misc/ei_pthreads.c $(TARGET)/config.h \
- ../include/ei.h misc/ei_locking.h
-$(MD_OBJDIR)/ei_trace.o: misc/ei_trace.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/ei_trace.h
-$(MD_OBJDIR)/ei_x_encode.o: misc/ei_x_encode.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/ei_x_encode.h \
- misc/ei_malloc.h
-$(MD_OBJDIR)/eimd5.o: misc/eimd5.c misc/eimd5.h
-$(MD_OBJDIR)/get_type.o: misc/get_type.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h misc/putget.h
-$(MD_OBJDIR)/show_msg.o: misc/show_msg.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h misc/putget.h misc/ei_printterm.h \
- misc/ei_internal.h misc/show_msg.h
-$(MD_OBJDIR)/ei_compat.o: misc/ei_compat.c ../include/ei.h misc/ei_internal.h
-$(MD_OBJDIR)/hash_dohash.o: registry/hash_dohash.c registry/hash.h ../include/ei.h
-$(MD_OBJDIR)/hash_foreach.o: registry/hash_foreach.c registry/hash.h ../include/ei.h
-$(MD_OBJDIR)/hash_freetab.o: registry/hash_freetab.c registry/hash.h ../include/ei.h
-$(MD_OBJDIR)/hash_insert.o: registry/hash_insert.c registry/hash.h ../include/ei.h
-$(MD_OBJDIR)/hash_isprime.o: registry/hash_isprime.c registry/hash.h ../include/ei.h
-$(MD_OBJDIR)/hash_lookup.o: registry/hash_lookup.c registry/hash.h ../include/ei.h
-$(MD_OBJDIR)/hash_newtab.o: registry/hash_newtab.c registry/hash.h ../include/ei.h
-$(MD_OBJDIR)/hash_remove.o: registry/hash_remove.c registry/hash.h ../include/ei.h
-$(MD_OBJDIR)/hash_resize.o: registry/hash_resize.c registry/hash.h ../include/ei.h
-$(MD_OBJDIR)/hash_rlookup.o: registry/hash_rlookup.c registry/hash.h ../include/ei.h
-$(MD_OBJDIR)/reg_close.o: registry/reg_close.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_delete.o: registry/reg_delete.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_dirty.o: registry/reg_dirty.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_dump.o: registry/reg_dump.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- registry/reg.h registry/hash.h connect/eisend.h connect/eirecv.h \
- connect/ei_connect_int.h
-$(MD_OBJDIR)/reg_free.o: registry/reg_free.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_get.o: registry/reg_get.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_getf.o: registry/reg_getf.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_geti.o: registry/reg_geti.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_getp.o: registry/reg_getp.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_gets.o: registry/reg_gets.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_make.o: registry/reg_make.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_open.o: registry/reg_open.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_purge.o: registry/reg_purge.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_resize.o: registry/reg_resize.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_restore.o: registry/reg_restore.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- registry/reg.h registry/hash.h connect/eisend.h connect/eirecv.h \
- connect/ei_connect_int.h
-$(MD_OBJDIR)/reg_set.o: registry/reg_set.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_setf.o: registry/reg_setf.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_seti.o: registry/reg_seti.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_setp.o: registry/reg_setp.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_sets.o: registry/reg_sets.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_stat.o: registry/reg_stat.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_tabstat.o: registry/reg_tabstat.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/decode_term.o: legacy/decode_term.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h ../include/erl_interface.h
-$(MD_OBJDIR)/encode_term.o: legacy/encode_term.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h misc/ei_x_encode.h ../include/erl_interface.h \
- legacy/erl_marshal.h legacy/erl_eterm.h legacy/portability.h
-$(MD_OBJDIR)/erl_connect.o: legacy/erl_connect.c $(TARGET)/config.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_config.h \
- legacy/erl_connect.h legacy/erl_eterm.h legacy/portability.h \
- legacy/erl_malloc.h misc/putget.h connect/ei_connect_int.h \
- misc/ei_locking.h epmd/ei_epmd.h misc/ei_internal.h
-$(MD_OBJDIR)/erl_error.o: legacy/erl_error.c $(TARGET)/config.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_error.h
-$(MD_OBJDIR)/erl_eterm.o: legacy/erl_eterm.c misc/ei_locking.h \
- $(TARGET)/config.h connect/ei_resolve.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_eterm.h \
- legacy/portability.h legacy/erl_malloc.h legacy/erl_marshal.h \
- legacy/erl_error.h legacy/erl_internal.h misc/ei_internal.h
-$(MD_OBJDIR)/erl_fix_alloc.o: legacy/erl_fix_alloc.c $(TARGET)/config.h \
- misc/ei_locking.h ../include/erl_interface.h ../include/ei.h \
- legacy/erl_error.h legacy/erl_malloc.h legacy/erl_fix_alloc.h \
- legacy/erl_eterm.h legacy/portability.h
-$(MD_OBJDIR)/erl_format.o: legacy/erl_format.c ../include/erl_interface.h \
- ../include/ei.h legacy/erl_eterm.h legacy/portability.h \
- legacy/erl_malloc.h legacy/erl_error.h legacy/erl_internal.h
-$(MD_OBJDIR)/erl_malloc.o: legacy/erl_malloc.c ../include/erl_interface.h \
- ../include/ei.h legacy/erl_fix_alloc.h legacy/erl_malloc.h \
- legacy/erl_internal.h legacy/erl_eterm.h legacy/portability.h \
- misc/ei_malloc.h
-$(MD_OBJDIR)/erl_marshal.o: legacy/erl_marshal.c $(TARGET)/config.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_marshal.h \
- legacy/erl_eterm.h legacy/portability.h legacy/erl_malloc.h \
- legacy/erl_error.h legacy/erl_internal.h misc/eiext.h misc/putget.h
-$(MD_OBJDIR)/erl_timeout.o: legacy/erl_timeout.c $(TARGET)/config.h \
- legacy/erl_timeout.h
-$(MD_OBJDIR)/global_names.o: legacy/global_names.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
- ../include/erl_interface.h legacy/erl_connect.h
-$(MD_OBJDIR)/global_register.o: legacy/global_register.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h ../include/erl_interface.h
-$(MD_OBJDIR)/global_unregister.o: legacy/global_unregister.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
- ../include/erl_interface.h legacy/erl_connect.h
-$(MD_OBJDIR)/global_whereis.o: legacy/global_whereis.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
- ../include/erl_interface.h legacy/erl_connect.h
-
-$(MDD_OBJDIR)/ei_connect.o: connect/ei_connect.c $(TARGET)/config.h \
- misc/eidef.h ../include/ei.h misc/eiext.h misc/ei_portio.h \
- misc/ei_internal.h connect/ei_connect_int.h misc/ei_locking.h \
- connect/eisend.h connect/eirecv.h misc/eimd5.h misc/putget.h \
- connect/ei_resolve.h epmd/ei_epmd.h
-$(MDD_OBJDIR)/ei_resolve.o: connect/ei_resolve.c $(TARGET)/config.h \
- misc/eidef.h ../include/ei.h connect/ei_resolve.h misc/ei_locking.h
-$(MDD_OBJDIR)/eirecv.o: connect/eirecv.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h connect/eirecv.h misc/ei_portio.h \
- misc/ei_internal.h misc/putget.h misc/ei_trace.h misc/show_msg.h
-$(MDD_OBJDIR)/send.o: connect/send.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h connect/eisend.h misc/putget.h \
- connect/ei_connect_int.h misc/ei_internal.h misc/ei_trace.h \
- misc/show_msg.h
-$(MDD_OBJDIR)/send_exit.o: connect/send_exit.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/ei_connect_int.h misc/ei_trace.h \
- misc/ei_internal.h misc/putget.h misc/show_msg.h
-$(MDD_OBJDIR)/send_reg.o: connect/send_reg.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h connect/eisend.h misc/putget.h \
- connect/ei_connect_int.h misc/ei_internal.h misc/ei_trace.h \
- misc/show_msg.h
-$(MDD_OBJDIR)/decode_atom.o: decode/decode_atom.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_big.o: decode/decode_big.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_bignum.o: decode/decode_bignum.c $(TARGET)/config.h
-$(MDD_OBJDIR)/decode_binary.o: decode/decode_binary.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_boolean.o: decode/decode_boolean.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_char.o: decode/decode_char.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_double.o: decode/decode_double.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_fun.o: decode/decode_fun.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/ei_malloc.h decode/decode_skip.h misc/putget.h
-$(MDD_OBJDIR)/decode_intlist.o: decode/decode_intlist.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_list_header.o: decode/decode_list_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_long.o: decode/decode_long.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_pid.o: decode/decode_pid.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_port.o: decode/decode_port.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_ref.o: decode/decode_ref.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_skip.o: decode/decode_skip.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- decode/decode_skip.h
-$(MDD_OBJDIR)/decode_string.o: decode/decode_string.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_trace.o: decode/decode_trace.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/putget.h
-$(MDD_OBJDIR)/decode_tuple_header.o: decode/decode_tuple_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_ulong.o: decode/decode_ulong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_version.o: decode/decode_version.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_longlong.o: decode/decode_longlong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_ulonglong.o: decode/decode_ulonglong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_atom.o: encode/encode_atom.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_bignum.o: encode/encode_bignum.c $(TARGET)/config.h
-$(MDD_OBJDIR)/encode_binary.o: encode/encode_binary.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_boolean.o: encode/encode_boolean.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_char.o: encode/encode_char.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_double.o: encode/encode_double.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_fun.o: encode/encode_fun.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_list_header.o: encode/encode_list_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_long.o: encode/encode_long.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_pid.o: encode/encode_pid.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_port.o: encode/encode_port.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_ref.o: encode/encode_ref.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_string.o: encode/encode_string.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_trace.o: encode/encode_trace.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/putget.h
-$(MDD_OBJDIR)/encode_tuple_header.o: encode/encode_tuple_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_ulong.o: encode/encode_ulong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_version.o: encode/encode_version.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_longlong.o: encode/encode_longlong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h misc/ei_x_encode.h
-$(MDD_OBJDIR)/encode_ulonglong.o: encode/encode_ulonglong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h misc/ei_x_encode.h
-$(MDD_OBJDIR)/epmd_port.o: epmd/epmd_port.c misc/ei_internal.h epmd/ei_epmd.h \
- misc/putget.h
-$(MDD_OBJDIR)/epmd_publish.o: epmd/epmd_publish.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/ei_internal.h \
- misc/putget.h ../include/erl_interface.h epmd/ei_epmd.h
-$(MDD_OBJDIR)/epmd_unpublish.o: epmd/epmd_unpublish.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/ei_internal.h \
- misc/putget.h ../include/erl_interface.h epmd/ei_epmd.h
-$(MDD_OBJDIR)/ei_decode_term.o: misc/ei_decode_term.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/ei_decode_term.h misc/putget.h
-$(MDD_OBJDIR)/ei_format.o: misc/ei_format.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/ei_malloc.h misc/ei_format.h
-$(MDD_OBJDIR)/ei_locking.o: misc/ei_locking.c $(TARGET)/config.h \
- misc/ei_malloc.h misc/ei_locking.h
-$(MDD_OBJDIR)/ei_malloc.o: misc/ei_malloc.c misc/ei_malloc.h
-$(MDD_OBJDIR)/ei_portio.o: misc/ei_portio.c misc/ei_portio.h misc/ei_internal.h
-$(MDD_OBJDIR)/ei_printterm.o: misc/ei_printterm.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/ei_printterm.h misc/ei_malloc.h
-$(MDD_OBJDIR)/ei_pthreads.o: misc/ei_pthreads.c $(TARGET)/config.h \
- ../include/ei.h misc/ei_locking.h
-$(MDD_OBJDIR)/ei_trace.o: misc/ei_trace.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/ei_trace.h
-$(MDD_OBJDIR)/ei_x_encode.o: misc/ei_x_encode.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/ei_x_encode.h \
- misc/ei_malloc.h
-$(MDD_OBJDIR)/eimd5.o: misc/eimd5.c misc/eimd5.h
-$(MDD_OBJDIR)/get_type.o: misc/get_type.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h misc/putget.h
-$(MDD_OBJDIR)/show_msg.o: misc/show_msg.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h misc/putget.h misc/ei_printterm.h \
- misc/ei_internal.h misc/show_msg.h
-$(MDD_OBJDIR)/ei_compat.o: misc/ei_compat.c ../include/ei.h misc/ei_internal.h
-$(MDD_OBJDIR)/hash_dohash.o: registry/hash_dohash.c registry/hash.h ../include/ei.h
-$(MDD_OBJDIR)/hash_foreach.o: registry/hash_foreach.c registry/hash.h ../include/ei.h
-$(MDD_OBJDIR)/hash_freetab.o: registry/hash_freetab.c registry/hash.h ../include/ei.h
-$(MDD_OBJDIR)/hash_insert.o: registry/hash_insert.c registry/hash.h ../include/ei.h
-$(MDD_OBJDIR)/hash_isprime.o: registry/hash_isprime.c registry/hash.h ../include/ei.h
-$(MDD_OBJDIR)/hash_lookup.o: registry/hash_lookup.c registry/hash.h ../include/ei.h
-$(MDD_OBJDIR)/hash_newtab.o: registry/hash_newtab.c registry/hash.h ../include/ei.h
-$(MDD_OBJDIR)/hash_remove.o: registry/hash_remove.c registry/hash.h ../include/ei.h
-$(MDD_OBJDIR)/hash_resize.o: registry/hash_resize.c registry/hash.h ../include/ei.h
-$(MDD_OBJDIR)/hash_rlookup.o: registry/hash_rlookup.c registry/hash.h ../include/ei.h
-$(MDD_OBJDIR)/reg_close.o: registry/reg_close.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_delete.o: registry/reg_delete.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_dirty.o: registry/reg_dirty.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_dump.o: registry/reg_dump.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- registry/reg.h registry/hash.h connect/eisend.h connect/eirecv.h \
- connect/ei_connect_int.h
-$(MDD_OBJDIR)/reg_free.o: registry/reg_free.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_get.o: registry/reg_get.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_getf.o: registry/reg_getf.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_geti.o: registry/reg_geti.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_getp.o: registry/reg_getp.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_gets.o: registry/reg_gets.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_make.o: registry/reg_make.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_open.o: registry/reg_open.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_purge.o: registry/reg_purge.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_resize.o: registry/reg_resize.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_restore.o: registry/reg_restore.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- registry/reg.h registry/hash.h connect/eisend.h connect/eirecv.h \
- connect/ei_connect_int.h
-$(MDD_OBJDIR)/reg_set.o: registry/reg_set.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_setf.o: registry/reg_setf.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_seti.o: registry/reg_seti.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_setp.o: registry/reg_setp.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_sets.o: registry/reg_sets.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_stat.o: registry/reg_stat.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_tabstat.o: registry/reg_tabstat.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/decode_term.o: legacy/decode_term.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h ../include/erl_interface.h
-$(MDD_OBJDIR)/encode_term.o: legacy/encode_term.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h misc/ei_x_encode.h ../include/erl_interface.h \
- legacy/erl_marshal.h legacy/erl_eterm.h legacy/portability.h
-$(MDD_OBJDIR)/erl_connect.o: legacy/erl_connect.c $(TARGET)/config.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_config.h \
- legacy/erl_connect.h legacy/erl_eterm.h legacy/portability.h \
- legacy/erl_malloc.h misc/putget.h connect/ei_connect_int.h \
- misc/ei_locking.h epmd/ei_epmd.h misc/ei_internal.h
-$(MDD_OBJDIR)/erl_error.o: legacy/erl_error.c $(TARGET)/config.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_error.h
-$(MDD_OBJDIR)/erl_eterm.o: legacy/erl_eterm.c misc/ei_locking.h \
- $(TARGET)/config.h connect/ei_resolve.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_eterm.h \
- legacy/portability.h legacy/erl_malloc.h legacy/erl_marshal.h \
- legacy/erl_error.h legacy/erl_internal.h misc/ei_internal.h
-$(MDD_OBJDIR)/erl_fix_alloc.o: legacy/erl_fix_alloc.c $(TARGET)/config.h \
- misc/ei_locking.h ../include/erl_interface.h ../include/ei.h \
- legacy/erl_error.h legacy/erl_malloc.h legacy/erl_fix_alloc.h \
- legacy/erl_eterm.h legacy/portability.h
-$(MDD_OBJDIR)/erl_format.o: legacy/erl_format.c ../include/erl_interface.h \
- ../include/ei.h legacy/erl_eterm.h legacy/portability.h \
- legacy/erl_malloc.h legacy/erl_error.h legacy/erl_internal.h
-$(MDD_OBJDIR)/erl_malloc.o: legacy/erl_malloc.c ../include/erl_interface.h \
- ../include/ei.h legacy/erl_fix_alloc.h legacy/erl_malloc.h \
- legacy/erl_internal.h legacy/erl_eterm.h legacy/portability.h \
- misc/ei_malloc.h
-$(MDD_OBJDIR)/erl_marshal.o: legacy/erl_marshal.c $(TARGET)/config.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_marshal.h \
- legacy/erl_eterm.h legacy/portability.h legacy/erl_malloc.h \
- legacy/erl_error.h legacy/erl_internal.h misc/eiext.h misc/putget.h
-$(MDD_OBJDIR)/erl_timeout.o: legacy/erl_timeout.c $(TARGET)/config.h \
- legacy/erl_timeout.h
-$(MDD_OBJDIR)/global_names.o: legacy/global_names.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
- ../include/erl_interface.h legacy/erl_connect.h
-$(MDD_OBJDIR)/global_register.o: legacy/global_register.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h ../include/erl_interface.h
-$(MDD_OBJDIR)/global_unregister.o: legacy/global_unregister.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
- ../include/erl_interface.h legacy/erl_connect.h
-$(MDD_OBJDIR)/global_whereis.o: legacy/global_whereis.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
- ../include/erl_interface.h legacy/erl_connect.h
-
diff --git a/lib/erl_interface/src/epmd/ei_epmd.h b/lib/erl_interface/src/epmd/ei_epmd.h
index ac153b6e66..f72c354e32 100644
--- a/lib/erl_interface/src/epmd/ei_epmd.h
+++ b/lib/erl_interface/src/epmd/ei_epmd.h
@@ -25,8 +25,8 @@
#endif
#ifndef EI_DIST_HIGH
-#define EI_DIST_HIGH 5 /* R4 and later */
-#define EI_DIST_LOW 1 /* R3 and earlier */
+#define EI_DIST_HIGH 6 /* OTP 22 and later */
+#define EI_DIST_LOW 5 /* OTP R4 - 21 */
#endif
#ifndef EPMD_PORT
@@ -45,6 +45,7 @@
#ifndef EI_EPMD_ALIVE2_REQ
#define EI_EPMD_ALIVE2_REQ 120
#define EI_EPMD_ALIVE2_RESP 121
+#define EI_EPMD_ALIVE2_X_RESP 118
#define EI_EPMD_PORT2_REQ 122
#define EI_EPMD_PORT2_RESP 119
#define EI_EPMD_STOP_REQ 's'
diff --git a/lib/erl_interface/src/epmd/epmd_publish.c b/lib/erl_interface/src/epmd/epmd_publish.c
index 20b8e867e8..ef8a5d6b70 100644
--- a/lib/erl_interface/src/epmd/epmd_publish.c
+++ b/lib/erl_interface/src/epmd/epmd_publish.c
@@ -68,7 +68,8 @@ static int ei_epmd_r4_publish (int port, const char *alive, unsigned ms)
int nlen = strlen(alive);
int len = elen + nlen + 13; /* hard coded: be careful! */
int n;
- int err, res, creation;
+ int err, response, res;
+ unsigned creation;
ssize_t dlen;
unsigned tmo = ms == 0 ? EI_SCLBK_INF_TMO : ms;
@@ -124,8 +125,10 @@ static int ei_epmd_r4_publish (int port, const char *alive, unsigned ms)
/* Don't close fd here! It keeps us registered with epmd */
s = buf;
- if (((res=get8(s)) != EI_EPMD_ALIVE2_RESP)) { /* response */
- EI_TRACE_ERR1("ei_epmd_r4_publish","<- unknown (%d)",res);
+ response = get8(s);
+ if (response != EI_EPMD_ALIVE2_RESP &&
+ response != EI_EPMD_ALIVE2_X_RESP) {
+ EI_TRACE_ERR1("ei_epmd_r4_publish","<- unknown (%d)",response);
EI_TRACE_ERR0("ei_epmd_r4_publish","-> CLOSE");
ei_close__(fd);
erl_errno = EIO;
@@ -141,18 +144,21 @@ static int ei_epmd_r4_publish (int port, const char *alive, unsigned ms)
return -1;
}
- creation = get16be(s);
+ if (response == EI_EPMD_ALIVE2_RESP)
+ creation = get16be(s);
+ else /* EI_EPMD_ALIVE2_X_RESP */
+ creation = get32be(s);
EI_TRACE_CONN2("ei_epmd_r4_publish",
- " result=%d (ok) creation=%d",res,creation);
+ " result=%d (ok) creation=%u",res,creation);
- /* probably should save fd so we can close it later... */
- /* epmd_saveconn(OPEN,fd,alive); */
+ /*
+ * Would be nice to somehow use the nice "unique" creation value
+ * received here from epmd instead of using the crappy one
+ * passed (already) to ei_connect_init.
+ */
- /* return the creation number, for no good reason */
- /* return creation;*/
-
- /* no - return the descriptor */
+ /* return the descriptor */
return fd;
}
diff --git a/lib/erl_interface/src/prog/erl_call.c b/lib/erl_interface/src/prog/erl_call.c
index ab91157035..dce2ecdec2 100644
--- a/lib/erl_interface/src/prog/erl_call.c
+++ b/lib/erl_interface/src/prog/erl_call.c
@@ -292,8 +292,7 @@ int erl_call(int argc, char **argv)
flags.cookie = NULL;
}
- /* FIXME decide how many bits etc or leave to connect_xinit? */
- creation = (time(NULL) % 3) + 1; /* "random" */
+ creation = time(NULL) + 1; /* "random" */
if (flags.hidden == NULL) {
/* As default we are c17@gethostname */
diff --git a/lib/inets/src/http_server/mod_responsecontrol.erl b/lib/inets/src/http_server/mod_responsecontrol.erl
index 07129940a5..a32ba65c22 100644
--- a/lib/inets/src/http_server/mod_responsecontrol.erl
+++ b/lib/inets/src/http_server/mod_responsecontrol.erl
@@ -71,7 +71,7 @@ do_responsecontrol(Info) ->
%% If a client sends more then one of the if-XXXX fields in a request
-%% The standard says it does not specify the behaviuor so I specified it :-)
+%% The standard says it does not specify the behaviour so I specified it :-)
%% The priority between the fields is
%% 1.If-modified
%% 2.If-Unmodified
diff --git a/lib/jinterface/doc/src/jinterface_users_guide.xml b/lib/jinterface/doc/src/jinterface_users_guide.xml
index 56f88124bf..504c77f339 100644
--- a/lib/jinterface/doc/src/jinterface_users_guide.xml
+++ b/lib/jinterface/doc/src/jinterface_users_guide.xml
@@ -366,20 +366,20 @@ OtpNode node = new OtpNode("gurka"); </code>
<seealso marker="java/com/ericsson/otp/erlang/OtpEpmd">OtpEpmd</seealso> class.
Nodes wishing to contact other nodes must first request information
from Epmd before a connection can be set up, however this is done automatically
- by <seealso marker="java/com/ericsson/otp/erlang/OtpSelf#connect(com.ericsson.otp.erlang.OtpPeer)">OtpSelf.connect()</seealso> when necessary. </p>
- <p>When you use <seealso marker="java/com/ericsson/otp/erlang/OtpSelf#connect(com.ericsson.otp.erlang.OtpPeer)">OtpSelf.connect()</seealso> to connect to an Erlang node,
+ by <seealso marker="java/com/ericsson/otp/erlang/OtpSelf#connect-com.ericsson.otp.erlang.OtpPeer-">OtpSelf.connect()</seealso> when necessary. </p>
+ <p>When you use <seealso marker="java/com/ericsson/otp/erlang/OtpSelf#connect-com.ericsson.otp.erlang.OtpPeer-">OtpSelf.connect()</seealso> to connect to an Erlang node,
a connection is first made to epmd and, if the node is known, a
connection is then made to the Erlang node.</p>
<p>Java nodes can also register themselves with epmd if they want other
nodes in the system to be able to find and connect to them.
- This is done by call to method <seealso marker="java/com/ericsson/otp/erlang/OtpEpmd#publishPort(com.ericsson.otp.erlang.OtpLocalNode)">OtpEpmd.publishPort()</seealso>.</p>
+ This is done by call to method <seealso marker="java/com/ericsson/otp/erlang/OtpEpmd#publishPort-com.ericsson.otp.erlang.OtpLocalNode-">OtpEpmd.publishPort()</seealso>.</p>
<p>Be aware that on some systems (such as VxWorks), a failed node will
not be detected by this mechanism since the operating system does not
automatically close descriptors that were left open when the node
failed. If a node has failed in this way, epmd will prevent you from
registering a new node with the old name, since it thinks that the old
name is still in use. In this case, you must unregister the name
- explicitly, by using <seealso marker="java/com/ericsson/otp/erlang/OtpEpmd#unPublishPort(com.ericsson.otp.erlang.OtpLocalNode)">OtpEpmd.unPublishPort()</seealso></p>
+ explicitly, by using <seealso marker="java/com/ericsson/otp/erlang/OtpEpmd#unPublishPort-com.ericsson.otp.erlang.OtpLocalNode-">OtpEpmd.unPublishPort()</seealso></p>
<p>This will cause epmd to close the connection from the far end. Note
that if the name was in fact still in use by a node, the results of
this operation are unpredictable. Also, doing this does not cause the
diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangPid.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangPid.java
index 9cbd735751..3abdf9535f 100644
--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangPid.java
+++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangPid.java
@@ -27,7 +27,6 @@ public class OtpErlangPid extends OtpErlangObject implements Comparable<Object>
// don't change this!
private static final long serialVersionUID = 1664394142301803659L;
- private final int tag;
private final String node;
private final int id;
private final int serial;
@@ -45,7 +44,6 @@ public class OtpErlangPid extends OtpErlangObject implements Comparable<Object>
public OtpErlangPid(final OtpLocalNode self) {
final OtpErlangPid p = self.createPid();
- tag = p.tag;
id = p.id;
serial = p.serial;
creation = p.creation;
@@ -67,7 +65,6 @@ public class OtpErlangPid extends OtpErlangObject implements Comparable<Object>
throws OtpErlangDecodeException {
final OtpErlangPid p = buf.read_pid();
- tag = p.tag;
node = p.node();
id = p.id();
serial = p.serial();
@@ -118,7 +115,6 @@ public class OtpErlangPid extends OtpErlangObject implements Comparable<Object>
*/
protected OtpErlangPid(final int tag, final String node, final int id,
final int serial, final int creation) {
- this.tag = tag;
this.node = node;
if (tag == OtpExternal.pidTag) {
this.id = id & 0x7fff; // 15 bits
@@ -133,7 +129,7 @@ public class OtpErlangPid extends OtpErlangObject implements Comparable<Object>
}
protected int tag() {
- return tag;
+ return OtpExternal.newPidTag;
}
/**
diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangPort.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangPort.java
index 79b5d2736c..c8648d7aa3 100644
--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangPort.java
+++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangPort.java
@@ -26,7 +26,6 @@ public class OtpErlangPort extends OtpErlangObject {
// don't change this!
private static final long serialVersionUID = 4037115468007644704L;
- private final int tag;
private final String node;
private final int id;
private final int creation;
@@ -43,7 +42,6 @@ public class OtpErlangPort extends OtpErlangObject {
private OtpErlangPort(final OtpSelf self) {
final OtpErlangPort p = self.createPort();
- tag = p.tag;
id = p.id;
creation = p.creation;
node = p.node;
@@ -64,7 +62,6 @@ public class OtpErlangPort extends OtpErlangObject {
throws OtpErlangDecodeException {
final OtpErlangPort p = buf.read_port();
- tag = p.tag;
node = p.node();
id = p.id();
creation = p.creation();
@@ -105,7 +102,6 @@ public class OtpErlangPort extends OtpErlangObject {
*/
public OtpErlangPort(final int tag, final String node, final int id,
final int creation) {
- this.tag = tag;
this.node = node;
if (tag == OtpExternal.portTag) {
this.id = id & 0xfffffff; // 28 bits
@@ -118,7 +114,7 @@ public class OtpErlangPort extends OtpErlangObject {
}
protected int tag() {
- return tag;
+ return OtpExternal.newPortTag;
}
/**
diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangRef.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangRef.java
index 2165397013..2bf8d9a56b 100644
--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangRef.java
+++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangRef.java
@@ -28,7 +28,6 @@ public class OtpErlangRef extends OtpErlangObject {
// don't change this!
private static final long serialVersionUID = -7022666480768586521L;
- private final int tag;
private final String node;
private final int creation;
@@ -49,7 +48,6 @@ public class OtpErlangRef extends OtpErlangObject {
public OtpErlangRef(final OtpLocalNode self) {
final OtpErlangRef r = self.createRef();
- tag = r.tag;
ids = r.ids;
creation = r.creation;
node = r.node;
@@ -70,7 +68,6 @@ public class OtpErlangRef extends OtpErlangObject {
throws OtpErlangDecodeException {
final OtpErlangRef r = buf.read_ref();
- tag = r.tag;
node = r.node();
creation = r.creation();
@@ -90,7 +87,6 @@ public class OtpErlangRef extends OtpErlangObject {
* another arbitrary number.
*/
public OtpErlangRef(final String node, final int id, final int creation) {
- this.tag = OtpExternal.newRefTag;
this.node = node;
ids = new int[1];
ids[0] = id & 0x3ffff; // 18 bits
@@ -138,7 +134,6 @@ public class OtpErlangRef extends OtpErlangObject {
*/
public OtpErlangRef(final int tag, final String node, final int[] ids,
final int creation) {
- this.tag = tag;
this.node = node;
// use at most 3 words
@@ -162,7 +157,7 @@ public class OtpErlangRef extends OtpErlangObject {
}
protected int tag() {
- return tag;
+ return OtpExternal.newerRefTag;
}
/**
diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpOutputStream.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpOutputStream.java
index 187705a0b5..a3b089c1da 100644
--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpOutputStream.java
+++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpOutputStream.java
@@ -713,7 +713,7 @@ public class OtpOutputStream extends ByteArrayOutputStream {
*/
public void write_pid(final String node, final int id, final int serial,
final int creation) {
- write1(OtpExternal.pidTag);
+ write1(OtpExternal.newPidTag);
write_atom(node);
write4BE(id & 0x7fff); // 15 bits
write4BE(serial & 0x1fff); // 13 bits
@@ -727,20 +727,11 @@ public class OtpOutputStream extends ByteArrayOutputStream {
* the pid
*/
public void write_pid(OtpErlangPid pid) {
- write1(pid.tag());
+ write1(OtpExternal.newPidTag);
write_atom(pid.node());
write4BE(pid.id());
write4BE(pid.serial());
- switch (pid.tag()) {
- case OtpExternal.pidTag:
- write1(pid.creation());
- break;
- case OtpExternal.newPidTag:
- write4BE(pid.creation());
- break;
- default:
- throw new AssertionError("Invalid pid tag " + pid.tag());
- }
+ write4BE(pid.creation());
}
@@ -758,7 +749,7 @@ public class OtpOutputStream extends ByteArrayOutputStream {
* be used.
*/
public void write_port(final String node, final int id, final int creation) {
- write1(OtpExternal.portTag);
+ write1(OtpExternal.newPortTag);
write_atom(node);
write4BE(id & 0xfffffff); // 28 bits
write1(creation & 0x3); // 2 bits
@@ -771,19 +762,10 @@ public class OtpOutputStream extends ByteArrayOutputStream {
* the port.
*/
public void write_port(OtpErlangPort port) {
- write1(port.tag());
+ write1(OtpExternal.newPortTag);
write_atom(port.node());
write4BE(port.id());
- switch (port.tag()) {
- case OtpExternal.portTag:
- write1(port.creation());
- break;
- case OtpExternal.newPortTag:
- write4BE(port.creation());
- break;
- default:
- throw new AssertionError("Invalid port tag " + port.tag());
- }
+ write4BE(port.creation());
}
/**
@@ -829,7 +811,7 @@ public class OtpOutputStream extends ByteArrayOutputStream {
arity = 3; // max 3 words in ref
}
- write1(OtpExternal.newRefTag);
+ write1(OtpExternal.newerRefTag);
// how many id values
write2BE(arity);
@@ -857,24 +839,12 @@ public class OtpOutputStream extends ByteArrayOutputStream {
int[] ids = ref.ids();
int arity = ids.length;
- write1(ref.tag());
+ write1(OtpExternal.newerRefTag);
write2BE(arity);
write_atom(ref.node());
+ write4BE(ref.creation());
- switch (ref.tag()) {
- case OtpExternal.newRefTag:
- write1(ref.creation());
- write4BE(ids[0] & 0x3ffff); // first word gets truncated to 18 bits
- break;
- case OtpExternal.newerRefTag:
- write4BE(ref.creation());
- write4BE(ids[0]); // full first word
- break;
- default:
- throw new AssertionError("Invalid ref tag " + ref.tag());
- }
-
- for (int i = 1; i < arity; i++) {
+ for (int i = 0; i < arity; i++) {
write4BE(ids[i]);
}
}
diff --git a/lib/kernel/doc/src/application.xml b/lib/kernel/doc/src/application.xml
index 83a83ebad2..f4ec2c610f 100644
--- a/lib/kernel/doc/src/application.xml
+++ b/lib/kernel/doc/src/application.xml
@@ -582,7 +582,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code>
the primary application) for the primary application and all
included applications, for which the start phase is defined.</p>
<p>For a description of <c>StartType</c>, see
- <seealso marker="Module:start/2"><c>Module:start/2</c></seealso>.</p>
+ <seealso marker="#Module:start/2"><c>Module:start/2</c></seealso>.</p>
</desc>
</func>
<func>
diff --git a/lib/kernel/doc/src/auth.xml b/lib/kernel/doc/src/auth.xml
index a57da18de9..c735d02fed 100644
--- a/lib/kernel/doc/src/auth.xml
+++ b/lib/kernel/doc/src/auth.xml
@@ -46,7 +46,7 @@
<fsummary>Magic cookie for local node (deprecated).</fsummary>
<desc>
<p>Use
- <seealso marker="erts:erlang#erlang:get_cookie/0"><c>erlang:get_cookie()</c></seealso>
+ <seealso marker="erts:erlang#get_cookie/0"><c>erlang:get_cookie()</c></seealso>
in ERTS instead.</p>
</desc>
</func>
@@ -58,7 +58,7 @@
</type_desc>
<desc>
<p>Use
- <seealso marker="erts:erlang#erlang:set_cookie/2"><c>erlang:set_cookie(node(), <anno>Cookie</anno>)</c>
+ <seealso marker="erts:erlang#set_cookie/2"><c>erlang:set_cookie(node(), <anno>Cookie</anno>)</c>
in ERTS</seealso> instead.</p>
</desc>
</func>
@@ -94,7 +94,7 @@
<p>Sets the magic cookie of <c><anno>Node</anno></c> to
<c><anno>Cookie</anno></c> and verifies the status of the authorization.
Equivalent to calling
- <seealso marker="erts:erlang#erlang:set_cookie/2"><c>erlang:set_cookie(<anno>Node</anno>, <anno>Cookie</anno>)</c></seealso>, followed by
+ <seealso marker="erts:erlang#set_cookie/2"><c>erlang:set_cookie(<anno>Node</anno>, <anno>Cookie</anno>)</c></seealso>, followed by
<seealso marker="#is_auth/1"><c>auth:is_auth(<anno>Node</anno>)</c></seealso>.</p>
</desc>
</func>
diff --git a/lib/kernel/doc/src/erl_ddll.xml b/lib/kernel/doc/src/erl_ddll.xml
index f2d5e1b397..52d5bcd079 100644
--- a/lib/kernel/doc/src/erl_ddll.xml
+++ b/lib/kernel/doc/src/erl_ddll.xml
@@ -200,7 +200,7 @@
<fsummary>Remove a monitor for a driver.</fsummary>
<desc>
<p>Removes a driver monitor in much the same way as
- <seealso marker="erts:erlang#erlang:demonitor/1"><c>erlang:demonitor/1</c></seealso>
+ <seealso marker="erts:erlang#demonitor/1"><c>erlang:demonitor/1</c></seealso>
in ERTS
does with process monitors. For details about how to create
driver monitors, see
@@ -430,7 +430,7 @@
<desc>
<p>Creates a driver monitor and works in many
ways as
- <seealso marker="erts:erlang#erlang:monitor/2"><c>erlang:monitor/2</c></seealso>
+ <seealso marker="erts:erlang#monitor/2"><c>erlang:monitor/2</c></seealso>
in ERTS,
does for processes. When a driver changes state, the monitor
results in a monitor message that is sent to the calling
diff --git a/lib/kernel/doc/src/gen_sctp.xml b/lib/kernel/doc/src/gen_sctp.xml
index f70d6c24db..61ac1485c1 100644
--- a/lib/kernel/doc/src/gen_sctp.xml
+++ b/lib/kernel/doc/src/gen_sctp.xml
@@ -253,7 +253,7 @@ connect(Socket, Ip, Port>,
<desc>
<p>Assigns a new controlling process <c><anno>Pid</anno></c> to
<c><anno>Socket</anno></c>. Same implementation as
- <seealso marker="gen_udp:controlling_process/2"><c>gen_udp:controlling_process/2</c></seealso>.
+ <seealso marker="gen_udp#controlling_process/2"><c>gen_udp:controlling_process/2</c></seealso>.
</p>
</desc>
</func>
diff --git a/lib/kernel/doc/src/logger_chapter.xml b/lib/kernel/doc/src/logger_chapter.xml
index 8458ffa042..1aa4b7a3a2 100644
--- a/lib/kernel/doc/src/logger_chapter.xml
+++ b/lib/kernel/doc/src/logger_chapter.xml
@@ -718,7 +718,7 @@ logger:debug(#{got => connection_request, id => Id, state => State},
</seealso></pre>
<p>For all other values of <c>HandlerId</c>, this entry
adds a new handler, equivalent to calling</p>
- <pre><seealso marker="logger:add_handler/3">
+ <pre><seealso marker="logger#add_handler/3">
logger:add_handler(HandlerId, Module, HandlerConfig)
</seealso></pre>
<p>Multiple entries of this type are allowed.</p></item>
diff --git a/lib/kernel/doc/src/notes.xml b/lib/kernel/doc/src/notes.xml
index 0c187eb19f..61bd598145 100644
--- a/lib/kernel/doc/src/notes.xml
+++ b/lib/kernel/doc/src/notes.xml
@@ -31,6 +31,21 @@
</header>
<p>This document describes the changes made to the Kernel application.</p>
+<section><title>Kernel 6.3.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fixed a performance regression when reading files
+ opened with the <c>compressed</c> flag.</p>
+ <p>
+ Own Id: OTP-15706 Aux Id: ERIERL-336 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Kernel 6.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/kernel/src/kernel.appup.src b/lib/kernel/src/kernel.appup.src
index 8fa3f5c588..aca3247c8f 100644
--- a/lib/kernel/src/kernel.appup.src
+++ b/lib/kernel/src/kernel.appup.src
@@ -43,7 +43,9 @@
{<<"^6\\.1\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
{<<"^6\\.2$">>,[restart_new_emulator]},
{<<"^6\\.2\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
- {<<"^6\\.2\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}],
+ {<<"^6\\.2\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
+ {<<"^6\\.3$">>,[restart_new_emulator]},
+ {<<"^6\\.3\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}],
[{<<"^5\\.3$">>,[restart_new_emulator]},
{<<"^5\\.3\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
{<<"^5\\.3\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
@@ -60,4 +62,6 @@
{<<"^6\\.1\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
{<<"^6\\.2$">>,[restart_new_emulator]},
{<<"^6\\.2\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
- {<<"^6\\.2\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}]}.
+ {<<"^6\\.2\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
+ {<<"^6\\.3$">>,[restart_new_emulator]},
+ {<<"^6\\.3\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}]}.
diff --git a/lib/kernel/src/kernel.erl b/lib/kernel/src/kernel.erl
index 111d103df2..bfa091a036 100644
--- a/lib/kernel/src/kernel.erl
+++ b/lib/kernel/src/kernel.erl
@@ -68,7 +68,7 @@ config_change(Changed, New, Removed) ->
%%% auth, ...) ...)
%%%
%%% The rectangular boxes are supervisors. All supervisors except
-%%% for kernel_safe_sup terminates the enitre erlang node if any of
+%%% for kernel_safe_sup terminates the entire erlang node if any of
%%% their children dies. Any child that can't be restarted in case
%%% of failure must be placed under one of these supervisors. Any
%%% other child must be placed under safe_sup. These children may
diff --git a/lib/kernel/src/raw_file_io_inflate.erl b/lib/kernel/src/raw_file_io_inflate.erl
index 7e9780310c..d3ed02dd03 100644
--- a/lib/kernel/src/raw_file_io_inflate.erl
+++ b/lib/kernel/src/raw_file_io_inflate.erl
@@ -26,7 +26,7 @@
-include("file_int.hrl").
--define(INFLATE_CHUNK_SIZE, (1 bsl 10)).
+-define(INFLATE_CHUNK_SIZE, (8 bsl 10)).
-define(GZIP_WBITS, (16 + 15)).
callback_mode() -> state_functions.
diff --git a/lib/kernel/test/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl
index 711ffccb67..3bc8e6e828 100644
--- a/lib/kernel/test/file_SUITE.erl
+++ b/lib/kernel/test/file_SUITE.erl
@@ -3744,19 +3744,33 @@ otp_10852(Config) when is_list(Config) ->
ok = rpc_call(Node, read_file, [B]),
ok = rpc_call(Node, make_link, [B,B]),
case rpc_call(Node, make_symlink, [B,B]) of
- ok -> ok;
- {error, E} when (E =:= enotsup) or (E =:= eperm) ->
- {win32,_} = os:type()
+ {error, eilseq} ->
+ %% Some versions of OS X refuse to create files with illegal names.
+ {unix,darwin} = os:type();
+ {error, eperm} ->
+ %% The test user might not have permission to create symlinks.
+ {win32,_} = os:type();
+ ok ->
+ ok
end,
ok = rpc_call(Node, delete, [B]),
- ok = rpc_call(Node, make_dir, [B]),
+ case rpc_call(Node, make_dir, [B]) of
+ {error, eilseq} ->
+ {unix,darwin} = os:type();
+ ok ->
+ ok
+ end,
ok = rpc_call(Node, del_dir, [B]),
- ok = rpc_call(Node, write_file, [B,B]),
- {ok, Fd} = rpc_call(Node, open, [B,[read]]),
- ok = rpc_call(Node, close, [Fd]),
- {ok,0} = rpc_call(Node, copy, [B,B]),
- {ok, Fd2, B} = rpc_call(Node, path_open, [["."], B, [read]]),
- ok = rpc_call(Node, close, [Fd2]),
+ case rpc_call(Node, write_file, [B,B]) of
+ {error, eilseq} ->
+ {unix,darwin} = os:type();
+ ok ->
+ {ok, Fd} = rpc_call(Node, open, [B,[read]]),
+ ok = rpc_call(Node, close, [Fd]),
+ {ok,0} = rpc_call(Node, copy, [B,B]),
+ {ok, Fd2, B} = rpc_call(Node, path_open, [["."], B, [read]]),
+ ok = rpc_call(Node, close, [Fd2])
+ end,
true = test_server:stop_node(Node),
ok.
@@ -4500,15 +4514,18 @@ run_large_file_test(Config, Run, Name) ->
{{unix,sunos},OsVersion} when OsVersion < {5,5,1} ->
{skip,"Only supported on Win32, Unix or SunOS >= 5.5.1"};
{{unix,_},_} ->
- N = disc_free(proplists:get_value(priv_dir, Config)),
- io:format("Free disk: ~w KByte~n", [N]),
- if N < 5 * (1 bsl 20) ->
- %% Less than 5 GByte free
- {skip,"Less than 5 GByte free"};
- true ->
- do_run_large_file_test(Config, Run, Name)
- end;
- _ ->
+ case disc_free(proplists:get_value(priv_dir, Config)) of
+ error ->
+ {skip, "Failed to query disk space for priv_dir. "
+ "Is it on a remote file system?~n"};
+ N when N >= 5 * (1 bsl 20) ->
+ ct:pal("Free disk: ~w KByte~n", [N]),
+ do_run_large_file_test(Config, Run, Name);
+ N when N < 5 * (1 bsl 20) ->
+ ct:pal("Free disk: ~w KByte~n", [N]),
+ {skip,"Less than 5 GByte free"}
+ end;
+ _ ->
{skip,"Only supported on Win32, Unix or SunOS >= 5.5.1"}
end.
@@ -4542,12 +4559,18 @@ do_run_large_file_test(Config, Run, Name0) ->
disc_free(Path) ->
Data = disksup:get_disk_data(),
- {_,Tot,Perc} = hd(lists:filter(
- fun({P,_Size,_Full}) ->
- lists:prefix(filename:nativename(P),
- filename:nativename(Path))
- end, lists:reverse(lists:sort(Data)))),
- round(Tot * (1-(Perc/100))).
+
+ %% What partitions could Data be mounted on?
+ Partitions =
+ [D || {P, _Tot, _Perc}=D <- Data,
+ lists:prefix(filename:nativename(P), filename:nativename(Path))],
+
+ %% Sorting in descending order places the partition with the most specific
+ %% path first.
+ case lists:sort(fun erlang:'>='/2, Partitions) of
+ [{_,Tot, Perc} | _] -> round(Tot * (1-(Perc/100)));
+ [] -> error
+ end.
memsize() ->
{Tot,_Used,_} = memsup:get_memory_data(),
diff --git a/lib/kernel/test/file_name_SUITE.erl b/lib/kernel/test/file_name_SUITE.erl
index 3afc647081..26cfd187c7 100644
--- a/lib/kernel/test/file_name_SUITE.erl
+++ b/lib/kernel/test/file_name_SUITE.erl
@@ -632,10 +632,13 @@ make_icky_dir(Mod, IckyDirName) ->
hopeless_darwin() ->
case {os:type(),os:version()} of
- {{unix,darwin},{Major,_,_}} when Major < 9 ->
- true;
- _ ->
- false
+ {{unix,darwin},{Major,_,_}} ->
+ %% icky file names worked between 10 and 17, but started returning
+ %% EILSEQ in 18. The check against 18 is exact in case newer
+ %% versions of Darwin support them again.
+ Major < 9 orelse Major =:= 18;
+ _ ->
+ false
end.
make_very_icky_dir(Mod, DirName) ->
diff --git a/lib/kernel/vsn.mk b/lib/kernel/vsn.mk
index 7bebe1ba70..b1ae513223 100644
--- a/lib/kernel/vsn.mk
+++ b/lib/kernel/vsn.mk
@@ -1 +1 @@
-KERNEL_VSN = 6.3
+KERNEL_VSN = 6.3.1
diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml
index fb81ea68a4..8db5620686 100644
--- a/lib/public_key/doc/src/public_key.xml
+++ b/lib/public_key/doc/src/public_key.xml
@@ -813,7 +813,8 @@ fun(#'DistributionPoint'{}, #'CertificateList'{},
<p>The <c>{OtherRefId,term()}</c> is defined by the user and is passed to the <c>match_fun</c>, if defined.
If the term in <c>OtherRefId</c> is a binary, it will be converted to a string.
</p>
- <p>The <c>ip</c> Reference ID takes an <seealso marker="inet:inet#type-ip_address">inet:ip_address()</seealso>
+ <p>The <c>ip</c> Reference ID takes an
+ <seealso marker="kernel:inet#type-ip_address">inet:ip_address()</seealso>
or an ip address in string format (E.g "10.0.1.1" or "1234::5678:9012") as second element.
</p>
<p>The options are:</p>
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index 1f4e281a30..2299346a30 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -170,7 +170,7 @@ supported_algorithms(cipher) ->
{'AEAD_AES_256_GCM', [{ciphers,aes_256_gcm}]},
{'AEAD_AES_128_GCM', [{ciphers,aes_128_gcm}]},
{'aes128-cbc', [{ciphers,aes_128_cbc}]},
- {'3des-cbc', [{ciphers,des3_cbc}]}
+ {'3des-cbc', [{ciphers,des_ede3_cbc}]}
]
));
supported_algorithms(mac) ->
@@ -1340,7 +1340,7 @@ cipher('AEAD_AES_256_GCM') ->
pkt_type = aead};
cipher('3des-cbc') ->
- #cipher{impl = des3_cbc,
+ #cipher{impl = des_ede3_cbc,
key_bytes = 24,
iv_bytes = 8,
block_bytes = 8};
@@ -1445,12 +1445,12 @@ encrypt(#ssh{encrypt = '[email protected]',
<<LenData:4/binary, PayloadData/binary>>) ->
%% Encrypt length
IV1 = <<0:8/unit:8, Seq:8/unit:8>>,
- EncLen = crypto:crypto_one_shot(chacha20, K1, IV1, LenData, true),
+ EncLen = crypto:crypto_one_time(chacha20, K1, IV1, LenData, true),
%% Encrypt payload
IV2 = <<1:8/little-unit:8, Seq:8/unit:8>>,
- EncPayloadData = crypto:crypto_one_shot(chacha20, K2, IV2, PayloadData, true),
+ EncPayloadData = crypto:crypto_one_time(chacha20, K2, IV2, PayloadData, true),
%% MAC tag
- PolyKey = crypto:crypto_one_shot(chacha20, K2, <<0:8/unit:8,Seq:8/unit:8>>, <<0:32/unit:8>>, true),
+ PolyKey = crypto:crypto_one_time(chacha20, K2, <<0:8/unit:8,Seq:8/unit:8>>, <<0:32/unit:8>>, true),
EncBytes = <<EncLen/binary,EncPayloadData/binary>>,
Ctag = crypto:poly1305(PolyKey, EncBytes),
%% Result
@@ -1519,7 +1519,7 @@ decrypt(Ssh, <<>>) ->
decrypt(#ssh{decrypt = '[email protected]',
decrypt_keys = {K1,_K2},
recv_sequence = Seq} = Ssh, {length,EncryptedLen}) ->
- PacketLenBin = crypto:crypto_one_shot(chacha20, K1, <<0:8/unit:8, Seq:8/unit:8>>, EncryptedLen, false),
+ PacketLenBin = crypto:crypto_one_time(chacha20, K1, <<0:8/unit:8, Seq:8/unit:8>>, EncryptedLen, false),
{Ssh, PacketLenBin};
decrypt(#ssh{decrypt = '[email protected]',
@@ -1527,12 +1527,12 @@ decrypt(#ssh{decrypt = '[email protected]',
recv_sequence = Seq} = Ssh, {AAD,Ctext,Ctag}) ->
%% The length is already decoded and used to divide the input
%% Check the mac (important that it is timing-safe):
- PolyKey = crypto:crypto_one_shot(chacha20, K2, <<0:8/unit:8,Seq:8/unit:8>>, <<0:32/unit:8>>, false),
+ PolyKey = crypto:crypto_one_time(chacha20, K2, <<0:8/unit:8,Seq:8/unit:8>>, <<0:32/unit:8>>, false),
case equal_const_time(Ctag, crypto:poly1305(PolyKey, <<AAD/binary,Ctext/binary>>)) of
true ->
%% MAC is ok, decode
IV2 = <<1:8/little-unit:8, Seq:8/unit:8>>,
- PlainText = crypto:crypto_one_shot(chacha20, K2, IV2, Ctext, false),
+ PlainText = crypto:crypto_one_time(chacha20, K2, IV2, Ctext, false),
{Ssh, PlainText};
false ->
{Ssh,error}
diff --git a/lib/ssl/src/dtls_connection.erl b/lib/ssl/src/dtls_connection.erl
index 30b2ab7c4f..7993be8a74 100644
--- a/lib/ssl/src/dtls_connection.erl
+++ b/lib/ssl/src/dtls_connection.erl
@@ -193,7 +193,8 @@ next_event(StateName, no_record,
%% TODO maybe buffer later epoch
next_event(StateName, no_record, State, Actions);
{#alert{} = Alert, State} ->
- {next_state, StateName, State, [{next_event, internal, Alert} | Actions]}
+ Version = State#state.connection_env#connection_env.negotiated_version,
+ handle_own_alert(Alert, Version, StateName, State)
end;
next_event(connection = StateName, Record,
#state{connection_states = #{current_read := #{epoch := CurrentEpoch}}} = State0, Actions) ->
@@ -233,7 +234,8 @@ next_event(StateName, Record,
%% TODO maybe buffer later epoch
next_event(StateName, no_record, State0, Actions);
#alert{} = Alert ->
- {next_state, StateName, State0, [{next_event, internal, Alert} | Actions]}
+ Version = State0#state.connection_env#connection_env.negotiated_version,
+ handle_own_alert(Alert, Version, StateName, State0)
end.
%%% DTLS record protocol level application data messages
@@ -1075,10 +1077,10 @@ start_retransmision_timer(Timeout, #state{protocol_specific = PS} = State) ->
{State#state{protocol_specific = PS#{flight_state => {retransmit, new_timeout(Timeout)}}},
[{state_timeout, Timeout, flight_retransmission_timeout}]}.
-new_timeout(N) when N =< 30 ->
+new_timeout(N) when N =< 30000 ->
N * 2;
new_timeout(_) ->
- 60.
+ 60000.
send_handshake_flight(#state{static_env = #static_env{socket = Socket,
transport_cb = Transport},
diff --git a/lib/ssl/src/dtls_packet_demux.erl b/lib/ssl/src/dtls_packet_demux.erl
index e0423b07b4..2e9184b7ac 100644
--- a/lib/ssl/src/dtls_packet_demux.erl
+++ b/lib/ssl/src/dtls_packet_demux.erl
@@ -203,9 +203,9 @@ dispatch(Client, Msg, #state{dtls_msq_queues = MsgQueues} = State) ->
Pid ! Msg,
State#state{dtls_msq_queues =
kv_update(Client, Queue, MsgQueues)};
- {{value, _}, Queue} ->
+ {{value, _UDP}, _Queue} ->
State#state{dtls_msq_queues =
- kv_update(Client, queue:in(Msg, Queue), MsgQueues)};
+ kv_update(Client, queue:in(Msg, Queue0), MsgQueues)};
{empty, Queue} ->
State#state{dtls_msq_queues =
kv_update(Client, queue:in(Msg, Queue), MsgQueues)}
diff --git a/lib/ssl/src/inet_tls_dist.erl b/lib/ssl/src/inet_tls_dist.erl
index e7fab7ebc5..8d9b92361b 100644
--- a/lib/ssl/src/inet_tls_dist.erl
+++ b/lib/ssl/src/inet_tls_dist.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -132,8 +132,8 @@ f_recv(SslSocket, Length, Timeout) ->
f_setopts_pre_nodeup(_SslSocket) ->
ok.
-f_setopts_post_nodeup(_SslSocket) ->
- ok.
+f_setopts_post_nodeup(SslSocket) ->
+ ssl:setopts(SslSocket, [nodelay()]).
f_getll(DistCtrl) ->
{ok, DistCtrl}.
@@ -199,7 +199,7 @@ listen(Name) ->
gen_listen(Driver, Name) ->
case inet_tcp_dist:gen_listen(Driver, Name) of
{ok, {Socket, Address, Creation}} ->
- inet:setopts(Socket, [{packet, 4}]),
+ inet:setopts(Socket, [{packet, 4}, {nodelay, true}]),
{ok, {Socket, Address#net_address{protocol=tls}, Creation}};
Other ->
Other
@@ -532,7 +532,7 @@ do_setup_connect(Driver, Kernel, Node, Address, Ip, TcpPort, Version, Type, MyNo
case ssl:connect(
Address, TcpPort,
[binary, {active, false}, {packet, 4},
- Driver:family(), nodelay()] ++ Opts,
+ Driver:family(), {nodelay, true}] ++ Opts,
net_kernel:connecttime()) of
{ok, #sslsocket{pid = [_, DistCtrl| _]} = SslSocket} ->
_ = monitor_pid(DistCtrl),
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index c7c96370b3..8807c575b1 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -112,6 +112,10 @@
aes_256_cbc |
aes_128_gcm |
aes_256_gcm |
+ aes_128_ccm |
+ aes_256_ccm |
+ aes_128_ccm_8 |
+ aes_256_ccm_8 |
chacha20_poly1305 |
legacy_cipher().
-type legacy_cipher() :: rc4_128 |
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl
index fe8736d2df..850dee7d4f 100644
--- a/lib/ssl/src/ssl_cipher.erl
+++ b/lib/ssl/src/ssl_cipher.erl
@@ -35,7 +35,7 @@
-include_lib("public_key/include/public_key.hrl").
-export([security_parameters/2, security_parameters/3, security_parameters_1_3/2,
- cipher_init/3, nonce_seed/2, decipher/6, cipher/5, aead_encrypt/5, aead_decrypt/6,
+ cipher_init/3, nonce_seed/2, decipher/6, cipher/5, aead_encrypt/6, aead_decrypt/6,
suites/1, all_suites/1, crypto_support_filters/0,
chacha_suites/1, anonymous_suites/1, psk_suites/1, psk_suites_anon/1,
srp_suites/0, srp_suites_anon/0,
@@ -106,9 +106,13 @@ security_parameters_1_3(SecParams, CipherSuite) ->
cipher_init(?RC4, IV, Key) ->
State = crypto:stream_init(rc4, Key),
#cipher_state{iv = IV, key = Key, state = State};
-cipher_init(?AES_GCM, IV, Key) ->
+cipher_init(Type, IV, Key) when Type == ?AES_GCM;
+ Type == ?AES_CCM ->
<<Nonce:64>> = random_bytes(8),
#cipher_state{iv = IV, key = Key, nonce = Nonce, tag_len = 16};
+cipher_init(?AES_CCM_8, IV, Key) ->
+ <<Nonce:64>> = random_bytes(8),
+ #cipher_state{iv = IV, key = Key, nonce = Nonce, tag_len = 8};
cipher_init(?CHACHA20_POLY1305, IV, Key) ->
#cipher_state{iv = IV, key = Key, tag_len = 16};
cipher_init(_BCA, IV, Key) ->
@@ -148,14 +152,18 @@ cipher(?AES_CBC, CipherState, Mac, Fragment, Version) ->
crypto:block_encrypt(aes_cbc256, Key, IV, T)
end, block_size(aes_128_cbc), CipherState, Mac, Fragment, Version).
-aead_encrypt(Type, Key, Nonce, Fragment, AdditionalData) ->
- crypto:block_encrypt(aead_type(Type), Key, Nonce, {AdditionalData, Fragment}).
+aead_encrypt(Type, Key, Nonce, Fragment, AdditionalData, TagLen) ->
+ crypto:block_encrypt(aead_type(Type), Key, Nonce, {AdditionalData, Fragment, TagLen}).
aead_decrypt(Type, Key, Nonce, CipherText, CipherTag, AdditionalData) ->
crypto:block_decrypt(aead_type(Type), Key, Nonce, {AdditionalData, CipherText, CipherTag}).
aead_type(?AES_GCM) ->
aes_gcm;
+aead_type(?AES_CCM) ->
+ aes_ccm;
+aead_type(?AES_CCM_8) ->
+ aes_ccm;
aead_type(?CHACHA20_POLY1305) ->
chacha20_poly1305.
@@ -311,8 +319,7 @@ anonymous_suites({254, _} = Version) ->
dtls_v1:anonymous_suites(Version);
anonymous_suites(4) ->
[]; %% Raw public key negotiation may be used instead
-anonymous_suites(N)
- when N >= 3 ->
+anonymous_suites( 3 = N) ->
psk_suites_anon(N) ++
[?TLS_DH_anon_WITH_AES_128_GCM_SHA256,
?TLS_DH_anon_WITH_AES_256_GCM_SHA384,
@@ -347,8 +354,7 @@ psk_suites({3, N}) ->
psk_suites(N);
psk_suites(4) ->
[]; %% TODO Add new PSK, PSK_(EC)DHE suites
-psk_suites(N)
- when N >= 3 ->
+psk_suites(3) ->
[
?TLS_RSA_PSK_WITH_AES_256_GCM_SHA384,
?TLS_RSA_PSK_WITH_AES_256_CBC_SHA384,
@@ -369,20 +375,32 @@ psk_suites(_) ->
%%--------------------------------------------------------------------
psk_suites_anon({3, N}) ->
psk_suites_anon(N);
-psk_suites_anon(N)
- when N >= 3 ->
+psk_suites_anon(3) ->
[
?TLS_DHE_PSK_WITH_AES_256_GCM_SHA384,
?TLS_PSK_WITH_AES_256_GCM_SHA384,
?TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384,
?TLS_DHE_PSK_WITH_AES_256_CBC_SHA384,
?TLS_PSK_WITH_AES_256_CBC_SHA384,
+ ?TLS_DHE_PSK_WITH_AES_256_CCM,
+ ?TLS_PSK_DHE_WITH_AES_256_CCM_8,
+ ?TLS_PSK_WITH_AES_256_CCM,
+ ?TLS_PSK_WITH_AES_256_CCM_8,
?TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256,
+ ?TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256,
+ ?TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256,
?TLS_DHE_PSK_WITH_AES_128_GCM_SHA256,
?TLS_PSK_WITH_AES_128_GCM_SHA256,
+ ?TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256,
+ ?TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256,
?TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256,
?TLS_DHE_PSK_WITH_AES_128_CBC_SHA256,
- ?TLS_PSK_WITH_AES_128_CBC_SHA256
+ ?TLS_PSK_WITH_AES_128_CBC_SHA256,
+ ?TLS_DHE_PSK_WITH_AES_128_CCM,
+ ?TLS_PSK_DHE_WITH_AES_128_CCM_8,
+ ?TLS_PSK_WITH_AES_128_CCM,
+ ?TLS_PSK_WITH_AES_128_CCM_8,
+ ?TLS_ECDHE_PSK_WITH_RC4_128_SHA
] ++ psk_suites_anon(0);
psk_suites_anon(_) ->
[?TLS_DHE_PSK_WITH_AES_256_CBC_SHA,
@@ -589,7 +607,7 @@ is_acceptable_keyexchange(dhe_rsa, Algos) ->
proplists:get_bool(dh, Algos) andalso
proplists:get_bool(rsa, Algos);
is_acceptable_keyexchange(KeyExchange, Algos) when KeyExchange == ecdh_anon;
- KeyExchange == ecdhe_psk ->
+ KeyExchange == ecdhe_psk ->
proplists:get_bool(ecdh, Algos);
is_acceptable_keyexchange(KeyExchange, Algos) when KeyExchange == ecdh_ecdsa;
KeyExchange == ecdhe_ecdsa ->
@@ -629,6 +647,12 @@ is_acceptable_cipher(Cipher, Algos)
when Cipher == aes_128_gcm;
Cipher == aes_256_gcm ->
proplists:get_bool(aes_gcm, Algos);
+is_acceptable_cipher(Cipher, Algos)
+ when Cipher == aes_128_ccm;
+ Cipher == aes_256_ccm;
+ Cipher == aes_128_ccm_8;
+ Cipher == aes_256_ccm_8 ->
+ proplists:get_bool(aes_ccm, Algos);
is_acceptable_cipher(Cipher, Algos) ->
proplists:get_bool(Cipher, Algos).
@@ -721,6 +745,12 @@ bulk_cipher_algorithm(Cipher) when Cipher == aes_128_cbc;
bulk_cipher_algorithm(Cipher) when Cipher == aes_128_gcm;
Cipher == aes_256_gcm ->
?AES_GCM;
+bulk_cipher_algorithm(Cipher) when Cipher == aes_128_ccm;
+ Cipher == aes_256_ccm ->
+ ?AES_CCM;
+bulk_cipher_algorithm(Cipher) when Cipher == aes_128_ccm_8;
+ Cipher == aes_256_ccm_8 ->
+ ?AES_CCM_8;
bulk_cipher_algorithm(chacha20_poly1305) ->
?CHACHA20_POLY1305.
@@ -735,6 +765,10 @@ type(Cipher) when Cipher == des_cbc;
?BLOCK;
type(Cipher) when Cipher == aes_128_gcm;
Cipher == aes_256_gcm;
+ Cipher == aes_128_ccm;
+ Cipher == aes_256_ccm;
+ Cipher == aes_128_ccm_8;
+ Cipher == aes_256_ccm_8;
Cipher == chacha20_poly1305 ->
?AEAD.
@@ -752,8 +786,16 @@ key_material(aes_256_cbc) ->
32;
key_material(aes_128_gcm) ->
16;
+key_material(aes_128_ccm) ->
+ 16;
+key_material(aes_128_ccm_8) ->
+ 16;
key_material(aes_256_gcm) ->
32;
+key_material(aes_256_ccm_8) ->
+ 32;
+key_material(aes_256_ccm) ->
+ 32;
key_material(chacha20_poly1305) ->
32.
@@ -769,6 +811,10 @@ expanded_key_material(Cipher) when Cipher == aes_128_cbc;
Cipher == aes_256_cbc;
Cipher == aes_128_gcm;
Cipher == aes_256_gcm;
+ Cipher == aes_128_ccm;
+ Cipher == aes_256_ccm;
+ Cipher == aes_128_ccm_8;
+ Cipher == aes_256_ccm_8;
Cipher == chacha20_poly1305 ->
unknown.
@@ -778,22 +824,31 @@ effective_key_bits(des_cbc) ->
56;
effective_key_bits(Cipher) when Cipher == rc4_128;
Cipher == aes_128_cbc;
- Cipher == aes_128_gcm ->
+ Cipher == aes_128_gcm;
+ Cipher == aes_128_ccm;
+ Cipher == aes_128_ccm_8 ->
128;
effective_key_bits('3des_ede_cbc') ->
168;
effective_key_bits(Cipher) when Cipher == aes_256_cbc;
Cipher == aes_256_gcm;
+ Cipher == aes_256_ccm;
+ Cipher == aes_256_ccm_8;
Cipher == chacha20_poly1305 ->
256.
iv_size(Cipher) when Cipher == null;
- Cipher == rc4_128;
- Cipher == chacha20_poly1305->
+ Cipher == rc4_128 ->
0;
iv_size(Cipher) when Cipher == aes_128_gcm;
- Cipher == aes_256_gcm ->
+ Cipher == aes_256_gcm;
+ Cipher == aes_128_ccm;
+ Cipher == aes_256_ccm;
+ Cipher == aes_128_ccm_8;
+ Cipher == aes_256_ccm_8 ->
4;
+iv_size(chacha20_poly1305) ->
+ 12;
iv_size(Cipher) ->
block_size(Cipher).
@@ -804,6 +859,10 @@ block_size(Cipher) when Cipher == aes_128_cbc;
Cipher == aes_256_cbc;
Cipher == aes_128_gcm;
Cipher == aes_256_gcm;
+ Cipher == aes_128_ccm;
+ Cipher == aes_256_ccm;
+ Cipher == aes_128_ccm_8;
+ Cipher == aes_256_ccm_8;
Cipher == chacha20_poly1305 ->
16.
diff --git a/lib/ssl/src/ssl_cipher.hrl b/lib/ssl/src/ssl_cipher.hrl
index 00822ad9de..9c5e2f80a9 100644
--- a/lib/ssl/src/ssl_cipher.hrl
+++ b/lib/ssl/src/ssl_cipher.hrl
@@ -601,16 +601,82 @@
%% TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 = {0xC0,0x32};
-define(TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, <<?BYTE(16#C0), ?BYTE(16#32)>>).
-%%% Chacha20/Poly1305 Suites draft-agl-tls-chacha20poly1305-04
-%% TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = {0xcc, 0x13}
--define(TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, <<?BYTE(16#CC), ?BYTE(16#13)>>).
+%%% ChaCha20-Poly1305 Cipher Suites for Transport Layer Security (TLS) RFC7905
-%% TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = {0xcc, 0x14}
--define(TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, <<?BYTE(16#CC), ?BYTE(16#14)>>).
+%% TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = {0xCC, 0xA8}
+-define(TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, <<?BYTE(16#CC), ?BYTE(16#A8)>>).
+
+%% TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = {0xCC, 0xA9}
+-define(TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, <<?BYTE(16#CC), ?BYTE(16#A9)>>).
+
+%% TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = {0xCC, 0xAA}
+-define(TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, <<?BYTE(16#CC), ?BYTE(16#AA)>>).
+
+%% TLS_PSK_WITH_CHACHA20_POLY1305_SHA256 = {0xCC, 0xAB}
+-define(TLS_PSK_WITH_CHACHA20_POLY1305_SHA256, <<?BYTE(16#CC), ?BYTE(16#AB)>>).
+
+%% TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 = {0xCC, 0xAC}
+-define(TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256, <<?BYTE(16#CC), ?BYTE(16#AC)>>).
+
+%% TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256 = {0xCC, 0xAD}
+-define(TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256, <<?BYTE(16#CC), ?BYTE(16#AD)>>).
+
+%% TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256 = {0xCC, 0xAE}
+-define(TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256, <<?BYTE(16#CC), ?BYTE(16#AE)>>).
+
+
+
+%% RFC 6655 - TLS-1.2 cipher suites
+
+%% TLS_RSA_WITH_AES_128_CCM = {0xC0,0x9C}
+-define(TLS_RSA_WITH_AES_128_CCM, <<?BYTE(16#C0), ?BYTE(16#9C)>>).
+
+%% TLS_RSA_WITH_AES_256_CCM = {0xC0,0x9D}
+-define(TLS_RSA_WITH_AES_256_CCM, <<?BYTE(16#C0), ?BYTE(16#9D)>>).
+
+%% TLS_DHE_RSA_WITH_AES_256_CCM = {0xC0,0x9E}
+-define(TLS_DHE_RSA_WITH_AES_256_CCM, <<?BYTE(16#C0), ?BYTE(16#9E)>>).
+
+%% TLS_DHE_RSA_WITH_AES_128_CCM = {0xC0,0x9F}
+-define(TLS_DHE_RSA_WITH_AES_128_CCM, <<?BYTE(16#C0), ?BYTE(16#9F)>>).
+
+%% TLS_RSA_WITH_AES_256_CCM_8 = {0xC0,0x9A0}
+-define(TLS_RSA_WITH_AES_256_CCM_8, <<?BYTE(16#C0), ?BYTE(16#A0)>>).
+
+%% TLS_RSA_WITH_AES_128_CCM_8 = {0xC0,0xA1}
+-define(TLS_RSA_WITH_AES_128_CCM_8, <<?BYTE(16#C0), ?BYTE(16#A1)>>).
+
+%% TLS_DHE_RSA_WITH_AES_128_CCM_8 = {0xC0,0xA2}
+-define(TLS_DHE_RSA_WITH_AES_128_CCM_8, <<?BYTE(16#C0), ?BYTE(16#A2)>>).
+
+%% TLS_DHE_RSA_WITH_AES_256_CCM_8 = {0xC0,0xA3}
+-define(TLS_DHE_RSA_WITH_AES_256_CCM_8, <<?BYTE(16#C0), ?BYTE(16#A3)>>).
+
+%% TLS_PSK_WITH_AES_128_CCM = {0xC0,0xA4}
+-define(TLS_PSK_WITH_AES_128_CCM, <<?BYTE(16#C0), ?BYTE(16#A4)>>).
+
+%% TLS_PSK_WITH_AES_256_CCM = {0xC0,0xA5)
+-define(TLS_PSK_WITH_AES_256_CCM, <<?BYTE(16#C0), ?BYTE(16#A5)>>).
+
+%% TLS_DHE_PSK_WITH_AES_128_CCM = {0xC0,0xA6}
+-define(TLS_DHE_PSK_WITH_AES_128_CCM, <<?BYTE(16#C0), ?BYTE(16#A6)>>).
+
+%% TLS_DHE_PSK_WITH_AES_256_CCM = {0xC0,0xA7}
+-define(TLS_DHE_PSK_WITH_AES_256_CCM, <<?BYTE(16#C0), ?BYTE(16#A7)>>).
+
+%% TLS_PSK_WITH_AES_128_CCM_8 = {0xC0,0xA8}
+-define(TLS_PSK_WITH_AES_128_CCM_8, <<?BYTE(16#C0), ?BYTE(16#A8)>>).
+
+%% TLS_PSK_WITH_AES_256_CCM_8 = {0xC0,0xA9)
+-define(TLS_PSK_WITH_AES_256_CCM_8, <<?BYTE(16#C0), ?BYTE(16#A9)>>).
+
+%% TLS_PSK_DHE_WITH_AES_128_CCM_8 = {0xC0,0xAA}
+-define(TLS_PSK_DHE_WITH_AES_128_CCM_8, <<?BYTE(16#C0), ?BYTE(16#AA)>>).
+
+%% TLS_PSK_DHE_WITH_AES_256_CCM_8 = << ?BYTE(0xC0,0xAB}
+-define(TLS_PSK_DHE_WITH_AES_256_CCM_8, <<?BYTE(16#C0),?BYTE(16#AB)>>).
-%% TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = {0xcc, 0x15}
--define(TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, <<?BYTE(16#CC), ?BYTE(16#15)>>).
%%% TLS 1.3 cipher suites RFC8446
diff --git a/lib/ssl/src/ssl_cipher_format.erl b/lib/ssl/src/ssl_cipher_format.erl
index b592295d56..8737181922 100644
--- a/lib/ssl/src/ssl_cipher_format.erl
+++ b/lib/ssl/src/ssl_cipher_format.erl
@@ -467,16 +467,16 @@ suite_definition(?TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384) ->
cipher => aes_256_gcm,
mac => null,
prf => sha384};
-%% suite_definition(?TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256) ->
-%% #{key_exchange => ecdhe_psk,
-%% cipher => aes_128_ccm,
-%% mac => null,
-%% prf =>sha256};
-%% suite_definition(?TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256) ->
-%% #{key_exchange => ecdhe_psk,
-%% cipher => aes_256_ccm,
-%% mac => null,
-%% prf => sha256};
+suite_definition(?TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256) ->
+ #{key_exchange => ecdhe_psk,
+ cipher => aes_128_ccm,
+ mac => null,
+ prf =>sha256};
+suite_definition(?TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256) ->
+ #{key_exchange => ecdhe_psk,
+ cipher => aes_128_ccm_8,
+ mac => null,
+ prf =>sha256};
%%% SRP Cipher Suites RFC 5054
suite_definition(?TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA) ->
#{key_exchange => srp_anon,
@@ -792,7 +792,53 @@ suite_definition(?TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384) ->
cipher => aes_256_gcm,
mac => aead,
prf => sha384};
-%% draft-agl-tls-chacha20poly1305-04 Chacha20/Poly1305 Suites
+suite_definition(?TLS_PSK_WITH_AES_128_CCM) ->
+ #{key_exchange => psk,
+ cipher => aes_128_ccm,
+ mac => aead,
+ prf => sha256};
+suite_definition(?TLS_PSK_WITH_AES_256_CCM) ->
+ #{key_exchange => psk,
+ cipher => aes_256_ccm,
+ mac => aead,
+ prf => sha256};
+suite_definition(?TLS_DHE_PSK_WITH_AES_128_CCM) ->
+ #{key_exchange => dhe_psk,
+ cipher => aes_128_ccm,
+ mac => aead,
+ prf => sha256};
+suite_definition(?TLS_DHE_PSK_WITH_AES_256_CCM) ->
+ #{key_exchange => dhe_psk,
+ cipher => aes_256_ccm,
+ mac => aead,
+ prf => sha256};
+suite_definition(?TLS_PSK_WITH_AES_128_CCM_8) ->
+ #{key_exchange => psk,
+ cipher => aes_128_ccm_8,
+ mac => aead,
+ prf => sha256};
+suite_definition(?TLS_PSK_WITH_AES_256_CCM_8) ->
+ #{key_exchange => psk,
+ cipher => aes_256_ccm_8,
+ mac => aead,
+ prf => sha256};
+suite_definition(?TLS_PSK_DHE_WITH_AES_128_CCM_8) ->
+ #{key_exchange => dhe_psk,
+ cipher => aes_128_ccm_8,
+ mac => aead,
+ prf => sha256};
+suite_definition(?TLS_PSK_DHE_WITH_AES_256_CCM_8) ->
+ #{key_exchange => dhe_psk,
+ cipher => aes_256_ccm_8,
+ mac => aead,
+ prf => sha256};
+suite_definition(#{key_exchange := psk_dhe,
+ cipher := aes_256_ccm_8,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_PSK_DHE_WITH_AES_256_CCM_8;
+
+% draft-agl-tls-chacha20poly1305-04 Chacha20/Poly1305 Suites
suite_definition(?TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256) ->
#{key_exchange => ecdhe_rsa,
cipher => chacha20_poly1305,
@@ -825,16 +871,15 @@ suite_definition(?TLS_CHACHA20_POLY1305_SHA256) ->
mac => aead,
prf => sha256}.
%% suite_definition(?TLS_AES_128_CCM_SHA256) ->
-%% #{key_exchange => any,
-%% cipher => aes_128_ccm,
-%% mac => aead,
-%% prf => sha256};
+%% #{key_exchange => any,
+%% cipher => aes_128_ccm,
+%% mac => aead,
+%% prf => sha256};
%% suite_definition(?TLS_AES_128_CCM_8_SHA256) ->
-%% #{key_exchange => any,
+%% #{key_exchange => any,
%% cipher => aes_128_ccm_8,
-%% mac => aead,
-%% prf => sha256}.
-
+%% mac => aead,
+%% prf => sha256}.
%%--------------------------------------------------------------------
-spec erl_suite_definition(cipher_suite() | internal_erl_cipher_suite()) -> old_erl_cipher_suite().
@@ -1154,16 +1199,16 @@ suite(#{key_exchange := ecdhe_psk,
mac := null,
prf := sha384}) ->
?TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384;
- %% suite(#{key_exchange := ecdhe_psk,
- %% cipher := aes_128_ccm,
- %% mac := null,
- %% prf := sha256}) ->
- %% ?TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256;
- %% suite(#{key_exchange := ecdhe_psk,
- %% cipher := aes_256_ccm,
- %% mac := null,
- %% prf := sha256}) ->
- %% ?TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256;
+suite(#{key_exchange := ecdhe_psk,
+ cipher := aes_128_ccm_8,
+ mac := null,
+ prf := sha256}) ->
+ ?TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256;
+suite(#{key_exchange := ecdhe_psk,
+ cipher := aes_128_ccm,
+ mac := null,
+ prf := sha256}) ->
+ ?TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256;
%%% SRP Cipher Suites RFC 5054
suite(#{key_exchange := srp_anon,
cipher := '3des_ede_cbc',
@@ -1460,6 +1505,90 @@ suite(#{key_exchange := dhe_rsa,
mac := aead,
prf := sha256}) ->
?TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256;
+
+%% RFC 6655 - TLS-1.2 cipher suites
+suite(#{key_exchange := psk,
+ cipher := aes_128_ccm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_PSK_WITH_AES_128_CCM;
+suite(#{key_exchange := psk,
+ cipher := aes_256_ccm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_PSK_WITH_AES_256_CCM;
+suite(#{key_exchange := dhe_psk,
+ cipher := aes_128_ccm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_DHE_PSK_WITH_AES_128_CCM;
+suite(#{key_exchange := dhe_psk,
+ cipher := aes_256_ccm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_DHE_PSK_WITH_AES_256_CCM;
+suite(#{key_exchange := rsa,
+ cipher := aes_128_ccm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_RSA_WITH_AES_128_CCM;
+suite(#{key_exchange := rsa,
+ cipher := aes_256_ccm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_RSA_WITH_AES_256_CCM;
+suite(#{key_exchange := dhe_rsa,
+ cipher := aes_128_ccm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_DHE_RSA_WITH_AES_128_CCM;
+suite(#{key_exchange := dhe_rsa,
+ cipher := aes_256_ccm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_DHE_RSA_WITH_AES_256_CCM;
+
+suite(#{key_exchange := psk,
+ cipher := aes_128_ccm_8,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_PSK_WITH_AES_128_CCM_8;
+suite(#{key_exchange := psk,
+ cipher := aes_256_ccm_8,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_PSK_WITH_AES_256_CCM_8;
+suite(#{key_exchange := dhe_psk,
+ cipher := aes_128_ccm_8,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_PSK_DHE_WITH_AES_128_CCM_8;
+suite(#{key_exchange := dhe_psk,
+ cipher := aes_256_ccm_8,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_PSK_DHE_WITH_AES_256_CCM_8;
+suite(#{key_exchange := rsa,
+ cipher := aes_128_ccm_8,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_RSA_WITH_AES_128_CCM_8;
+suite(#{key_exchange := rsa,
+ cipher := aes_256_ccm_8,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_RSA_WITH_AES_256_CCM_8;
+suite(#{key_exchange := dhe_rsa,
+ cipher := aes_128_ccm_8,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_DHE_RSA_WITH_AES_128_CCM_8;
+suite(#{key_exchange := dhe_rsa,
+ cipher := aes_256_ccm_8,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_DHE_RSA_WITH_AES_256_CCM_8;
+
%% TLS 1.3 Cipher Suites RFC8446
suite(#{key_exchange := any,
cipher := aes_128_gcm,
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index 6c95a7edf8..3a69c86e47 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -2421,7 +2421,7 @@ decode_extensions(<<?UINT16(?KEY_SHARE_EXT), ?UINT16(Len),
decode_extensions(<<?UINT16(?KEY_SHARE_EXT), ?UINT16(Len),
ExtData:Len/binary, Rest/binary>>,
Version, MessageType = hello_retry_request, Acc) ->
- <<?UINT16(Group),Rest/binary>> = ExtData,
+ <<?UINT16(Group)>> = ExtData,
decode_extensions(Rest, Version, MessageType,
Acc#{key_share =>
#key_share_hello_retry_request{
diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl
index 91f1876980..867d2cfc5a 100644
--- a/lib/ssl/src/ssl_record.erl
+++ b/lib/ssl/src/ssl_record.erl
@@ -395,7 +395,7 @@ decipher_aead(Type, #cipher_state{key = Key} = CipherState, AAD0, CipherFragment
try
Nonce = decrypt_nonce(Type, CipherState, CipherFragment),
{AAD, CipherText, CipherTag} = aead_ciphertext_split(Type, CipherState, CipherFragment, AAD0),
- case ssl_cipher:aead_decrypt(Type, Key, Nonce, CipherText, CipherTag, AAD) of
+ case ssl_cipher:aead_decrypt(Type, Key, Nonce, CipherText, CipherTag, AAD) of
Content when is_binary(Content) ->
Content;
_ ->
@@ -471,34 +471,43 @@ initial_security_params(ConnectionEnd) ->
-define(end_additional_data(AAD, Len), << (begin(AAD)end)/binary, ?UINT16(begin(Len)end) >>).
-do_cipher_aead(?CHACHA20_POLY1305 = Type, Fragment, #cipher_state{key=Key} = CipherState, AAD0) ->
+do_cipher_aead(?CHACHA20_POLY1305 = Type, Fragment, #cipher_state{key=Key, tag_len = TagLen} = CipherState, AAD0) ->
AAD = ?end_additional_data(AAD0, erlang:iolist_size(Fragment)),
- Nonce = encrypt_nonce(Type, CipherState),
- {Content, CipherTag} = ssl_cipher:aead_encrypt(Type, Key, Nonce, Fragment, AAD),
+ Nonce = chacha_nonce(CipherState),
+ {Content, CipherTag} = ssl_cipher:aead_encrypt(Type, Key, Nonce, Fragment, AAD, TagLen),
{<<Content/binary, CipherTag/binary>>, CipherState};
-do_cipher_aead(Type, Fragment, #cipher_state{key=Key, nonce = ExplicitNonce} = CipherState, AAD0) ->
+do_cipher_aead(Type, Fragment, #cipher_state{key=Key, tag_len = TagLen, nonce = ExplicitNonce} = CipherState, AAD0) ->
AAD = ?end_additional_data(AAD0, erlang:iolist_size(Fragment)),
Nonce = encrypt_nonce(Type, CipherState),
- {Content, CipherTag} = ssl_cipher:aead_encrypt(Type, Key, Nonce, Fragment, AAD),
+ {Content, CipherTag} = ssl_cipher:aead_encrypt(Type, Key, Nonce, Fragment, AAD, TagLen),
{<<ExplicitNonce:64/integer, Content/binary, CipherTag/binary>>, CipherState#cipher_state{nonce = ExplicitNonce + 1}}.
-encrypt_nonce(?CHACHA20_POLY1305, #cipher_state{nonce = Nonce, iv = IV}) ->
- crypto:exor(<<?UINT32(0), Nonce/binary>>, IV);
-encrypt_nonce(?AES_GCM, #cipher_state{iv = IV, nonce = ExplicitNonce}) ->
+
+chacha_nonce(#cipher_state{nonce = Nonce, iv = IV}) ->
+ crypto:exor(<<?UINT32(0), Nonce/binary>>, IV).
+
+encrypt_nonce(Type, #cipher_state{iv = IV, nonce = ExplicitNonce}) when Type == ?AES_GCM;
+ Type == ?AES_CCM;
+ Type == ?AES_CCM_8 ->
<<Salt:4/bytes, _/binary>> = IV,
<<Salt/binary, ExplicitNonce:64/integer>>.
-decrypt_nonce(?CHACHA20_POLY1305, #cipher_state{nonce = Nonce, iv = IV}, _) ->
- crypto:exor(<<Nonce:96/unsigned-big-integer>>, IV);
-decrypt_nonce(?AES_GCM, #cipher_state{iv = <<Salt:4/bytes, _/binary>>}, <<ExplicitNonce:8/bytes, _/binary>>) ->
- <<Salt/binary, ExplicitNonce/binary>>.
+decrypt_nonce(?CHACHA20_POLY1305, CipherState, _) ->
+ chacha_nonce(CipherState);
+decrypt_nonce(Type, #cipher_state{iv = <<Salt:4/bytes, _/binary>>}, <<ExplicitNonce:8/bytes, _/binary>>) when
+ Type == ?AES_GCM;
+ Type == ?AES_CCM;
+ Type == ?AES_CCM_8 ->
+ <<Salt/binary, ExplicitNonce/binary>>.
-compile({inline, [aead_ciphertext_split/4]}).
aead_ciphertext_split(?CHACHA20_POLY1305, #cipher_state{tag_len = Len}, CipherTextFragment, AAD) ->
CipherLen = byte_size(CipherTextFragment) - Len,
<<CipherText:CipherLen/bytes, CipherTag:Len/bytes>> = CipherTextFragment,
{?end_additional_data(AAD, CipherLen), CipherText, CipherTag};
-aead_ciphertext_split(?AES_GCM, #cipher_state{tag_len = Len}, CipherTextFragment, AAD) ->
+aead_ciphertext_split(Type, #cipher_state{tag_len = Len}, CipherTextFragment, AAD) when Type == ?AES_GCM;
+ Type == ?AES_CCM;
+ Type == ?AES_CCM_8 ->
CipherLen = byte_size(CipherTextFragment) - (Len + 8), %% 8 is length of explicit Nonce
<< _:8/bytes, CipherText:CipherLen/bytes, CipherTag:Len/bytes>> = CipherTextFragment,
{?end_additional_data(AAD, CipherLen), CipherText, CipherTag}.
diff --git a/lib/ssl/src/ssl_record.hrl b/lib/ssl/src/ssl_record.hrl
index eb718fd20c..6d4d47cedb 100644
--- a/lib/ssl/src/ssl_record.hrl
+++ b/lib/ssl/src/ssl_record.hrl
@@ -96,6 +96,11 @@
-define(AES_CBC, 7).
-define(AES_GCM, 8).
-define(CHACHA20_POLY1305, 9).
+%% Following two are not defined in any RFC but we want to have the
+%% same type of handling internaly, all of these "bulk_cipher_algorithm"
+%% enums are only used internaly anyway.
+-define(AES_CCM, 10).
+-define(AES_CCM_8, 11).
%% CipherType
-define(STREAM, 0).
diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl
index fde73cdef1..a05858221a 100644
--- a/lib/ssl/src/tls_connection.erl
+++ b/lib/ssl/src/tls_connection.erl
@@ -934,7 +934,7 @@ wait_sh(Type, Event, State) ->
callback_mode() ->
state_functions.
-terminate({shutdown, sender_died, Reason}, _StateName,
+terminate({shutdown, {sender_died, Reason}}, _StateName,
#state{static_env = #static_env{socket = Socket,
transport_cb = Transport}}
= State) ->
@@ -1119,7 +1119,7 @@ handle_info({CloseTag, Socket}, StateName,
end;
handle_info({'EXIT', Sender, Reason}, _,
#state{protocol_specific = #{sender := Sender}} = State) ->
- {stop, {shutdown, sender_died, Reason}, State};
+ {stop, {shutdown, {sender_died, Reason}}, State};
handle_info(Msg, StateName, State) ->
ssl_connection:StateName(info, Msg, State, ?MODULE).
diff --git a/lib/ssl/src/tls_record_1_3.erl b/lib/ssl/src/tls_record_1_3.erl
index 97331e1510..74321a1ae2 100644
--- a/lib/ssl/src/tls_record_1_3.erl
+++ b/lib/ssl/src/tls_record_1_3.erl
@@ -252,7 +252,7 @@ cipher_aead(Fragment, BulkCipherAlgo, Key, Seq, IV, TagLen) ->
AAD = additional_data(erlang:iolist_size(Fragment) + TagLen),
Nonce = nonce(Seq, IV),
{Content, CipherTag} =
- ssl_cipher:aead_encrypt(BulkCipherAlgo, Key, Nonce, Fragment, AAD),
+ ssl_cipher:aead_encrypt(BulkCipherAlgo, Key, Nonce, Fragment, AAD, TagLen),
<<Content/binary, CipherTag/binary>>.
encode_tls_cipher_text(#tls_cipher_text{opaque_type = Type,
diff --git a/lib/ssl/test/Makefile b/lib/ssl/test/Makefile
index fc483b0a94..f7fae16088 100644
--- a/lib/ssl/test/Makefile
+++ b/lib/ssl/test/Makefile
@@ -64,8 +64,9 @@ MODULES = \
ssl_sni_SUITE \
ssl_eqc_SUITE \
ssl_rfc_5869_SUITE \
- make_certs\
- x509_test
+ make_certs \
+ x509_test \
+ inet_crypto_dist
ERL_FILES = $(MODULES:%=%.erl)
diff --git a/lib/ssl/test/inet_crypto_dist.erl b/lib/ssl/test/inet_crypto_dist.erl
new file mode 100644
index 0000000000..5aafaac983
--- /dev/null
+++ b/lib/ssl/test/inet_crypto_dist.erl
@@ -0,0 +1,1323 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%% -------------------------------------------------------------------------
+%%
+%% Module for encrypted Erlang protocol - a minimal encrypted
+%% distribution protocol based on only a shared secret
+%% and the crypto application
+%%
+-module(inet_crypto_dist).
+-define(DIST_NAME, inet_crypto).
+-define(DIST_PROTO, crypto).
+-define(DRIVER, inet_tcp).
+-define(FAMILY, inet).
+
+-define(PROTOCOL, inet_crypto_dist_v1).
+-define(DEFAULT_BLOCK_CRYPTO, aes_128_gcm).
+-define(DEFAULT_HASH_ALGORITHM, sha256).
+-define(DEFAULT_REKEY_INTERVAL, 32768).
+
+-export([listen/1, accept/1, accept_connection/5,
+ setup/5, close/1, select/1, is_node_name/1]).
+-export([is_supported/0]).
+
+%% Generalized dist API, for sibling IPv6 module inet6_crypto_dist
+-export([gen_listen/2, gen_accept/2, gen_accept_connection/6,
+ gen_setup/6, gen_close/2, gen_select/2]).
+
+-export([nodelay/0]).
+
+%% Debug
+%%%-compile(export_all).
+-export([dbg/0, test_server/0, test_client/1]).
+
+-include_lib("kernel/include/net_address.hrl").
+-include_lib("kernel/include/dist.hrl").
+-include_lib("kernel/include/dist_util.hrl").
+
+%% Test if crypto has got enough capabilities for this module to run
+%%
+is_supported() ->
+ try {crypto:cipher_info(?DEFAULT_BLOCK_CRYPTO),
+ crypto:hash_info(?DEFAULT_HASH_ALGORITHM)}
+ of
+ {#{block_size := _, iv_length := _, key_length := _},
+ #{size := _}} ->
+ true
+ catch
+ error:undef ->
+ false
+ end.
+
+%% -------------------------------------------------------------------------
+%% Erlang distribution plugin structure explained to myself
+%% -------
+%% These are the processes involved in the distribution:
+%% * net_kernel
+%% * The Acceptor
+%% * The Controller | Handshaker | Ticker
+%% * The DistCtrl process that may be split into:
+%% + The Output controller
+%% + The Input controller
+%% For the regular inet_tcp_dist distribution module, DistCtrl
+%% is not one or two processes, but one port - a gen_tcp socket
+%%
+%% When the VM is started with the argument "-proto_dist inet_crypto"
+%% net_kernel registers the module inet_crypto_dist as distribution
+%% module. net_kernel calls listen/1 to create a listen socket
+%% and then accept/1 with the listen socket as argument to spawn
+%% the Acceptor process, which is linked to net_kernel. Apparently
+%% the listen socket is owned by net_kernel - I wonder if it could
+%% be owned by the Acceptor process instead...
+%%
+%% The Acceptor process calls blocking accept on the listen socket
+%% and when an incoming socket is returned it spawns the DistCtrl
+%% process a linked to the Acceptor. The ownership of the accepted
+%% socket is transferred to the DistCtrl process.
+%% A message is sent to net_kernel to inform it that an incoming
+%% connection has appeared and the Acceptor awaits a reply from net_kernel.
+%%
+%% net_kernel then calls accept_connection/5 to spawn the Controller |
+%% Handshaker | Ticker process that is linked to net_kernel.
+%% The Controller then awaits a message from the Acceptor process.
+%%
+%% When net_kernel has spawned the Controller it replies with a message
+%% to the Acceptor that then calls DistCtrl to changes its links
+%% so DistCtrl ends up linked to the Controller and not to the Acceptor.
+%% The Acceptor then sends a message to the Controller. The Controller
+%% then changes role into the Handshaker creates a #hs_data{} record
+%% and calls dist_util:handshake_other_started/1. After this
+%% the Acceptor goes back into a blocking accept on the listen socket.
+%%
+%% For the regular distribution inet_tcp_dist DistCtrl is a gen_tcp socket
+%% and when it is a process it also acts as a socket. The #hs_data{}
+%% record used by dist_util presents a set of funs that are used
+%% by dist_util to perform the distribution handshake. These funs
+%% make sure to transfer the handshake messages through the DistCtrl
+%% "socket".
+%%
+%% When the handshake is finished a fun for this purpose in #hs_data{}
+%% is called, which tells DistCtrl that it does not need to be prepared
+%% for any more #hs_data{} handshake calls. The DistCtrl process in this
+%% module then spawns the Input controller process that gets ownership
+%% of the connection's gen_tcp socket and changes into {active, N} mode
+%% so now it gets all incoming traffic and delivers that to the VM.
+%% The original DistCtrl process changes role into the Output controller
+%% process and starts asking the VM for outbound messages and transfers
+%% them on the connection socket.
+%%
+%% The Handshaker now changes into the Ticker role, and uses only two
+%% functions in the #hs_data{} record; one to get socket statistics
+%% and one to send a tick. None of these may block for any reason
+%% in particular not for a congested socket since that would destroy
+%% connection supervision.
+%%
+%%
+%% For an connection net_kernel calls setup/5 which spawns the
+%% Controller process as linked to net_kernel. This Controller process
+%% connects to the other node's listen socket and when that is succesful
+%% spawns the DistCtrl process as linked to the controller and transfers
+%% socket ownership to it.
+%%
+%% Then the Controller creates the #hs_data{} record and calls
+%% dist_util:handshake_we_started/1 which changes the process role
+%% into Handshaker.
+%%
+%% When the distribution handshake is finished the procedure is just
+%% as for an incoming connection above.
+%%
+%%
+%% To sum it up.
+%%
+%% There is an Acceptor process that is linked to net_kernel and
+%% informs it when new connections arrive.
+%%
+%% net_kernel spawns Controllers for incoming and for outgoing connections.
+%% these Controllers use the DistCtrl processes to do distribution
+%% handshake and after that becomes Tickers that supervise the connection.
+%%
+%% The Controller | Handshaker | Ticker is linked to net_kernel, and to
+%% DistCtrl, one or both. If any of these connection processes would die
+%% all others should be killed by the links. Therefore none of them may
+%% terminate with reason 'normal'.
+%% -------------------------------------------------------------------------
+
+%% -------------------------------------------------------------------------
+%% select/1 is called by net_kernel to ask if this distribution protocol
+%% is willing to handle Node
+%%
+
+select(Node) ->
+ gen_select(Node, ?DRIVER).
+
+gen_select(Node, Driver) ->
+ case dist_util:split_node(Node) of
+ {node, _, Host} ->
+ case Driver:getaddr(Host) of
+ {ok, _} -> true;
+ _ -> false
+ end;
+ _ ->
+ false
+ end.
+
+%% -------------------------------------------------------------------------
+
+is_node_name(Node) ->
+ dist_util:is_node_name(Node).
+
+%% -------------------------------------------------------------------------
+%% Called by net_kernel to create a listen socket for this
+%% distribution protocol. This listen socket is used by
+%% the Acceptor process.
+%%
+
+listen(Name) ->
+ gen_listen(Name, ?DRIVER).
+
+gen_listen(Name, Driver) ->
+ case inet_tcp_dist:gen_listen(Driver, Name) of
+ {ok, {Socket, Address, Creation}} ->
+ inet:setopts(Socket, [binary, {nodelay, true}]),
+ {ok,
+ {Socket, Address#net_address{protocol = ?DIST_PROTO}, Creation}};
+ Other ->
+ Other
+ end.
+
+%% -------------------------------------------------------------------------
+%% Called by net_kernel to spawn the Acceptor process that awaits
+%% new connection in a blocking accept and informs net_kernel
+%% when a new connection has appeared, and starts the DistCtrl
+%% "socket" process for the connection.
+%%
+
+accept(Listen) ->
+ gen_accept(Listen, ?DRIVER).
+
+gen_accept(Listen, Driver) ->
+ NetKernel = self(),
+ %%
+ %% Spawn Acceptor process
+ %%
+ Config = config(),
+ monitor_dist_proc(
+ spawn_opt(
+ fun () ->
+ accept_loop(Listen, Driver, NetKernel, Config)
+ end,
+ [link, {priority, max}])).
+
+accept_loop(Listen, Driver, NetKernel, Config) ->
+ case Driver:accept(Listen) of
+ {ok, Socket} ->
+ wait_for_code_server(),
+ Timeout = net_kernel:connecttime(),
+ DistCtrl = start_dist_ctrl(Socket, Config, Timeout),
+ %% DistCtrl is a "socket"
+ NetKernel !
+ {accept,
+ self(), DistCtrl, Driver:family(), ?DIST_PROTO},
+ receive
+ {NetKernel, controller, Controller} ->
+ call_dist_ctrl(DistCtrl, {controller, Controller, self()}),
+ Controller ! {self(), controller, Socket};
+ {NetKernel, unsupported_protocol} ->
+ exit(unsupported_protocol)
+ end,
+ accept_loop(Listen, Driver, NetKernel, Config);
+ AcceptError ->
+ exit({accept, AcceptError})
+ end.
+
+wait_for_code_server() ->
+ %% This is an ugly hack. Starting encryption on a connection
+ %% requires the crypto module to be loaded. Loading the crypto
+ %% module triggers its on_load function, which calls
+ %% code:priv_dir/1 to find the directory where its NIF library is.
+ %% However, distribution is started earlier than the code server,
+ %% so the code server is not necessarily started yet, and
+ %% code:priv_dir/1 might fail because of that, if we receive
+ %% an incoming connection on the distribution port early enough.
+ %%
+ %% If the on_load function of a module fails, the module is
+ %% unloaded, and the function call that triggered loading it fails
+ %% with 'undef', which is rather confusing.
+ %%
+ %% So let's avoid that by waiting for the code server to start.
+ %%
+ case whereis(code_server) of
+ undefined ->
+ timer:sleep(10),
+ wait_for_code_server();
+ Pid when is_pid(Pid) ->
+ ok
+ end.
+
+%% -------------------------------------------------------------------------
+%% Called by net_kernel when a new connection has appeared, to spawn
+%% a Controller process that performs the handshake with the new node,
+%% and then becomes the Ticker connection supervisor.
+%% -------------------------------------------------------------------------
+
+accept_connection(Acceptor, DistCtrl, MyNode, Allowed, SetupTime) ->
+ gen_accept_connection(
+ Acceptor, DistCtrl, MyNode, Allowed, SetupTime, ?DRIVER).
+
+gen_accept_connection(
+ Acceptor, DistCtrl, MyNode, Allowed, SetupTime, Driver) ->
+ NetKernel = self(),
+ %%
+ %% Spawn Controller/handshaker/ticker process
+ %%
+ monitor_dist_proc(
+ spawn_opt(
+ fun() ->
+ do_accept(
+ Acceptor, DistCtrl,
+ MyNode, Allowed, SetupTime, Driver, NetKernel)
+ end,
+ [link, {priority, max}])).
+
+do_accept(
+ Acceptor, DistCtrl, MyNode, Allowed, SetupTime, Driver, NetKernel) ->
+ receive
+ {Acceptor, controller, Socket} ->
+ Timer = dist_util:start_timer(SetupTime),
+ HSData =
+ hs_data_common(
+ NetKernel, MyNode, DistCtrl, Timer,
+ Socket, Driver:family()),
+ HSData_1 =
+ HSData#hs_data{
+ this_node = MyNode,
+ this_flags = 0,
+ allowed = Allowed},
+ dist_util:handshake_other_started(trace(HSData_1))
+ end.
+
+%% -------------------------------------------------------------------------
+%% Called by net_kernel to spawn a Controller process that sets up
+%% a new connection to another Erlang node, performs the handshake
+%% with the other it, and then becomes the Ticker process
+%% that supervises the connection.
+%% -------------------------------------------------------------------------
+
+setup(Node, Type, MyNode, LongOrShortNames, SetupTime) ->
+ gen_setup(Node, Type, MyNode, LongOrShortNames, SetupTime, ?DRIVER).
+
+gen_setup(Node, Type, MyNode, LongOrShortNames, SetupTime, Driver) ->
+ NetKernel = self(),
+ %%
+ %% Spawn Controller/handshaker/ticker process
+ %%
+ monitor_dist_proc(
+ spawn_opt(
+ setup_fun(
+ Node, Type, MyNode, LongOrShortNames, SetupTime, Driver, NetKernel),
+ [link, {priority, max}])).
+
+-spec setup_fun(_,_,_,_,_,_,_) -> fun(() -> no_return()).
+setup_fun(
+ Node, Type, MyNode, LongOrShortNames, SetupTime, Driver, NetKernel) ->
+ fun() ->
+ do_setup(
+ Node, Type, MyNode, LongOrShortNames, SetupTime,
+ Driver, NetKernel)
+ end.
+
+-spec do_setup(_,_,_,_,_,_,_) -> no_return().
+do_setup(
+ Node, Type, MyNode, LongOrShortNames, SetupTime, Driver, NetKernel) ->
+ {Name, Address} = split_node(Driver, Node, LongOrShortNames),
+ ErlEpmd = net_kernel:epmd_module(),
+ {ARMod, ARFun} = get_address_resolver(ErlEpmd, Driver),
+ Timer = trace(dist_util:start_timer(SetupTime)),
+ case ARMod:ARFun(Name, Address, Driver:family()) of
+ {ok, Ip, TcpPort, Version} ->
+ do_setup_connect(
+ Node, Type, MyNode, Timer, Driver, NetKernel,
+ Ip, TcpPort, Version);
+ {ok, Ip} ->
+ case ErlEpmd:port_please(Name, Ip) of
+ {port, TcpPort, Version} ->
+ do_setup_connect(
+ Node, Type, MyNode, Timer, Driver, NetKernel,
+ Ip, TcpPort, Version);
+ Other ->
+ ?shutdown2(
+ Node,
+ trace(
+ {port_please_failed, ErlEpmd, Name, Ip, Other}))
+ end;
+ Other ->
+ ?shutdown2(
+ Node,
+ trace({getaddr_failed, Driver, Address, Other}))
+ end.
+
+-spec do_setup_connect(_,_,_,_,_,_,_,_,_) -> no_return().
+
+do_setup_connect(
+ Node, Type, MyNode, Timer, Driver, NetKernel,
+ Ip, TcpPort, Version) ->
+ dist_util:reset_timer(Timer),
+ ConnectOpts =
+ trace(
+ connect_options(
+ [binary, {active, false}, {packet, 2}, {nodelay, true}])),
+ case Driver:connect(Ip, TcpPort, ConnectOpts) of
+ {ok, Socket} ->
+ Config = config(),
+ DistCtrl =
+ start_dist_ctrl(Socket, Config, net_kernel:connecttime()),
+ %% DistCtrl is a "socket"
+ HSData =
+ hs_data_common(
+ NetKernel, MyNode, DistCtrl, Timer,
+ Socket, Driver:family()),
+ HSData_1 =
+ HSData#hs_data{
+ other_node = Node,
+ this_flags = 0,
+ other_version = Version,
+ request_type = Type},
+ dist_util:handshake_we_started(trace(HSData_1));
+ ConnectError ->
+ ?shutdown2(Node,
+ trace({connect_failed, Ip, TcpPort, ConnectError}))
+ end.
+
+%% -------------------------------------------------------------------------
+%% close/1 is only called by net_kernel on the socket returned by listen/1.
+
+close(Socket) ->
+ gen_close(Socket, ?DRIVER).
+
+gen_close(Socket, Driver) ->
+ trace(Driver:close(Socket)).
+
+%% -------------------------------------------------------------------------
+
+
+hs_data_common(NetKernel, MyNode, DistCtrl, Timer, Socket, Family) ->
+ %% Field 'socket' below is set to DistCtrl, which makes
+ %% the distribution handshake process (ticker) call
+ %% the funs below with DistCtrl as the S argument.
+ %% So, S =:= DistCtrl below...
+ #hs_data{
+ kernel_pid = NetKernel,
+ this_node = MyNode,
+ socket = DistCtrl,
+ timer = Timer,
+ %%
+ f_send =
+ fun (S, Packet) when S =:= DistCtrl ->
+ call_dist_ctrl(S, {send, Packet})
+ end,
+ f_recv =
+ fun (S, 0, infinity) when S =:= DistCtrl ->
+ case call_dist_ctrl(S, recv) of
+ {ok, Bin} when is_binary(Bin) ->
+ {ok, binary_to_list(Bin)};
+ Error ->
+ Error
+ end
+ end,
+ f_setopts_pre_nodeup =
+ fun (S) when S =:= DistCtrl ->
+ ok
+ end,
+ f_setopts_post_nodeup =
+ fun (S) when S =:= DistCtrl ->
+ ok
+ end,
+ f_getll =
+ fun (S) when S =:= DistCtrl ->
+ {ok, S} %% DistCtrl is the distribution port
+ end,
+ f_address =
+ fun (S, Node) when S =:= DistCtrl ->
+ case call_dist_ctrl(S, peername) of
+ {ok, Address} ->
+ case dist_util:split_node(Node) of
+ {node, _, Host} ->
+ #net_address{
+ address = Address,
+ host = Host,
+ protocol = ?DIST_PROTO,
+ family = Family};
+ _ ->
+ {error, no_node}
+ end
+ end
+ end,
+ f_handshake_complete =
+ fun (S, _Node, DistHandle) when S =:= DistCtrl ->
+ call_dist_ctrl(S, {handshake_complete, DistHandle})
+ end,
+ %%
+ %% mf_tick/1, mf_getstat/1, mf_setopts/2 and mf_getopts/2
+ %% are called by the ticker any time after f_handshake_complete/3
+ %% so they may not block the caller even for congested socket
+ mf_tick =
+ fun (S) when S =:= DistCtrl ->
+ S ! dist_tick
+ end,
+ mf_getstat =
+ fun (S) when S =:= DistCtrl ->
+ case
+ inet:getstat(Socket, [recv_cnt, send_cnt, send_pend])
+ of
+ {ok, Stat} ->
+ split_stat(Stat, 0, 0, 0);
+ Error ->
+ Error
+ end
+ end,
+ mf_setopts =
+ fun (S, Opts) when S =:= DistCtrl ->
+ inet:setopts(Socket, setopts_filter(Opts))
+ end,
+ mf_getopts =
+ fun (S, Opts) when S =:= DistCtrl ->
+ inet:getopts(Socket, Opts)
+ end}.
+
+setopts_filter(Opts) ->
+ [Opt ||
+ Opt <- Opts,
+ case Opt of
+ {K, _} when K =:= active; K =:= deliver; K =:= packet -> false;
+ K when K =:= list; K =:= binary -> false;
+ K when K =:= inet; K =:= inet6 -> false;
+ _ -> true
+ end].
+
+split_stat([{recv_cnt, R}|Stat], _, W, P) ->
+ split_stat(Stat, R, W, P);
+split_stat([{send_cnt, W}|Stat], R, _, P) ->
+ split_stat(Stat, R, W, P);
+split_stat([{send_pend, P}|Stat], R, W, _) ->
+ split_stat(Stat, R, W, P);
+split_stat([], R, W, P) ->
+ {ok, R, W, P}.
+
+%% ------------------------------------------------------------
+%% Determine if EPMD module supports address resolving. Default
+%% is to use inet_tcp:getaddr/2.
+%% ------------------------------------------------------------
+get_address_resolver(EpmdModule, _Driver) ->
+ case erlang:function_exported(EpmdModule, address_please, 3) of
+ true -> {EpmdModule, address_please};
+ _ -> {erl_epmd, address_please}
+ end.
+
+
+%% If Node is illegal terminate the connection setup!!
+split_node(Driver, Node, LongOrShortNames) ->
+ case dist_util:split_node(Node) of
+ {node, Name, Host} ->
+ check_node(Driver, Node, Name, Host, LongOrShortNames);
+ {host, _} ->
+ error_logger:error_msg(
+ "** Nodename ~p illegal, no '@' character **~n",
+ [Node]),
+ ?shutdown2(Node, trace({illegal_node_n@me, Node}));
+ _ ->
+ error_logger:error_msg(
+ "** Nodename ~p illegal **~n", [Node]),
+ ?shutdown2(Node, trace({illegal_node_name, Node}))
+ end.
+
+check_node(Driver, Node, Name, Host, LongOrShortNames) ->
+ case string:split(Host, ".", all) of
+ [_] when LongOrShortNames =:= longnames ->
+ case Driver:parse_address(Host) of
+ {ok, _} ->
+ {Name, Host};
+ _ ->
+ error_logger:error_msg(
+ "** System running to use "
+ "fully qualified hostnames **~n"
+ "** Hostname ~s is illegal **~n",
+ [Host]),
+ ?shutdown2(Node, trace({not_longnames, Host}))
+ end;
+ [_, _|_] when LongOrShortNames =:= shortnames ->
+ error_logger:error_msg(
+ "** System NOT running to use "
+ "fully qualified hostnames **~n"
+ "** Hostname ~s is illegal **~n",
+ [Host]),
+ ?shutdown2(Node, trace({not_shortnames, Host}));
+ _ ->
+ {Name, Host}
+ end.
+
+%% -------------------------------------------------------------------------
+
+connect_options(Opts) ->
+ case application:get_env(kernel, inet_dist_connect_options) of
+ {ok, ConnectOpts} ->
+ Opts ++ setopts_filter(ConnectOpts);
+ _ ->
+ Opts
+ end.
+
+%% we may not always want the nodelay behaviour
+%% for performance reasons
+nodelay() ->
+ case application:get_env(kernel, dist_nodelay) of
+ undefined ->
+ {nodelay, true};
+ {ok, true} ->
+ {nodelay, true};
+ {ok, false} ->
+ {nodelay, false};
+ _ ->
+ {nodelay, true}
+ end.
+
+config() ->
+ case init:get_argument(?DIST_NAME) of
+ error ->
+ error({missing_argument, ?DIST_NAME});
+ {ok, [[String]]} ->
+ {ok, Tokens, _} = erl_scan:string(String ++ "."),
+ case erl_parse:parse_term(Tokens) of
+ {ok, #{secret := Secret} = Config}
+ when is_binary(Secret); is_list(Secret) ->
+ Config;
+ {ok, #{} = Config} ->
+ error({missing_secret, [{?DIST_NAME,Config}]});
+ _ ->
+ error({bad_argument_value, [{?DIST_NAME,String}]})
+ end;
+ {ok, Value} ->
+ error({malformed_argument, [{?DIST_NAME,Value}]})
+ end.
+
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%
+%% The DistCtrl process(es).
+%%
+%% At net_kernel handshake_complete spawns off the input controller that
+%% takes over the socket ownership, and itself becomes the output controller
+%%
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%% XXX Missing to "productified":
+%%% * Cryptoanalysis by experts
+%%% * Proof of usefulness
+%%% * Unifying exit reasons using a death_row() function
+%%% * Verification (and rejection) of other end's crypto parameters
+%%% * OTP:ification (proc_lib?)
+%%% * An application to belong to (crypto|kernel?)
+%%% * Secret on file (cookie as default?), parameter handling
+%%% * Restart and/or code reload policy
+
+%% Debug client and server
+
+test_config() ->
+ #{secret => <<"Secret Cluster Password 123456">>}.
+
+test_server() ->
+ {ok, Listen} = gen_tcp:listen(0, [{packet, 2}, {active, false}, binary]),
+ {ok, Port} = inet:port(Listen),
+ io:format(?MODULE_STRING":test_client(~w).~n", [Port]),
+ {ok, Socket} = gen_tcp:accept(Listen),
+ test(Socket).
+
+test_client(Port) ->
+ {ok, Socket} =
+ gen_tcp:connect(
+ localhost, Port, [{packet, 2}, {active, false}, binary]),
+ test(Socket).
+
+test(Socket) ->
+ start_dist_ctrl(Socket, test_config(), 10000).
+
+%% -------------------------------------------------------------------------
+
+start_dist_ctrl(Socket, Config, Timeout) ->
+ Protocol = ?PROTOCOL,
+ Controller = self(),
+ Server =
+ monitor_dist_proc(
+ spawn_opt(
+ fun () ->
+ receive
+ {?MODULE, From, start} ->
+ {SendParams, RecvParams} =
+ init(Socket, Config, Protocol),
+ reply(From, self()),
+ handshake(SendParams, 0, RecvParams, 0, Controller)
+ end
+ end,
+ [link,
+ {priority, max},
+ {message_queue_data, off_heap},
+ {fullsweep_after, 0}])),
+ ok = gen_tcp:controlling_process(Socket, Server),
+ call_dist_ctrl(Server, start, Timeout).
+
+
+call_dist_ctrl(Server, Msg) ->
+ call_dist_ctrl(Server, Msg, infinity).
+%%
+call_dist_ctrl(Server, Msg, Timeout) ->
+ Ref = erlang:monitor(process, Server),
+ Server ! {?MODULE, {Ref, self()}, Msg},
+ receive
+ {Ref, Res} ->
+ erlang:demonitor(Ref, [flush]),
+ Res;
+ {'DOWN', Ref, process, Server, Reason} ->
+ exit({?PROTOCOL, Reason})
+ after Timeout ->
+ exit(Server, timeout),
+ receive
+ {'DOWN', Ref, process, Server, _} ->
+ exit({?PROTOCOL, timeout})
+ end
+ end.
+
+reply({Ref, Pid}, Msg) ->
+ Pid ! {Ref, Msg},
+ ok.
+
+%% -------------------------------------------------------------------------
+
+-record(params,
+ {protocol, % Encryption protocol tag
+ socket,
+ dist_handle,
+ hash_algorithm,
+ block_crypto,
+ rekey_interval,
+ iv,
+ key,
+ tag_len}).
+
+-define(TCP_ACTIVE, 64).
+-define(CHUNK_SIZE, (65536 - 512)).
+%% The start chunk starts with zeros, so it seems logical to not have
+%% a chunk type with value 0
+-define(HANDSHAKE_CHUNK, 1).
+-define(DATA_CHUNK, 2).
+-define(TICK_CHUNK, 3).
+-define(REKEY_CHUNK, 4).
+
+%% -------------------------------------------------------------------------
+%% Crypto strategy
+%% -------
+%% The crypto strategy is as simple as possible to get an encrypted
+%% connection as benchmark reference. It is geared around AEAD
+%% ciphers in particular AES-GCM.
+%%
+%% The init message and the start message must fit in the TCP buffers
+%% since both sides start with sending the init message, waits
+%% for the other end's init message, sends the start message
+%% and waits for the other end's start message. So if the send
+%% blocks we have a deadlock.
+%%
+%% The init message is unencrypted and contains the block cipher and hash
+%% algorithms the sender will use, the IV and a key salt. Both sides'
+%% key salt is used with the mutual secret as input to the hash algorithm
+%% to create different encryption/decryption keys for both directions.
+%%
+%% The start message is the first encrypted message and contains just
+%% encrypted zeros the width of the key, with the header of the init
+%% message as AAD data. Successfully decrypting this message
+%% verifies that we have an encrypted channel.
+%%
+%% Subsequent encrypted messages has the sequence number and the length
+%% of the message as AAD data. These messages has got a message type
+%% differentiating data from ticks. Ticks have a random size in an
+%% attempt to make them less obvious to spot.
+%%
+%% The only reaction to errors is to crash noisily wich will bring
+%% down the connection and hopefully produce something useful
+%% in the local log, but all the other end sees is a closed connection.
+%% -------------------------------------------------------------------------
+
+init(Socket, Config, Protocol) ->
+ Secret = maps:get(secret, Config),
+ HashAlgorithm =
+ maps:get(hash_algorithm, Config, ?DEFAULT_HASH_ALGORITHM),
+ BlockCrypto =
+ maps:get(block_crypto, Config, ?DEFAULT_BLOCK_CRYPTO),
+ RekeyInterval =
+ maps:get(rekey_interval, Config, ?DEFAULT_REKEY_INTERVAL),
+ %%
+ SendParams =
+ init_params(
+ Socket, Protocol, HashAlgorithm, BlockCrypto, RekeyInterval),
+ send_init(SendParams, Secret).
+
+send_init(
+ #params{
+ protocol = Protocol,
+ socket = Socket,
+ block_crypto = BlockCrypto,
+ iv = IVLen,
+ key = KeyLen,
+ hash_algorithm = HashAlgorithm} = SendParams,
+ Secret) ->
+ %%
+ ProtocolString = atom_to_binary(Protocol, utf8),
+ BlockCryptoString = atom_to_binary(BlockCrypto, utf8),
+ HashAlgorithmString = atom_to_binary(HashAlgorithm, utf8),
+ SendHeader =
+ <<ProtocolString/binary, 0,
+ HashAlgorithmString/binary, 0,
+ BlockCryptoString/binary, 0>>,
+ <<IV:IVLen/binary, KeySalt:KeyLen/binary>> = IV_KeySalt =
+ crypto:strong_rand_bytes(IVLen + KeyLen),
+ InitPacket = [SendHeader, IV_KeySalt],
+ ok = gen_tcp:send(Socket, InitPacket),
+ recv_init(SendParams#params{iv = IV, key = KeySalt}, Secret, SendHeader).
+
+recv_init(
+ #params{
+ socket = Socket,
+ hash_algorithm = SendHashAlgorithm,
+ key = SendKeySalt} = SendParams, Secret, SendHeader) ->
+ %%
+ {ok, InitPacket} = gen_tcp:recv(Socket, 0),
+ [ProtocolString, Rest_1] = binary:split(InitPacket, <<0>>),
+ Protocol = binary_to_existing_atom(ProtocolString, utf8),
+ case Protocol of
+ ?PROTOCOL ->
+ [HashAlgorithmString, Rest_2] = binary:split(Rest_1, <<0>>),
+ HashAlgorithm = binary_to_existing_atom(HashAlgorithmString, utf8),
+ [BlockCryptoString, Rest_3] = binary:split(Rest_2, <<0>>),
+ BlockCrypto = binary_to_existing_atom(BlockCryptoString, utf8),
+ #params{
+ hash_algorithm = RecvHashAlgorithm,
+ iv = RecvIVLen,
+ key = RecvKeyLen} = RecvParams =
+ init_params(
+ Socket, Protocol, HashAlgorithm, BlockCrypto, undefined),
+ <<RecvIV:RecvIVLen/binary,
+ RecvKeySalt:RecvKeyLen/binary>> = Rest_3,
+ SendKey =
+ hash_key(SendHashAlgorithm, SendKeySalt, [RecvKeySalt, Secret]),
+ RecvKey =
+ hash_key(RecvHashAlgorithm, RecvKeySalt, [SendKeySalt, Secret]),
+ SendParams_1 = SendParams#params{key = SendKey},
+ RecvParams_1 = RecvParams#params{iv = RecvIV, key = RecvKey},
+ RecvHeaderLen = byte_size(InitPacket) - RecvIVLen - RecvKeyLen,
+ <<RecvHeader:RecvHeaderLen/binary, _/binary>> = InitPacket,
+ send_start(SendParams_1, SendHeader),
+ RecvRekeyInterval = recv_start(RecvParams_1, RecvHeader),
+ {SendParams_1,
+ RecvParams_1#params{rekey_interval = RecvRekeyInterval}}
+ end.
+
+send_start(
+ #params{
+ socket = Socket,
+ block_crypto = BlockCrypto,
+ rekey_interval= RekeyInterval,
+ iv = IV,
+ key = Key,
+ tag_len = TagLen}, AAD) ->
+ %%
+ KeyLen = byte_size(Key),
+ Zeros = binary:copy(<<0>>, KeyLen),
+ {Ciphertext, CipherTag} =
+ crypto:block_encrypt(
+ crypto_cipher_name(BlockCrypto),
+ Key, IV, {AAD, [Zeros, <<RekeyInterval:32>>], TagLen}),
+ ok = gen_tcp:send(Socket, [Ciphertext, CipherTag]).
+
+recv_start(
+ #params{
+ socket = Socket,
+ block_crypto = BlockCrypto,
+ iv = IV,
+ key = Key,
+ tag_len = TagLen}, AAD) ->
+ {ok, Packet} = gen_tcp:recv(Socket, 0),
+ KeyLen = byte_size(Key),
+ PacketLen = KeyLen + 4,
+ <<Ciphertext:PacketLen/binary, CipherTag:TagLen/binary>> = Packet,
+ Zeros = binary:copy(<<0>>, KeyLen),
+ case
+ crypto:block_decrypt(
+ crypto_cipher_name(BlockCrypto),
+ Key, IV, {AAD, Ciphertext, CipherTag})
+ of
+ <<Zeros:KeyLen/binary, RekeyInterval:32>>
+ when 1 =< RekeyInterval ->
+ RekeyInterval;
+ _ ->
+ error(decrypt_error)
+ end.
+
+init_params(Socket, Protocol, HashAlgorithm, BlockCrypto, RekeyInterval) ->
+ #{block_size := 1,
+ iv_length := IVLen,
+ key_length := KeyLen} = crypto:cipher_info(BlockCrypto),
+ case crypto:hash_info(HashAlgorithm) of
+ #{size := HashSize} when HashSize >= KeyLen ->
+ #params{
+ socket = Socket,
+ protocol = Protocol,
+ hash_algorithm = HashAlgorithm,
+ block_crypto = BlockCrypto,
+ rekey_interval = RekeyInterval,
+ iv = IVLen,
+ key = KeyLen,
+ tag_len = 16}
+ end.
+
+crypto_cipher_name(BlockCrypto) ->
+ case BlockCrypto of
+ aes_128_gcm -> aes_gcm;
+ aes_192_gcm -> aes_gcm;
+ aes_256_gcm -> aes_gcm
+ end.
+
+hash_key(HashAlgorithm, KeySalt, OtherSalt) ->
+ KeyLen = byte_size(KeySalt),
+ <<Key:KeyLen/binary, _/binary>> =
+ crypto:hash(HashAlgorithm, [KeySalt, OtherSalt]),
+ Key.
+
+%% -------------------------------------------------------------------------
+%% net_kernel distribution handshake in progress
+%%
+
+handshake(
+ SendParams, SendSeq,
+ #params{socket = Socket} = RecvParams, RecvSeq, Controller) ->
+ receive
+ {?MODULE, From, {controller, Controller_1, Parent}} ->
+ Result = link(Controller_1),
+ true = unlink(Parent),
+ reply(From, Result),
+ handshake(SendParams, SendSeq, RecvParams, RecvSeq, Controller_1);
+ {?MODULE, From, {handshake_complete, DistHandle}} ->
+ reply(From, ok),
+ InputHandler =
+ monitor_dist_proc(
+ spawn_opt(
+ fun () ->
+ link(Controller),
+ receive
+ DistHandle ->
+ ok =
+ inet:setopts(
+ Socket,
+ [{active, ?TCP_ACTIVE},
+ nodelay()]),
+ input_handler(
+ RecvParams#params{
+ dist_handle = DistHandle},
+ RecvSeq, empty_q(), infinity)
+ end
+ end,
+ [link,
+ {priority, normal},
+ {message_queue_data, off_heap},
+ {fullsweep_after, 0}])),
+ _ = monitor(process, InputHandler), % For the benchmark test
+ ok = gen_tcp:controlling_process(Socket, InputHandler),
+ ok = erlang:dist_ctrl_input_handler(DistHandle, InputHandler),
+ InputHandler ! DistHandle,
+ process_flag(priority, normal),
+ erlang:dist_ctrl_get_data_notification(DistHandle),
+ crypto:rand_seed_alg(crypto_cache),
+ output_handler(
+ SendParams#params{dist_handle = DistHandle}, SendSeq);
+ %%
+ {?MODULE, From, {send, Data}} ->
+ {SendParams_1, SendSeq_1} =
+ encrypt_and_send_chunk(
+ SendParams, SendSeq, [?HANDSHAKE_CHUNK, Data]),
+ reply(From, ok),
+ handshake(
+ SendParams_1, SendSeq_1, RecvParams, RecvSeq, Controller);
+ {?MODULE, From, recv} ->
+ {RecvParams_1, RecvSeq_1, Reply} =
+ recv_and_decrypt_chunk(RecvParams, RecvSeq),
+ reply(From, Reply),
+ handshake(
+ SendParams, SendSeq, RecvParams_1, RecvSeq_1, Controller);
+ {?MODULE, From, peername} ->
+ reply(From, inet:peername(Socket)),
+ handshake(SendParams, SendSeq, RecvParams, RecvSeq, Controller);
+ %%
+ _Alien ->
+ handshake(SendParams, SendSeq, RecvParams, RecvSeq, Controller)
+ end.
+
+recv_and_decrypt_chunk(#params{socket = Socket} = RecvParams, RecvSeq) ->
+ case gen_tcp:recv(Socket, 0) of
+ {ok, Chunk} ->
+ case decrypt_chunk(RecvParams, RecvSeq, Chunk) of
+ <<?HANDSHAKE_CHUNK, Cleartext/binary>> ->
+ {RecvParams, RecvSeq + 1, {ok, Cleartext}};
+ #params{} = RecvParams_1 ->
+ recv_and_decrypt_chunk(RecvParams_1, 0);
+ _ ->
+ error(decrypt_error)
+ end;
+ Error ->
+ {RecvParams, RecvSeq, Error}
+ end.
+
+%% -------------------------------------------------------------------------
+%% Output handler process
+%%
+%% The game here is to flush all dist_data and dist_tick messages,
+%% prioritize dist_data over dist_tick, and to not use selective receive
+
+output_handler(Params, Seq) ->
+ receive
+ Msg ->
+ case Msg of
+ dist_data ->
+ output_handler_data(Params, Seq);
+ dist_tick ->
+ output_handler_tick(Params, Seq);
+ _Other ->
+ %% Ignore
+ output_handler(Params, Seq)
+ end
+ end.
+
+output_handler_data(Params, Seq) ->
+ receive
+ Msg ->
+ case Msg of
+ dist_data ->
+ output_handler_data(Params, Seq);
+ dist_tick ->
+ output_handler_data(Params, Seq);
+ _Other ->
+ %% Ignore
+ output_handler_data(Params, Seq)
+ end
+ after 0 ->
+ DistHandle = Params#params.dist_handle,
+ Q = get_data(DistHandle, empty_q()),
+ {Params_1, Seq_1} = output_handler_send(Params, Seq, Q, true),
+ erlang:dist_ctrl_get_data_notification(DistHandle),
+ output_handler(Params_1, Seq_1)
+ end.
+
+output_handler_tick(Params, Seq) ->
+ receive
+ Msg ->
+ case Msg of
+ dist_data ->
+ output_handler_data(Params, Seq);
+ dist_tick ->
+ output_handler_tick(Params, Seq);
+ _Other ->
+ %% Ignore
+ output_handler_tick(Params, Seq)
+ end
+ after 0 ->
+ TickSize = 8 + rand:uniform(56),
+ TickData = binary:copy(<<0>>, TickSize),
+ {Params_1, Seq_1} =
+ encrypt_and_send_chunk(Params, Seq, [?TICK_CHUNK, TickData]),
+ output_handler(Params_1, Seq_1)
+ end.
+
+output_handler_send(
+ #params{dist_handle = DistHandle} = Params, Seq, {_, Size, _} = Q, Retry) ->
+ %%
+ if
+ ?CHUNK_SIZE < Size ->
+ {Cleartext, Q_1} = deq_iovec(?CHUNK_SIZE, Q),
+ {Params_1, Seq_1} =
+ encrypt_and_send_chunk(Params, Seq, [?DATA_CHUNK, Cleartext]),
+ output_handler_send(Params_1, Seq_1, Q_1, Retry);
+ Retry ->
+ Q_1 = get_data(DistHandle, Q),
+ output_handler_send(Params, Seq, Q_1, false);
+ true ->
+ {Cleartext, _} = deq_iovec(Size, Q),
+ encrypt_and_send_chunk(Params, Seq, [?DATA_CHUNK, Cleartext])
+ end.
+
+%% -------------------------------------------------------------------------
+%% Input handler process
+%%
+%% Here is T 0 or infinity to steer if we should try to receive
+%% more data or not; start with infinity, and when we get some
+%% data try with 0 to see if more is waiting
+
+input_handler(#params{socket = Socket} = Params, Seq, Q, T) ->
+ receive
+ Msg ->
+ case Msg of
+ {tcp_passive, Socket} ->
+ ok = inet:setopts(Socket, [{active, ?TCP_ACTIVE}]),
+ Q_1 =
+ case T of
+ 0 ->
+ deliver_data(Params#params.dist_handle, Q);
+ infinity ->
+ Q
+ end,
+ input_handler(Params, Seq, Q_1, infinity);
+ {tcp, Socket, Chunk} ->
+ input_chunk(Params, Seq, Q, Chunk);
+ {tcp_closed, Socket} ->
+ error(connection_closed);
+ _Other ->
+ %% Ignore...
+ input_handler(Params, Seq, Q, T)
+ end
+ after T ->
+ Q_1 = deliver_data(Params#params.dist_handle, Q),
+ input_handler(Params, Seq, Q_1, infinity)
+ end.
+
+input_chunk(Params, Seq, Q, Chunk) ->
+ case decrypt_chunk(Params, Seq, Chunk) of
+ <<?DATA_CHUNK, Cleartext/binary>> ->
+ input_handler(Params, Seq + 1, enq_binary(Cleartext, Q), 0);
+ <<?TICK_CHUNK, _/binary>> ->
+ input_handler(Params, Seq + 1, Q, 0);
+ #params{} = Params_1 ->
+ input_handler(Params_1, 0, Q, 0);
+ _ ->
+ error(decrypt_error)
+ end.
+
+%% -------------------------------------------------------------------------
+%% erlang:dist_ctrl_* helpers
+
+%% Get data for sending from the VM and place it in a queue
+%%
+get_data(DistHandle, {Front, Size, Rear}) ->
+ get_data(DistHandle, Front, Size, Rear).
+%%
+get_data(DistHandle, Front, Size, Rear) ->
+ case erlang:dist_ctrl_get_data(DistHandle) of
+ none ->
+ {Front, Size, Rear};
+ Bin when is_binary(Bin) ->
+ Len = byte_size(Bin),
+ get_data(
+ DistHandle, Front, Size + 4 + Len,
+ [Bin, <<Len:32>>|Rear]);
+ [Bin1, Bin2] ->
+ Len = byte_size(Bin1) + byte_size(Bin2),
+ get_data(
+ DistHandle, Front, Size + 4 + Len,
+ [Bin2, Bin1, <<Len:32>>|Rear]);
+ Iovec ->
+ Len = iolist_size(Iovec),
+ get_data(
+ DistHandle, Front, Size + 4 + Len,
+ lists:reverse(Iovec, [<<Len:32>>|Rear]))
+ end.
+
+%% De-packet and deliver received data to the VM from a queue
+%%
+deliver_data(DistHandle, Q) ->
+ case Q of
+ {[], Size, []} ->
+ Size = 0, % Assert
+ Q;
+ {[], Size, Rear} ->
+ [Bin|Front] = lists:reverse(Rear),
+ deliver_data(DistHandle, Front, Size, [], Bin);
+ {[Bin|Front], Size, Rear} ->
+ deliver_data(DistHandle, Front, Size, Rear, Bin)
+ end.
+%%
+deliver_data(DistHandle, Front, Size, Rear, Bin) ->
+ case Bin of
+ <<DataSizeA:32, DataA:DataSizeA/binary,
+ DataSizeB:32, DataB:DataSizeB/binary, Rest/binary>> ->
+ erlang:dist_ctrl_put_data(DistHandle, DataA),
+ erlang:dist_ctrl_put_data(DistHandle, DataB),
+ deliver_data(
+ DistHandle,
+ Front, Size - (4 + DataSizeA + 4 + DataSizeB), Rear,
+ Rest);
+ <<DataSize:32, Data:DataSize/binary, Rest/binary>> ->
+ erlang:dist_ctrl_put_data(DistHandle, Data),
+ deliver_data(DistHandle, Front, Size - (4 + DataSize), Rear, Rest);
+ <<DataSize:32, FirstData/binary>> ->
+ TotalSize = 4 + DataSize,
+ if
+ TotalSize =< Size ->
+ BinSize = byte_size(Bin),
+ {MoreData, Q} =
+ deq_iovec(
+ TotalSize - BinSize,
+ Front, Size - BinSize, Rear),
+ erlang:dist_ctrl_put_data(DistHandle, [FirstData|MoreData]),
+ deliver_data(DistHandle, Q);
+ true -> % Incomplete data
+ {[Bin|Front], Size, Rear}
+ end;
+ <<_/binary>> ->
+ BinSize = byte_size(Bin),
+ if
+ 4 =< Size -> % Fragmented header - extract a header bin
+ {RestHeader, {Front_1, _Size_1, Rear_1}} =
+ deq_iovec(4 - BinSize, Front, Size - BinSize, Rear),
+ Header = iolist_to_binary([Bin|RestHeader]),
+ deliver_data(DistHandle, Front_1, Size, Rear_1, Header);
+ true -> % Incomplete header
+ {[Bin|Front], Size, Rear}
+ end
+ end.
+
+%% -------------------------------------------------------------------------
+%% Encryption and decryption helpers
+
+encrypt_and_send_chunk(
+ #params{
+ socket = Socket, rekey_interval = Seq,
+ key = Key, iv = IV, hash_algorithm = HashAlgorithm} = Params,
+ Seq, Cleartext) ->
+ %%
+ KeyLen = byte_size(Key),
+ IVLen = byte_size(IV),
+ Chunk = <<IV_1:IVLen/binary, KeySalt:KeyLen/binary>> =
+ crypto:strong_rand_bytes(IVLen + KeyLen),
+ ok = gen_tcp:send(Socket, encrypt_chunk(Params, Seq, [?REKEY_CHUNK, Chunk])),
+ Key_1 = hash_key(HashAlgorithm, Key, KeySalt),
+ Params_1 = Params#params{key = Key_1, iv = IV_1},
+ ok = gen_tcp:send(Socket, encrypt_chunk(Params_1, 0, Cleartext)),
+ {Params_1, 1};
+encrypt_and_send_chunk(#params{socket = Socket} = Params, Seq, Cleartext) ->
+ ok = gen_tcp:send(Socket, encrypt_chunk(Params, Seq, Cleartext)),
+ {Params, Seq + 1}.
+
+encrypt_chunk(
+ #params{
+ block_crypto = BlockCrypto,
+ iv = IV, key = Key, tag_len = TagLen}, Seq, Cleartext) ->
+ %%
+ ChunkLen = iolist_size(Cleartext) + TagLen,
+ AAD = <<Seq:32, ChunkLen:32>>,
+ {Ciphertext, CipherTag} =
+ crypto:block_encrypt(
+ crypto_cipher_name(BlockCrypto), Key, IV, {AAD, Cleartext, TagLen}),
+ Chunk = [Ciphertext,CipherTag],
+ Chunk.
+
+decrypt_chunk(
+ #params{
+ block_crypto = BlockCrypto,
+ iv = IV, key = Key, tag_len = TagLen} = Params, Seq, Chunk) ->
+ %%
+ ChunkLen = byte_size(Chunk),
+ true = TagLen =< ChunkLen, % Assert
+ AAD = <<Seq:32, ChunkLen:32>>,
+ CiphertextLen = ChunkLen - TagLen,
+ <<Ciphertext:CiphertextLen/binary, CipherTag:TagLen/binary>> = Chunk,
+ block_decrypt(
+ Params, Seq, crypto_cipher_name(BlockCrypto),
+ Key, IV, {AAD, Ciphertext, CipherTag}).
+
+block_decrypt(
+ #params{rekey_interval = Seq} = Params, Seq, CipherName, Key, IV, Data) ->
+ %%
+ KeyLen = byte_size(Key),
+ IVLen = byte_size(IV),
+ case crypto:block_decrypt(CipherName, Key, IV, Data) of
+ <<?REKEY_CHUNK, IV_1:IVLen/binary, KeySalt:KeyLen/binary>> ->
+ Key_1 = hash_key(Params#params.hash_algorithm, Key, KeySalt),
+ Params#params{iv = IV_1, key = Key_1};
+ _ ->
+ error(decrypt_error)
+ end;
+block_decrypt(_Params, _Seq, CipherName, Key, IV, Data) ->
+ crypto:block_decrypt(CipherName, Key, IV, Data).
+
+%% -------------------------------------------------------------------------
+%% Queue of binaries i.e an iovec queue
+
+empty_q() ->
+ {[], 0, []}.
+
+enq_binary(Bin, {Front, Size, Rear}) ->
+ {Front, Size + byte_size(Bin), [Bin|Rear]}.
+
+deq_iovec(GetSize, {Front, Size, Rear}) when GetSize =< Size ->
+ deq_iovec(GetSize, Front, Size, Rear, []).
+%%
+deq_iovec(GetSize, Front, Size, Rear) ->
+ deq_iovec(GetSize, Front, Size, Rear, []).
+%%
+deq_iovec(GetSize, [], Size, Rear, Acc) ->
+ deq_iovec(GetSize, lists:reverse(Rear), Size, [], Acc);
+deq_iovec(GetSize, [Bin|Front], Size, Rear, Acc) ->
+ BinSize = byte_size(Bin),
+ if
+ BinSize < GetSize ->
+ deq_iovec(
+ GetSize - BinSize, Front, Size - BinSize, Rear, [Bin|Acc]);
+ GetSize < BinSize ->
+ {Bin1,Bin2} = erlang:split_binary(Bin, GetSize),
+ {lists:reverse(Acc, [Bin1]), {[Bin2|Front], Size - GetSize, Rear}};
+ true ->
+ {lists:reverse(Acc, [Bin]), {Front, Size - BinSize, Rear}}
+ end.
+
+%% -------------------------------------------------------------------------
+
+%% Trace point
+trace(Term) -> Term.
+
+%% Keep an eye on this Pid (debug)
+monitor_dist_proc(Pid) ->
+%%% spawn(
+%%% fun () ->
+%%% MRef = erlang:monitor(process, Pid),
+%%% receive
+%%% {'DOWN', MRef, _, _, normal} ->
+%%% error_logger:error_report(
+%%% [dist_proc_died,
+%%% {reason, normal},
+%%% {pid, Pid}]);
+%%% {'DOWN', MRef, _, _, Reason} ->
+%%% error_logger:info_report(
+%%% [dist_proc_died,
+%%% {reason, Reason},
+%%% {pid, Pid}])
+%%% end
+%%% end),
+ Pid.
+
+dbg() ->
+ dbg:stop(),
+ dbg:tracer(),
+ dbg:p(all, c),
+ dbg:tpl(?MODULE, cx),
+ dbg:tpl(erlang, dist_ctrl_get_data_notification, cx),
+ dbg:tpl(erlang, dist_ctrl_get_data, cx),
+ dbg:tpl(erlang, dist_ctrl_put_data, cx),
+ ok.
diff --git a/lib/ssl/test/ssl.spec b/lib/ssl/test/ssl.spec
index 24272327c3..15587abecd 100644
--- a/lib/ssl/test/ssl.spec
+++ b/lib/ssl/test/ssl.spec
@@ -6,5 +6,7 @@
{skip_groups,dir,ssl_bench_SUITE,payload,"Benchmarks run separately"}.
{skip_groups,dir,ssl_bench_SUITE,pem_cache,"Benchmarks run separately"}.
{skip_groups,dir,ssl_dist_bench_SUITE,setup,"Benchmarks run separately"}.
+{skip_groups,dir,ssl_dist_bench_SUITE,roundtrip,"Benchmarks run separately"}.
{skip_groups,dir,ssl_dist_bench_SUITE,throughput,"Benchmarks run separately"}.
+{skip_groups,dir,ssl_dist_bench_SUITE,sched_utilization,"Benchmarks run separately"}.
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index 6c536816aa..7b98209b31 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -76,11 +76,9 @@ groups() ->
{'sslv3', [], all_versions_groups() ++ tls_versions_groups() ++ rizzo_tests() ++ [tls_ciphersuite_vs_version]},
{api,[], api_tests()},
{api_tls,[], api_tests_tls()},
- {tls_ciphers,[], tls_cipher_tests()},
{session, [], session_tests()},
{renegotiate, [], renegotiate_tests()},
{ciphers, [], cipher_tests()},
- {ciphers_ec, [], cipher_tests_ec()},
{error_handling_tests, [], error_handling_tests()},
{error_handling_tests_tls, [], error_handling_tests_tls()}
].
@@ -88,14 +86,12 @@ groups() ->
tls_versions_groups ()->
[
{group, api_tls},
- {group, tls_ciphers},
{group, error_handling_tests_tls}].
all_versions_groups ()->
[{group, api},
{group, renegotiate},
{group, ciphers},
- {group, ciphers_ec},
{group, error_handling_tests}].
@@ -211,38 +207,11 @@ renegotiate_tests() ->
renegotiate_dos_mitigate_passive,
renegotiate_dos_mitigate_absolute].
-tls_cipher_tests() ->
- [rc4_rsa_cipher_suites,
- rc4_ecdh_rsa_cipher_suites,
- rc4_ecdsa_cipher_suites].
-
cipher_tests() ->
[old_cipher_suites,
- cipher_suites_mix,
- %%ciphers_rsa_signed_certs,
- %%ciphers_rsa_signed_certs_openssl_names,
- %%ciphers_dsa_signed_certs,
- %%ciphers_dsa_signed_certs_openssl_names,
- chacha_rsa_cipher_suites,
- chacha_ecdsa_cipher_suites,
- %%anonymous_cipher_suites,
- %%psk_cipher_suites,
- %%psk_with_hint_cipher_suites,
- %%psk_anon_cipher_suites,
- %%psk_anon_with_hint_cipher_suites,
- %%srp_cipher_suites,
- %%srp_anon_cipher_suites,
- %%srp_dsa_cipher_suites,
- %%des_rsa_cipher_suites,
- %%des_ecdh_rsa_cipher_suites,
+ cipher_suites_mix,
default_reject_anonymous].
-cipher_tests_ec() ->
- [ciphers_ecdsa_signed_certs,
- ciphers_ecdsa_signed_certs_openssl_names,
- ciphers_ecdh_rsa_signed_certs,
- ciphers_ecdh_rsa_signed_certs_openssl_names].
-
error_handling_tests()->
[close_transport_accept,
recv_active,
@@ -410,26 +379,7 @@ init_per_testcase(TestCase, Config) when TestCase == client_renegotiate;
ct:timetrap({seconds, ?SEC_RENEGOTIATION_TIMEOUT + 5}),
Config;
-init_per_testcase(TestCase, Config) when TestCase == psk_cipher_suites;
- TestCase == psk_with_hint_cipher_suites;
- TestCase == ciphers_rsa_signed_certs;
- TestCase == ciphers_rsa_signed_certs_openssl_names;
- TestCase == ciphers_ecdh_rsa_signed_certs_openssl_names;
- TestCase == ciphers_ecdh_rsa_signed_certs;
- TestCase == ciphers_dsa_signed_certs;
- TestCase == ciphers_dsa_signed_certs_openssl_names;
- TestCase == anonymous_cipher_suites;
- TestCase == ciphers_ecdsa_signed_certs;
- TestCase == ciphers_ecdsa_signed_certs_openssl_names;
- TestCase == anonymous_cipher_suites;
- TestCase == psk_anon_cipher_suites;
- TestCase == psk_anon_with_hint_cipher_suites;
- TestCase == srp_cipher_suites;
- TestCase == srp_anon_cipher_suites;
- TestCase == srp_dsa_cipher_suites;
- TestCase == des_rsa_cipher_suites;
- TestCase == des_ecdh_rsa_cipher_suites;
- TestCase == versions_option;
+init_per_testcase(TestCase, Config) when TestCase == versions_option;
TestCase == tls_tcp_connect_big ->
ssl_test_lib:ct_log_supported_protocol_versions(Config),
ct:timetrap({seconds, 60}),
@@ -2709,144 +2659,6 @@ tls_shutdown_error(Config) when is_list(Config) ->
ok = ssl:close(Listen),
{error, closed} = ssl:shutdown(Listen, read_write).
-%%-------------------------------------------------------------------
-ciphers_rsa_signed_certs() ->
- [{doc,"Test all rsa ssl cipher suites in highest support ssl/tls version"}].
-
-ciphers_rsa_signed_certs(Config) when is_list(Config) ->
- Ciphers = ssl_test_lib:rsa_suites(crypto),
- run_suites(Ciphers, Config, rsa).
-%%-------------------------------------------------------------------
-ciphers_rsa_signed_certs_openssl_names() ->
- [{doc,"Test all rsa ssl cipher suites in highest support ssl/tls version"}].
-
-ciphers_rsa_signed_certs_openssl_names(Config) when is_list(Config) ->
- Ciphers = ssl_test_lib:openssl_rsa_suites(),
- run_suites(Ciphers, Config, rsa).
-
-%%-------------------------------------------------------------------
-ciphers_dsa_signed_certs() ->
- [{doc,"Test all dsa ssl cipher suites in highest support ssl/tls version"}].
-
-ciphers_dsa_signed_certs(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:dsa_suites(NVersion),
- run_suites(Ciphers, Config, dsa).
-%%-------------------------------------------------------------------
-ciphers_dsa_signed_certs_openssl_names() ->
- [{doc,"Test all dsa ssl cipher suites in highest support ssl/tls version"}].
-
-ciphers_dsa_signed_certs_openssl_names(Config) when is_list(Config) ->
- Ciphers = ssl_test_lib:openssl_dsa_suites(),
- run_suites(Ciphers, Config, dsa).
-
-%%-------------------------------------------------------------------
-chacha_rsa_cipher_suites()->
- [{doc,"Test the cacha with ECDSA signed certs ciphersuites"}].
-chacha_rsa_cipher_suites(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = [S || {KeyEx,_,_} = S <- ssl_test_lib:chacha_suites(NVersion),
- KeyEx == ecdhe_rsa, KeyEx == dhe_rsa],
- run_suites(Ciphers, Config, chacha_ecdsa).
-
-%%-------------------------------------------------------------------
-chacha_ecdsa_cipher_suites()->
- [{doc,"Test the cacha with ECDSA signed certs ciphersuites"}].
-chacha_ecdsa_cipher_suites(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = [S || {ecdhe_ecdsa,_,_} = S <- ssl_test_lib:chacha_suites(NVersion)],
- run_suites(Ciphers, Config, chacha_rsa).
-%%-----------------------------------------------------------------
-anonymous_cipher_suites()->
- [{doc,"Test the anonymous ciphersuites"}].
-anonymous_cipher_suites(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:ecdh_dh_anonymous_suites(NVersion),
- run_suites(Ciphers, Config, anonymous).
-%%-------------------------------------------------------------------
-psk_cipher_suites() ->
- [{doc, "Test the PSK ciphersuites WITHOUT server supplied identity hint"}].
-psk_cipher_suites(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:psk_suites(NVersion),
- run_suites(Ciphers, Config, psk).
-%%-------------------------------------------------------------------
-psk_with_hint_cipher_suites()->
- [{doc, "Test the PSK ciphersuites WITH server supplied identity hint"}].
-psk_with_hint_cipher_suites(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:psk_suites(NVersion),
- run_suites(Ciphers, Config, psk_with_hint).
-%%-------------------------------------------------------------------
-psk_anon_cipher_suites() ->
- [{doc, "Test the anonymous PSK ciphersuites WITHOUT server supplied identity hint"}].
-psk_anon_cipher_suites(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:psk_anon_suites(NVersion),
- run_suites(Ciphers, Config, psk_anon).
-%%-------------------------------------------------------------------
-psk_anon_with_hint_cipher_suites()->
- [{doc, "Test the anonymous PSK ciphersuites WITH server supplied identity hint"}].
-psk_anon_with_hint_cipher_suites(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:psk_anon_suites(NVersion),
- run_suites(Ciphers, Config, psk_anon_with_hint).
-%%-------------------------------------------------------------------
-srp_cipher_suites()->
- [{doc, "Test the SRP ciphersuites"}].
-srp_cipher_suites(Config) when is_list(Config) ->
- Ciphers = ssl_test_lib:srp_suites(),
- run_suites(Ciphers, Config, srp).
-%%-------------------------------------------------------------------
-srp_anon_cipher_suites()->
- [{doc, "Test the anonymous SRP ciphersuites"}].
-srp_anon_cipher_suites(Config) when is_list(Config) ->
- Ciphers = ssl_test_lib:srp_anon_suites(),
- run_suites(Ciphers, Config, srp_anon).
-%%-------------------------------------------------------------------
-srp_dsa_cipher_suites()->
- [{doc, "Test the SRP DSA ciphersuites"}].
-srp_dsa_cipher_suites(Config) when is_list(Config) ->
- Ciphers = ssl_test_lib:srp_dss_suites(),
- run_suites(Ciphers, Config, srp_dsa).
-%%-------------------------------------------------------------------
-rc4_rsa_cipher_suites()->
- [{doc, "Test the RC4 ciphersuites"}].
-rc4_rsa_cipher_suites(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = [S || {rsa,_,_} = S <- ssl_test_lib:rc4_suites(NVersion)],
- run_suites(Ciphers, Config, rc4_rsa).
-%-------------------------------------------------------------------
-rc4_ecdh_rsa_cipher_suites()->
- [{doc, "Test the RC4 ciphersuites"}].
-rc4_ecdh_rsa_cipher_suites(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = [S || {ecdh_rsa,_,_} = S <- ssl_test_lib:rc4_suites(NVersion)],
- run_suites(Ciphers, Config, rc4_ecdh_rsa).
-
-%%-------------------------------------------------------------------
-rc4_ecdsa_cipher_suites()->
- [{doc, "Test the RC4 ciphersuites"}].
-rc4_ecdsa_cipher_suites(Config) when is_list(Config) ->
- NVersion = tls_record:highest_protocol_version([]),
- Ciphers = [S || {ecdhe_ecdsa,_,_} = S <- ssl_test_lib:rc4_suites(NVersion)],
- run_suites(Ciphers, Config, rc4_ecdsa).
-
-%%-------------------------------------------------------------------
-des_rsa_cipher_suites()->
- [{doc, "Test the des_rsa ciphersuites"}].
-des_rsa_cipher_suites(Config) when is_list(Config) ->
- NVersion = tls_record:highest_protocol_version([]),
- Ciphers = [S || {rsa,_,_} = S <- ssl_test_lib:des_suites(NVersion)],
- run_suites(Ciphers, Config, des_rsa).
-%-------------------------------------------------------------------
-des_ecdh_rsa_cipher_suites()->
- [{doc, "Test ECDH rsa signed ciphersuites"}].
-des_ecdh_rsa_cipher_suites(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = [S || {dhe_rsa,_,_} = S <- ssl_test_lib:des_suites(NVersion)],
- run_suites(Ciphers, Config, des_dhe_rsa).
-
%%--------------------------------------------------------------------
default_reject_anonymous()->
[{doc,"Test that by default anonymous cipher suites are rejected "}].
@@ -2873,36 +2685,6 @@ default_reject_anonymous(Config) when is_list(Config) ->
ssl_test_lib:check_server_alert(Server, Client, insufficient_security).
%%--------------------------------------------------------------------
-ciphers_ecdsa_signed_certs() ->
- [{doc, "Test all ecdsa ssl cipher suites in highest support ssl/tls version"}].
-
-ciphers_ecdsa_signed_certs(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:ecdsa_suites(NVersion),
- run_suites(Ciphers, Config, ecdsa).
-%%--------------------------------------------------------------------
-ciphers_ecdsa_signed_certs_openssl_names() ->
- [{doc, "Test all ecdsa ssl cipher suites in highest support ssl/tls version"}].
-
-ciphers_ecdsa_signed_certs_openssl_names(Config) when is_list(Config) ->
- Ciphers = ssl_test_lib:openssl_ecdsa_suites(),
- run_suites(Ciphers, Config, ecdsa).
-%%--------------------------------------------------------------------
-ciphers_ecdh_rsa_signed_certs() ->
- [{doc, "Test all ecdh_rsa ssl cipher suites in highest support ssl/tls version"}].
-
-ciphers_ecdh_rsa_signed_certs(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:ecdh_rsa_suites(NVersion),
- run_suites(Ciphers, Config, ecdh_rsa).
-%%--------------------------------------------------------------------
-ciphers_ecdh_rsa_signed_certs_openssl_names() ->
- [{doc, "Test all ecdh_rsa ssl cipher suites in highest support ssl/tls version"}].
-
-ciphers_ecdh_rsa_signed_certs_openssl_names(Config) when is_list(Config) ->
- Ciphers = ssl_test_lib:openssl_ecdh_rsa_suites(),
- run_suites(Ciphers, Config, ecdh_rsa).
-%%--------------------------------------------------------------------
reuse_session() ->
[{doc,"Test reuse of sessions (short handshake)"}].
reuse_session(Config) when is_list(Config) ->
@@ -2993,8 +2775,8 @@ make_sure_expired(Host, Port, Id) ->
server_does_not_want_to_reuse_session() ->
[{doc,"Test reuse of sessions (short handshake)"}].
server_does_not_want_to_reuse_session(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server =
@@ -6356,147 +6138,6 @@ client_server_opts(#{key_exchange := KeyAlgo}, Config) when KeyAlgo == ecdh_rsa
{ssl_test_lib:ssl_options(client_opts, Config),
ssl_test_lib:ssl_options(server_ecdh_rsa_opts, Config)}.
-run_suites(Ciphers, Config, Type) ->
- Version = ssl_test_lib:protocol_version(Config),
- ct:log("Running cipher suites ~p~n", [Ciphers]),
- {ClientOpts, ServerOpts} =
- case Type of
- rsa ->
- {ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_rsa_opts, Config)]};
- dsa ->
- {ssl_test_lib:ssl_options(client_dsa_verify_opts, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_dsa_opts, Config)]};
- anonymous ->
- %% No certs in opts!
- {ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options([], Config)]};
- psk ->
- {ssl_test_lib:ssl_options(client_psk, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_psk, Config)]};
- psk_with_hint ->
- {ssl_test_lib:ssl_options(client_psk, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_psk_hint, Config)
- ]};
- psk_anon ->
- {ssl_test_lib:ssl_options(client_psk, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_psk_anon, Config)]};
- psk_anon_with_hint ->
- {ssl_test_lib:ssl_options(client_psk, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_psk_anon_hint, Config)]};
- srp ->
- {ssl_test_lib:ssl_options(client_srp, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_srp, Config)]};
- srp_anon ->
- {ssl_test_lib:ssl_options(client_srp, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_srp_anon, Config)]};
- srp_dsa ->
- {ssl_test_lib:ssl_options(client_srp_dsa, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_srp_dsa, Config)]};
- ecdsa ->
- {ssl_test_lib:ssl_options(client_ecdsa_opts, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_ecdsa_opts, Config)]};
- ecdh_rsa ->
- {ssl_test_lib:ssl_options(client_ecdh_rsa_opts, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_ecdh_rsa_opts, Config)]};
- rc4_rsa ->
- {ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_rsa_verify_opts, Config)]};
- rc4_ecdh_rsa ->
- {ssl_test_lib:ssl_options(client_ecdh_rsa_opts, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_ecdh_rsa_opts, Config)]};
- rc4_ecdsa ->
- {ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_ecdsa_opts, Config)]};
- des_dhe_rsa ->
- {ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_verification_opts, Config)]};
- des_rsa ->
- {ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_rsa_verify_opts, Config)]};
- chacha_rsa ->
- {ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_rsa_verify_opts, Config)]};
- chacha_ecdsa ->
- {ssl_test_lib:ssl_options(client_ecdsa_opts, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_ecdsa_opts, Config)]}
- end,
- Suites = ssl_test_lib:filter_suites(Ciphers, Version),
- ct:pal("ssl_test_lib:filter_suites(~p ~p) -> ~p ", [Ciphers, Version, Suites]),
- Results0 = lists:map(fun(Cipher) ->
- cipher(Cipher, Version, Config, ClientOpts, ServerOpts) end,
- ssl_test_lib:filter_suites(Ciphers, Version)),
- Results = lists:flatten(Results0),
- true = length(Results) == length(Suites),
- check_cipher_result(Results).
-
-check_cipher_result([]) ->
- ok;
-check_cipher_result([ok | Rest]) ->
- check_cipher_result(Rest);
-check_cipher_result([_ |_] = Error) ->
- ct:fail(Error).
-
-erlang_cipher_suite(Suite) when is_list(Suite)->
- ssl_cipher_format:suite_definition(ssl_cipher_format:openssl_suite(Suite));
-erlang_cipher_suite(Suite) ->
- Suite.
-
-cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
- %% process_flag(trap_exit, true),
- ct:log("Testing CipherSuite ~p~n", [CipherSuite]),
- ct:log("Server Opts ~p~n", [ServerOpts]),
- ct:log("Client Opts ~p~n", [ClientOpts]),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- ErlangCipherSuite = erlang_cipher_suite(CipherSuite),
-
- ConnectionInfo = {ok, {Version, ErlangCipherSuite}},
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, cipher_result, [ConnectionInfo]}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, cipher_result, [ConnectionInfo]}},
- {options,
- [{ciphers,[CipherSuite]} |
- ClientOpts]}]),
-
- Result = ssl_test_lib:wait_for_result(Server, ok, Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client),
-
- case Result of
- ok ->
- [ok];
- Error ->
- [{ErlangCipherSuite, Error}]
- end.
-
connection_information_result(Socket) ->
{ok, Info = [_ | _]} = ssl:connection_information(Socket),
case length(Info) > 3 of
diff --git a/lib/ssl/test/ssl_cipher_suite_SUITE.erl b/lib/ssl/test/ssl_cipher_suite_SUITE.erl
index 6a2be0e267..bf1bc0e752 100644
--- a/lib/ssl/test/ssl_cipher_suite_SUITE.erl
+++ b/lib/ssl/test/ssl_cipher_suite_SUITE.erl
@@ -50,25 +50,29 @@ groups() ->
{'dtlsv1', [], kex()},
{dhe_rsa, [],[dhe_rsa_3des_ede_cbc,
dhe_rsa_aes_128_cbc,
- dhe_rsa_aes_256_cbc
+ dhe_rsa_aes_256_cbc,
+ dhe_rsa_chacha20_poly1305
]},
{ecdhe_rsa, [], [ecdhe_rsa_3des_ede_cbc,
ecdhe_rsa_aes_128_cbc,
ecdhe_rsa_aes_128_gcm,
ecdhe_rsa_aes_256_cbc,
- ecdhe_rsa_aes_256_gcm
+ ecdhe_rsa_aes_256_gcm,
+ ecdhe_rsa_chacha20_poly1305
]},
{ecdhe_ecdsa, [],[ecdhe_ecdsa_rc4_128,
ecdhe_ecdsa_3des_ede_cbc,
ecdhe_ecdsa_aes_128_cbc,
ecdhe_ecdsa_aes_128_gcm,
ecdhe_ecdsa_aes_256_cbc,
- ecdhe_ecdsa_aes_256_gcm
+ ecdhe_ecdsa_aes_256_gcm,
+ ecdhe_ecdsa_chacha20_poly1305
]},
{rsa, [], [rsa_3des_ede_cbc,
rsa_aes_128_cbc,
rsa_aes_256_cbc,
- rsa_rc4_128]},
+ rsa_rc4_128
+ ]},
{dhe_dss, [], [dhe_dss_3des_ede_cbc,
dhe_dss_aes_128_cbc,
dhe_dss_aes_256_cbc]},
@@ -81,11 +85,7 @@ groups() ->
{rsa_psk, [], [rsa_psk_3des_ede_cbc,
rsa_psk_rc4_128,
rsa_psk_aes_128_cbc,
- %% rsa_psk_aes_128_ccm,
- %% rsa_psk_aes_128_ccm_8,
rsa_psk_aes_256_cbc
- %% rsa_psk_aes_256_ccm,
- %% rsa_psk_aes_256_ccm_8
]},
{dh_anon, [], [dh_anon_rc4_128,
dh_anon_3des_ede_cbc,
@@ -97,26 +97,33 @@ groups() ->
ecdh_anon_aes_128_cbc,
ecdh_anon_aes_256_cbc
]},
- {srp, [], [srp_3des_ede_cbc,
- srp_aes_128_cbc,
- srp_aes_256_cbc]},
+ {srp_anon, [], [srp_anon_3des_ede_cbc,
+ srp_anon_aes_128_cbc,
+ srp_anon_aes_256_cbc]},
{psk, [], [psk_3des_ede_cbc,
psk_rc4_128,
psk_aes_128_cbc,
- %% psk_aes_128_ccm,
- %% psk_aes_128_ccm_8,
- psk_aes_256_cbc
- %% psk_aes_256_ccm,
- %% psk_aes_256_ccm_8
+ psk_aes_128_ccm,
+ psk_aes_128_ccm_8,
+ psk_aes_256_cbc,
+ psk_aes_256_ccm,
+ psk_aes_256_ccm_8
]},
{dhe_psk, [], [dhe_psk_3des_ede_cbc,
dhe_psk_rc4_128,
dhe_psk_aes_128_cbc,
- %% dhe_psk_aes_128_ccm,
- %% dhe_psk_aes_128_ccm_8,
- dhe_psk_aes_256_cbc
- %% dhe_psk_aes_256_ccm,
- %% dhe_psk_aes_256_ccm_8
+ dhe_psk_aes_128_ccm,
+ dhe_psk_aes_128_ccm_8,
+ dhe_psk_aes_256_cbc,
+ dhe_psk_aes_256_ccm,
+ dhe_psk_aes_256_ccm_8
+ ]},
+ {ecdhe_psk, [], [ecdhe_psk_3des_ede_cbc,
+ ecdhe_psk_rc4_128,
+ ecdhe_psk_aes_128_cbc,
+ ecdhe_psk_aes_128_ccm,
+ ecdhe_psk_aes_128_ccm_8,
+ ecdhe_psk_aes_256_cbc
]}
].
@@ -144,7 +151,8 @@ anonymous() ->
{group, ecdh_anon},
{group, psk},
{group, dhe_psk},
- {group, srp}
+ {group, ecdhe_psk},
+ {group, srp_anon}
].
@@ -165,8 +173,16 @@ end_per_suite(_Config) ->
%%--------------------------------------------------------------------
init_per_group(GroupName, Config) when GroupName == ecdh_anon;
GroupName == ecdhe_rsa;
- GroupName == ecdhe_ecdsa ->
- case ssl_test_lib:sufficient_crypto_support(ec_cipher) of
+ GroupName == ecdhe_psk ->
+ case proplists:get_bool(ecdh, proplists:get_value(public_keys, crypto:supports())) of
+ true ->
+ init_certs(GroupName, Config);
+ false ->
+ {skip, "Missing EC crypto support"}
+ end;
+init_per_group(ecdhe_ecdsa = GroupName, Config) ->
+ PKAlg = proplists:get_value(public_keys, crypto:supports()),
+ case lists:member(ecdh, PKAlg) andalso lists:member(ecdsa, PKAlg) of
true ->
init_certs(GroupName, Config);
false ->
@@ -188,7 +204,7 @@ init_per_group(srp_dss = GroupName, Config) ->
false ->
{skip, "Missing DSS_SRP crypto support"}
end;
-init_per_group(GroupName, Config) when GroupName == srp;
+init_per_group(GroupName, Config) when GroupName == srp_anon;
GroupName == srp_rsa ->
PKAlg = proplists:get_value(public_keys, crypto:supports()),
case lists:member(srp, PKAlg) of
@@ -221,27 +237,30 @@ end_per_group(GroupName, Config) ->
Config
end.
init_per_testcase(TestCase, Config) when TestCase == psk_3des_ede_cbc;
- TestCase == srp_3des_ede_cbc;
+ TestCase == srp_anon_3des_ede_cbc;
TestCase == dhe_psk_3des_ede_cbc;
+ TestCase == ecdhe_psk_3des_ede_cbc;
TestCase == srp_rsa_3des_ede_cbc;
+ TestCase == srp_dss_3des_ede_cbc;
TestCase == rsa_psk_3des_ede_cbc;
TestCase == rsa_3des_ede_cbc;
TestCase == dhe_rsa_3des_ede_cbc;
TestCase == dhe_dss_3des_ede_cbc;
TestCase == ecdhe_rsa_3des_ede_cbc;
- TestCase == srp_dss_3des_ede_cbc;
+ TestCase == srp_anon_dss_3des_ede_cbc;
TestCase == dh_anon_3des_ede_cbc;
TestCase == ecdh_anon_3des_ede_cbc;
TestCase == ecdhe_ecdsa_3des_ede_cbc ->
SupCiphers = proplists:get_value(ciphers, crypto:supports()),
case lists:member(des_ede3, SupCiphers) of
true ->
- ct:timetrap({seconds, 2}),
+ ct:timetrap({seconds, 5}),
Config;
_ ->
{skip, "Missing 3DES crypto support"}
end;
init_per_testcase(TestCase, Config) when TestCase == psk_rc4_128;
+ TestCase == ecdhe_psk_rc4_128;
TestCase == dhe_psk_rc4_128;
TestCase == rsa_psk_rc4_128;
TestCase == rsa_rc4_128;
@@ -251,18 +270,44 @@ init_per_testcase(TestCase, Config) when TestCase == psk_rc4_128;
SupCiphers = proplists:get_value(ciphers, crypto:supports()),
case lists:member(rc4, SupCiphers) of
true ->
- ct:timetrap({seconds, 2}),
+ ct:timetrap({seconds, 5}),
Config;
_ ->
{skip, "Missing RC4 crypto support"}
end;
-init_per_testcase(TestCase, Config) ->
+init_per_testcase(TestCase, Config) when TestCase == psk_aes_128_ccm_8;
+ TestCase == rsa_psk_aes_128_ccm_8;
+ TestCase == psk_aes_128_ccm_8;
+ TestCase == dhe_psk_aes_128_ccm_8;
+ TestCase == ecdhe_psk_aes_128_ccm_8 ->
+ SupCiphers = proplists:get_value(ciphers, crypto:supports()),
+ case lists:member(aes_128_ccm, SupCiphers) of
+ true ->
+ ct:timetrap({seconds, 5}),
+ Config;
+ _ ->
+ {skip, "Missing AES_128_CCM crypto support"}
+ end;
+init_per_testcase(TestCase, Config) when TestCase == psk_aes_256_ccm_8;
+ TestCase == rsa_psk_aes_256_ccm_8;
+ TestCase == psk_aes_256_ccm_8;
+ TestCase == dhe_psk_aes_256_ccm_8;
+ TestCase == ecdhe_psk_aes_256_ccm_8 ->
+ SupCiphers = proplists:get_value(ciphers, crypto:supports()),
+ case lists:member(aes_256_ccm, SupCiphers) of
+ true ->
+ ct:timetrap({seconds, 5}),
+ Config;
+ _ ->
+ {skip, "Missing AES_256_CCM crypto support"}
+ end;
+init_per_testcase(TestCase, Config) ->
Cipher = test_cipher(TestCase, Config),
%%Reason = io_lib:format("Missing ~p crypto support", [Cipher]),
SupCiphers = proplists:get_value(ciphers, crypto:supports()),
case lists:member(Cipher, SupCiphers) of
true ->
- ct:timetrap({seconds, 2}),
+ ct:timetrap({seconds, 5}),
Config;
_ ->
{skip, {Cipher, SupCiphers}}
@@ -280,6 +325,10 @@ init_certs(srp_rsa, Config) ->
[{tls_config, #{server_config => [{user_lookup_fun, {fun user_lookup/3, undefined}} | ServerOpts],
client_config => [{srp_identity, {"Test-User", "secret"}} | ClientOpts]}} |
proplists:delete(tls_config, Config)];
+init_certs(srp_anon, Config) ->
+ [{tls_config, #{server_config => [{user_lookup_fun, {fun user_lookup/3, undefined}}],
+ client_config => [{srp_identity, {"Test-User", "secret"}}]}} |
+ proplists:delete(tls_config, Config)];
init_certs(rsa_psk, Config) ->
ClientExt = x509_test:extensions([{key_usage, [digitalSignature, keyEncipherment]}]),
{ClientOpts, ServerOpts} = ssl_test_lib:make_rsa_cert_chains([{server_chain,
@@ -337,7 +386,8 @@ init_certs(GroupName, Config) when GroupName == dhe_ecdsa;
client_config => ClientOpts}} |
proplists:delete(tls_config, Config)];
init_certs(GroupName, Config) when GroupName == psk;
- GroupName == dhe_psk ->
+ GroupName == dhe_psk;
+ GroupName == ecdhe_psk ->
PskSharedSecret = <<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15>>,
[{tls_config, #{server_config => [{user_lookup_fun, {fun user_lookup/3, PskSharedSecret}}],
client_config => [{psk_identity, "Test-User"},
@@ -443,7 +493,10 @@ dhe_rsa_aes_256_cbc(Config) when is_list(Config) ->
run_ciphers_test(dhe_rsa, 'aes_256_cbc', Config).
dhe_rsa_aes_256_gcm(Config) when is_list(Config) ->
- run_ciphers_test(dhe_rsa, 'aes_256_gcm', Config).
+ run_ciphers_test(dhe_rsa, 'aes_256_gcm', Config).
+
+dhe_rsa_chacha20_poly1305(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_rsa, 'chacha20_poly1305', Config).
%%--------------------------------------------------------------------
%% ECDHE_RSA --------------------------------------------------------
%%--------------------------------------------------------------------
@@ -464,6 +517,10 @@ ecdhe_rsa_aes_256_gcm(Config) when is_list(Config) ->
ecdhe_rsa_rc4_128(Config) when is_list(Config) ->
run_ciphers_test(ecdhe_rsa, 'rc4_128', Config).
+
+ecdhe_rsa_chacha20_poly1305(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_rsa, 'chacha20_poly1305', Config).
+
%%--------------------------------------------------------------------
%% ECDHE_ECDSA --------------------------------------------------------
%%--------------------------------------------------------------------
@@ -485,6 +542,8 @@ ecdhe_ecdsa_aes_256_cbc(Config) when is_list(Config) ->
ecdhe_ecdsa_aes_256_gcm(Config) when is_list(Config) ->
run_ciphers_test(ecdhe_ecdsa, 'aes_256_gcm', Config).
+ecdhe_ecdsa_chacha20_poly1305(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_ecdsa, 'chacha20_poly1305', Config).
%%--------------------------------------------------------------------
%% DHE_DSS --------------------------------------------------------
%%--------------------------------------------------------------------
@@ -536,14 +595,14 @@ ecdh_anon_aes_128_cbc(Config) when is_list(Config) ->
ecdh_anon_aes_256_cbc(Config) when is_list(Config) ->
run_ciphers_test(ecdh_anon, 'aes_256_cbc', Config).
-srp_3des_ede_cbc(Config) when is_list(Config) ->
- run_ciphers_test(srp, '3des_ede_cbc', Config).
+srp_anon_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_anon, '3des_ede_cbc', Config).
-srp_aes_128_cbc(Config) when is_list(Config) ->
- run_ciphers_test(srp, 'aes_128_cbc', Config).
+srp_anon_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_anon, 'aes_128_cbc', Config).
-srp_aes_256_cbc(Config) when is_list(Config) ->
- run_ciphers_test(srp, 'aes_256_cbc', Config).
+srp_anon_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_anon, 'aes_256_cbc', Config).
dhe_psk_des_cbc(Config) when is_list(Config) ->
run_ciphers_test(dhe_psk, 'des_cbc', Config).
@@ -578,6 +637,33 @@ dhe_psk_aes_128_ccm_8(Config) when is_list(Config) ->
dhe_psk_aes_256_ccm_8(Config) when is_list(Config) ->
run_ciphers_test(dhe_psk, 'aes_256_ccm_8', Config).
+ecdhe_psk_des_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'des_cbc', Config).
+
+ecdhe_psk_rc4_128(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'rc4_128', Config).
+
+ecdhe_psk_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, '3des_ede_cbc', Config).
+
+ecdhe_psk_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'aes_128_cbc', Config).
+
+ecdhe_psk_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'aes_256_cbc', Config).
+
+ecdhe_psk_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'aes_128_gcm', Config).
+
+ecdhe_psk_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'aes_256_gcm', Config).
+
+ecdhe_psk_aes_128_ccm(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'aes_128_ccm', Config).
+
+ecdhe_psk_aes_128_ccm_8(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'aes_128_ccm_8', Config).
+
psk_des_cbc(Config) when is_list(Config) ->
run_ciphers_test(psk, 'des_cbc', Config).
@@ -654,9 +740,8 @@ cipher_suite_test(CipherSuite, Version, Config) ->
{host, Hostname},
{from, self()},
{mfa, {ssl_test_lib, cipher_result, [ConnectionInfo]}},
- {options,
- [{versions, [Version]}, {ciphers, [CipherSuite]} |
- ClientOpts]}]),
+ {options, [{versions, [Version]}, {ciphers, [CipherSuite]} |
+ ClientOpts]}]),
ssl_test_lib:check_result(Server, ok, Client, ok),
diff --git a/lib/ssl/test/ssl_dist_bench_SUITE.erl b/lib/ssl/test/ssl_dist_bench_SUITE.erl
index 7e7de5c9bf..1fea6f6f72 100644
--- a/lib/ssl/test/ssl_dist_bench_SUITE.erl
+++ b/lib/ssl/test/ssl_dist_bench_SUITE.erl
@@ -49,10 +49,14 @@
suite() -> [{ct_hooks, [{ts_install_cth, [{nodenames, 2}]}]}].
-all() -> [{group, ssl}, {group, plain}].
+all() ->
+ [{group, ssl},
+ {group, crypto},
+ {group, plain}].
groups() ->
[{ssl, all_groups()},
+ {crypto, all_groups()},
{plain, all_groups()},
%%
{setup, [{repeat, 1}], [setup]},
@@ -164,6 +168,17 @@ end_per_suite(Config) ->
init_per_group(ssl, Config) ->
[{ssl_dist, true}, {ssl_dist_prefix, "SSL"}|Config];
+init_per_group(crypto, Config) ->
+ case inet_crypto_dist:is_supported() of
+ true ->
+ [{ssl_dist, false}, {ssl_dist_prefix, "Crypto"},
+ {ssl_dist_args,
+ "-proto_dist inet_crypto "
+ "-inet_crypto '#{secret => \"123456\"}'"}
+ |Config];
+ false ->
+ {skip, "Not supported on this OTP version"}
+ end;
init_per_group(plain, Config) ->
[{ssl_dist, false}, {ssl_dist_prefix, "Plain"}|Config];
init_per_group(_GroupName, Config) ->
@@ -374,29 +389,46 @@ sched_utilization(A, B, Prefix, HA, HB, SSL) ->
[A] = ssl_apply(HB, erlang, nodes, []),
msacc:print(ClientMsacc),
msacc:print(ServerMsacc),
- ct:pal("Got ~p msgs",[length(Msgs)]),
- report(Prefix++" Sched Utilization Client",
- 10000 * msacc:stats(system_runtime,ClientMsacc) /
- msacc:stats(system_realtime,ClientMsacc), "util 0.01 %"),
- report(Prefix++" Sched Utilization Server",
- 10000 * msacc:stats(system_runtime,ServerMsacc) /
- msacc:stats(system_realtime,ServerMsacc), "util 0.01 %"),
- ok.
+ ct:pal("Got ~p busy_dist_port msgs",[length(Msgs)]),
+ ct:log("Stats of B from A: ~p",
+ [ssl_apply(HA, net_kernel, node_info, [B])]),
+ ct:log("Stats of A from B: ~p",
+ [ssl_apply(HB, net_kernel, node_info, [A])]),
+ SchedUtilClient =
+ round(10000 * msacc:stats(system_runtime,ClientMsacc) /
+ msacc:stats(system_realtime,ClientMsacc)),
+ SchedUtilServer =
+ round(10000 * msacc:stats(system_runtime,ServerMsacc) /
+ msacc:stats(system_realtime,ServerMsacc)),
+ Verdict =
+ case Msgs of
+ [] ->
+ "";
+ _ ->
+ " ???"
+ end,
+ {comment, ClientComment} =
+ report(Prefix ++ " Sched Utilization Client" ++ Verdict,
+ SchedUtilClient, "/100 %" ++ Verdict),
+ {comment, ServerComment} =
+ report(Prefix++" Sched Utilization Server" ++ Verdict,
+ SchedUtilServer, "/100 %" ++ Verdict),
+ {comment, "Client " ++ ClientComment ++ ", Server " ++ ServerComment}.
%% Runs on node A and spawns a server on node B
%% We want to avoid getting busy_dist_port as it hides the true SU usage
%% of the receiver and sender.
sched_util_runner(A, B, true) ->
- sched_util_runner(A, B, 50);
+ sched_util_runner(A, B, 250);
sched_util_runner(A, B, false) ->
sched_util_runner(A, B, 250);
sched_util_runner(A, B, Senders) ->
Payload = payload(5),
[A] = rpc:call(B, erlang, nodes, []),
- ServerPid =
- erlang:spawn(
- B,
- fun () -> throughput_server() end),
+ ServerPids =
+ [erlang:spawn_link(
+ B, fun () -> throughput_server() end)
+ || _ <- lists:seq(1, Senders)],
ServerMsacc =
erlang:spawn(
B,
@@ -404,24 +436,28 @@ sched_util_runner(A, B, Senders) ->
receive
{start,Pid} ->
msacc:start(10000),
- Pid ! {ServerPid,msacc:stats()}
+ receive
+ {done,Pid} ->
+ Pid ! {self(),msacc:stats()}
+ end
end
end),
- spawn_link(
- fun() ->
- %% We spawn 250 senders which should mean that we
- %% have a load of 250 msgs/msec
- [spawn_link(
- fun() ->
- throughput_client(ServerPid,Payload)
- end) || _ <- lists:seq(1, Senders)]
- end),
-
erlang:system_monitor(self(),[busy_dist_port]),
+ %% We spawn 250 senders which should mean that we
+ %% have a load of 250 msgs/msec
+ [spawn_link(
+ fun() ->
+ throughput_client(Pid, Payload)
+ end) || Pid <- ServerPids],
+ %%
+ receive after 1000 -> ok end,
ServerMsacc ! {start,self()},
msacc:start(10000),
ClientMsaccStats = msacc:stats(),
- ServerMsaccStats = receive {ServerPid,Stats} -> Stats end,
+ receive after 1000 -> ok end,
+ ServerMsacc ! {done,self()},
+ ServerMsaccStats = receive {ServerMsacc,Stats} -> Stats end,
+ %%
{ClientMsaccStats,ServerMsaccStats, flush()}.
flush() ->
@@ -522,15 +558,20 @@ throughput(A, B, Prefix, HA, HB, Packets, Size) ->
+ byte_size(erlang:term_to_binary([0|<<>>])), % Benchmark overhead
Bytes = Packets * (Size + Overhead),
io:format("~w bytes, ~.4g s~n", [Bytes,Time/1000000]),
+ SizeString = integer_to_list(Size),
ClientMsaccStats =:= undefined orelse
- io:format(
- "Sender core usage ratio: ~.4g ns/byte~n",
- [msacc:stats(system_runtime, ClientMsaccStats)*1000/Bytes]),
+ report(
+ Prefix ++ " Sender_RelativeCoreLoad_" ++ SizeString,
+ round(msacc:stats(system_runtime, ClientMsaccStats)
+ * 1000000 / Bytes),
+ "ps/byte"),
ServerMsaccStats =:= undefined orelse
begin
- io:format(
- "Receiver core usage ratio: ~.4g ns/byte~n",
- [msacc:stats(system_runtime, ServerMsaccStats)*1000/Bytes]),
+ report(
+ Prefix ++ " Receiver_RelativeCoreLoad_" ++ SizeString,
+ round(msacc:stats(system_runtime, ServerMsaccStats)
+ * 1000000 / Bytes),
+ "ps/byte"),
msacc:print(ServerMsaccStats)
end,
io:format("******* ClientProf:~n", []), prof_print(ClientProf),
@@ -538,7 +579,7 @@ throughput(A, B, Prefix, HA, HB, Packets, Size) ->
io:format("******* Server GC Before:~n~p~n", [Server_GC_Before]),
io:format("******* Server GC After:~n~p~n", [Server_GC_After]),
Speed = round((Bytes * 1000000) / (1024 * Time)),
- report(Prefix++" Throughput_"++integer_to_list(Size), Speed, "kB/s").
+ report(Prefix ++ " Throughput_" ++ SizeString, Speed, "kB/s").
%% Runs on node A and spawns a server on node B
throughput_runner(A, B, Rounds, Size) ->
@@ -546,11 +587,12 @@ throughput_runner(A, B, Rounds, Size) ->
[A] = rpc:call(B, erlang, nodes, []),
ClientPid = self(),
ServerPid =
- erlang:spawn(
+ erlang:spawn_opt(
B,
- fun () -> throughput_server(ClientPid, Rounds) end),
+ fun () -> throughput_server(ClientPid, Rounds) end,
+ [{message_queue_data, off_heap}]),
ServerMon = erlang:monitor(process, ServerPid),
- msacc:available() andalso
+ msacc_available() andalso
begin
msacc:stop(),
msacc:reset(),
@@ -562,7 +604,7 @@ throughput_runner(A, B, Rounds, Size) ->
throughput_client(ServerPid, ServerMon, Payload, Rounds),
prof_stop(),
MsaccStats =
- case msacc:available() of
+ case msacc_available() of
true ->
MStats = msacc:stats(),
msacc:stop(),
@@ -602,7 +644,7 @@ throughput_server(Pid, N) ->
GC_Before = get_server_gc_info(),
%% dbg:tracer(port, dbg:trace_port(file, "throughput_server_gc.log")),
%% dbg:p(TLSDistReceiver, garbage_collection),
- msacc:available() andalso
+ msacc_available() andalso
begin
msacc:stop(),
msacc:reset(),
@@ -615,7 +657,7 @@ throughput_server(Pid, N) ->
throughput_server_loop(_Pid, GC_Before, 0) ->
prof_stop(),
MsaccStats =
- case msacc:available() of
+ case msacc_available() of
true ->
msacc:stop(),
MStats = msacc:stats(),
@@ -632,8 +674,13 @@ throughput_server_loop(_Pid, GC_Before, 0) ->
server_gc_after => get_server_gc_info()});
throughput_server_loop(Pid, GC_Before, N) ->
receive
- {Pid, N, _} ->
- throughput_server_loop(Pid, GC_Before, N-1)
+ Msg ->
+ case Msg of
+ {Pid, N, _} ->
+ throughput_server_loop(Pid, GC_Before, N - 1);
+ Other ->
+ erlang:error({self(),?FUNCTION_NAME,Other})
+ end
end.
get_server_gc_info() ->
@@ -773,7 +820,7 @@ get_node_args(Tag, Config) ->
true ->
proplists:get_value(Tag, Config);
false ->
- ""
+ proplists:get_value(ssl_dist_args, Config, "")
end.
@@ -828,3 +875,6 @@ report(Name, Value, Unit) ->
term_to_string(Term) ->
unicode:characters_to_list(
io_lib:write(Term, [{encoding, unicode}])).
+
+msacc_available() ->
+ msacc:available().
diff --git a/lib/ssl/test/ssl_session_cache_SUITE.erl b/lib/ssl/test/ssl_session_cache_SUITE.erl
index 7f33fe3204..b71b15b028 100644
--- a/lib/ssl/test/ssl_session_cache_SUITE.erl
+++ b/lib/ssl/test/ssl_session_cache_SUITE.erl
@@ -186,7 +186,7 @@ session_cleanup() ->
session_cleanup(Config) when is_list(Config) ->
process_flag(trap_exit, true),
ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server =
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index f79f57fbd7..b8672f46ba 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -51,20 +51,20 @@ node_to_hostip(Node) ->
Address.
start_server(Args) ->
- Result = spawn_link(?MODULE, run_server, [Args]),
+ Node = proplists:get_value(node, Args),
+ Result = spawn_link(Node, ?MODULE, run_server, [Args]),
receive
{listen, up} ->
Result
end.
run_server(Opts) ->
- Node = proplists:get_value(node, Opts),
Port = proplists:get_value(port, Opts),
Options = proplists:get_value(options, Opts),
Pid = proplists:get_value(from, Opts),
Transport = proplists:get_value(transport, Opts, ssl),
ct:log("~p:~p~nssl:listen(~p, ~p)~n", [?MODULE,?LINE, Port, Options]),
- {ok, ListenSocket} = rpc:call(Node, Transport, listen, [Port, Options]),
+ {ok, ListenSocket} = Transport:listen(Port, Options),
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
run_server(ListenSocket, Opts).
@@ -90,13 +90,12 @@ do_run_server(_, ok = Result, Opts) ->
Pid = proplists:get_value(from, Opts),
Pid ! {self(), Result};
do_run_server(ListenSocket, AcceptSocket, Opts) ->
- Node = proplists:get_value(node, Opts),
Pid = proplists:get_value(from, Opts),
Transport = proplists:get_value(transport, Opts, ssl),
{Module, Function, Args} = proplists:get_value(mfa, Opts),
ct:log("~p:~p~nServer: apply(~p,~p,~p)~n",
[?MODULE,?LINE, Module, Function, [AcceptSocket | Args]]),
- case rpc:call(Node, Module, Function, [AcceptSocket | Args]) of
+ case apply(Module, Function, [AcceptSocket | Args]) of
no_result_msg ->
ok;
Msg ->
@@ -110,8 +109,8 @@ do_run_server(ListenSocket, AcceptSocket, Opts) ->
run_server(ListenSocket, [MFA | proplists:delete(mfa, Opts)]);
close ->
ct:log("~p:~p~nServer closing ~p ~n", [?MODULE,?LINE, self()]),
- Result = rpc:call(Node, Transport, close, [AcceptSocket], 500),
- Result1 = rpc:call(Node, Transport, close, [ListenSocket], 500),
+ Result = Transport:close(AcceptSocket),
+ Result1 = Transport:close(ListenSocket),
ct:log("~p:~p~nResult ~p : ~p ~n", [?MODULE,?LINE, Result, Result1]);
{ssl_closed, _} ->
ok
@@ -132,41 +131,37 @@ connect(#sslsocket{} = ListenSocket, Opts) ->
remove_close_msg(ReconnectTimes),
AcceptSocket
end;
-connect(ListenSocket, Opts) ->
- Node = proplists:get_value(node, Opts),
+connect(ListenSocket, _Opts) ->
ct:log("~p:~p~ngen_tcp:accept(~p)~n", [?MODULE,?LINE, ListenSocket]),
- {ok, AcceptSocket} = rpc:call(Node, gen_tcp, accept,
- [ListenSocket]),
+ {ok, AcceptSocket} = gen_tcp:accept(ListenSocket),
AcceptSocket.
connect(_, _, 0, AcceptSocket, _, _, _) ->
AcceptSocket;
connect(ListenSocket, Node, _N, _, Timeout, SslOpts, cancel) ->
ct:log("ssl:transport_accept(~p)~n", [ListenSocket]),
- {ok, AcceptSocket} = rpc:call(Node, ssl, transport_accept,
- [ListenSocket]),
+ {ok, AcceptSocket} = ssl:transport_accept(ListenSocket),
ct:log("~p:~p~nssl:handshake(~p,~p,~p)~n", [?MODULE,?LINE, AcceptSocket, SslOpts,Timeout]),
- case rpc:call(Node, ssl, handshake, [AcceptSocket, SslOpts, Timeout]) of
+ case ssl:handshake(AcceptSocket, SslOpts, Timeout) of
{ok, Socket0, Ext} ->
ct:log("Ext ~p:~n", [Ext]),
ct:log("~p:~p~nssl:handshake_cancel(~p)~n", [?MODULE,?LINE, Socket0]),
- rpc:call(Node, ssl, handshake_cancel, [Socket0]);
+ ssl:handshake_cancel(Socket0);
Result ->
ct:log("~p:~p~nssl:handshake@~p ret ~p",[?MODULE,?LINE, Node,Result]),
Result
end;
connect(ListenSocket, Node, N, _, Timeout, SslOpts, [_|_] =ContOpts) ->
ct:log("ssl:transport_accept(~p)~n", [ListenSocket]),
- {ok, AcceptSocket} = rpc:call(Node, ssl, transport_accept,
- [ListenSocket]),
+ {ok, AcceptSocket} = ssl:transport_accept(ListenSocket),
ct:log("~p:~p~nssl:handshake(~p,~p,~p)~n", [?MODULE,?LINE, AcceptSocket, SslOpts,Timeout]),
- case rpc:call(Node, ssl, handshake, [AcceptSocket, SslOpts, Timeout]) of
+ case ssl:handshake(AcceptSocket, SslOpts, Timeout) of
{ok, Socket0, Ext} ->
ct:log("Ext ~p:~n", [Ext]),
ct:log("~p:~p~nssl:handshake_continue(~p,~p,~p)~n", [?MODULE,?LINE, Socket0, ContOpts,Timeout]),
- case rpc:call(Node, ssl, handshake_continue, [Socket0, ContOpts, Timeout]) of
+ case ssl:handshake_continue(Socket0, ContOpts, Timeout) of
{ok, Socket} ->
connect(ListenSocket, Node, N-1, Socket, Timeout, SslOpts, ContOpts);
Error ->
@@ -179,35 +174,35 @@ connect(ListenSocket, Node, N, _, Timeout, SslOpts, [_|_] =ContOpts) ->
end;
connect(ListenSocket, Node, N, _, Timeout, [], ContOpts) ->
ct:log("ssl:transport_accept(~p)~n", [ListenSocket]),
- {ok, AcceptSocket} = rpc:call(Node, ssl, transport_accept,
- [ListenSocket]),
+ {ok, AcceptSocket} = ssl:transport_accept(ListenSocket),
ct:log("~p:~p~nssl:ssl_accept(~p, ~p)~n", [?MODULE,?LINE, AcceptSocket, Timeout]),
- case rpc:call(Node, ssl, ssl_accept, [AcceptSocket, Timeout]) of
- ok ->
- connect(ListenSocket, Node, N-1, AcceptSocket, Timeout, [], ContOpts);
+ case ssl:handshake(AcceptSocket, Timeout) of
+ {ok, Socket} ->
+ connect(ListenSocket, Node, N-1, Socket, Timeout, [], ContOpts);
Result ->
- ct:log("~p:~p~nssl:ssl_accept@~p ret ~p",[?MODULE,?LINE, Node,Result]),
+ ct:log("~p:~p~nssl:handshake@~p ret ~p",[?MODULE,?LINE, Node,Result]),
Result
end;
-connect(ListenSocket, Node, _, _, Timeout, Opts, _) ->
+connect(ListenSocket, _Node, _, _, Timeout, Opts, _) ->
ct:log("ssl:transport_accept(~p)~n", [ListenSocket]),
- {ok, AcceptSocket} = rpc:call(Node, ssl, transport_accept,
- [ListenSocket]),
- ct:log("ssl:ssl_accept(~p,~p, ~p)~n", [AcceptSocket, Opts, Timeout]),
- rpc:call(Node, ssl, ssl_accept, [AcceptSocket, Opts, Timeout]),
+ {ok, AcceptSocket} = ssl:transport_accept(ListenSocket),
+ ct:log("ssl:handshake(~p,~p, ~p)~n", [AcceptSocket, Opts, Timeout]),
+ ssl:handshake(AcceptSocket, Opts, Timeout),
AcceptSocket.
start_server_transport_abuse_socket(Args) ->
- Result = spawn_link(?MODULE, transport_accept_abuse, [Args]),
+ Node = proplists:get_value(node, Args),
+ Result = spawn_link(Node, ?MODULE, transport_accept_abuse, [Args]),
receive
{listen, up} ->
Result
end.
start_server_transport_control(Args) ->
- Result = spawn_link(?MODULE, transport_switch_control, [Args]),
+ Node = proplists:get_value(node, Args),
+ Result = spawn_link(Node, ?MODULE, transport_switch_control, [Args]),
receive
{listen, up} ->
Result
@@ -215,35 +210,31 @@ start_server_transport_control(Args) ->
transport_accept_abuse(Opts) ->
- Node = proplists:get_value(node, Opts),
Port = proplists:get_value(port, Opts),
Options = proplists:get_value(options, Opts),
Pid = proplists:get_value(from, Opts),
Transport = proplists:get_value(transport, Opts, ssl),
ct:log("~p:~p~nssl:listen(~p, ~p)~n", [?MODULE,?LINE, Port, Options]),
- {ok, ListenSocket} = rpc:call(Node, Transport, listen, [Port, Options]),
+ {ok, ListenSocket} = Transport:listen(Port, Options),
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
- {ok, AcceptSocket} = rpc:call(Node, ssl, transport_accept,
- [ListenSocket]),
- {error, _} = rpc:call(Node, ssl, connection_information, [AcceptSocket]),
- _ = rpc:call(Node, ssl, handshake, [AcceptSocket, infinity]),
+ {ok, AcceptSocket} = ssl:transport_accept(ListenSocket),
+ {error, _} = ssl:connection_information(AcceptSocket),
+ _ = ssl:handshake(AcceptSocket, infinity),
Pid ! {self(), ok}.
transport_switch_control(Opts) ->
- Node = proplists:get_value(node, Opts),
Port = proplists:get_value(port, Opts),
Options = proplists:get_value(options, Opts),
Pid = proplists:get_value(from, Opts),
Transport = proplists:get_value(transport, Opts, ssl),
ct:log("~p:~p~nssl:listen(~p, ~p)~n", [?MODULE,?LINE, Port, Options]),
- {ok, ListenSocket} = rpc:call(Node, Transport, listen, [Port, Options]),
+ {ok, ListenSocket} = Transport:listen(Port, Options),
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
- {ok, AcceptSocket} = rpc:call(Node, ssl, transport_accept,
- [ListenSocket]),
- ok = rpc:call(Node, ssl, controlling_process, [AcceptSocket, self()]),
+ {ok, AcceptSocket} = ssl:transport_accept(ListenSocket),
+ ok = ssl:controlling_process(AcceptSocket, self()),
Pid ! {self(), ok}.
@@ -256,7 +247,8 @@ remove_close_msg(ReconnectTimes) ->
end.
start_client(Args) ->
- Result = spawn_link(?MODULE, run_client_init, [lists:delete(return_socket, Args)]),
+ Node = proplists:get_value(node, Args),
+ Result = spawn_link(Node, ?MODULE, run_client_init, [lists:delete(return_socket, Args)]),
receive
{connected, Socket} ->
case lists:member(return_socket, Args) of
@@ -288,8 +280,8 @@ run_client(Opts) ->
client_cont_loop(Node, Host, Port, Pid, Transport, Options, ContOpts, Opts)
end.
-client_loop(Node, Host, Port, Pid, Transport, Options, Opts) ->
- case rpc:call(Node, Transport, connect, [Host, Port, Options]) of
+client_loop(_Node, Host, Port, Pid, Transport, Options, Opts) ->
+ case Transport:connect(Host, Port, Options) of
{ok, Socket} ->
Pid ! {connected, Socket},
ct:log("~p:~p~nClient: connected~n", [?MODULE,?LINE]),
@@ -299,7 +291,7 @@ client_loop(Node, Host, Port, Pid, Transport, Options, Opts) ->
{Module, Function, Args} = proplists:get_value(mfa, Opts),
ct:log("~p:~p~nClient: apply(~p,~p,~p)~n",
[?MODULE,?LINE, Module, Function, [Socket | Args]]),
- case rpc:call(Node, Module, Function, [Socket | Args]) of
+ case apply(Module, Function, [Socket | Args]) of
no_result_msg ->
ok;
Msg ->
@@ -309,7 +301,7 @@ client_loop(Node, Host, Port, Pid, Transport, Options, Opts) ->
receive
close ->
ct:log("~p:~p~nClient closing~n", [?MODULE,?LINE]),
- rpc:call(Node, Transport, close, [Socket]);
+ Transport:close(Socket);
{ssl_closed, Socket} ->
ok;
{gen_tcp, closed} ->
@@ -339,16 +331,13 @@ client_loop(Node, Host, Port, Pid, Transport, Options, Opts) ->
end;
{error, Reason} ->
ct:log("~p:~p~nClient: connection failed: ~p ~n", [?MODULE,?LINE, Reason]),
- Pid ! {connect_failed, Reason};
- {badrpc,BadRPC} ->
- ct:log("~p:~p~nBad rpc: ~p",[?MODULE,?LINE, BadRPC]),
- Pid ! {connect_failed, {badrpc,BadRPC}}
+ Pid ! {connect_failed, Reason}
end.
-client_cont_loop(Node, Host, Port, Pid, Transport, Options, cancel, _Opts) ->
- case rpc:call(Node, Transport, connect, [Host, Port, Options]) of
+client_cont_loop(_Node, Host, Port, Pid, Transport, Options, cancel, _Opts) ->
+ case Transport:connect(Host, Port, Options) of
{ok, Socket, _} ->
- Result = rpc:call(Node, Transport, handshake_cancel, [Socket]),
+ Result = Transport:handshake_cancel(Socket),
ct:log("~p:~p~nClient: Cancel: ~p ~n", [?MODULE,?LINE, Result]),
Pid ! {connect_failed, Result};
{error, Reason} ->
@@ -356,17 +345,17 @@ client_cont_loop(Node, Host, Port, Pid, Transport, Options, cancel, _Opts) ->
Pid ! {connect_failed, Reason}
end;
-client_cont_loop(Node, Host, Port, Pid, Transport, Options, ContOpts, Opts) ->
- case rpc:call(Node, Transport, connect, [Host, Port, Options]) of
+client_cont_loop(_Node, Host, Port, Pid, Transport, Options, ContOpts, Opts) ->
+ case Transport:connect(Host, Port, Options) of
{ok, Socket0, _} ->
ct:log("~p:~p~nClient: handshake_continue(~p, ~p, infinity) ~n", [?MODULE, ?LINE, Socket0, ContOpts]),
- case rpc:call(Node, Transport, handshake_continue, [Socket0, ContOpts]) of
+ case Transport:handshake_continue(Socket0, ContOpts) of
{ok, Socket} ->
Pid ! {connected, Socket},
{Module, Function, Args} = proplists:get_value(mfa, Opts),
ct:log("~p:~p~nClient: apply(~p,~p,~p)~n",
[?MODULE,?LINE, Module, Function, [Socket | Args]]),
- case rpc:call(Node, Module, Function, [Socket | Args]) of
+ case apply(Module, Function, [Socket | Args]) of
no_result_msg ->
ok;
Msg ->
@@ -896,14 +885,14 @@ make_ecdh_rsa_cert(Config) ->
end.
start_upgrade_server(Args) ->
- Result = spawn_link(?MODULE, run_upgrade_server, [Args]),
+ Node = proplists:get_value(node, Args),
+ Result = spawn_link(Node, ?MODULE, run_upgrade_server, [Args]),
receive
{listen, up} ->
Result
end.
run_upgrade_server(Opts) ->
- Node = proplists:get_value(node, Opts),
Port = proplists:get_value(port, Opts),
TimeOut = proplists:get_value(timeout, Opts, infinity),
TcpOptions = proplists:get_value(tcp_options, Opts),
@@ -911,43 +900,41 @@ run_upgrade_server(Opts) ->
Pid = proplists:get_value(from, Opts),
ct:log("~p:~p~ngen_tcp:listen(~p, ~p)~n", [?MODULE,?LINE, Port, TcpOptions]),
- {ok, ListenSocket} = rpc:call(Node, gen_tcp, listen, [Port, TcpOptions]),
+ {ok, ListenSocket} = gen_tcp:listen(Port, TcpOptions),
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
ct:log("~p:~p~ngen_tcp:accept(~p)~n", [?MODULE,?LINE, ListenSocket]),
- {ok, AcceptSocket} = rpc:call(Node, gen_tcp, accept, [ListenSocket]),
+ {ok, AcceptSocket} = gen_tcp:accept(ListenSocket),
try
{ok, SslAcceptSocket} = case TimeOut of
infinity ->
- ct:log("~p:~p~nssl:ssl_accept(~p, ~p)~n",
+ ct:log("~p:~p~nssl:handshake(~p, ~p)~n",
[?MODULE,?LINE, AcceptSocket, SslOptions]),
- rpc:call(Node, ssl, ssl_accept,
- [AcceptSocket, SslOptions]);
+ ssl:handshake(AcceptSocket, SslOptions);
_ ->
- ct:log("~p:~p~nssl:ssl_accept(~p, ~p, ~p)~n",
+ ct:log("~p:~p~nssl:handshake(~p, ~p, ~p)~n",
[?MODULE,?LINE, AcceptSocket, SslOptions, TimeOut]),
- rpc:call(Node, ssl, ssl_accept,
- [AcceptSocket, SslOptions, TimeOut])
+ ssl:handshake(AcceptSocket, SslOptions, TimeOut)
end,
{Module, Function, Args} = proplists:get_value(mfa, Opts),
- Msg = rpc:call(Node, Module, Function, [SslAcceptSocket | Args]),
+ Msg = apply(Module, Function, [SslAcceptSocket | Args]),
ct:log("~p:~p~nUpgrade Server Msg: ~p ~n", [?MODULE,?LINE, Msg]),
Pid ! {self(), Msg},
receive
close ->
ct:log("~p:~p~nUpgrade Server closing~n", [?MODULE,?LINE]),
- rpc:call(Node, ssl, close, [SslAcceptSocket])
+ ssl:close(SslAcceptSocket)
end
catch error:{badmatch, Error} ->
Pid ! {self(), Error}
end.
start_upgrade_client(Args) ->
- spawn_link(?MODULE, run_upgrade_client, [Args]).
+ Node = proplists:get_value(node, Args),
+ spawn_link(Node, ?MODULE, run_upgrade_client, [Args]).
run_upgrade_client(Opts) ->
- Node = proplists:get_value(node, Opts),
Host = proplists:get_value(host, Opts),
Port = proplists:get_value(port, Opts),
Pid = proplists:get_value(from, Opts),
@@ -956,34 +943,34 @@ run_upgrade_client(Opts) ->
ct:log("~p:~p~ngen_tcp:connect(~p, ~p, ~p)~n",
[?MODULE,?LINE, Host, Port, TcpOptions]),
- {ok, Socket} = rpc:call(Node, gen_tcp, connect, [Host, Port, TcpOptions]),
+ {ok, Socket} = gen_tcp:connect(Host, Port, TcpOptions),
send_selected_port(Pid, Port, Socket),
ct:log("~p:~p~nssl:connect(~p, ~p)~n", [?MODULE,?LINE, Socket, SslOptions]),
- {ok, SslSocket} = rpc:call(Node, ssl, connect, [Socket, SslOptions]),
+ {ok, SslSocket} = ssl:connect(Socket, SslOptions),
{Module, Function, Args} = proplists:get_value(mfa, Opts),
ct:log("~p:~p~napply(~p, ~p, ~p)~n",
[?MODULE,?LINE, Module, Function, [SslSocket | Args]]),
- Msg = rpc:call(Node, Module, Function, [SslSocket | Args]),
+ Msg = apply(Module, Function, [SslSocket | Args]),
ct:log("~p:~p~nUpgrade Client Msg: ~p ~n", [?MODULE,?LINE, Msg]),
Pid ! {self(), Msg},
receive
close ->
ct:log("~p:~p~nUpgrade Client closing~n", [?MODULE,?LINE]),
- rpc:call(Node, ssl, close, [SslSocket])
+ ssl:close(SslSocket)
end.
start_upgrade_server_error(Args) ->
- Result = spawn_link(?MODULE, run_upgrade_server_error, [Args]),
+ Node = proplists:get_value(node, Args),
+ Result = spawn_link(Node,?MODULE, run_upgrade_server_error, [Args]),
receive
{listen, up} ->
Result
end.
run_upgrade_server_error(Opts) ->
- Node = proplists:get_value(node, Opts),
Port = proplists:get_value(port, Opts),
TimeOut = proplists:get_value(timeout, Opts, infinity),
TcpOptions = proplists:get_value(tcp_options, Opts),
@@ -991,22 +978,20 @@ run_upgrade_server_error(Opts) ->
Pid = proplists:get_value(from, Opts),
ct:log("~p:~p~ngen_tcp:listen(~p, ~p)~n", [?MODULE,?LINE, Port, TcpOptions]),
- {ok, ListenSocket} = rpc:call(Node, gen_tcp, listen, [Port, TcpOptions]),
+ {ok, ListenSocket} = gen_tcp:listen(Port, TcpOptions),
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
ct:log("~p:~p~ngen_tcp:accept(~p)~n", [?MODULE,?LINE, ListenSocket]),
- {ok, AcceptSocket} = rpc:call(Node, gen_tcp, accept, [ListenSocket]),
+ {ok, AcceptSocket} = gen_tcp:accept(ListenSocket),
Error = case TimeOut of
infinity ->
- ct:log("~p:~p~nssl:ssl_accept(~p, ~p)~n",
+ ct:log("~p:~p~nssl:handshake(~p, ~p)~n",
[?MODULE,?LINE, AcceptSocket, SslOptions]),
- rpc:call(Node, ssl, ssl_accept,
- [AcceptSocket, SslOptions]);
+ ssl:handshake(AcceptSocket, SslOptions);
_ ->
- ct:log("~p:~p~nssl:ssl_accept(~p, ~p, ~p)~n",
+ ct:log("~p:~p~nssl:ssl_handshake(~p, ~p, ~p)~n",
[?MODULE,?LINE, AcceptSocket, SslOptions, TimeOut]),
- rpc:call(Node, ssl, ssl_accept,
- [AcceptSocket, SslOptions, TimeOut])
+ ssl:handshake(AcceptSocket, SslOptions, TimeOut)
end,
Pid ! {self(), Error}.
@@ -1018,32 +1003,31 @@ start_server_error(Args) ->
end.
run_server_error(Opts) ->
- Node = proplists:get_value(node, Opts),
Port = proplists:get_value(port, Opts),
Options = proplists:get_value(options, Opts),
Pid = proplists:get_value(from, Opts),
Transport = proplists:get_value(transport, Opts, ssl),
ct:log("~p:~p~nssl:listen(~p, ~p)~n", [?MODULE,?LINE, Port, Options]),
- case rpc:call(Node, Transport, listen, [Port, Options]) of
+ case Transport:listen(Port, Options) of
{ok, #sslsocket{} = ListenSocket} ->
%% To make sure error_client will
%% get {error, closed} and not {error, connection_refused}
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
ct:log("~p:~p~nssl:transport_accept(~p)~n", [?MODULE,?LINE, ListenSocket]),
- case rpc:call(Node, Transport, transport_accept, [ListenSocket]) of
+ case Transport:transport_accept(ListenSocket) of
{error, _} = Error ->
Pid ! {self(), Error};
{ok, AcceptSocket} ->
ct:log("~p:~p~nssl:ssl_accept(~p)~n", [?MODULE,?LINE, AcceptSocket]),
- Error = rpc:call(Node, ssl, ssl_accept, [AcceptSocket]),
+ Error = ssl:handshake(AcceptSocket),
Pid ! {self(), Error}
end;
{ok, ListenSocket} ->
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
ct:log("~p:~p~n~p:accept(~p)~n", [?MODULE,?LINE, Transport, ListenSocket]),
- case rpc:call(Node, Transport, accept, [ListenSocket]) of
+ case Transport:accept(ListenSocket) of
{error, _} = Error ->
Pid ! {self(), Error}
end;
@@ -1055,17 +1039,17 @@ run_server_error(Opts) ->
end.
start_client_error(Args) ->
- spawn_link(?MODULE, run_client_error, [Args]).
+ Node = proplists:get_value(node, Args),
+ spawn_link(Node, ?MODULE, run_client_error, [Args]).
run_client_error(Opts) ->
- Node = proplists:get_value(node, Opts),
Host = proplists:get_value(host, Opts),
Port = proplists:get_value(port, Opts),
Pid = proplists:get_value(from, Opts),
Transport = proplists:get_value(transport, Opts, ssl),
Options = proplists:get_value(options, Opts),
ct:log("~p:~p~nssl:connect(~p, ~p, ~p)~n", [?MODULE,?LINE, Host, Port, Options]),
- Error = rpc:call(Node, Transport, connect, [Host, Port, Options]),
+ Error = Transport:connect(Host, Port, Options),
Pid ! {self(), Error}.
accepters(N) ->
@@ -1533,10 +1517,13 @@ cipher_result(Socket, 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"),
- "Hello\n" = active_recv(Socket, length( "Hello\n")),
- ssl:send(Socket, " world\n"),
- " world\n" = active_recv(Socket, length(" world\n")),
+ Hello = "Hello\n",
+ World = " world\n",
+ ssl:send(Socket, Hello),
+ ct:sleep(500),
+ ssl:send(Socket, World),
+ Expected = Hello ++ World,
+ Expected = active_recv(Socket, length(Expected)),
ok.
session_info_result(Socket) ->
@@ -1769,6 +1756,15 @@ is_sane_ecc(crypto) ->
is_sane_ecc(_) ->
sufficient_crypto_support(cipher_ec).
+is_sane_oppenssl_client() ->
+ [{_,_, Bin}] = crypto:info_lib(),
+ case binary_to_list(Bin) of
+ "OpenSSL 0.9" ++ _ ->
+ false;
+ _ ->
+ true
+ end.
+
is_fips(openssl) ->
VersionStr = os:cmd("openssl version"),
case re:split(VersionStr, "fips") of
diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl
index df84411b6d..07abddbcf7 100644
--- a/lib/ssl/test/ssl_to_openssl_SUITE.erl
+++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl
@@ -39,16 +39,14 @@
all() ->
case ssl_test_lib:openssl_sane_dtls() of
true ->
- [{group, basic},
- {group, 'tlsv1.2'},
+ [{group, 'tlsv1.2'},
{group, 'tlsv1.1'},
{group, 'tlsv1'},
{group, 'sslv3'},
{group, 'dtlsv1.2'},
{group, 'dtlsv1'}];
false ->
- [{group, basic},
- {group, 'tlsv1.2'},
+ [{group, 'tlsv1.2'},
{group, 'tlsv1.1'},
{group, 'tlsv1'},
{group, 'sslv3'}]
@@ -57,8 +55,7 @@ all() ->
groups() ->
case ssl_test_lib:openssl_sane_dtls() of
true ->
- [{basic, [], basic_tests()},
- {'tlsv1.2', [], all_versions_tests() ++ alpn_tests() ++ npn_tests() ++ sni_server_tests()},
+ [{'tlsv1.2', [], all_versions_tests() ++ alpn_tests() ++ npn_tests() ++ sni_server_tests()},
{'tlsv1.1', [], all_versions_tests() ++ alpn_tests() ++ npn_tests() ++ sni_server_tests()},
{'tlsv1', [], all_versions_tests()++ alpn_tests() ++ npn_tests() ++ sni_server_tests()},
{'sslv3', [], all_versions_tests()},
@@ -66,20 +63,13 @@ groups() ->
{'dtlsv1', [], dtls_all_versions_tests()}
];
false ->
- [{basic, [], basic_tests()},
- {'tlsv1.2', [], all_versions_tests() ++ alpn_tests() ++ npn_tests() ++ sni_server_tests()},
+ [{'tlsv1.2', [], all_versions_tests() ++ alpn_tests() ++ npn_tests() ++ sni_server_tests()},
{'tlsv1.1', [], all_versions_tests() ++ alpn_tests() ++ npn_tests() ++ sni_server_tests()},
{'tlsv1', [], all_versions_tests()++ alpn_tests() ++ npn_tests() ++ sni_server_tests()},
{'sslv3', [], all_versions_tests()}
]
end.
-
-basic_tests() ->
- [basic_erlang_client_openssl_server,
- basic_erlang_server_openssl_client,
- expired_session
- ].
-
+
all_versions_tests() ->
[
erlang_client_openssl_server,
@@ -191,16 +181,6 @@ end_per_suite(_Config) ->
ssl:stop(),
application:stop(crypto).
-init_per_group(basic, Config0) ->
- case ssl_test_lib:supports_ssl_tls_version('tlsv1.2')
- orelse ssl_test_lib:supports_ssl_tls_version('tlsv1.1')
- orelse ssl_test_lib:supports_ssl_tls_version('tlsv1')
- of
- true ->
- ssl_test_lib:clean_tls_version(Config0);
- false ->
- {skip, "only sslv3 supported by OpenSSL"}
- end;
init_per_group(GroupName, Config) ->
case ssl_test_lib:is_tls_version(GroupName) of
@@ -243,7 +223,7 @@ init_per_testcase(TestCase, Config) when
TestCase == erlang_server_openssl_client_dsa_cert;
TestCase == erlang_client_openssl_server_dsa_cert;
TestCase == erlang_server_openssl_client_dsa_cert ->
- case ssl_test_lib:openssl_dsa_support() of
+ case ssl_test_lib:openssl_dsa_support() andalso ssl_test_lib:is_sane_oppenssl_client() of
true ->
special_init(TestCase, Config);
false ->
@@ -344,7 +324,16 @@ special_init(TestCase, Config0)
]}
]}]} | Config0],
check_openssl_sni_support(Config);
-
+special_init(TestCase, Config)
+ when TestCase == erlang_server_openssl_client;
+ TestCase == erlang_server_openssl_client_client_cert;
+ TestCase == erlang_server_openssl_client_reuse_session ->
+ case ssl_test_lib:is_sane_oppenssl_client() of
+ true ->
+ Config;
+ false ->
+ {skip, "Broken OpenSSL client"}
+ end;
special_init(_, Config) ->
Config.
@@ -357,85 +346,7 @@ end_per_testcase(_, Config) ->
%%--------------------------------------------------------------------
%% Test Cases --------------------------------------------------------
%%--------------------------------------------------------------------
-basic_erlang_client_openssl_server() ->
- [{doc,"Test erlang client with openssl server"}].
-basic_erlang_client_openssl_server(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
-
- {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
-
- Data = "From openssl to erlang",
-
- Port = ssl_test_lib:inet_port(node()),
- CertFile = proplists:get_value(certfile, ServerOpts),
- KeyFile = proplists:get_value(keyfile, ServerOpts),
-
- Exe = "openssl",
- Args = ["s_server", "-accept", integer_to_list(Port),
- "-cert", CertFile, "-key", KeyFile],
-
- OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
-
- ssl_test_lib:wait_for_openssl_server(Port, tls),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- erlang_ssl_receive, [Data]}},
- {options, ClientOpts}]),
- true = port_command(OpensslPort, Data),
-
- ssl_test_lib:check_result(Client, ok),
-
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close_port(OpensslPort),
- ssl_test_lib:close(Client),
- process_flag(trap_exit, false).
-
-%%--------------------------------------------------------------------
-basic_erlang_server_openssl_client() ->
- [{doc,"Test erlang server with openssl client"}].
-basic_erlang_server_openssl_client(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
-
- {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Data = "From openssl to erlang",
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, erlang_ssl_receive, [Data]}},
- {options,ServerOpts}]),
-
- Port = ssl_test_lib:inet_port(Server),
-
- Exe = "openssl",
- Args = case no_low_flag("-no_ssl2") of
- [] ->
- ["s_client", "-connect", hostname_format(Hostname) ++
- ":" ++ integer_to_list(Port), no_low_flag("-no_ssl3")
- | workaround_openssl_s_clinent()];
- Flag ->
- ["s_client", "-connect", hostname_format(Hostname) ++
- ":" ++ integer_to_list(Port), no_low_flag("-no_ssl3"), Flag
- | workaround_openssl_s_clinent()]
- end,
-
- OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
- true = port_command(OpenSslPort, Data),
-
- ssl_test_lib:check_result(Server, ok),
-
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(OpenSslPort),
- process_flag(trap_exit, false).
-%%--------------------------------------------------------------------
erlang_client_openssl_server() ->
[{doc,"Test erlang client with openssl server"}].
erlang_client_openssl_server(Config) when is_list(Config) ->
@@ -1161,7 +1072,7 @@ erlang_client_bad_openssl_server(Config) when is_list(Config) ->
Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
{from, self()},
- {mfa, {ssl_test_lib, no_result_msg, []}},
+ {mfa, {ssl_test_lib, no_result, []}},
{options,
[{versions, [Version]} | ClientOpts]}]),
@@ -1249,7 +1160,7 @@ ssl2_erlang_server_openssl_client(Config) when is_list(Config) ->
ct:log("Ports ~p~n", [[erlang:port_info(P) || P <- erlang:ports()]]),
ssl_test_lib:consume_port_exit(OpenSslPort),
- ssl_test_lib:check_server_alert(Server, bad_record_mac),
+ ssl_test_lib:check_server_alert(Server, unexpected_message),
process_flag(trap_exit, false).
%%--------------------------------------------------------------------
@@ -1550,6 +1461,7 @@ send_and_hostname(SSLSocket) ->
end.
erlang_server_openssl_client_sni_test(Config, SNIHostname, ExpectedSNIHostname, ExpectedCN) ->
+ Version = ssl_test_lib:protocol_version(Config),
ct:log("Start running handshake, Config: ~p, SNIHostname: ~p, ExpectedSNIHostname: ~p, ExpectedCN: ~p", [Config, SNIHostname, ExpectedSNIHostname, ExpectedCN]),
ServerOptions = proplists:get_value(sni_server_opts, Config) ++ proplists:get_value(server_rsa_opts, Config),
{_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
@@ -1560,9 +1472,9 @@ erlang_server_openssl_client_sni_test(Config, SNIHostname, ExpectedSNIHostname,
Exe = "openssl",
ClientArgs = case SNIHostname of
undefined ->
- openssl_client_args(ssl_test_lib:supports_ssl_tls_version(sslv2), Hostname,Port);
+ openssl_client_args(Version, Hostname,Port);
_ ->
- openssl_client_args(ssl_test_lib:supports_ssl_tls_version(sslv2), Hostname, Port, SNIHostname)
+ openssl_client_args(Version, Hostname, Port, SNIHostname)
end,
ClientPort = ssl_test_lib:portable_open_port(Exe, ClientArgs),
@@ -1573,6 +1485,7 @@ erlang_server_openssl_client_sni_test(Config, SNIHostname, ExpectedSNIHostname,
erlang_server_openssl_client_sni_test_sni_fun(Config, SNIHostname, ExpectedSNIHostname, ExpectedCN) ->
+ Version = ssl_test_lib:protocol_version(Config),
ct:log("Start running handshake for sni_fun, Config: ~p, SNIHostname: ~p, ExpectedSNIHostname: ~p, ExpectedCN: ~p", [Config, SNIHostname, ExpectedSNIHostname, ExpectedCN]),
[{sni_hosts, ServerSNIConf}] = proplists:get_value(sni_server_opts, Config),
SNIFun = fun(Domain) -> proplists:get_value(Domain, ServerSNIConf, undefined) end,
@@ -1585,9 +1498,9 @@ erlang_server_openssl_client_sni_test_sni_fun(Config, SNIHostname, ExpectedSNIHo
Exe = "openssl",
ClientArgs = case SNIHostname of
undefined ->
- openssl_client_args(ssl_test_lib:supports_ssl_tls_version(sslv2), Hostname,Port);
+ openssl_client_args(Version, Hostname,Port);
_ ->
- openssl_client_args(ssl_test_lib:supports_ssl_tls_version(sslv2), Hostname, Port, SNIHostname)
+ openssl_client_args(Version, Hostname, Port, SNIHostname)
end,
ClientPort = ssl_test_lib:portable_open_port(Exe, ClientArgs),
@@ -1998,13 +1911,19 @@ send_wait_send(Socket, [ErlData, OpenSslData]) ->
check_openssl_sni_support(Config) ->
HelpText = os:cmd("openssl s_client --help"),
- case string:str(HelpText, "-servername") of
- 0 ->
- {skip, "Current openssl doesn't support SNI"};
- _ ->
- Config
+ case ssl_test_lib:is_sane_oppenssl_client() of
+ true ->
+ case string:str(HelpText, "-servername") of
+ 0 ->
+ {skip, "Current openssl doesn't support SNI"};
+ _ ->
+ Config
+ end;
+ false ->
+ {skip, "Current openssl doesn't support SNI or extension handling is flawed"}
end.
+
check_openssl_npn_support(Config) ->
HelpText = os:cmd("openssl s_client --help"),
case string:str(HelpText, "nextprotoneg") of
@@ -2070,17 +1989,13 @@ workaround_openssl_s_clinent() ->
[]
end.
-openssl_client_args(false, Hostname, Port) ->
- ["s_client", "-connect", Hostname ++ ":" ++ integer_to_list(Port)];
-openssl_client_args(true, Hostname, Port) ->
- ["s_client", "-no_ssl2", "-connect", Hostname ++ ":" ++ integer_to_list(Port)].
+openssl_client_args(Version, Hostname, Port) ->
+ ["s_client", "-connect", Hostname ++ ":" ++ integer_to_list(Port), ssl_test_lib:version_flag(Version)].
-openssl_client_args(false, Hostname, Port, ServerName) ->
+openssl_client_args(Version, Hostname, Port, ServerName) ->
["s_client", "-connect", Hostname ++ ":" ++
- integer_to_list(Port), "-servername", ServerName];
-openssl_client_args(true, Hostname, Port, ServerName) ->
- ["s_client", "-no_ssl2", "-connect", Hostname ++ ":" ++
- integer_to_list(Port), "-servername", ServerName].
+ integer_to_list(Port), ssl_test_lib:version_flag(Version), "-servername", ServerName].
+
hostname_format(Hostname) ->
case lists:member($., Hostname) of
@@ -2090,22 +2005,12 @@ hostname_format(Hostname) ->
"localhost"
end.
-no_low_flag("-no_ssl2" = Flag) ->
- case ssl_test_lib:supports_ssl_tls_version(sslv2) of
- true ->
- Flag;
- false ->
- ""
- end;
-no_low_flag(Flag) ->
- Flag.
-
openssl_has_common_ciphers(Ciphers) ->
OCiphers = ssl_test_lib:common_ciphers(openssl),
has_common_ciphers(Ciphers, OCiphers).
-has_common_ciphers([], OCiphers) ->
+has_common_ciphers([], _) ->
false;
has_common_ciphers([Cipher | Rest], OCiphers) ->
case lists:member(Cipher, OCiphers) of
diff --git a/lib/ssl/test/ssl_upgrade_SUITE.erl b/lib/ssl/test/ssl_upgrade_SUITE.erl
index 875399db76..ead18aeb73 100644
--- a/lib/ssl/test/ssl_upgrade_SUITE.erl
+++ b/lib/ssl/test/ssl_upgrade_SUITE.erl
@@ -47,10 +47,7 @@ init_per_suite(Config0) ->
{skip, Reason} ->
{skip, Reason};
Config ->
- Result =
- {ok, _} = make_certs:all(proplists:get_value(data_dir, Config),
- proplists:get_value(priv_dir, Config)),
- ssl_test_lib:cert_options(Config)
+ ssl_test_lib:make_rsa_cert(Config)
end
catch _:_ ->
{skip, "Crypto did not start"}
@@ -149,8 +146,8 @@ use_connection(Socket) ->
end.
soft_start_connection(Config, ResulProxy) ->
- ClientOpts = proplists:get_value(client_verification_opts, Config),
- ServerOpts = proplists:get_value(server_verification_opts, Config),
+ ClientOpts = proplists:get_value(client_rsa_verify_opts, Config),
+ ServerOpts = proplists:get_value(server_rsa_verify_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server = start_server([{node, ServerNode}, {port, 0},
{from, ResulProxy},
@@ -166,8 +163,8 @@ soft_start_connection(Config, ResulProxy) ->
{Server, Client}.
restart_start_connection(Config, ResulProxy) ->
- ClientOpts = proplists:get_value(client_verification_opts, Config),
- ServerOpts = proplists:get_value(server_verification_opts, Config),
+ ClientOpts = proplists:get_value(client_rsa_verify_opts, Config),
+ ServerOpts = proplists:get_value(server_rsa_verify_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server = start_server([{node, ServerNode}, {port, 0},
{from, ResulProxy},
diff --git a/lib/stdlib/doc/src/calendar.xml b/lib/stdlib/doc/src/calendar.xml
index 518a085c89..6308420c52 100644
--- a/lib/stdlib/doc/src/calendar.xml
+++ b/lib/stdlib/doc/src/calendar.xml
@@ -513,7 +513,7 @@
<title>Date and Time Source</title>
<p>Local time is obtained from the Erlang BIF <c>localtime/0</c>.
Universal time is computed from the BIF <c>universaltime/0</c>.</p>
- <p>The following fapply:</p>
+ <p>The following apply:</p>
<list type="bulleted">
<item>There are 86400 seconds in a day.</item>
<item>There are 365 days in an ordinary year.</item>
diff --git a/lib/stdlib/doc/src/dets.xml b/lib/stdlib/doc/src/dets.xml
index 8e4e002000..8b9502a3b1 100644
--- a/lib/stdlib/doc/src/dets.xml
+++ b/lib/stdlib/doc/src/dets.xml
@@ -1090,8 +1090,8 @@ ok
</item>
<item>
<p><c>select</c> - The table is traversed by calling
- <seealso marker="dets:select/3"><c>dets:select/3</c></seealso> and
- <seealso marker="dets:select/1"><c>dets:select/1</c></seealso>.
+ <seealso marker="dets#select/3"><c>dets:select/3</c></seealso> and
+ <seealso marker="dets#select/1"><c>dets:select/1</c></seealso>.
Option <c>n_objects</c> determines the number of objects
returned (the third argument of <c>select/3</c>). The
match specification (the second argument of
diff --git a/lib/stdlib/doc/src/digraph_utils.xml b/lib/stdlib/doc/src/digraph_utils.xml
index 13b0aaad9e..a23b02c6c1 100644
--- a/lib/stdlib/doc/src/digraph_utils.xml
+++ b/lib/stdlib/doc/src/digraph_utils.xml
@@ -371,7 +371,7 @@
the default, the type of <c><anno>Digraph</anno></c> is used
for the subgraph as well. Otherwise the option value of <c>type</c>
is used as argument to
- <seealso marker="digraph:new/1"><c>digraph:new/1</c></seealso>.</p>
+ <seealso marker="digraph#new/1"><c>digraph:new/1</c></seealso>.</p>
<p>If the value of option <c>keep_labels</c> is <c>true</c>,
which is the default,
the <seealso marker="#label">labels</seealso> of vertices and edges
diff --git a/lib/stdlib/doc/src/notes.xml b/lib/stdlib/doc/src/notes.xml
index 23c3f6e981..65650a25c7 100644
--- a/lib/stdlib/doc/src/notes.xml
+++ b/lib/stdlib/doc/src/notes.xml
@@ -31,6 +31,21 @@
</header>
<p>This document describes the changes made to the STDLIB application.</p>
+<section><title>STDLIB 3.8.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fixed a performance regression when reading files
+ opened with the <c>compressed</c> flag.</p>
+ <p>
+ Own Id: OTP-15706 Aux Id: ERIERL-336 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>STDLIB 3.8</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/stdlib/doc/src/proc_lib.xml b/lib/stdlib/doc/src/proc_lib.xml
index aeb9f48735..bb983903a9 100644
--- a/lib/stdlib/doc/src/proc_lib.xml
+++ b/lib/stdlib/doc/src/proc_lib.xml
@@ -166,7 +166,7 @@
<fsummary>Hibernate a process until a message is sent to it.</fsummary>
<desc>
<p>This function does the same as (and does call) the
- <seealso marker="erts:erlang#erlang:hibernate/3">
+ <seealso marker="erts:erlang#hibernate/3">
<c>hibernate/3</c></seealso> BIF,
but ensures that exception handling and logging continues to
work as expected when the process wakes up.</p>
diff --git a/lib/stdlib/doc/src/slave.xml b/lib/stdlib/doc/src/slave.xml
index 778c5f66e5..f9e42ad47d 100644
--- a/lib/stdlib/doc/src/slave.xml
+++ b/lib/stdlib/doc/src/slave.xml
@@ -51,7 +51,7 @@
<p>An alternative to the <c>ssh</c> program can be specified on
the command line to
- <seealso marker="erts:erl#erl"><c>erl(1)</c></seealso> as follows:</p>
+ <seealso marker="erts:erl"><c>erl(1)</c></seealso> as follows:</p>
<pre>
-rsh Program</pre>
@@ -140,7 +140,7 @@ rpc:call(N, slave, pseudo, [node(), [pxw_server]]).</code>
<p>Argument <c><anno>Args</anno></c> is used to set <c>erl</c>
command-line arguments. If provided, it is passed to the new
node and can be used for a variety of purposes; see
- <seealso marker="erts:erl#erl"><c>erl(1)</c></seealso>.</p>
+ <seealso marker="erts:erl"><c>erl(1)</c></seealso>.</p>
<p>As an example, suppose that you want to start a slave node at
host <c>H</c> with node name <c>Name@H</c> and
want the slave node to have the following properties:</p>
diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl
index 3ec78a2667..00fd731e1d 100644
--- a/lib/stdlib/src/erl_lint.erl
+++ b/lib/stdlib/src/erl_lint.erl
@@ -79,6 +79,8 @@ value_option(Flag, Default, On, OnVal, Off, OffVal, Opts) ->
-type fa() :: {atom(), arity()}. % function+arity
-type ta() :: {atom(), arity()}. % type+arity
+-type module_or_mfa() :: module() | mfa().
+
-record(typeinfo, {attr, line}).
%% Usage of records, functions, and imports. The variable table, which
@@ -115,6 +117,8 @@ value_option(Flag, Default, On, OnVal, Off, OffVal, Opts) ->
:: erl_anno:anno(),
clashes=[], %Exported functions named as BIFs
not_deprecated=[], %Not considered deprecated
+ not_removed=gb_sets:empty() %Not considered removed
+ :: gb_sets:set(module_or_mfa()),
func=[], %Current function
warn_format=0, %Warn format calls
enabled_warnings=[], %All enabled warnings (ordset).
@@ -573,7 +577,10 @@ start(File, Opts) ->
false, Opts)},
{missing_spec_all,
bool_option(warn_missing_spec_all, nowarn_missing_spec_all,
- false, Opts)}
+ false, Opts)},
+ {removed,
+ bool_option(warn_removed, nowarn_removed,
+ true, Opts)}
],
Enabled1 = [Category || {Category,true} <- Enabled0],
Enabled = ordsets:from_list(Enabled1),
@@ -670,8 +677,9 @@ forms(Forms0, St0) ->
no_auto = AutoImportSuppressed}),
St2 = bif_clashes(Forms, St1),
St3 = not_deprecated(Forms, St2),
- St4 = foldl(fun form/2, pre_scan(Forms, St3), Forms),
- post_traversal_check(Forms, St4).
+ St4 = not_removed(Forms, St3),
+ St5 = foldl(fun form/2, pre_scan(Forms, St4), Forms),
+ post_traversal_check(Forms, St5).
pre_scan([{attribute,L,compile,C} | Fs], St) ->
case is_warn_enabled(export_all, St) andalso
@@ -846,6 +854,24 @@ not_deprecated(Forms, #lint{compile=Opts}=St0) ->
end, St0, ML),
St1#lint{not_deprecated = ordsets:from_list(Nowarn)}.
+%% not_removed(Forms, State0) -> State
+
+not_removed(Forms, #lint{compile=Opts}=St0) ->
+ %% There are no line numbers in St0#lint.compile.
+ MFAsL = [{MFA,L} ||
+ {attribute, L, compile, Args} <- Forms,
+ {nowarn_removed, MFAs0} <- lists:flatten([Args]),
+ MFA <- lists:flatten([MFAs0])],
+ Nowarn = [MFA ||
+ {nowarn_removed, MFAs0} <- Opts,
+ MFA <- lists:flatten([MFAs0])],
+ St1 = foldl(fun ({{M, _F, _A}, L}, St2) ->
+ check_module_name(M, L, St2);
+ ({M,L}, St2) ->
+ check_module_name(M, L, St2)
+ end, St0, MFAsL),
+ St1#lint{not_removed = gb_sets:from_list(Nowarn)}.
+
%% The nowarn_bif_clash directive is not only deprecated, it's actually an error from R14A
disallowed_compile_flags(Forms, St0) ->
%% There are (still) no line numbers in St0#lint.compile.
@@ -3769,13 +3795,23 @@ deprecated_function(Line, M, F, As, St) ->
add_warning(Line, {deprecated, MFA, Replacement, Rel}, St)
end;
{removed, String} when is_list(String) ->
- add_warning(Line, {removed, MFA, String}, St);
+ add_removed_warning(Line, MFA, {removed, MFA, String}, St);
{removed, Replacement, Rel} ->
- add_warning(Line, {removed, MFA, Replacement, Rel}, St);
+ add_removed_warning(Line, MFA, {removed, MFA, Replacement, Rel}, St);
no ->
St
end.
+add_removed_warning(Line, {M, _, _}=MFA, Warning, #lint{not_removed=NotRemoved}=St) ->
+ case is_warn_enabled(removed, St) andalso
+ not gb_sets:is_element(M, NotRemoved) andalso
+ not gb_sets:is_element(MFA, NotRemoved) of
+ true ->
+ add_warning(Line, Warning, St);
+ false ->
+ St
+ end.
+
-dialyzer({no_match, deprecated_type/5}).
deprecated_type(L, M, N, As, St) ->
diff --git a/lib/stdlib/src/erl_pp.erl b/lib/stdlib/src/erl_pp.erl
index ada3ff5de3..3e68c1b225 100644
--- a/lib/stdlib/src/erl_pp.erl
+++ b/lib/stdlib/src/erl_pp.erl
@@ -808,12 +808,6 @@ cr_clause({clause,_,[T],G,B}, Opts) ->
try_clauses(Cs, Opts) ->
clauses(fun try_clause/2, Opts, Cs).
-try_clause({clause,_,[{tuple,_,[{atom,_,throw},V,S]}],G,B}, Opts) ->
- El = lexpr(V, 0, Opts),
- Sl = stack_backtrace(S, [El], Opts),
- Gl = guard_when(Sl, G, Opts),
- Bl = body(B, Opts),
- {step,Gl,Bl};
try_clause({clause,_,[{tuple,_,[C,V,S]}],G,B}, Opts) ->
Cs = lexpr(C, 0, Opts),
El = lexpr(V, 0, Opts),
diff --git a/lib/stdlib/src/erl_tar.erl b/lib/stdlib/src/erl_tar.erl
index d8b8f466b1..7064fcacfa 100644
--- a/lib/stdlib/src/erl_tar.erl
+++ b/lib/stdlib/src/erl_tar.erl
@@ -324,7 +324,7 @@ do_open(Name, Mode) when is_list(Mode) ->
open1({binary,Bin}, read, _Raw, Opts) when is_binary(Bin) ->
case file:open(Bin, [ram,binary,read]) of
{ok,File} ->
- _ = [ram_file:uncompress(File) || Opts =:= [compressed]],
+ _ = [ram_file:uncompress(File) || lists:member(compressed, Opts)],
{ok, #reader{handle=File,access=read,func=fun file_op/2}};
Error ->
Error
@@ -357,7 +357,7 @@ open_mode([read|Rest], false, Raw, Opts) ->
open_mode([write|Rest], false, Raw, Opts) ->
open_mode(Rest, write, Raw, Opts);
open_mode([compressed|Rest], Access, Raw, Opts) ->
- open_mode(Rest, Access, Raw, [compressed|Opts]);
+ open_mode(Rest, Access, Raw, [compressed,read_ahead|Opts]);
open_mode([cooked|Rest], Access, _Raw, Opts) ->
open_mode(Rest, Access, [], Opts);
open_mode([], Access, Raw, Opts) ->
diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl
index b95cb8f525..fa34f19637 100644
--- a/lib/stdlib/src/otp_internal.erl
+++ b/lib/stdlib/src/otp_internal.erl
@@ -323,90 +323,6 @@ obsolete_1(snmp, N, A) ->
obsolete_1(snmpa, old_info_format, 1) ->
{deprecated, "Deprecated; (will be removed in OTP 18); use \"new\" format instead"};
-obsolete_1(snmpm, agent_info, 3) ->
- {removed, {snmpm, agent_info, 2}, "R16B"};
-obsolete_1(snmpm, update_agent_info, 5) ->
- {removed, {snmpm, update_agent_info, 4}, "R16B"};
-obsolete_1(snmpm, g, 3) ->
- {removed, {snmpm, sync_get, 3}, "R16B"};
-obsolete_1(snmpm, g, 4) ->
- {removed, {snmpm, sync_get, [3,4]}, "R16B"};
-obsolete_1(snmpm, g, 5) ->
- {removed, {snmpm, sync_get, [4,5]}, "R16B"};
-obsolete_1(snmpm, g, 6) ->
- {removed, {snmpm, sync_get, [5,6]}, "R16B"};
-obsolete_1(snmpm, g, 7) ->
- {removed, {snmpm, sync_get, 6}, "R16B"};
-obsolete_1(snmpm, ag, 3) ->
- {removed, {snmpm, async_get, 3}, "R16B"};
-obsolete_1(snmpm, ag, 4) ->
- {removed, {snmpm, async_get, [3,4]}, "R16B"};
-obsolete_1(snmpm, ag, 5) ->
- {removed, {snmpm, async_get, [4,5]}, "R16B"};
-obsolete_1(snmpm, ag, 6) ->
- {removed, {snmpm, async_get, [5,6]}, "R16B"};
-obsolete_1(snmpm, ag, 7) ->
- {removed, {snmpm, async_get, 6}, "R16B"};
-obsolete_1(snmpm, gn, 3) ->
- {removed, {snmpm, sync_get_next, 3}, "R16B"};
-obsolete_1(snmpm, gn, 4) ->
- {removed, {snmpm, sync_get_next, [3,4]}, "R16B"};
-obsolete_1(snmpm, gn, 5) ->
- {removed, {snmpm, sync_get_next, [4,5]}, "R16B"};
-obsolete_1(snmpm, gn, 6) ->
- {removed, {snmpm, sync_get_next, [5,6]}, "R16B"};
-obsolete_1(snmpm, gn, 7) ->
- {removed, {snmpm, sync_get_next, 6}, "R16B"};
-obsolete_1(snmpm, agn, 3) ->
- {removed, {snmpm, async_get_next, 3}, "R16B"};
-obsolete_1(snmpm, agn, 4) ->
- {removed, {snmpm, async_get_next, [3,4]}, "R16B"};
-obsolete_1(snmpm, agn, 5) ->
- {removed, {snmpm, async_get_next, [4,5]}, "R16B"};
-obsolete_1(snmpm, agn, 6) ->
- {removed, {snmpm, async_get_next, [5,6]}, "R16B"};
-obsolete_1(snmpm, agn, 7) ->
- {removed, {snmpm, async_get_next, 6}, "R16B"};
-obsolete_1(snmpm, s, 3) ->
- {removed, {snmpm, sync_set, 3}, "R16B"};
-obsolete_1(snmpm, s, 4) ->
- {removed, {snmpm, sync_set, [3,4]}, "R16B"};
-obsolete_1(snmpm, s, 5) ->
- {removed, {snmpm, sync_set, [4,5]}, "R16B"};
-obsolete_1(snmpm, s, 6) ->
- {removed, {snmpm, sync_set, [5,6]}, "R16B"};
-obsolete_1(snmpm, s, 7) ->
- {removed, {snmpm, sync_set, 6}, "R16B"};
-obsolete_1(snmpm, as, 3) ->
- {removed, {snmpm, async_set, 3}, "R16B"};
-obsolete_1(snmpm, as, 4) ->
- {removed, {snmpm, async_set, [3,4]}, "R16B"};
-obsolete_1(snmpm, as, 5) ->
- {removed, {snmpm, async_set, [4,5]}, "R16B"};
-obsolete_1(snmpm, as, 6) ->
- {removed, {snmpm, async_set, [5,6]}, "R16B"};
-obsolete_1(snmpm, as, 7) ->
- {removed, {snmpm, async_set, 6}, "R16B"};
-obsolete_1(snmpm, gb, 5) ->
- {removed, {snmpm, sync_get_bulk, 5}, "R16B"};
-obsolete_1(snmpm, gb, 6) ->
- {removed, {snmpm, sync_get_bulk, [5,6]}, "R16B"};
-obsolete_1(snmpm, gb, 7) ->
- {removed, {snmpm, sync_get_bulk, [6,7]}, "R16B"};
-obsolete_1(snmpm, gb, 8) ->
- {removed, {snmpm, sync_get_bulk, [7,8]}, "R16B"};
-obsolete_1(snmpm, gb, 9) ->
- {removed, {snmpm, sync_get_bulk, 8}, "R16B"};
-obsolete_1(snmpm, agb, 5) ->
- {removed, {snmpm, async_get_bulk, 5}, "R16B"};
-obsolete_1(snmpm, agb, 6) ->
- {removed, {snmpm, async_get_bulk, [5,6]}, "R16B"};
-obsolete_1(snmpm, agb, 7) ->
- {removed, {snmpm, async_get_bulk, [6,7]}, "R16B"};
-obsolete_1(snmpm, agb, 8) ->
- {removed, {snmpm, async_get_bulk, [7,8]}, "R16B"};
-obsolete_1(snmpm, agb, 9) ->
- {removed, {snmpm, async_get_bulk, 8}, "R16B"};
%% *** MEGACO ***
@@ -417,6 +333,7 @@ obsolete_1(megaco, format_versions, 1) ->
%% *** OS-MON-MIB ***
+%% FIXME: Remove this warning in OTP 24.
obsolete_1(os_mon_mib, _, _) ->
{removed, "was removed in 22.0"};
@@ -431,64 +348,6 @@ obsolete_1(auth, node_cookie, 1) ->
obsolete_1(auth, node_cookie, 2) ->
{deprecated, "Deprecated; use erlang:set_cookie/2 and net_adm:ping/1 instead"};
-obsolete_1(http, request, 1) -> {removed,{httpc,request,1},"R15B"};
-obsolete_1(http, request, 2) -> {removed,{httpc,request,2},"R15B"};
-obsolete_1(http, request, 4) -> {removed,{httpc,request,4},"R15B"};
-obsolete_1(http, request, 5) -> {removed,{httpc,request,5},"R15B"};
-obsolete_1(http, cancel_request, 1) -> {removed,{httpc,cancel_request,1},"R15B"};
-obsolete_1(http, cancel_request, 2) -> {removed,{httpc,cancel_request,2},"R15B"};
-obsolete_1(http, set_option, 2) -> {removed,{httpc,set_option,2},"R15B"};
-obsolete_1(http, set_option, 3) -> {removed,{httpc,set_option,3},"R15B"};
-obsolete_1(http, set_options, 1) -> {removed,{httpc,set_options,1},"R15B"};
-obsolete_1(http, set_options, 2) -> {removed,{httpc,set_options,2},"R15B"};
-obsolete_1(http, verify_cookies, 2) -> {removed,{httpc,store_cookies,2},"R15B"};
-obsolete_1(http, verify_cookies, 3) -> {removed,{httpc,store_cookies,3},"R15B"};
-obsolete_1(http, cookie_header, 1) -> {removed,{httpc,cookie_header,1},"R15B"};
-obsolete_1(http, cookie_header, 2) -> {removed,{httpc,cookie_header,2},"R15B"};
-obsolete_1(http, stream_next, 1) -> {removed,{httpc,stream_next,1},"R15B"};
-obsolete_1(http, default_profile, 0) -> {removed,{httpc,default_profile,0},"R15B"};
-
-%% Added in R13A.
-obsolete_1(regexp, _, _) ->
- {removed, "removed in R15; use the re module instead"};
-
-%% Added in R13B04.
-obsolete_1(erlang, concat_binary, 1) ->
- {removed,{erlang,list_to_binary,1},"R15B"};
-
-%% Added in R14A.
-obsolete_1(ssl, peercert, 2) ->
- {removed ,"removed in R15A; use ssl:peercert/1 and public_key:pkix_decode_cert/2 instead"};
-
-%% Added in R14B.
-obsolete_1(public_key, pem_to_der, 1) ->
- {removed,"removed in R15A; use file:read_file/1 and public_key:pem_decode/1"};
-obsolete_1(public_key, decode_private_key, A) when A =:= 1; A =:= 2 ->
- {removed, "removed in R15A; use public_key:pem_entry_decode/1"};
-
-%% Added in R14B03.
-obsolete_1(docb_gen, _, _) ->
- {removed,"the DocBuilder application was removed in R15B"};
-obsolete_1(docb_transform, _, _) ->
- {removed,"the DocBuilder application was removed in R15B"};
-obsolete_1(docb_xml_check, _, _) ->
- {removed,"the DocBuilder application was removed in R15B"};
-
-%% Added in R15B
-obsolete_1(asn1rt, F, _) when F == load_driver; F == unload_driver ->
- {removed,"removed (will be removed in OTP 18); has no effect as drivers are no longer used"};
-obsolete_1(ssl, pid, 1) ->
- {removed,"was removed in R16; is no longer needed"};
-obsolete_1(inviso, _, _) ->
- {removed,"the inviso application was removed in R16"};
-
-%% Added in R15B01.
-obsolete_1(ssh, sign_data, 2) ->
- {removed,"removed in R16A; use public_key:pem_decode/1, public_key:pem_entry_decode/1 "
- "and public_key:sign/3 instead"};
-obsolete_1(ssh, verify_data, 3) ->
- {removed,"removed in R16A; use public_key:ssh_decode/1, and public_key:verify/4 instead"};
-
%% Added in R16
obsolete_1(wxCalendarCtrl, enableYearChange, _) -> %% wx bug documented?
{deprecated,"deprecated function not available in wxWidgets-2.9 and later"};
@@ -609,10 +468,8 @@ obsolete_1(queue, lait, 1) ->
%% Removed in OTP 19.
-obsolete_1(overload, _, _) ->
- {removed, "removed in OTP 19"};
obsolete_1(rpc, safe_multi_server_call, A) when A =:= 2; A =:= 3 ->
- {removed, {rpc, multi_server_call, A}, "removed in OTP 19"};
+ {removed, {rpc, multi_server_call, A}, "19.0"};
%% Added in OTP 20.
diff --git a/lib/stdlib/src/stdlib.appup.src b/lib/stdlib/src/stdlib.appup.src
index 37ea97c353..08612ed17f 100644
--- a/lib/stdlib/src/stdlib.appup.src
+++ b/lib/stdlib/src/stdlib.appup.src
@@ -41,7 +41,9 @@
{<<"^3\\.6\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
{<<"^3\\.7$">>,[restart_new_emulator]},
{<<"^3\\.7\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
- {<<"^3\\.7\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}],
+ {<<"^3\\.7\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
+ {<<"^3\\.8$">>,[restart_new_emulator]},
+ {<<"^3\\.8\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}],
[{<<"^3\\.4$">>,[restart_new_emulator]},
{<<"^3\\.4\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
{<<"^3\\.4\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
@@ -56,4 +58,6 @@
{<<"^3\\.6\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
{<<"^3\\.7$">>,[restart_new_emulator]},
{<<"^3\\.7\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
- {<<"^3\\.7\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}]}.
+ {<<"^3\\.7\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
+ {<<"^3\\.8$">>,[restart_new_emulator]},
+ {<<"^3\\.8\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}]}.
diff --git a/lib/stdlib/test/erl_lint_SUITE.erl b/lib/stdlib/test/erl_lint_SUITE.erl
index e791da48cf..939cc1024c 100644
--- a/lib/stdlib/test/erl_lint_SUITE.erl
+++ b/lib/stdlib/test/erl_lint_SUITE.erl
@@ -2109,11 +2109,32 @@ otp_5362(Config) when is_list(Config) ->
{calendar,local_time_to_universal_time_dst,1}, "a future release"}}]}},
{call_removed_function,
- <<"t(X) -> regexp:match(X).">>,
+ <<"t(X) -> erlang:hash(X, 10000).">>,
[],
{warnings,
- [{1,erl_lint,{removed,{regexp,match,1},
- "removed in R15; use the re module instead"}}]}}
+ [{1,erl_lint,{removed,{erlang,hash,2},{erlang,phash2,2},"20.0"}}]}},
+
+ {nowarn_call_removed_function_1,
+ <<"t(X) -> erlang:hash(X, 10000).">>,
+ [{nowarn_removed,{erlang,hash,2}}],
+ []},
+
+ {nowarn_call_removed_function_2,
+ <<"t(X) -> os_mon_mib:any_function_really(erlang:hash(X, 10000)).">>,
+ [nowarn_removed],
+ []},
+
+ {call_removed_module,
+ <<"t(X) -> os_mon_mib:any_function_really(X).">>,
+ [],
+ {warnings,[{1,erl_lint,
+ {removed,{os_mon_mib,any_function_really,1},
+ "was removed in 22.0"}}]}},
+
+ {nowarn_call_removed_module,
+ <<"t(X) -> os_mon_mib:any_function_really(X).">>,
+ [{nowarn_removed,os_mon_mib}],
+ []}
],
diff --git a/lib/stdlib/test/erl_pp_SUITE.erl b/lib/stdlib/test/erl_pp_SUITE.erl
index f5d80e7e68..e5d1910070 100644
--- a/lib/stdlib/test/erl_pp_SUITE.erl
+++ b/lib/stdlib/test/erl_pp_SUITE.erl
@@ -51,7 +51,7 @@
otp_6321/1, otp_6911/1, otp_6914/1, otp_8150/1, otp_8238/1,
otp_8473/1, otp_8522/1, otp_8567/1, otp_8664/1, otp_9147/1,
otp_10302/1, otp_10820/1, otp_11100/1, otp_11861/1, pr_1014/1,
- otp_13662/1, otp_14285/1, otp_15592/1]).
+ otp_13662/1, otp_14285/1, otp_15592/1, otp_15751/1]).
%% Internal export.
-export([ehook/6]).
@@ -81,7 +81,7 @@ groups() ->
[otp_6321, otp_6911, otp_6914, otp_8150, otp_8238,
otp_8473, otp_8522, otp_8567, otp_8664, otp_9147,
otp_10302, otp_10820, otp_11100, otp_11861, pr_1014, otp_13662,
- otp_14285, otp_15592]}].
+ otp_14285, otp_15592, otp_15751]}].
init_per_suite(Config) ->
Config.
@@ -1172,6 +1172,39 @@ otp_15592(_Config) ->
"56789012345678901234:f(<<>>)">>),
ok.
+otp_15751(_Config) ->
+ ok = pp_expr(<<"try foo:bar()
+ catch
+ Reason : Stacktrace ->
+ {Reason, Stacktrace}
+ end">>),
+ ok = pp_expr(<<"try foo:bar()
+ catch
+ throw: Reason : Stacktrace ->
+ {Reason, Stacktrace}
+ end">>),
+ ok = pp_expr(<<"try foo:bar()
+ catch
+ Reason : _ ->
+ Reason
+ end">>),
+ ok = pp_expr(<<"try foo:bar()
+ catch
+ throw: Reason : _ ->
+ Reason
+ end">>),
+ ok = pp_expr(<<"try foo:bar()
+ catch
+ Reason ->
+ Reason
+ end">>),
+ ok = pp_expr(<<"try foo:bar()
+ catch
+ throw: Reason ->
+ Reason
+ end">>),
+ ok.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
compile(Config, Tests) ->
diff --git a/lib/stdlib/test/stdlib_bench_SUITE_data/generic_fsm.erl b/lib/stdlib/test/stdlib_bench_SUITE_data/generic_fsm.erl
index 50f7df7a2a..1abd9b1f2f 100644
--- a/lib/stdlib/test/stdlib_bench_SUITE_data/generic_fsm.erl
+++ b/lib/stdlib/test/stdlib_bench_SUITE_data/generic_fsm.erl
@@ -24,7 +24,7 @@
-export([init/1, terminate/3]).
-export([state1/3, state2/3]).
--behaivour(gen_fsm).
+-behaviour(gen_fsm).
%% API
diff --git a/lib/stdlib/vsn.mk b/lib/stdlib/vsn.mk
index cbefd6590a..6471dc70e0 100644
--- a/lib/stdlib/vsn.mk
+++ b/lib/stdlib/vsn.mk
@@ -1 +1 @@
-STDLIB_VSN = 3.8
+STDLIB_VSN = 3.8.1
diff --git a/lib/syntax_tools/test/syntax_tools_SUITE.erl b/lib/syntax_tools/test/syntax_tools_SUITE.erl
index 6b42f7a0a1..e1dd1bd73b 100644
--- a/lib/syntax_tools/test/syntax_tools_SUITE.erl
+++ b/lib/syntax_tools/test/syntax_tools_SUITE.erl
@@ -74,7 +74,7 @@ smoke_test_file(File) ->
[print_error_markers(F, File) || F <- Forms],
ok;
{error,Reason} ->
- io:format("~s: ~p\n", [File,Reason]),
+ io:format("~ts: ~p\n", [File,Reason]),
error
end.
@@ -82,7 +82,7 @@ print_error_markers(F, File) ->
case erl_syntax:type(F) of
error_marker ->
{L,M,Info} = erl_syntax:error_marker_info(F),
- io:format("~ts:~p: ~s", [File,L,M:format_error(Info)]);
+ io:format("~ts:~p: ~ts", [File,L,M:format_error(Info)]);
_ ->
ok
end.
@@ -362,7 +362,7 @@ test_comment_scan([File|Files],DataDir) ->
end,
Fs1 = erl_recomment:recomment_forms(Fs0, Comments),
Fs2 = erl_syntax_lib:map(Fun, Fs1),
- io:format("File: ~s~n", [Filename]),
+ io:format("File: ~ts~n", [Filename]),
io:put_chars(erl_prettypr:format(Fs2, [{paper, 120},
{ribbon, 110}])),
test_comment_scan(Files,DataDir).
@@ -377,8 +377,8 @@ test_prettypr([File|Files],DataDir,PrivDir) ->
PP = erl_prettypr:format(Fs, [{paper, 120}, {ribbon, 110}]),
io:put_chars(PP),
OutFile = filename:join(PrivDir, File),
- ok = file:write_file(OutFile,iolist_to_binary(PP)),
- io:format("Parsing OutFile: ~s~n", [OutFile]),
+ ok = file:write_file(OutFile,unicode:characters_to_binary(PP)),
+ io:format("Parsing OutFile: ~ts~n", [OutFile]),
{ok, Fs2} = epp:parse_file(OutFile, [], []),
case [Error || {error, _} = Error <- Fs2] of
[] ->
@@ -445,7 +445,7 @@ pretty_print_parse_forms([{Fs0,Type}|FsForms],PrivDir,Filename) ->
{Fs2,{CC,CT}} = erl_syntax_lib:mapfold(Comment,{0,0}, Fs1),
io:format("Commented on ~w cases and ~w tries~n", [CC,CT]),
PP = erl_prettypr:format(Fs2),
- ok = file:write_file(OutFile,iolist_to_binary(PP)),
+ ok = file:write_file(OutFile,unicode:characters_to_binary(PP)),
pretty_print_parse_forms(FsForms,PrivDir,Filename).
diff --git a/lib/tools/emacs/erlang-test.el b/lib/tools/emacs/erlang-test.el
index 2ee584d11a..fbdd298da3 100644
--- a/lib/tools/emacs/erlang-test.el
+++ b/lib/tools/emacs/erlang-test.el
@@ -50,8 +50,15 @@
;; The -L option adds a directory to the load-path. It should be the
;; directory containing erlang.el and erlang-test.el.
;;
-;; 3. Call the script test-erlang-mode in this directory. This script
-;; use the second method.
+;; 3. Run the emacs_SUITE. The testcases tests_interpreted/1 and
+;; tests_compiled/1 in this suite are using the second method. One
+;; way to run this suite is with the ct_run tool, for example like the
+;; following when standing at the OTP repo top directory:
+;;
+;; ct_run -suite lib/tools/test/emacs_SUITE
+;;
+;; Note that this creates a lot of html log files in the current
+;; directory.
;;; Code:
diff --git a/lib/tools/emacs/erlang.el b/lib/tools/emacs/erlang.el
index 38c0eba92b..0b3a2319e2 100644
--- a/lib/tools/emacs/erlang.el
+++ b/lib/tools/emacs/erlang.el
@@ -4,7 +4,7 @@
;; Author: Anders Lindgren
;; Keywords: erlang, languages, processes
;; Date: 2011-12-11
-;; Version: 2.8.1
+;; Version: 2.8.2
;; Package-Requires: ((emacs "24.1"))
;; %CopyrightBegin%
@@ -87,7 +87,7 @@
"The Erlang programming language."
:group 'languages)
-(defconst erlang-version "2.8.1"
+(defconst erlang-version "2.8.2"
"The version number of Erlang mode.")
(defcustom erlang-root-dir nil
@@ -502,6 +502,13 @@ regardless of where in the line point is when the TAB command is used."
:type 'boolean
:safe 'booleanp)
+(defcustom erlang-max-files-to-visit-for-refining-xrefs 32
+ "Upper limit how many files to visit for checking arity.
+When `nil' there is no limit."
+ :group 'erlang
+ :type '(restricted-sexp :match-alternatives (integerp 'nil))
+ :safe (lambda (val) (or (eq val nil) (integerp val))))
+
(defvar erlang-man-inhibit (eq system-type 'windows-nt)
"Inhibit the creation of the Erlang Manual Pages menu.
@@ -3689,10 +3696,13 @@ When an identifier is found return a list with 4 elements:
module or nil.
2. Module - Module name string or nil. In case of a
-qualified-function a search fails if no entries with correct
-module are found. For other kinds the module is just a
-preference. If no matching entries are found the search will be
-retried without regard to module.
+qualified-function the module is explicitly specified (like
+module:fun()) and the search fails if no entries with correct
+module are found. For other kinds the module is guessed: either
+fetched from import statements or it is assumed to be the local
+module. In these cases the module is just a preference. If no
+matching entries are found the search will be retried without
+regard to module.
3. Name - String name of function, module, record or macro.
@@ -3704,18 +3714,22 @@ of arguments could be found, otherwise nil."
(if (eq (char-syntax (following-char)) ? )
(skip-chars-backward " \t"))
(skip-chars-backward "[:word:]_:'")
- (cond ((looking-at erlang-module-function-regexp)
+ (cond ((and (eq (preceding-char) ??)
+ (looking-at (concat "\\(MODULE\\):" erlang-atom-regexp)))
+ (erlang-get-qualified-function-id-at-point (erlang-get-module)))
+ ((looking-at erlang-module-function-regexp)
(erlang-get-qualified-function-id-at-point))
((looking-at (concat erlang-atom-regexp ":"))
(erlang-get-module-id-at-point))
((looking-at erlang-name-regexp)
(erlang-get-some-other-id-at-point)))))))
-(defun erlang-get-qualified-function-id-at-point ()
+(defun erlang-get-qualified-function-id-at-point (&optional module)
(let ((kind 'qualified-function)
- (module (erlang-remove-quotes
- (buffer-substring-no-properties
- (match-beginning 1) (match-end 1))))
+ (module (or module
+ (erlang-remove-quotes
+ (buffer-substring-no-properties
+ (match-beginning 1) (match-end 1)))))
(name (erlang-remove-quotes
(buffer-substring-no-properties
(match-beginning (1+ erlang-atom-regexp-matches))
@@ -3825,7 +3839,8 @@ of arguments could be found, otherwise nil."
(let ((case-fold-search nil)) ; force string matching to be case sensitive
(if (and (stringp str)
(not (string-match (eval-when-compile
- (concat "\\`" erlang-atom-regexp "\\'")) str)))
+ (concat "\\`" erlang-atom-regexp "\\'"))
+ str)))
(progn
(setq str (replace-regexp-in-string "'" "\\'" str t t ))
(concat "'" str "'"))
@@ -4879,15 +4894,36 @@ about Erlang modules."
;; The backend below is a wrapper around the built-in etags backend.
;; It adds awareness of the module:tag syntax in a similar way that is
;; done above for the old etags commands.
+;;
+;; In addition arity is also considered when jumping to definitions.
+;; There is however currently no information about arity in the TAGS
+;; file. Also two functions with the same name but different arity
+;; _sometimes_ get one TAGS entry each and sometimes are joined in one
+;; single entry. If they are directly consecutive they will be
+;; joined. If there are other functions etc in between then they will
+;; get one entry each.
+;;
+;; These limitations are present in both the etags program shipped
+;; with GNU Emacs and the tags.erl program in this repository.
+;;
+;; Therefore erlang.el must complement the information in TAGS by
+;; visiting files and checking arity. When searching for popular
+;; function names (like init, handle_call etc) in a big TAGS file
+;; (like one indexing this repository) this may be quite
+;; time-consuming. There exists therefore an upper limit for the
+;; number of files to visit (called
+;; `erlang-max-files-to-visit-for-refining-xrefs').
+;;
+;; As mentioned this xref implementation is based on the etags xref
+;; implementation. But in the cases where arity is considered the
+;; etags information structures (class xref-etags-location) will be
+;; translated to our own structures which include arity (class
+;; erlang-xref-location). This translation is started in the function
+;; `erlang-refine-xrefs'.
-(defvar erlang-current-arity nil
- "The arity of the function currently being searched.
-
-There is no information about arity in the TAGS file.
-Consecutive functions with same name but different arity will
-only get one entry in the TAGS file. Matching TAGS entries are
-therefore selected without regarding arity. The arity is
-considered first when it is time to jump to the definition.")
+;; I mention this as a head up that some of the functions below deal
+;; with xref items with xref-etags-location and some deal with xref
+;; items with erlang-xref-location.
(defun erlang-etags--xref-backend () 'erlang-etags)
@@ -4895,127 +4931,80 @@ considered first when it is time to jump to the definition.")
(when (locate-library (symbol-name feature))
(require feature)))
-(and (erlang-soft-require 'xref)
- (erlang-soft-require 'cl-generic)
- (erlang-soft-require 'eieio)
- (erlang-soft-require 'etags)
- ;; The purpose of using eval here is to avoid compilation
- ;; warnings in emacsen without cl-defmethod etc.
- (eval
- '(progn
- (cl-defmethod xref-backend-identifier-at-point
- ((_backend (eql erlang-etags)))
- (if (eq this-command 'xref-find-references)
- (if (use-region-p)
- (buffer-substring-no-properties (region-beginning)
- (region-end))
- (thing-at-point 'symbol))
- (erlang-id-to-string (erlang-get-identifier-at-point))))
-
- (cl-defmethod xref-backend-definitions
- ((_backend (eql erlang-etags)) identifier)
- (erlang-xref-find-definitions identifier))
-
- (cl-defmethod xref-backend-apropos
- ((_backend (eql erlang-etags)) identifier)
- (erlang-xref-find-definitions identifier t))
-
- (cl-defmethod xref-backend-identifier-completion-table
- ((_backend (eql erlang-etags)))
- (let ((erlang-replace-etags-tags-completion-table t))
- (tags-completion-table)))
-
- (defclass erlang-xref-location (xref-etags-location) ())
-
- (defun erlang-convert-xrefs (xrefs)
- (mapcar (lambda (xref)
- (oset xref location (erlang-make-location
- (oref xref location)))
- xref)
- xrefs))
-
- (defun erlang-make-location (etags-location)
- (with-slots (tag-info file) etags-location
- (make-instance 'erlang-xref-location :tag-info tag-info
- :file file)))
-
- (cl-defmethod xref-location-marker ((locus erlang-xref-location))
- (with-slots (tag-info file) locus
- (with-current-buffer (find-file-noselect file)
- (save-excursion
- (or (erlang-goto-tag-location-by-arity tag-info)
- (etags-goto-tag-location tag-info))
- ;; Reset erlang-current-arity. We want to jump to
- ;; correct arity in the first attempt. That is now
- ;; done. Possible remaining jumps will be from
- ;; entries in the *xref* buffer and then we want to
- ;; ignore the arity. (Alternatively we could remove
- ;; all but one xref entry per file when we know the
- ;; arity).
- (setq erlang-current-arity nil)
- (point-marker)))))
-
- (defun erlang-xref-context (xref)
- (with-slots (tag-info) (xref-item-location xref)
- (car tag-info))))))
-
-
-(defun erlang-goto-tag-location-by-arity (tag-info)
- (when erlang-current-arity
- (let* ((tag-text (car tag-info))
- (tag-pos (cdr (cdr tag-info)))
- (tag-line (car (cdr tag-info)))
- (regexp (erlang-tag-info-regexp tag-text))
- (startpos (or tag-pos
- (when tag-line
- (goto-char (point-min))
- (forward-line (1- tag-line))
- (point))
- (point-min))))
- (setq startpos (max (- startpos 2000)
- (point-min)))
- (goto-char startpos)
- (let ((pos (or (erlang-search-by-arity regexp)
- (unless (eq startpos (point-min))
- (goto-char (point-min))
- (erlang-search-by-arity regexp)))))
- (when pos
- (goto-char pos)
- t)))))
-
-(defun erlang-tag-info-regexp (tag-text)
- (concat "^"
- (regexp-quote tag-text)
- ;; Erlang function entries in TAGS includes the opening
- ;; parenthesis for the argument list. Erlang macro entries
- ;; do not. Add it here in order to end up in correct
- ;; position for erlang-get-arity.
- (if (string-prefix-p "-define" tag-text)
- "\\s-*("
- "")))
-
-(defun erlang-search-by-arity (regexp)
- (let (pos)
- (while (and (null pos)
- (re-search-forward regexp nil t))
- (when (eq erlang-current-arity (save-excursion (erlang-get-arity)))
- (setq pos (point-at-bol))))
- pos))
-
-
+(when (and (erlang-soft-require 'xref)
+ (erlang-soft-require 'cl-generic)
+ (erlang-soft-require 'eieio)
+ (erlang-soft-require 'etags))
+ ;; The purpose of using eval here is to avoid compilation
+ ;; warnings in emacsen without cl-defmethod etc.
+ (eval
+ '(progn
+ (cl-defmethod xref-backend-identifier-at-point ((_backend
+ (eql erlang-etags)))
+ (if (eq this-command 'xref-find-references)
+ (if (use-region-p)
+ (buffer-substring-no-properties (region-beginning)
+ (region-end))
+ (thing-at-point 'symbol))
+ (erlang-id-to-string (erlang-get-identifier-at-point))))
+
+ (cl-defmethod xref-backend-definitions ((_backend (eql erlang-etags))
+ identifier)
+ (erlang-xref-find-definitions identifier))
+
+ (cl-defmethod xref-backend-apropos ((_backend (eql erlang-etags))
+ identifier)
+ (erlang-xref-find-definitions identifier t))
+
+ (cl-defmethod xref-backend-identifier-completion-table
+ ((_backend (eql erlang-etags)))
+ (let ((erlang-replace-etags-tags-completion-table t))
+ (tags-completion-table)))
+
+ (defclass erlang-xref-location (xref-file-location)
+ ((arity :type fixnum :initarg :arity
+ :reader erlang-xref-location-arity))
+ :documentation "An erlang location is a file location plus arity.")
+
+ ;; This method definition only calls the superclass which is
+ ;; the default behaviour if it was not defined. It is only
+ ;; needed for "upgrade" purposes. In version 2.8.1 of
+ ;; erlang.el this method was defined differently and in case
+ ;; user switch to a new erlang.el without restarting Emacs
+ ;; this method needs to be redefined.
+ (cl-defmethod xref-location-marker ((locus erlang-xref-location))
+ (cl-call-next-method locus)))))
+
+;; If this function returns a single xref the user will jump to that
+;; directly. If two or more xrefs are returned a *xref* window is
+;; displayed and the user can choose where to jump. Hence we want to
+;; return a single xref when we are pretty sure that is where the user
+;; wants to go. Otherwise return all possible xrefs but sort them so
+;; that xrefs in the local file is first and if arity is known sort
+;; the xrefs with matching arity before others.
+
+;; Note that the arity sorting work may partly be undone later when
+;; the hits are presented in the *xref* buffer since they then will be
+;; grouped together by file. Ie when one file have one hit with
+;; correct arity and others with wrong arity these hits will be
+;; grouped together and may end up before hits with correct arity.
(defun erlang-xref-find-definitions (identifier &optional is-regexp)
(erlang-with-id (kind module name arity) identifier
- (setq erlang-current-arity arity)
(cond ((eq kind 'module)
(erlang-xref-find-definitions-module name))
+ ((eq kind 'qualified-function)
+ (erlang-xref-find-definitions-qualified-function module
+ name
+ arity
+ is-regexp))
(module
- (erlang-xref-find-definitions-module-tag module
+ (erlang-xref-find-definitions-module-tag kind
+ module
name
- (eq kind
- 'qualified-function)
+ arity
is-regexp))
(t
- (erlang-xref-find-definitions-tag kind name is-regexp)))))
+ (erlang-xref-find-definitions-tag kind name arity is-regexp)))))
(defun erlang-xref-find-definitions-module (module)
(and (fboundp 'xref-make)
@@ -5040,65 +5029,252 @@ considered first when it is time to jump to the definition.")
(setq files (cdr files))))))
(nreverse xrefs))))
-(defun erlang-visit-tags-table-buffer (cont cbuf)
- (if (< emacs-major-version 26)
- (visit-tags-table-buffer cont)
- ;; Remove this with-no-warnings when Emacs 26 is the required
- ;; version minimum.
- (with-no-warnings
- (visit-tags-table-buffer cont cbuf))))
-
-(defun erlang-xref-find-definitions-module-tag (module
+(defun erlang-xref-find-definitions-qualified-function (module
+ tag
+ arity
+ is-regexp)
+ "Find definitions of TAG in MODULE preferably with arity ARITY.
+If one single perfect match was found return only that (ignoring
+other definitions matching TAG). If IS-REGEXP is non-nil then
+TAG is a regexp."
+ (let* ((xrefs (when (fboundp 'etags--xref-find-definitions)
+ (etags--xref-find-definitions tag is-regexp)))
+ (xrefs-split (erlang-split-xrefs-on-module xrefs module))
+ (module-xrefs (car xrefs-split))
+ (module-xrefs (erlang-refine-xrefs module-xrefs
+ 'qualified-function
+ tag
+ is-regexp)))
+ (or (erlang-single-arity-match module-xrefs arity)
+ (erlang-sort-by-arity module-xrefs arity))))
+
+
+;; We will end up here when erlang-get-some-other-id-at-point either
+;; found module among the import statements or module is just the
+;; current local file.
+(defun erlang-xref-find-definitions-module-tag (kind
+ module
tag
- is-qualified
+ arity
is-regexp)
- "Find definitions of TAG and filter away definitions outside of
-MODULE. If IS-QUALIFIED is nil and no definitions was found inside
-the MODULE then return any definitions found outside. If
-IS-REGEXP is non-nil then TAG is a regexp."
- (and (fboundp 'etags--xref-find-definitions)
- (fboundp 'erlang-convert-xrefs)
- (let ((xrefs (erlang-convert-xrefs
- (etags--xref-find-definitions tag is-regexp)))
- xrefs-in-module)
- (dolist (xref xrefs)
- (when (string-equal module (erlang-xref-module xref))
- (push xref xrefs-in-module)))
- (cond (is-qualified xrefs-in-module)
- (xrefs-in-module xrefs-in-module)
- (t xrefs)))))
-
-(defun erlang-xref-find-definitions-tag (kind tag is-regexp)
- "Find all definitions of TAG and reorder them so that
-definitions in the currently visited file comes first."
- (and (fboundp 'etags--xref-find-definitions)
- (fboundp 'erlang-convert-xrefs)
- (let* ((current-file (and (buffer-file-name)
- (file-truename (buffer-file-name))))
- (regexp (erlang-etags-regexp kind tag is-regexp))
- (xrefs (erlang-convert-xrefs
- (etags--xref-find-definitions regexp t)))
- local-xrefs non-local-xrefs)
- (while xrefs
- (let ((xref (car xrefs)))
- (if (string-equal (erlang-xref-truename-file xref)
- current-file)
- (push xref local-xrefs)
- (push xref non-local-xrefs))
- (setq xrefs (cdr xrefs))))
- (append (reverse local-xrefs)
- (reverse non-local-xrefs)))))
+ "Find definitions of TAG preferably in MODULE and with arity ARITY.
+Return definitions outside MODULE if none are found inside. If
+IS-REGEXP is non-nil then TAG is a regexp.
+
+If one single perfect match was found return only that (ignoring
+other definitions matching TAG)."
+ (let* ((xrefs (when (fboundp 'etags--xref-find-definitions)
+ (etags--xref-find-definitions tag is-regexp)))
+ (xrefs-split (erlang-split-xrefs-on-module xrefs module))
+ (module-xrefs (car xrefs-split))
+ (module-xrefs (erlang-refine-xrefs module-xrefs
+ kind
+ tag
+ is-regexp)))
+ (or (erlang-single-arity-match module-xrefs arity)
+ (erlang-xref-find-definitions-tag kind tag arity is-regexp xrefs))))
+
+(defun erlang-xref-find-definitions-tag (kind
+ tag
+ arity
+ is-regexp
+ &optional xrefs)
+ "Find definitions of TAG preferably in local file and with arity ARITY.
+If one single perfect match was found return only that (ignoring
+other definitions matching TAG). If no such local match was
+found then look for a matching BIF in the same way. If IS-REGEXP
+is non-nil then TAG is a regexp."
+ (let* ((regexp (erlang-etags-regexp kind tag is-regexp))
+ (xrefs (or xrefs
+ (when (fboundp 'etags--xref-find-definitions)
+ (etags--xref-find-definitions regexp t))))
+ (xrefs-split (erlang-split-xrefs xrefs))
+ (local-xrefs (car xrefs-split))
+ (local-xrefs (erlang-refine-xrefs local-xrefs
+ kind
+ tag
+ is-regexp))
+ (bif-xrefs (cadr xrefs-split))
+ (other-xrefs (caddr xrefs-split)))
+ (or (erlang-single-arity-match local-xrefs arity)
+ ;; No local match, look for a matching BIF.
+ (progn
+ (setq bif-xrefs (erlang-refine-xrefs bif-xrefs
+ kind
+ tag
+ is-regexp))
+ (erlang-single-arity-match bif-xrefs arity))
+ (progn
+ (setq other-xrefs (erlang-refine-xrefs other-xrefs
+ kind
+ tag
+ is-regexp))
+ (and (null local-xrefs)
+ (null bif-xrefs)
+ ;; No local of BIF matches at all. Is there a single
+ ;; arity match among the rest?
+ (erlang-single-arity-match other-xrefs arity)))
+ (append (erlang-sort-by-arity local-xrefs arity)
+ (erlang-sort-by-arity bif-xrefs arity)
+ (erlang-sort-by-arity other-xrefs arity)))))
+
+
+(defun erlang-refine-xrefs (xrefs kind tag is-regexp)
+ (if (or (memq kind '(record module))
+ ;; No support for apropos here.
+ is-regexp
+ (erlang-too-many-files-in-xrefs xrefs))
+ xrefs
+ (when (and xrefs
+ (fboundp 'xref-item-location)
+ (fboundp 'xref-location-group)
+ (fboundp 'slot-value))
+ (let (files)
+ (cl-loop for xref in xrefs
+ for loc = (xref-item-location xref)
+ for file = (xref-location-group loc)
+ do (pushnew file files :test 'string-equal))
+ (or (cl-loop for file in files
+ append (erlang-xrefs-in-file file kind tag is-regexp))
+ ;; Failed for some reason. Pretend like it is raining and
+ ;; return the unrefined xrefs.
+ xrefs)))))
+
+(defun erlang-too-many-files-in-xrefs (xrefs)
+ (and erlang-max-files-to-visit-for-refining-xrefs
+ (let ((files-to-visit (delete-dups
+ (mapcar #'erlang-xref-truename-file
+ xrefs))))
+ (if (< (length files-to-visit)
+ erlang-max-files-to-visit-for-refining-xrefs)
+ nil
+ (message (concat "Too many hits to consider arity (see "
+ "`erlang-max-files-to-visit-for-refining-xrefs')"))
+ t))))
+
+(defun erlang-xrefs-in-file (file kind tag is-regexp)
+ (when (fboundp 'make-instance)
+ (with-current-buffer (find-file-noselect file)
+ (save-excursion
+ (goto-char (point-min))
+ (let ((regexp (concat ; "^"
+ (erlang-etags-regexp kind tag is-regexp)
+ "\\s *("))
+ last-arity)
+ (cl-loop while (re-search-forward regexp nil t)
+ for name = (match-string-no-properties 1)
+ for arity = (save-excursion
+ (erlang-get-arity))
+ for loc = (make-instance 'erlang-xref-location
+ :file file
+ :line (line-number-at-pos)
+ :column 0
+ :arity arity)
+ for sum = (erlang-xref-summary kind name arity)
+ when (and arity
+ (not (eq arity last-arity)))
+ collect (make-instance 'xref-item
+ :summary sum
+ :location loc)
+ do (setq last-arity arity)))))))
+
+(defun erlang-xref-summary (kind tag arity)
+ (format "%s%s%s"
+ (if (memq kind '(record macro module))
+ (format "%s " kind)
+ "")
+ tag
+ (if arity (format "/%s" arity) "")))
+
+(defun erlang-single-arity-match (xrefs wanted-arity)
+ "Attempt to find one perfect match.
+
+If we have all information needed to consider arity then return a
+single perfect match or nothing. If there are more than one
+match nothing is returned.
+
+If we don't have all information needed to consider arity just
+return XREFS as is."
+ (if (erlang-should-consider-arity-p xrefs wanted-arity)
+ (let ((nr-matches 0)
+ match)
+ (while (and xrefs
+ (< nr-matches 2))
+ (let* ((xref (car xrefs))
+ (arity (erlang-xref-arity xref)))
+ (when (eq arity wanted-arity)
+ (setq match xref
+ nr-matches (1+ nr-matches)))
+ (setq xrefs (cdr xrefs))))
+ (when (eq nr-matches 1)
+ (list match)))
+ (when (eq (length xrefs) 1)
+ xrefs)))
+
+(defun erlang-sort-by-arity (xrefs wanted-arity)
+ (if (erlang-should-consider-arity-p xrefs wanted-arity)
+ (let (matches non-matches)
+ (while xrefs
+ (let* ((xref (car xrefs))
+ (arity (erlang-xref-arity xref)))
+ (push xref (if (eq arity wanted-arity)
+ matches
+ non-matches))
+ (setq xrefs (cdr xrefs))))
+ (append (reverse matches) (reverse non-matches) xrefs))
+ xrefs))
+
+(defun erlang-should-consider-arity-p (xrefs wanted-arity)
+ (and wanted-arity
+ xrefs
+ (fboundp 'erlang-xref-location-p)
+ (fboundp 'xref-item-location)
+ (erlang-xref-location-p (xref-item-location (car xrefs)))))
(defun erlang-etags-regexp (kind tag is-regexp)
- (let ((tag-regexp (if is-regexp
- tag
- (regexp-quote tag))))
- (cond ((eq kind 'record)
- (concat "-record\\s-*(\\s-*" tag-regexp))
- ((eq kind 'macro)
- (concat "-define\\s-*(\\s-*" tag-regexp))
- (t tag-regexp))))
-
+ (let ((tag-regexp (concat "\\("
+ (if is-regexp
+ tag
+ (regexp-quote tag))
+ "\\)")))
+ (concat (if is-regexp "" "^")
+ (cond ((eq kind 'record)
+ (concat "-record\\s-*(\\s-*" tag-regexp))
+ ((eq kind 'macro)
+ (concat "-define\\s-*(\\s-*" tag-regexp))
+ (t
+ tag-regexp))
+ (if is-regexp "" "\\_>"))))
+
+(defun erlang-xref-arity (xref)
+ (and (fboundp 'erlang-xref-location-arity)
+ (fboundp 'xref-item-location)
+ (erlang-xref-location-arity (xref-item-location xref))))
+
+(defun erlang-split-xrefs-on-module (xrefs module)
+ (let (local-xrefs non-local-xrefs)
+ (dolist (xref xrefs)
+ (if (string-equal (erlang-xref-module xref)
+ module)
+ (push xref local-xrefs)
+ (push xref non-local-xrefs)))
+ (cons (reverse local-xrefs)
+ (reverse non-local-xrefs))))
+
+(defun erlang-split-xrefs (xrefs)
+ (let ((current-file (and (buffer-file-name)
+ (file-truename (buffer-file-name))))
+ local-xrefs bif-xrefs other-xrefs)
+ (dolist (xref xrefs)
+ (cond ((string-equal (erlang-xref-truename-file xref) current-file)
+ (push xref local-xrefs))
+ ((string-equal (erlang-xref-module xref) "erlang")
+ (push xref bif-xrefs))
+ (t
+ (push xref other-xrefs))))
+ (list (reverse local-xrefs)
+ (reverse bif-xrefs)
+ (reverse other-xrefs))))
(defun erlang-xref-module (xref)
(erlang-get-module-from-file-name (erlang-xref-file xref)))
@@ -5113,7 +5289,13 @@ definitions in the currently visited file comes first."
(fboundp 'xref-item-location)
(xref-location-group (xref-item-location xref))))
-
+(defun erlang-visit-tags-table-buffer (cont cbuf)
+ (if (< emacs-major-version 26)
+ (visit-tags-table-buffer cont)
+ ;; Remove this with-no-warnings when Emacs 26 is the required
+ ;; version minimum.
+ (with-no-warnings
+ (visit-tags-table-buffer cont cbuf))))
;;;
;;; Prepare for other methods to run an Erlang slave process.
diff --git a/lib/tools/test/emacs_SUITE.erl b/lib/tools/test/emacs_SUITE.erl
index a6d43d1816..8756a4e9b3 100644
--- a/lib/tools/test/emacs_SUITE.erl
+++ b/lib/tools/test/emacs_SUITE.erl
@@ -70,19 +70,20 @@ bif_highlight(Config) ->
check_bif_highlight(Bin, Tag, Compare) ->
- [_H,IntMatch,_T] =
+ [_H,Match,_T] =
re:split(Bin,<<"defvar ",Tag/binary,
"[^(]*\\(([^)]*)">>,[]),
- EmacsIntBifs = [list_to_atom(S) ||
- S <- string:tokens(binary_to_list(IntMatch)," '\"\n")],
+ EmacsBifs = [list_to_atom(S) ||
+ S <- string:tokens(binary_to_list(Match)," '\"\n")],
- ct:log("Emacs ~p",[EmacsIntBifs]),
- ct:log("Int ~p",[Compare]),
+ ct:log("Comparing ~s", [Tag]),
+ ct:log("Emacs ~p",[EmacsBifs]),
+ ct:log("Erlang ~p",[Compare]),
- ct:log("Diff1 ~p",[Compare -- EmacsIntBifs]),
- ct:log("Diff2 ~p",[EmacsIntBifs -- Compare]),
- [] = Compare -- EmacsIntBifs,
- [] = EmacsIntBifs -- Compare.
+ ct:log("Only in Erlang ~p",[Compare -- EmacsBifs]),
+ ct:log("Only in Emacs ~p",[EmacsBifs -- Compare]),
+ [] = Compare -- EmacsBifs,
+ [] = EmacsBifs -- Compare.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -188,7 +189,9 @@ diff(Orig, File) ->
end.
emacs_version_ok(AcceptVer) ->
- case os:cmd("emacs --version | head -1") of
+ VersionLine = os:cmd("emacs --version | head -1"),
+ io:format("~s~n", [VersionLine]),
+ case VersionLine of
"GNU Emacs " ++ Ver ->
case string:to_float(Ver) of
{Vsn, _} when Vsn >= AcceptVer ->
diff --git a/lib/wx/examples/simple/hello2.erl b/lib/wx/examples/simple/hello2.erl
index 656c056d9a..07a9a56b7d 100644
--- a/lib/wx/examples/simple/hello2.erl
+++ b/lib/wx/examples/simple/hello2.erl
@@ -33,7 +33,7 @@
init/1, handle_info/2, handle_event/2, handle_call/3,
code_change/3, terminate/2]).
--behavoiur(wx_object).
+-behaviour(wx_object).
-record(state, {win}).
diff --git a/make/emd2exml.in b/make/emd2exml.in
index 24837696f4..ec3de0a7f8 100755
--- a/make/emd2exml.in
+++ b/make/emd2exml.in
@@ -462,7 +462,7 @@ url([C|Cs], Bool, Acc) ->
url(Cs, Bool, [C|Acc]).
link_or_image(Str, Type) ->
- case link_or_image_text(Str, "") of
+ case link_or_image_text(Str) of
no -> no;
{Text, Cont1} ->
case link_or_image_data(Cont1, none, Type, "", "") of
@@ -471,9 +471,14 @@ link_or_image(Str, Type) ->
{["<url href=\"", text(Url), "\">", text(Text), "</url>"],
Cont2};
{seealso, SeeAlso, _Title, Cont2} ->
- {["<seealso marker=\"", text(SeeAlso), "\">",
- text(Text), "</seealso>"],
- Cont2};
+ case internal_seealso(SeeAlso) of
+ no ->
+ {["<seealso marker=\"", text(SeeAlso), "\">",
+ text(Text), "</seealso>"],
+ Cont2};
+ {yes, SeeAlsoKey} ->
+ {delayed, link, SeeAlsoKey, text(Text), Cont2}
+ end;
{image, Image, Title, Cont2} ->
{["<image file=\"", text(Image), "\"><icaption>",
text(Title), "</icaption></image>"],
@@ -485,16 +490,41 @@ link_or_image(Str, Type) ->
end
end.
+internal_seealso("#" ++ Marker) ->
+ {yes, {internal, Marker}};
+internal_seealso(_) ->
+ no.
+
+link_or_image_text(Cs0) ->
+ {Prefix, Cs2} = case Cs0 of
+ "__" ++ Cs1 -> {"__", Cs1};
+ "_" ++ Cs1 -> {"_", Cs1};
+ "**" ++ Cs1 -> {"**", Cs1};
+ "*" ++ Cs1 -> {"*", Cs1};
+ Cs1 -> {"", Cs1}
+ end,
+ {Text0, Cs} = link_or_image_text(Cs2, []),
+ Text = case lists:prefix(Prefix, Text0) of
+ false ->
+ lists:reverse(Text0, Prefix);
+ true ->
+ lists:reverse(lists:nthtail(length(Prefix), Text0))
+ end,
+ case Text of
+ [] ->
+ no;
+ [_|_] ->
+ {Text, Cs}
+ end.
+
link_or_image_text([$\\,C|Cs], Acc) ->
link_or_image_text(Cs, [C|Acc]);
-link_or_image_text([$]|_Cs], "") ->
- no;
link_or_image_text([$]|Cs], Acc) ->
- {lists:reverse(Acc), Cs};
+ {Acc, Cs};
link_or_image_text([C|Cs], Acc) ->
link_or_image_text(Cs, [C|Acc]);
link_or_image_text([], _Acc) ->
- no.
+ {[], []}.
link_or_image_data([C|Cs], none, link, "", "") when C == $ ; C == $\t ->
link_or_image_data(Cs, none, link, "", "");
@@ -615,8 +645,10 @@ put_title(S, 1, Title) ->
put_title(#state{mlist = MList0,
toc = TOC} = S0, H, Title) ->
TitleStr = text(Title),
- MList1 = [mk_lvl_marker(Title) | MList0],
+ TitleMarker = mk_lvl_marker(Title),
+ MList1 = [TitleMarker | MList0],
Marker = mk_marker(MList1),
+ MarkerKey = string:lowercase(TitleMarker),
S1 = chk_h1(H,
S0#state{toc = [TOC,
lists:duplicate(H," "),
@@ -624,13 +656,15 @@ put_title(#state{mlist = MList0,
"<seealso marker=\"#",Marker,"\">",
TitleStr,"</seealso>",nl()],
h = H,
- mlist = MList1}),
+ mlist = MList1
+ }),
S2 = put_chars(S1, ["<marker id=\"", Marker, "\"/>",nl()]),
+ S3 = write_delayed(S2, {internal, MarkerKey}, {"#" ++ Marker, ""}),
{STag, ETag} = case H > ?MAX_HEADING of
true -> {"<p><strong>", "</strong></p>"};
false -> {"<title>", "</title>"}
end,
- put_chars(S2, [STag, TitleStr, ETag, nl()]).
+ put_chars(S3, [STag, TitleStr, ETag, nl()]).
setext_heading(H, #state{line = Line, h = OldH} = S0) ->
S1 = sections(H, OldH, S0),
@@ -1204,7 +1238,7 @@ put_delayed(#state{out = Out} = S, Key, Data) ->
S#state{out = [{delayed, Key, Data} | Out]}.
put_chars(#state{out = Out} = S, Chars) ->
- S#state{out = [[Chars] | Out]}.
+ S#state{out = [Chars | Out]}.
put_line(#state{out = Out} = S, String) ->
S#state{out = [[String, nl()] | Out]}.
@@ -1219,6 +1253,15 @@ complete_output(S, [], Out) ->
Out]};
complete_output(S, [{delayed, IX}|Rest], Out) ->
complete_output(S, Rest, [read_delayed(S, IX)|Out]);
+complete_output(S, [{delayed, {internal, Key0}, {link, Text, _Line}}|Rest], Out) ->
+ Key = [C || C <- Key0, C =/= $_],
+ case read_delayed(S, {internal, Key}) of
+ {value, {Url, _}} ->
+ complete_output(S, Rest, [mk_link(Text, Url)|Out]);
+ none ->
+ Url = "#" ++ Key0,
+ complete_output(S, Rest, [mk_link(Text, Url)|Out])
+ end;
complete_output(S, [{delayed, Key, {link, Text, Line}}|Rest], Out) ->
case read_delayed(S, Key) of
{value, {Url, _Title}} ->
@@ -1235,9 +1278,27 @@ complete_output(S, [{delayed, Key, {image, _Text, Line}}|Rest], Out) ->
{File, _} = S#state.ifile,
error(File, Line, "Image definition name `~ts' not found~n", [Key])
end;
+complete_output(S, [["</p>","\n"]=ParaStart,
+ Contents,
+ ["<p>","\n"]=ParaEnd|Rest], Out) ->
+ case is_image_tag(Contents) of
+ true ->
+ %% Get rid of the paragraph around an image tag. It would mess up
+ %% figure numbering.
+ complete_output(S, Rest, [Contents|Out]);
+ false ->
+ complete_output(S, [Contents,ParaEnd|Rest], [ParaStart|Out])
+ end;
complete_output(S, [Next|Rest], Out) ->
complete_output(S, Rest, [Next|Out]).
+is_image_tag("<image" ++ _) ->
+ true;
+is_image_tag([[_|_]=H | _]) ->
+ is_image_tag(H);
+is_image_tag(_) ->
+ false.
+
write_output(_OFD, []) ->
ok;
write_output(OFD, [O|Os]) ->
diff --git a/make/otp_release_targets.mk b/make/otp_release_targets.mk
index d1fbf6c58f..615bf1adb7 100644
--- a/make/otp_release_targets.mk
+++ b/make/otp_release_targets.mk
@@ -156,7 +156,7 @@ endif
## These are the patterns of file names that xmllint cannot currently parse
-XI_INC_FILES:=%user_man.xml %usersguide.xml %refman.xml %ref_man.xml %part.xml %book.xml
+XI_INC_FILES:=%user_man.xml %usersguide.xml %refman.xml %ref_man.xml %part.xml %book.xml %internal.xml
## These are the files that we should run the xmllint on
LINT_XI_INC_FILES := $(filter-out $(XI_INC_FILES), $(ALL_XI_INC_FILES))
diff --git a/otp_versions.table b/otp_versions.table
index cc5d331b06..37b5061519 100644
--- a/otp_versions.table
+++ b/otp_versions.table
@@ -1,3 +1,4 @@
+OTP-21.3.3 : erts-10.3.2 kernel-6.3.1 stdlib-3.8.1 # asn1-5.0.8 common_test-1.17 compiler-7.3.2 crypto-4.4.1 debugger-4.2.6 dialyzer-3.3.2 diameter-2.2 edoc-0.10 eldap-1.2.6 erl_docgen-0.9 erl_interface-3.11.1 et-1.6.4 eunit-2.3.7 ftp-1.0.2 hipe-3.18.3 inets-7.0.6 jinterface-1.9.1 megaco-3.18.4 mnesia-4.15.6 observer-2.9 odbc-2.12.3 os_mon-2.4.7 otp_mibs-1.2.1 parsetools-2.1.8 public_key-1.6.5 reltool-0.7.8 runtime_tools-1.13.2 sasl-3.3 snmp-5.2.12 ssh-4.7.4 ssl-9.2.1 syntax_tools-2.1.7 tftp-1.0.1 tools-3.1 wx-1.8.7 xmerl-1.3.20 :
OTP-21.3.2 : erts-10.3.1 xmerl-1.3.20 # asn1-5.0.8 common_test-1.17 compiler-7.3.2 crypto-4.4.1 debugger-4.2.6 dialyzer-3.3.2 diameter-2.2 edoc-0.10 eldap-1.2.6 erl_docgen-0.9 erl_interface-3.11.1 et-1.6.4 eunit-2.3.7 ftp-1.0.2 hipe-3.18.3 inets-7.0.6 jinterface-1.9.1 kernel-6.3 megaco-3.18.4 mnesia-4.15.6 observer-2.9 odbc-2.12.3 os_mon-2.4.7 otp_mibs-1.2.1 parsetools-2.1.8 public_key-1.6.5 reltool-0.7.8 runtime_tools-1.13.2 sasl-3.3 snmp-5.2.12 ssh-4.7.4 ssl-9.2.1 stdlib-3.8 syntax_tools-2.1.7 tftp-1.0.1 tools-3.1 wx-1.8.7 :
OTP-21.3.1 : erl_interface-3.11.1 ssl-9.2.1 # asn1-5.0.8 common_test-1.17 compiler-7.3.2 crypto-4.4.1 debugger-4.2.6 dialyzer-3.3.2 diameter-2.2 edoc-0.10 eldap-1.2.6 erl_docgen-0.9 erts-10.3 et-1.6.4 eunit-2.3.7 ftp-1.0.2 hipe-3.18.3 inets-7.0.6 jinterface-1.9.1 kernel-6.3 megaco-3.18.4 mnesia-4.15.6 observer-2.9 odbc-2.12.3 os_mon-2.4.7 otp_mibs-1.2.1 parsetools-2.1.8 public_key-1.6.5 reltool-0.7.8 runtime_tools-1.13.2 sasl-3.3 snmp-5.2.12 ssh-4.7.4 stdlib-3.8 syntax_tools-2.1.7 tftp-1.0.1 tools-3.1 wx-1.8.7 xmerl-1.3.19 :
OTP-21.3 : common_test-1.17 compiler-7.3.2 crypto-4.4.1 dialyzer-3.3.2 diameter-2.2 edoc-0.10 erl_docgen-0.9 erl_interface-3.11 erts-10.3 ftp-1.0.2 hipe-3.18.3 inets-7.0.6 kernel-6.3 mnesia-4.15.6 observer-2.9 odbc-2.12.3 public_key-1.6.5 runtime_tools-1.13.2 ssh-4.7.4 ssl-9.2 stdlib-3.8 syntax_tools-2.1.7 tools-3.1 wx-1.8.7 # asn1-5.0.8 debugger-4.2.6 eldap-1.2.6 et-1.6.4 eunit-2.3.7 jinterface-1.9.1 megaco-3.18.4 os_mon-2.4.7 otp_mibs-1.2.1 parsetools-2.1.8 reltool-0.7.8 sasl-3.3 snmp-5.2.12 tftp-1.0.1 xmerl-1.3.19 :
diff --git a/system/doc/efficiency_guide/commoncaveats.xml b/system/doc/efficiency_guide/commoncaveats.xml
index 367da09ba3..7b2128d888 100644
--- a/system/doc/efficiency_guide/commoncaveats.xml
+++ b/system/doc/efficiency_guide/commoncaveats.xml
@@ -36,10 +36,9 @@
<title>Timer Module</title>
<p>Creating timers using <seealso
- marker="erts:erlang#erlang:send_after/3">erlang:send_after/3</seealso>
+ marker="erts:erlang#send_after/3">erlang:send_after/3</seealso>
and
- <seealso marker="erts:erlang#erlang:start_timer/3">erlang:start_timer/3</seealso>
-,
+ <seealso marker="erts:erlang#start_timer/3">erlang:start_timer/3</seealso>,
is much more efficient than using the timers provided by the
<seealso marker="stdlib:timer">timer</seealso> module in STDLIB.
The <c>timer</c> module uses a separate process to manage the timers.
diff --git a/system/doc/installation_guide/Makefile b/system/doc/installation_guide/Makefile
index 38252757d6..c5234c1c9a 100644
--- a/system/doc/installation_guide/Makefile
+++ b/system/doc/installation_guide/Makefile
@@ -113,6 +113,8 @@ clean clean_docs:
rm -f $(GENERATED_XML_FILES)
rm -f $(XMLDIR)/*.xml
rm -f $(HTMLDIR)/*.gif $(HTMLDIR)/*.html
+ rm -f $(XML_GEN_FILES)
+ rm -rf $(HTMLDIR)
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/system/doc/tutorial/overview.xml b/system/doc/tutorial/overview.xml
index 255c22f2c1..bd652b1e4b 100644
--- a/system/doc/tutorial/overview.xml
+++ b/system/doc/tutorial/overview.xml
@@ -245,13 +245,13 @@ Term = binary_to_term(Binary)</pre>
</section>
<section>
- <title>IC</title>
+ <title>IC and CORBA</title>
<p>IC (Erlang IDL Compiler) is an interface generator that, given
an IDL interface specification, automatically generates stub
code in Erlang, C, or Java. See the IC User's Guide and IC
Reference Manual.</p>
- <p>For details, see the <seealso marker="ic:ic">ic</seealso>
- manual page in IC.</p>
+ <p>For details, see the
+ <url href="https://github.com/erlang/corba">corba repository</url>.</p>
</section>
<section>