aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/asn1/doc/src/notes.xml32
-rw-r--r--lib/asn1/vsn.mk2
-rw-r--r--lib/common_test/doc/src/notes.xml88
-rw-r--r--lib/common_test/vsn.mk2
-rw-r--r--lib/compiler/doc/src/notes.xml29
-rw-r--r--lib/compiler/vsn.mk2
-rw-r--r--lib/crypto/doc/src/notes.xml25
-rw-r--r--lib/crypto/vsn.mk2
-rw-r--r--lib/debugger/doc/src/i.xml2
-rw-r--r--lib/debugger/doc/src/int.xml2
-rw-r--r--lib/debugger/doc/src/notes.xml23
-rw-r--r--lib/debugger/src/dbg_wx_mon.erl2
-rw-r--r--lib/debugger/src/i.erl4
-rw-r--r--lib/debugger/vsn.mk2
-rw-r--r--lib/dialyzer/doc/src/notes.xml38
-rw-r--r--lib/dialyzer/vsn.mk2
-rw-r--r--lib/diameter/doc/src/notes.xml62
-rw-r--r--lib/edoc/doc/src/notes.xml16
-rw-r--r--lib/edoc/vsn.mk2
-rw-r--r--lib/eldap/doc/src/eldap.xml20
-rw-r--r--lib/eldap/doc/src/notes.xml29
-rw-r--r--lib/eldap/src/eldap.erl3
-rw-r--r--lib/eldap/test/Makefile5
-rw-r--r--lib/eldap/test/eldap_basic_SUITE.erl1144
-rw-r--r--lib/eldap/test/eldap_basic_SUITE_data/RANDbin0 -> 512 bytes
-rw-r--r--lib/eldap/test/eldap_connections_SUITE.erl147
-rw-r--r--lib/eldap/test/eldap_misc_SUITE.erl51
-rw-r--r--lib/eldap/test/make_certs.erl357
-rw-r--r--lib/erl_docgen/doc/src/notes.xml18
-rw-r--r--lib/erl_docgen/vsn.mk2
-rw-r--r--lib/erl_interface/doc/src/notes.xml36
-rw-r--r--lib/erl_interface/src/Makefile.in22
-rw-r--r--lib/erl_interface/src/erl_interface.appup.src18
-rw-r--r--lib/erl_interface/vsn.mk2
-rw-r--r--lib/eunit/doc/src/notes.xml22
-rw-r--r--lib/eunit/vsn.mk2
-rw-r--r--lib/hipe/doc/src/notes.xml16
-rw-r--r--lib/hipe/rtl/hipe_rtl_binary_match.erl18
-rw-r--r--lib/hipe/vsn.mk2
-rw-r--r--lib/inets/doc/src/notes.xml32
-rw-r--r--lib/inets/src/http_client/httpc_handler.erl19
-rw-r--r--lib/inets/test/httpc_SUITE.erl29
-rw-r--r--lib/jinterface/doc/src/notes.xml34
-rw-r--r--lib/jinterface/java_src/com/ericsson/otp/erlang/Makefile10
-rw-r--r--lib/jinterface/java_src/com/ericsson/otp/erlang/jinterface.appup.src18
-rw-r--r--lib/jinterface/vsn.mk2
-rw-r--r--lib/kernel/doc/src/notes.xml53
-rw-r--r--lib/kernel/vsn.mk2
-rw-r--r--lib/megaco/doc/src/notes.xml19
-rw-r--r--lib/megaco/src/app/megaco.appup.src5
-rw-r--r--lib/megaco/vsn.mk2
-rw-r--r--lib/mnesia/doc/src/notes.xml25
-rw-r--r--lib/mnesia/vsn.mk2
-rw-r--r--lib/observer/doc/src/notes.xml16
-rw-r--r--lib/observer/vsn.mk2
-rw-r--r--lib/odbc/doc/src/notes.xml41
-rw-r--r--lib/odbc/vsn.mk2
-rw-r--r--lib/orber/src/cdr_decode.erl4
-rw-r--r--lib/otp_mibs/doc/src/notes.xml16
-rw-r--r--lib/otp_mibs/vsn.mk2
-rw-r--r--lib/parsetools/doc/src/notes.xml18
-rw-r--r--lib/parsetools/vsn.mk2
-rw-r--r--lib/percept/doc/src/notes.xml15
-rw-r--r--lib/percept/vsn.mk2
-rw-r--r--lib/runtime_tools/doc/src/notes.xml17
-rw-r--r--lib/runtime_tools/vsn.mk2
-rw-r--r--lib/ssh/doc/src/notes.xml94
-rw-r--r--lib/ssh/doc/src/ssh_connection.xml14
-rw-r--r--lib/ssh/src/ssh.app.src2
-rw-r--r--lib/ssh/src/ssh.appup.src2
-rw-r--r--lib/ssh/src/ssh_connection.erl34
-rw-r--r--lib/ssh/src/ssh_connection_handler.erl15
-rw-r--r--lib/ssh/test/ssh_connection_SUITE.erl54
-rw-r--r--lib/ssl/doc/src/notes.xml31
-rw-r--r--lib/stdlib/doc/src/ets.xml15
-rw-r--r--lib/stdlib/doc/src/notes.xml103
-rw-r--r--lib/stdlib/src/binary.erl8
-rw-r--r--lib/stdlib/src/ets.erl9
-rw-r--r--lib/stdlib/test/ets_SUITE.erl39
-rw-r--r--lib/stdlib/vsn.mk2
-rw-r--r--lib/syntax_tools/doc/src/notes.xml21
-rw-r--r--lib/syntax_tools/vsn.mk2
-rw-r--r--lib/test_server/doc/src/notes.xml41
-rw-r--r--lib/test_server/vsn.mk2
-rw-r--r--lib/tools/doc/src/notes.xml35
-rw-r--r--lib/tools/vsn.mk2
-rw-r--r--lib/wx/doc/src/notes.xml29
-rw-r--r--lib/wx/vsn.mk2
88 files changed, 2484 insertions, 714 deletions
diff --git a/lib/asn1/doc/src/notes.xml b/lib/asn1/doc/src/notes.xml
index a7032737bd..cf87c01658 100644
--- a/lib/asn1/doc/src/notes.xml
+++ b/lib/asn1/doc/src/notes.xml
@@ -31,6 +31,38 @@
<p>This document describes the changes made to the asn1 application.</p>
+<section><title>Asn1 3.0.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ When decoding BER, primitives with an indefinite length
+ will be immediately rejected. (Thanks to Simon Cornish
+ for reporting this bug.)</p>
+ <p>
+ Own Id: OTP-12205</p>
+ </item>
+ <item>
+ <p>
+ BER: A bug with compliance to X.680 (200811) s31.2.7 has
+ been fixed. Basically, when TagDefault is AUTOMATIC then
+ tags are IMPLICIT unless EXPLICIT is given.</p>
+ <p>
+ Own Id: OTP-12318</p>
+ </item>
+ <item>
+ <p>
+ Usage of the <c>EXTERNAL</c> 1994 variant type was
+ broken.</p>
+ <p>
+ Own Id: OTP-12326</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Asn1 3.0.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/asn1/vsn.mk b/lib/asn1/vsn.mk
index d87c50637d..daaf26a17f 100644
--- a/lib/asn1/vsn.mk
+++ b/lib/asn1/vsn.mk
@@ -1,2 +1,2 @@
#next version number to use is 2.0
-ASN1_VSN = 3.0.2
+ASN1_VSN = 3.0.3
diff --git a/lib/common_test/doc/src/notes.xml b/lib/common_test/doc/src/notes.xml
index f4ce5369f7..94738d2eff 100644
--- a/lib/common_test/doc/src/notes.xml
+++ b/lib/common_test/doc/src/notes.xml
@@ -32,6 +32,94 @@
<file>notes.xml</file>
</header>
+<section><title>Common_Test 1.9</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The source code to html code generator in Test Server
+ (and Common Test) would fail to generate anchors in the
+ html code for functions with non-expandable macros,
+ resulting in bad html links to such functions. This
+ correction lets the code generator ignore macros that
+ can't be expanded (i.e. not pre-process them), so that
+ correct anchors will always be produced.</p>
+ <p>
+ Own Id: OTP-11766 Aux Id: seq12556 </p>
+ </item>
+ <item>
+ <p>
+ OTP-11971 erroneously changed the handling of relative
+ paths (import/export files) specified in the cover spec
+ file. This is now corrected so these are expected to be
+ relative to the directory where the cover spec file
+ itself is stored.</p>
+ <p>
+ Own Id: OTP-12031</p>
+ </item>
+ <item>
+ <p>
+ Common Test would sometimes crash while trying to print
+ large amounts of SASL reports to log on a computer with a
+ slow file system. This problem (due to an error in IO
+ message buffering in ct_logs) has been fixed.</p>
+ <p>
+ Own Id: OTP-12159</p>
+ </item>
+ <item>
+ <p>
+ The common_test telnet client, ct_telnet and friends, had
+ some unstable test cases. Some of these were caused by
+ the unix_telnet callback sending an extra newline after
+ sending the password. This caused the sever to send an
+ extra prompt back which confused the tests. The extra
+ newline is no longer sent.</p>
+ <p>
+ Also, debug printouts and logging from the telnet client
+ is improved, and some test cases are slightly modified in
+ order to stabilize the test.</p>
+ <p>
+ Own Id: OTP-12329</p>
+ </item>
+ <item>
+ <p>
+ ct_netconfc did not expect the return value
+ {error,timeout} from ssh_connection:subsystem/4. This has
+ been corrected.</p>
+ <p>
+ Own Id: OTP-12334</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ A new option, <c>{newline,boolean()}</c> is added to all
+ functions in <c>ct_telnet</c> that send data (command
+ strings) to the telnet server. By default,
+ <c>ct_telnet</c> adds a newline to all command strings,
+ and by setting the new option to <c>false</c> this
+ behavior is turned off.</p>
+ <p>
+ Own Id: OTP-12252 Aux Id: seq12730 </p>
+ </item>
+ <item>
+ <p>
+ Distribute <c>autoconf</c> helpers to applications at
+ build time instead of having multiple identical copies
+ committed in the repository.</p>
+ <p>
+ Own Id: OTP-12348</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Common_Test 1.8.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/common_test/vsn.mk b/lib/common_test/vsn.mk
index 00c0925b40..849edc15e1 100644
--- a/lib/common_test/vsn.mk
+++ b/lib/common_test/vsn.mk
@@ -1 +1 @@
-COMMON_TEST_VSN = 1.8.2
+COMMON_TEST_VSN = 1.9
diff --git a/lib/compiler/doc/src/notes.xml b/lib/compiler/doc/src/notes.xml
index d48a0a5599..84ebd2f210 100644
--- a/lib/compiler/doc/src/notes.xml
+++ b/lib/compiler/doc/src/notes.xml
@@ -31,6 +31,35 @@
<p>This document describes the changes made to the Compiler
application.</p>
+<section><title>Compiler 5.0.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Named funs with the same name and arity could get mixed
+ up with each other.</p>
+ <p>
+ Own Id: OTP-12262</p>
+ </item>
+ <item>
+ <p>
+ Coalesce map keys in dialyzer mode</p>
+ <p>
+ This fixes a regression introduced in commit
+ 805f9c89fc01220bc1bb0f27e1b68fd4eca688ba The problem
+ occurred with compounded map keys compiled with dialyzer
+ option turned on, '+dialyzer'.</p>
+ <p>
+ Reported by: Ivan Uemlianin</p>
+ <p>
+ Own Id: OTP-12347</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Compiler 5.0.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/compiler/vsn.mk b/lib/compiler/vsn.mk
index d042596557..b1a6c15ac9 100644
--- a/lib/compiler/vsn.mk
+++ b/lib/compiler/vsn.mk
@@ -1 +1 @@
-COMPILER_VSN = 5.0.2
+COMPILER_VSN = 5.0.3
diff --git a/lib/crypto/doc/src/notes.xml b/lib/crypto/doc/src/notes.xml
index 82b6de9acd..605d61e8e4 100644
--- a/lib/crypto/doc/src/notes.xml
+++ b/lib/crypto/doc/src/notes.xml
@@ -30,6 +30,31 @@
</header>
<p>This document describes the changes made to the Crypto application.</p>
+<section><title>Crypto 3.4.2</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Add configure option --with-ssl-incl=PATH to support
+ OpenSSL installations with headers and libraries at
+ different places.</p>
+ <p>
+ Own Id: OTP-12215 Aux Id: seq12700 </p>
+ </item>
+ <item>
+ <p>
+ Add configure option --with-ssl-rpath to control which
+ runtime library path to use for dynamic linkage toward
+ OpenSSL.</p>
+ <p>
+ Own Id: OTP-12316 Aux Id: seq12753 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Crypto 3.4.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/crypto/vsn.mk b/lib/crypto/vsn.mk
index 2a7f3c4558..b87685cb3f 100644
--- a/lib/crypto/vsn.mk
+++ b/lib/crypto/vsn.mk
@@ -1 +1 @@
-CRYPTO_VSN = 3.4.1
+CRYPTO_VSN = 3.4.2
diff --git a/lib/debugger/doc/src/i.xml b/lib/debugger/doc/src/i.xml
index fb7641c30e..7564da79b3 100644
--- a/lib/debugger/doc/src/i.xml
+++ b/lib/debugger/doc/src/i.xml
@@ -211,7 +211,7 @@
the result of calling the shell function <c>pid(X,Y,Z)</c>.
An attached process is expected to call the unofficial
<c>int:attached(Pid)</c> function and to be able to handle
- messages from the interpreter, see <c>dbg_ui_trace.erl</c> for
+ messages from the interpreter, see <c>dbg_wx_trace.erl</c> for
an example.</p>
</desc>
</func>
diff --git a/lib/debugger/doc/src/int.xml b/lib/debugger/doc/src/int.xml
index 3a5886ceb9..96d0d7f83d 100644
--- a/lib/debugger/doc/src/int.xml
+++ b/lib/debugger/doc/src/int.xml
@@ -49,7 +49,7 @@
execution. This is done by sending and receiving information
to/from the process via a third process, called the meta process.
It is possible to implement your own attached process. See
- <c>int.erl</c> for available functions and <c>dbg_ui_trace.erl</c>
+ <c>int.erl</c> for available functions and <c>dbg_wx_trace.erl</c>
for possible messages.</p>
<p>The interpreter depends on the Kernel, STDLIB and GS
diff --git a/lib/debugger/doc/src/notes.xml b/lib/debugger/doc/src/notes.xml
index c1ba1eec6b..b4baa2a1cd 100644
--- a/lib/debugger/doc/src/notes.xml
+++ b/lib/debugger/doc/src/notes.xml
@@ -32,6 +32,29 @@
<p>This document describes the changes made to the Debugger
application.</p>
+<section><title>Debugger 4.0.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Make sure to install .hrl files when needed</p>
+ <p>
+ Own Id: OTP-12197</p>
+ </item>
+ <item>
+ <p>
+ Invoking debugger functions <c>ia/1</c> and <c>iaa/1</c>
+ crashed, when it tried to invoke the old and removed gs
+ based gui functions.</p>
+ <p>
+ Own Id: OTP-12357</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Debugger 4.0.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/debugger/src/dbg_wx_mon.erl b/lib/debugger/src/dbg_wx_mon.erl
index 4ab03985d3..aed86f5232 100644
--- a/lib/debugger/src/dbg_wx_mon.erl
+++ b/lib/debugger/src/dbg_wx_mon.erl
@@ -414,7 +414,7 @@ gui_cmd({'Trace Window', TraceWin}, State) ->
State2 = State#state{tracewin=TraceWin},
case State#state.attach of
false -> ignore;
- {Flags, {dbg_ui_trace, start, StartFlags}} ->
+ {Flags, {dbg_wx_trace, start, StartFlags}} ->
case trace_function(State2) of
{_, _, StartFlags} -> ignore;
NewFunction -> % {_, _, NewStartFlags}
diff --git a/lib/debugger/src/i.erl b/lib/debugger/src/i.erl
index 5805501524..0afb998097 100644
--- a/lib/debugger/src/i.erl
+++ b/lib/debugger/src/i.erl
@@ -250,7 +250,7 @@ ist(Flag) ->
%% -------------------------------------------
iaa(Flag) ->
- iaa(Flag,{dbg_ui_trace,start,[]}).
+ iaa(Flag,{dbg_wx_trace,start,[]}).
%% -------------------------------------------
%% Set the automatic attachment flag.
@@ -271,7 +271,7 @@ iaa(Flag,Fnk) ->
%% -------------------------------------------
ia(Pid) ->
- ia(Pid,{dbg_ui_trace,start}).
+ ia(Pid,{dbg_wx_trace,start}).
%% -------------------------------------------
%% Attach to process.
diff --git a/lib/debugger/vsn.mk b/lib/debugger/vsn.mk
index 33481a1537..38c19be93e 100644
--- a/lib/debugger/vsn.mk
+++ b/lib/debugger/vsn.mk
@@ -1 +1 @@
-DEBUGGER_VSN = 4.0.1
+DEBUGGER_VSN = 4.0.2
diff --git a/lib/dialyzer/doc/src/notes.xml b/lib/dialyzer/doc/src/notes.xml
index d35639aa32..4020165697 100644
--- a/lib/dialyzer/doc/src/notes.xml
+++ b/lib/dialyzer/doc/src/notes.xml
@@ -31,6 +31,44 @@
<p>This document describes the changes made to the Dialyzer
application.</p>
+<section><title>Dialyzer 2.7.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> When compiling Erlang source, Dialyzer now ignores
+ the environment variable ERL_COMPILER_OPTIONS as well as
+ skips the Erlang Compiler option
+ <c>warnings_as_errors</c>. </p>
+ <p>
+ Own Id: OTP-12225</p>
+ </item>
+ <item>
+ <p> Dialyzer did not check the type of record elements
+ when updating them. The bug, introduced in Erlang/OTP
+ 17.1, has been corrected. (Thanks to Nicolas Dudebout for
+ pointing it out.) </p>
+ <p>
+ Own Id: OTP-12319</p>
+ </item>
+ <item>
+ <p>
+ Coalesce map keys in dialyzer mode</p>
+ <p>
+ This fixes a regression introduced in commit
+ 805f9c89fc01220bc1bb0f27e1b68fd4eca688ba The problem
+ occurred with compounded map keys compiled with dialyzer
+ option turned on, '+dialyzer'.</p>
+ <p>
+ Reported by: Ivan Uemlianin</p>
+ <p>
+ Own Id: OTP-12347</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Dialyzer 2.7.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/dialyzer/vsn.mk b/lib/dialyzer/vsn.mk
index 58cc77c2fa..e7c13f04ad 100644
--- a/lib/dialyzer/vsn.mk
+++ b/lib/dialyzer/vsn.mk
@@ -1 +1 @@
-DIALYZER_VSN = 2.7.2
+DIALYZER_VSN = 2.7.3
diff --git a/lib/diameter/doc/src/notes.xml b/lib/diameter/doc/src/notes.xml
index 7f69bdbfbf..e6ac332c10 100644
--- a/lib/diameter/doc/src/notes.xml
+++ b/lib/diameter/doc/src/notes.xml
@@ -42,6 +42,68 @@ first.</p>
<!-- ===================================================================== -->
+<section><title>diameter 1.8</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix remote diameter_request table leak.</p>
+ <p>
+ An outgoing request whose pick_peer callback selected a
+ transport on another node resulted in an orphaned table
+ entry on that node.</p>
+ <p>
+ Own Id: OTP-12196</p>
+ </item>
+ <item>
+ <p>
+ Fix handling of 3xxx Result-Code without E-bit.</p>
+ <p>
+ OTP-12233 broke the population of the errors field of the
+ diameter_packet record when an incoming request with an
+ E-bit/Result-Code mismatch was detected, causing a
+ 4-tuple to be inserted as Result-Code in a diameter_avp
+ record.</p>
+ <p>
+ Own Id: OTP-12233</p>
+ </item>
+ <item>
+ <p>
+ Fix ignored connect timer.</p>
+ <p>
+ There are two timers governing the establishment of peer
+ connections: connect_timer and watchdog_timer. The former
+ is the RFC 6733 Tc timer, and is used at initial
+ connection establishment. The latter is RFC 3539 TwInit,
+ and is used for connection reestablishment. A connecting
+ transport erroneously used watchdog_timer in both cases.</p>
+ <p>
+ Own Id: OTP-12281 Aux Id: seq12728 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Order candidate peers in pick_peer callbacks.</p>
+ <p>
+ The order of candidate peers presented to a
+ diameter_app(3) pick_peer callback has previously not
+ been documented, but there are use cases that are
+ simplified by an ordering. The order is now determined by
+ the filter.</p>
+ <p>
+ Own Id: OTP-12308</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>diameter 1.7.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/edoc/doc/src/notes.xml b/lib/edoc/doc/src/notes.xml
index 52b7529f70..e350adb540 100644
--- a/lib/edoc/doc/src/notes.xml
+++ b/lib/edoc/doc/src/notes.xml
@@ -31,6 +31,22 @@
<p>This document describes the changes made to the EDoc
application.</p>
+<section><title>Edoc 0.7.16</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Maps: Properly align union typed assoc values in
+ documentation</p>
+ <p>
+ Own Id: OTP-12190</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Edoc 0.7.15</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/edoc/vsn.mk b/lib/edoc/vsn.mk
index b1cf115b29..24cfbf16d5 100644
--- a/lib/edoc/vsn.mk
+++ b/lib/edoc/vsn.mk
@@ -1 +1 @@
-EDOC_VSN = 0.7.15
+EDOC_VSN = 0.7.16
diff --git a/lib/eldap/doc/src/eldap.xml b/lib/eldap/doc/src/eldap.xml
index 718a8afeec..b68115cd82 100644
--- a/lib/eldap/doc/src/eldap.xml
+++ b/lib/eldap/doc/src/eldap.xml
@@ -107,19 +107,23 @@ filter() See present/1, substrings/2,
</type>
<desc>
<p>Upgrade the connection associated with <c>Handle</c> to a tls connection if possible.</p>
- <p>The upgrade is done in two phases: first the server is asked for permission to upgrade. Second, if the request is acknowledged, the upgrade is performed.</p>
- <p>Error responese from phase one will not affect the current encryption state of the connection. Those responses are:</p>
+ <p>The upgrade is done in two phases: first the server is asked for permission to upgrade. Second, if the request is acknowledged, the upgrade to tls is performed.</p>
+ <p>Error responses from phase one will not affect the current encryption state of the connection. Those responses are:</p>
<taglist>
<tag><c>tls_already_started</c></tag>
<item>The connection is already encrypted. The connection is not affected.</item>
<tag><c>{response,ResponseFromServer}</c></tag>
<item>The upgrade was refused by the LDAP server. The <c>ResponseFromServer</c> is an atom delivered byt the LDAP server explained in section 2.3 of rfc 2830. The connection is not affected, so it is still un-encrypted.</item>
</taglist>
- <p>Errors in the seconde phase will however end the connection:</p>
+ <p>Errors in the second phase will however end the connection:</p>
<taglist>
<tag><c>Error</c></tag>
<item>Any error responded from ssl:connect/3</item>
</taglist>
+ <p>The <c>Timeout</c> parameter is for the actual tls upgrade (phase 2) while the timeout in
+ <seealso marker="#open/2">erl_tar:open/2</seealso> is used for the initial negotiation about
+ upgrade (phase 1).
+ </p>
</desc>
</func>
<func>
@@ -264,9 +268,9 @@ filter() See present/1, substrings/2,
</type>
<desc>
<p> Modify the DN of an entry. <c>DeleteOldRDN</c> indicates
- whether the current RDN should be removed after operation.
- <c>NewSupDN</c> should be "" if the RDN should not be moved or the new parent which
- the RDN will be moved to.</p>
+ whether the current RDN should be removed from the attribute list after the after operation.
+ <c>NewSupDN</c> is the new parent that the RDN shall be moved to. If the old parent should
+ remain as parent, <c>NewSupDN</c> shall be "".</p>
<pre>
modify_dn(Handle, "cn=Bill Valentine, ou=people, o=Example Org, dc=example, dc=com ",
"cn=Bill Jr Valentine", true, "")
@@ -293,6 +297,10 @@ filter() See present/1, substrings/2,
Filter = eldap:substrings("cn", [{any,"V"}]),
search(Handle, [{base, "dc=example, dc=com"}, {filter, Filter}, {attributes, ["cn"]}]),
</pre>
+ <p>The <c>timeout</c> option in the <c>SearchOptions</c> is for the ldap server, while
+ the timeout in <seealso marker="#open/2">erl_tar:open/2</seealso> is used for each
+ individual request in the search operation.
+ </p>
</desc>
</func>
diff --git a/lib/eldap/doc/src/notes.xml b/lib/eldap/doc/src/notes.xml
index f92d100757..e5cbcb26ff 100644
--- a/lib/eldap/doc/src/notes.xml
+++ b/lib/eldap/doc/src/notes.xml
@@ -30,6 +30,35 @@
</header>
<p>This document describes the changes made to the Eldap application.</p>
+<section><title>Eldap 1.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed that eldap:open did not use the Timeout parameter
+ when calling ssl:connect. (Thanks Wiesław Bieniek for
+ reporting)</p>
+ <p>
+ Own Id: OTP-12311</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Added the LDAP filter <c>extensibleMatch</c>.</p>
+ <p>
+ Own Id: OTP-12174</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Eldap 1.0.4</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/eldap/src/eldap.erl b/lib/eldap/src/eldap.erl
index c636e0e0cd..977f7d2809 100644
--- a/lib/eldap/src/eldap.erl
+++ b/lib/eldap/src/eldap.erl
@@ -125,7 +125,8 @@ getopts(Handle, OptNames) when is_pid(Handle), is_list(OptNames) ->
%%% --------------------------------------------------------------------
close(Handle) when is_pid(Handle) ->
- send(Handle, close).
+ send(Handle, close),
+ ok.
%%% --------------------------------------------------------------------
%%% Set who we should link ourselves to
diff --git a/lib/eldap/test/Makefile b/lib/eldap/test/Makefile
index 24e71cebaa..28a7a107e1 100644
--- a/lib/eldap/test/Makefile
+++ b/lib/eldap/test/Makefile
@@ -28,8 +28,9 @@ INCLUDES= -I. -I ../include
# ----------------------------------------------------
MODULES= \
- eldap_connections_SUITE \
- eldap_basic_SUITE
+ eldap_basic_SUITE \
+ make_certs
+
ERL_FILES= $(MODULES:%=%.erl)
diff --git a/lib/eldap/test/eldap_basic_SUITE.erl b/lib/eldap/test/eldap_basic_SUITE.erl
index 7f2be54b71..137c61b2d9 100644
--- a/lib/eldap/test/eldap_basic_SUITE.erl
+++ b/lib/eldap/test/eldap_basic_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -24,323 +24,919 @@
%%-include_lib("common_test/include/ct.hrl").
-include_lib("test_server/include/test_server.hrl").
-include_lib("eldap/include/eldap.hrl").
+-include_lib("eldap/ebin/ELDAPv3.hrl").
+
-define(TIMEOUT, 120000). % 2 min
+all() ->
+ [app,
+ appup,
+ {group, encode_decode},
+ {group, return_values},
+ {group, v4_connections},
+ {group, v6_connections},
+ {group, plain_api},
+ {group, ssl_api},
+ {group, start_tls_api}
+ ].
+
+groups() ->
+ [{encode_decode, [], [encode,
+ decode
+ ]},
+ {plain_api, [], [{group,api}]},
+ {ssl_api, [], [{group,api}, start_tls_on_ssl_should_fail]},
+ {start_tls_api, [], [{group,api}, start_tls_twice_should_fail]},
+
+ {api, [], [{group,api_not_bound},
+ {group,api_bound}]},
+
+ {api_not_bound, [], [elementary_search, search_non_existant,
+ add_when_not_bound,
+ bind]},
+ {api_bound, [], [add_when_bound,
+ add_already_exists,
+ more_add,
+ search_filter_equalityMatch,
+ search_filter_substring_any,
+ search_filter_initial,
+ search_filter_final,
+ search_filter_and,
+ search_filter_or,
+ search_filter_and_not,
+ search_two_hits,
+ modify,
+ delete,
+ modify_dn_delete_old,
+ modify_dn_keep_old]},
+ {v4_connections, [], connection_tests()},
+ {v6_connections, [], connection_tests()},
+ {return_values, [], [open_ret_val_success,
+ open_ret_val_error,
+ close_ret_val]}
+ ].
+
+connection_tests() ->
+ [tcp_connection,
+ tcp_connection_option,
+ ssl_connection,
+ client_side_start_tls_timeout,
+ client_side_bind_timeout,
+ client_side_add_timeout,
+ client_side_search_timeout
+ ].
+
+
+
init_per_suite(Config) ->
- StartSsl = try ssl:start()
- catch
- Error:Reason ->
- {skip, lists:flatten(io_lib:format("eldap init_per_suite failed to start ssl Error=~p Reason=~p", [Error, Reason]))}
- end,
- case StartSsl of
- ok ->
- chk_config(ldap_server, {"localhost",9876},
- chk_config(ldaps_server, {"localhost",9877},
- Config));
- _ ->
- StartSsl
- end.
+ SSL_available = init_ssl_certs_et_al(Config),
+ LDAP_server = find_first_server(false, [{config,eldap_server}, {config,ldap_server}, {"localhost",9876}]),
+ LDAPS_server =
+ case SSL_available of
+ true ->
+ find_first_server(true, [{config,ldaps_server}, {"localhost",9877}]);
+ false ->
+ undefined
+ end,
+ [{ssl_available, SSL_available},
+ {ldap_server, LDAP_server},
+ {ldaps_server, LDAPS_server} | Config].
end_per_suite(_Config) ->
- ok.
-
-init_per_testcase(_TestCase, Config0) ->
- {EldapHost,Port} = proplists:get_value(ldap_server,Config0),
- try
- {ok, Handle} = eldap:open([EldapHost], [{port,Port}]),
- ok = eldap:simple_bind(Handle, "cn=Manager,dc=ericsson,dc=se", "hejsan"),
- {ok, MyHost} = inet:gethostname(),
- Path = "dc="++MyHost++",dc=ericsson,dc=se",
- eldap:add(Handle,"dc=ericsson,dc=se",
- [{"objectclass", ["dcObject", "organization"]},
- {"dc", ["ericsson"]}, {"o", ["Testing"]}]),
- eldap:add(Handle,Path,
- [{"objectclass", ["dcObject", "organization"]},
- {"dc", [MyHost]}, {"o", ["Test machine"]}]),
- [{eldap_path,Path}|Config0]
- catch error:{badmatch,Error} ->
- io:format("Eldap init error ~p~n ~p~n",[Error, erlang:get_stacktrace()]),
- {skip, lists:flatten(io_lib:format("Ldap init failed with host ~p:~p. Error=~p", [EldapHost,Port,Error]))}
+ ssl:stop().
+
+
+init_per_group(return_values, Config) ->
+ case ?config(ldap_server,Config) of
+ undefined ->
+ {skip, "LDAP server not availble"};
+ {Host,Port} ->
+ ct:comment("ldap://~s:~p",[Host,Port]),
+ Config
+ end;
+init_per_group(plain_api, Config0) ->
+ case ?config(ldap_server,Config0) of
+ undefined ->
+ {skip, "LDAP server not availble"};
+ Server = {Host,Port} ->
+ ct:comment("ldap://~s:~p",[Host,Port]),
+ initialize_db([{server,Server}, {ssl_flag,false}, {start_tls,false} | Config0])
+ end;
+init_per_group(ssl_api, Config0) ->
+ case ?config(ldaps_server,Config0) of
+ undefined ->
+ {skip, "LDAPS server not availble"};
+ Server = {Host,Port} ->
+ ct:comment("ldaps://~s:~p",[Host,Port]),
+ initialize_db([{server,Server}, {ssl_flag,true}, {start_tls,false} | Config0])
+ end;
+init_per_group(start_tls_api, Config0) ->
+ case {?config(ldap_server,Config0), ?config(ssl_available,Config0)} of
+ {undefined,true} ->
+ {skip, "LDAP server not availble"};
+ {_,false} ->
+ {skip, "TLS not availble"};
+ {Server={Host,Port}, true} ->
+ ct:comment("ldap://~s:~p + start_tls",[Host,Port]),
+ Config = [{server,Server}, {ssl_flag,false} | Config0],
+ case supported_extension("1.3.6.1.4.1.1466.20037", Config) of
+ true -> initialize_db([{start_tls,true} | Config]);
+ false -> {skip, "start_tls not supported according to the server"}
+ end
+ end;
+init_per_group(v4_connections, Config) ->
+ [{tcp_listen_opts, [{reuseaddr, true}]},
+ {listen_host, "localhost"},
+ {tcp_connect_opts, []}
+ | Config];
+init_per_group(v6_connections, Config) ->
+ {ok, Hostname} = inet:gethostname(),
+ case lists:member(list_to_atom(Hostname), ct:get_config(ipv6_hosts,[])) of
+ true ->
+ [{tcp_listen_opts, [inet6,{reuseaddr, true}]},
+ {listen_host, "::"},
+ {tcp_connect_opts, [{tcpopts,[inet6]}]}
+ | Config];
+ false ->
+ {skip, io_lib:format("~p is not an ipv6_host",[Hostname])}
+ end;
+init_per_group(_, Config) ->
+ Config.
+
+end_per_group(plain_api, Config) -> clear_db(Config);
+end_per_group(ssl_api, Config) -> clear_db(Config);
+end_per_group(start_tls_api, Config) -> clear_db(Config);
+end_per_group(_Group, Config) -> Config.
+
+
+init_per_testcase(ssl_connection, Config) ->
+ case ?config(ssl_available,Config) of
+ true ->
+ SSL_Port = 9999,
+ CertFile = filename:join(?config(data_dir,Config), "certs/server/cert.pem"),
+ KeyFile = filename:join(?config(data_dir,Config), "certs/server/key.pem"),
+
+ Parent = self(),
+ Listener = spawn_link(
+ fun() ->
+ case ssl:listen(SSL_Port, [{certfile, CertFile},
+ {keyfile, KeyFile}
+ | ?config(tcp_listen_opts,Config)
+ ]) of
+ {ok,SSL_LSock} ->
+ Parent ! {ok,self()},
+ (fun L() ->
+ ct:log("ssl server waiting for connections...",[]),
+ {ok, S} = ssl:transport_accept(SSL_LSock),
+ ct:log("ssl:transport_accept/1 ok",[]),
+ ok = ssl:ssl_accept(S),
+ ct:log("ssl:ssl_accept/1 ok",[]),
+ L()
+ end)();
+ Other ->
+ Parent ! {not_ok,Other,self()}
+ end
+ end),
+ receive
+ {ok,Listener} ->
+ ct:log("SSL listening to port ~p (process ~p)",[SSL_Port, Listener]),
+ [{ssl_listener,Listener},
+ {ssl_listen_port,SSL_Port},
+ {ssl_connect_opts,[]}
+ | Config];
+ {no_ok,SSL_Other,Listener} ->
+ ct:log("ssl:listen on port ~p failed: ~p",[SSL_Port,SSL_Other]),
+ {fail, "ssl:listen/2 failed"}
+ after 5000 ->
+ {fail, "Waiting for ssl:listen timeout"}
+ end;
+ false ->
+ {skip, "ssl not available"}
+ end;
+
+init_per_testcase(TC, Config) ->
+ case lists:member(TC,connection_tests()) of
+ true ->
+ case gen_tcp:listen(0, proplists:get_value(tcp_listen_opts,Config)) of
+ {ok,LSock} ->
+ {ok,{_,Port}} = inet:sockname(LSock),
+ [{listen_socket,LSock},
+ {listen_port,Port}
+ | Config];
+ Other ->
+ {fail, Other}
+ end;
+
+ false ->
+ case proplists:get_value(name,?config(tc_group_properties, Config)) of
+ api_not_bound ->
+ {ok,H} = open(Config),
+ [{handle,H} | Config];
+ api_bound ->
+ {ok,H} = open(Config),
+ ok = eldap:simple_bind(H,
+ "cn=Manager,dc=ericsson,dc=se",
+ "hejsan"),
+ [{handle,H} | Config];
+ _Name ->
+ Config
+ end
end.
-end_per_testcase(_TestCase, Config) ->
- {EHost, Port} = proplists:get_value(ldap_server, Config),
- Path = proplists:get_value(eldap_path, Config),
- {ok, H} = eldap:open([EHost], [{port, Port}]),
- ok = eldap:simple_bind(H, "cn=Manager,dc=ericsson,dc=se", "hejsan"),
- case eldap:search(H, [{base, Path},
- {filter, eldap:present("objectclass")},
- {scope, eldap:wholeSubtree()}])
- of
- {ok, {eldap_search_result, Entries, _}} ->
- [ok = eldap:delete(H, Entry) || {eldap_entry, Entry, _} <- Entries];
- _ -> ignore
- end,
-
- ok.
+end_per_testcase(_, Config) ->
+ catch gen_tcp:close( proplists:get_value(listen_socket, Config) ),
+ catch eldap:close( proplists:get_value(handle,Config) ).
-%% suite() ->
-all() ->
- [app,
- appup,
- api,
- ssl_api,
- start_tls,
- tls_operations,
- start_tls_twice,
- start_tls_on_ssl
- ].
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%
+%%% Test cases
+%%%
-app(doc) -> "Test that the eldap app file is ok";
-app(suite) -> [];
+%%%----------------------------------------------------------------
+%%% Test that the eldap app file is ok
app(Config) when is_list(Config) ->
ok = test_server:app_test(eldap).
-%% Test that the eldap appup file is ok
+%%%----------------------------------------------------------------
+%%% Test that the eldap appup file is ok
appup(Config) when is_list(Config) ->
ok = test_server:appup_test(eldap).
-api(doc) -> "Basic test that all api functions works as expected";
-api(suite) -> [];
-api(Config) ->
- {Host,Port} = proplists:get_value(ldap_server, Config),
- {ok, H} = eldap:open([Host], [{port,Port}
- ,{log,fun(Lvl,Fmt,Args)-> io:format("~p: ~s",[Lvl,io_lib:format(Fmt,Args)]) end}
- ]),
- %% {ok, H} = eldap:open([Host], [{port,Port+1}, {ssl, true}]),
- do_api_checks(H, Config),
- eldap:close(H),
- ok.
+%%%----------------------------------------------------------------
+open_ret_val_success(Config) ->
+ {Host,Port} = ?config(ldap_server,Config),
+ {ok,H} = eldap:open([Host], [{port,Port}]),
+ catch eldap:close(H).
+
+%%%----------------------------------------------------------------
+open_ret_val_error(_Config) ->
+ {error,_} = eldap:open(["nohost.example.com"], [{port,65535}]).
+
+%%%----------------------------------------------------------------
+close_ret_val(Config) ->
+ {Host,Port} = ?config(ldap_server,Config),
+ {ok,H} = eldap:open([Host], [{port,Port}]),
+ ok = eldap:close(H).
+
+%%%----------------------------------------------------------------
+tcp_connection(Config) ->
+ Host = proplists:get_value(listen_host, Config),
+ Port = proplists:get_value(listen_port, Config),
+ Opts = proplists:get_value(tcp_connect_opts, Config),
+ case eldap:open([Host], [{port,Port}|Opts]) of
+ {ok,_H} ->
+ Sl = proplists:get_value(listen_socket, Config),
+ case gen_tcp:accept(Sl,1000) of
+ {ok,_S} -> ok;
+ {error,timeout} -> ct:fail("server side accept timeout",[]);
+ Other -> ct:fail("gen_tdp:accept failed: ~p",[Other])
+ end;
+ Other -> ct:fail("eldap:open failed: ~p",[Other])
+ end.
+%%%----------------------------------------------------------------
+ssl_connection(Config) ->
+ Host = proplists:get_value(listen_host, Config),
+ Port = proplists:get_value(ssl_listen_port, Config),
+ Opts = proplists:get_value(tcp_connect_opts, Config),
+ SSLOpts = proplists:get_value(ssl_connect_opts, Config),
+ case eldap:open([Host], [{port,Port},
+ {ssl,true},
+ {timeout,5000},
+ {sslopts,SSLOpts}|Opts]) of
+ {ok,_H} -> ok;
+ Other -> ct:fail("eldap:open failed: ~p",[Other])
+ end.
-ssl_api(doc) -> "Basic test that all api functions works as expected";
-ssl_api(suite) -> [];
-ssl_api(Config) ->
- {Host,Port} = proplists:get_value(ldaps_server, Config),
- {ok, H} = eldap:open([Host], [{port,Port}, {ssl,true}]),
- do_api_checks(H, Config),
- eldap:close(H),
- ok.
+%%%----------------------------------------------------------------
+client_side_add_timeout(Config) ->
+ client_timeout(
+ fun(H) ->
+ eldap:add(H, "cn=Foo Bar,dc=host,dc=ericsson,dc=se",
+ [{"objectclass", ["person"]},
+ {"cn", ["Foo Bar"]},
+ {"sn", ["Bar"]},
+ {"telephoneNumber", ["555-1232", "555-5432"]}])
+ end, Config).
+
+%%%----------------------------------------------------------------
+client_side_bind_timeout(Config) ->
+ client_timeout(
+ fun(H) ->
+ eldap:simple_bind(H, anon, anon)
+ end, Config).
+
+%%%----------------------------------------------------------------
+client_side_search_timeout(Config) ->
+ client_timeout(
+ fun(H) ->
+ eldap:search(H, [{base,"dc=host,dc=ericsson,dc=se"},
+ {filter, eldap:present("objectclass")},
+ {scope, eldap:wholeSubtree()}])
+ end, Config).
+
+%%%----------------------------------------------------------------
+client_side_start_tls_timeout(Config) ->
+ client_timeout(
+ fun(H) ->
+ eldap:start_tls(H, [])
+ end, Config).
+
+%%%----------------------------------------------------------------
+tcp_connection_option(Config) ->
+ Host = proplists:get_value(listen_host, Config),
+ Port = proplists:get_value(listen_port, Config),
+ Opts = proplists:get_value(tcp_connect_opts, Config),
+ Sl = proplists:get_value(listen_socket, Config),
+
+ %% Make an option value to test. The option must be implemented on all
+ %% platforms that we test on. Must check what the default value is
+ %% so we don't happen to choose that particular value.
+ {ok,[{linger,DefaultLinger}]} = inet:getopts(Sl, [linger]),
+ TestLinger = case DefaultLinger of
+ {false,_} -> {true,5};
+ {true,_} -> {false,0}
+ end,
+
+ case catch eldap:open([Host],
+ [{port,Port},{tcpopts,[{linger,TestLinger}]}|Opts]) of
+ {ok,H} ->
+ case gen_tcp:accept(Sl,1000) of
+ {ok,_} ->
+ case eldap:getopts(H, [{tcpopts,[linger]}]) of
+ {ok,[{tcpopts,[{linger,ActualLinger}]}]} ->
+ case ActualLinger of
+ TestLinger ->
+ ok;
+ DefaultLinger ->
+ ct:fail("eldap:getopts: 'linger' didn't change,"
+ " got ~p (=default) expected ~p",
+ [ActualLinger,TestLinger]);
+ _ ->
+ ct:fail("eldap:getopts: bad 'linger', got ~p expected ~p",
+ [ActualLinger,TestLinger])
+ end;
+ Other ->
+ ct:fail("eldap:getopts: bad result ~p",[Other])
+ end;
+ {error,timeout} ->
+ ct:fail("server side accept timeout",[])
+ end;
+
+ Other ->
+ ct:fail("eldap:open failed: ~p",[Other])
+ end.
-start_tls(doc) -> "Test that an existing (tcp) connection can be upgraded to tls";
-start_tls(suite) -> [];
-start_tls(Config) ->
- {Host,Port} = proplists:get_value(ldap_server, Config),
- {ok, H} = eldap:open([Host], [{port,Port}]),
- ok = eldap:start_tls(H, [
- {keyfile, filename:join([proplists:get_value(data_dir,Config),
- "certs/client/key.pem"])}
- ]),
- eldap:close(H).
+%%%----------------------------------------------------------------
+%%% Basic test that all api functions works as expected
+
+%%%----------------------------------------------------------------
+elementary_search(Config) ->
+ {ok, #eldap_search_result{entries=[_]}} =
+ eldap:search(?config(handle,Config),
+ #eldap_search{base = ?config(eldap_path, Config),
+ filter= eldap:present("objectclass"),
+ scope = eldap:wholeSubtree()}).
+
+%%%----------------------------------------------------------------
+search_non_existant(Config) ->
+ {error, noSuchObject} =
+ eldap:search(?config(handle,Config),
+ #eldap_search{base = "cn=Bar," ++ ?config(eldap_path, Config),
+ filter= eldap:present("objectclass"),
+ scope = eldap:wholeSubtree()}).
+
+%%%----------------------------------------------------------------
+add_when_not_bound(Config) ->
+ {error, _} = eldap:add(?config(handle,Config),
+ "cn=Jonas Jonsson," ++ ?config(eldap_path, Config),
+ [{"objectclass", ["person"]},
+ {"cn", ["Jonas Jonsson"]},
+ {"sn", ["Jonsson"]}]).
+
+%%%----------------------------------------------------------------
+bind(Config) ->
+ ok = eldap:simple_bind(?config(handle,Config),
+ "cn=Manager,dc=ericsson,dc=se",
+ "hejsan").
+
+%%%----------------------------------------------------------------
+add_when_bound(Config) ->
+ ok = eldap:add(?config(handle, Config),
+ "cn=Jonas Jonsson," ++ ?config(eldap_path, Config),
+ [{"objectclass", ["person"]},
+ {"cn", ["Jonas Jonsson"]},
+ {"sn", ["Jonsson"]}]).
+
+%%%----------------------------------------------------------------
+add_already_exists(Config) ->
+ {error, entryAlreadyExists} =
+ eldap:add(?config(handle, Config),
+ "cn=Jonas Jonsson," ++ ?config(eldap_path, Config),
+ [{"objectclass", ["person"]},
+ {"cn", ["Jonas Jonsson"]},
+ {"sn", ["Jonsson"]}]).
+
+%%%----------------------------------------------------------------
+more_add(Config) ->
+ H = ?config(handle, Config),
+ BasePath = ?config(eldap_path, Config),
+ ok = eldap:add(H, "cn=Foo Bar," ++ BasePath,
+ [{"objectclass", ["person"]},
+ {"cn", ["Foo Bar"]},
+ {"sn", ["Bar"]},
+ {"telephoneNumber", ["555-1232", "555-5432"]}]),
+ ok = eldap:add(H, "ou=Team," ++ BasePath,
+ [{"objectclass", ["organizationalUnit"]},
+ {"ou", ["Team"]}]).
-tls_operations(doc) -> "Test that an upgraded connection is usable for ldap stuff";
-tls_operations(suite) -> [];
-tls_operations(Config) ->
- {Host,Port} = proplists:get_value(ldap_server, Config),
- {ok, H} = eldap:open([Host], [{port,Port}]),
- ok = eldap:start_tls(H, [
- {keyfile, filename:join([proplists:get_value(data_dir,Config),
- "certs/client/key.pem"])}
- ]),
- do_api_checks(H, Config),
+%%%----------------------------------------------------------------
+search_filter_equalityMatch(Config) ->
+ BasePath = ?config(eldap_path, Config),
+ ExpectedDN = "cn=Jonas Jonsson," ++ BasePath,
+ {ok, #eldap_search_result{entries=[#eldap_entry{object_name=ExpectedDN}]}} =
+ eldap:search(?config(handle, Config),
+ #eldap_search{base = BasePath,
+ filter = eldap:equalityMatch("sn", "Jonsson"),
+ scope=eldap:singleLevel()}).
+
+%%%----------------------------------------------------------------
+search_filter_substring_any(Config) ->
+ BasePath = ?config(eldap_path, Config),
+ ExpectedDN = "cn=Jonas Jonsson," ++ BasePath,
+ {ok, #eldap_search_result{entries=[#eldap_entry{object_name=ExpectedDN}]}} =
+ eldap:search(?config(handle, Config),
+ #eldap_search{base = BasePath,
+ filter = eldap:substrings("sn", [{any, "ss"}]),
+ scope=eldap:singleLevel()}).
+
+%%%----------------------------------------------------------------
+search_filter_initial(Config) ->
+ H = ?config(handle, Config),
+ BasePath = ?config(eldap_path, Config),
+ ExpectedDN = "cn=Foo Bar," ++ BasePath,
+ {ok, #eldap_search_result{entries=[#eldap_entry{object_name=ExpectedDN}]}} =
+ eldap:search(H,
+ #eldap_search{base = BasePath,
+ filter = eldap:substrings("sn", [{initial, "B"}]),
+ scope=eldap:singleLevel()}).
+
+%%%----------------------------------------------------------------
+search_filter_final(Config) ->
+ H = ?config(handle, Config),
+ BasePath = ?config(eldap_path, Config),
+ ExpectedDN = "cn=Foo Bar," ++ BasePath,
+ {ok, #eldap_search_result{entries=[#eldap_entry{object_name=ExpectedDN}]}} =
+ eldap:search(H,
+ #eldap_search{base = BasePath,
+ filter = eldap:substrings("sn", [{final, "r"}]),
+ scope=eldap:singleLevel()}).
+
+%%%----------------------------------------------------------------
+search_filter_and(Config) ->
+ H = ?config(handle, Config),
+ BasePath = ?config(eldap_path, Config),
+ ExpectedDN = "cn=Foo Bar," ++ BasePath,
+ {ok, #eldap_search_result{entries=[#eldap_entry{object_name=ExpectedDN}]}} =
+ eldap:search(H,
+ #eldap_search{base = BasePath,
+ filter = eldap:'and'([eldap:substrings("sn", [{any, "a"}]),
+ eldap:equalityMatch("cn","Foo Bar")]),
+ scope=eldap:singleLevel()}).
+
+%%%----------------------------------------------------------------
+search_filter_or(Config) ->
+ H = ?config(handle, Config),
+ BasePath = ?config(eldap_path, Config),
+ ExpectedDNs = lists:sort(["cn=Foo Bar," ++ BasePath,
+ "ou=Team," ++ BasePath]),
+ {ok, #eldap_search_result{entries=Es}} =
+ eldap:search(H,
+ #eldap_search{base = BasePath,
+ filter = eldap:'or'([eldap:substrings("sn", [{any, "a"}]),
+ eldap:equalityMatch("ou","Team")]),
+ scope=eldap:singleLevel()}),
+ ExpectedDNs = lists:sort([DN || #eldap_entry{object_name=DN} <- Es]).
+
+%%%----------------------------------------------------------------
+search_filter_and_not(Config) ->
+ H = ?config(handle, Config),
+ BasePath = ?config(eldap_path, Config),
+ {ok, #eldap_search_result{entries=[]}} =
+ eldap:search(H,
+ #eldap_search{base = BasePath,
+ filter = eldap:'and'([eldap:substrings("sn", [{any, "a"}]),
+ eldap:'not'(
+ eldap:equalityMatch("cn","Foo Bar")
+ )]),
+ scope=eldap:singleLevel()}).
+
+%%%----------------------------------------------------------------
+search_two_hits(Config) ->
+ H = ?config(handle, Config),
+ BasePath = ?config(eldap_path, Config),
+ DN1 = "cn=Santa Claus," ++ BasePath,
+ DN2 = "cn=Jultomten," ++ BasePath,
+ %% Add two objects:
+ ok = eldap:add(H, DN1,
+ [{"objectclass", ["person"]},
+ {"cn", ["Santa Claus"]},
+ {"sn", ["Santa"]},
+ {"description", ["USA"]}]),
+ ok = eldap:add(H, DN2,
+ [{"objectclass", ["person"]},
+ {"cn", ["Jultomten"]},
+ {"sn", ["Tomten"]},
+ {"description", ["Sweden"]}]),
+
+ %% Search for them:
+ {ok, #eldap_search_result{entries=Es}} =
+ eldap:search(H,
+ #eldap_search{base = BasePath,
+ filter = eldap:present("description"),
+ scope=eldap:singleLevel()}),
+
+ %% And check that they are the expected ones:
+ ExpectedDNs = lists:sort([DN1, DN2]),
+ ExpectedDNs = lists:sort([D || #eldap_entry{object_name=D} <- Es]),
+
+ %% Restore the database:
+ [ok=eldap:delete(H,DN) || DN <- ExpectedDNs].
+
+%%%----------------------------------------------------------------
+modify(Config) ->
+ H = ?config(handle, Config),
+ BasePath = ?config(eldap_path, Config),
+ %% The object to modify
+ DN = "cn=Foo Bar," ++ BasePath,
+
+ %% Save a copy to restore later:
+ {ok,OriginalAttrs} = attributes(H, DN),
+
+ %% Do a change
+ Mod = [eldap:mod_replace("telephoneNumber", ["555-12345"]),
+ eldap:mod_add("description", ["Nice guy"])],
+ ok = eldap:modify(H, DN, Mod),
+
+ %% Check that the object was changed
+ {ok, #eldap_search_result{entries=[#eldap_entry{object_name=DN}]}} =
+ eldap:search(H,
+ #eldap_search{base = BasePath,
+ filter = eldap:equalityMatch("telephoneNumber", "555-12345"),
+ scope=eldap:singleLevel()}),
+
+ %% Do another type of change
+ ok = eldap:modify(H, DN, [eldap:mod_delete("telephoneNumber", [])]),
+ %% and check that it worked by repeating the test above
+ {ok, #eldap_search_result{entries=[]}} =
+ eldap:search(H,
+ #eldap_search{base = BasePath,
+ filter = eldap:equalityMatch("telephoneNumber", "555-12345"),
+ scope=eldap:singleLevel()}),
+ %% restore the orignal version:
+ restore_original_object(H, DN, OriginalAttrs).
+
+%%%----------------------------------------------------------------
+delete(Config) ->
+ H = ?config(handle, Config),
+ BasePath = ?config(eldap_path, Config),
+ %% The element to play with:
+ DN = "cn=Jonas Jonsson," ++ BasePath,
+
+ %% Prove that the element is present before deletion
+ {ok,OriginalAttrs} = attributes(H, DN),
+
+ %% Do what the test has to do:
+ ok = eldap:delete(H, DN),
+ %% check that it really was deleted:
+ {error, noSuchObject} = eldap:delete(H, DN),
+
+ %% And restore the object for subsequent tests
+ restore_original_object(H, DN, OriginalAttrs).
+
+%%%----------------------------------------------------------------
+modify_dn_delete_old(Config) ->
+ H = ?config(handle, Config),
+ BasePath = ?config(eldap_path, Config),
+ OrigCN = "Foo Bar",
+ OriginalRDN = "cn="++OrigCN,
+ DN = OriginalRDN ++ "," ++ BasePath,
+ NewCN = "Niclas Andre",
+ NewRDN = "cn="++NewCN,
+ NewDN = NewRDN ++ "," ++BasePath,
+
+ %% Check that the object to modify_dn of exists:
+ {ok,OriginalAttrs} = attributes(H, DN),
+ CN_orig = lists:sort(proplists:get_value("cn",OriginalAttrs)),
+ {ok, #eldap_search_result{entries=[#eldap_entry{object_name=DN}]}} =
+ eldap:search(H,
+ #eldap_search{base = BasePath,
+ filter = eldap:substrings("sn", [{any, "a"}]),
+ scope = eldap:singleLevel()}),
+
+ %% Modify and delete the old one:
+ ok = eldap:modify_dn(H, DN, NewRDN, true, ""),
+
+ %% Check that DN was modified and the old one was deleted:
+ {ok,NewAttrs} = attributes(H, NewDN),
+ CN_new = lists:sort(proplists:get_value("cn",NewAttrs)),
+ {ok, #eldap_search_result{entries=[#eldap_entry{object_name=NewDN}]}} =
+ eldap:search(H,
+ #eldap_search{base = BasePath,
+ filter = eldap:substrings("sn", [{any, "a"}]),
+ scope = eldap:singleLevel()}),
+ %% What we expect:
+ CN_new = lists:sort([NewCN | CN_orig -- [OrigCN]]),
+
+ %% Change back:
+ ok = eldap:modify_dn(H, NewDN, OriginalRDN, true, ""),
+
+ %% Check that DN was modified and the new one was deleted:
+ {ok,SameAsOriginalAttrs} = attributes(H, DN),
+ CN_orig = lists:sort(proplists:get_value("cn",SameAsOriginalAttrs)),
+ {ok, #eldap_search_result{entries=[#eldap_entry{object_name=DN}]}} =
+ eldap:search(H,
+ #eldap_search{base = BasePath,
+ filter = eldap:substrings("sn", [{any, "a"}]),
+ scope = eldap:singleLevel()}).
+
+%%%----------------------------------------------------------------
+modify_dn_keep_old(Config) ->
+ H = ?config(handle, Config),
+ BasePath = ?config(eldap_path, Config),
+ OriginalRDN = "cn=Foo Bar",
+ DN = OriginalRDN ++ "," ++ BasePath,
+ NewCN = "Niclas Andre",
+ NewRDN = "cn="++NewCN,
+ NewDN = NewRDN ++ "," ++BasePath,
+
+ %% Check that the object to modify_dn of exists but the new one does not:
+ {ok,OriginalAttrs} = attributes(H, DN),
+ {ok, #eldap_search_result{entries=[#eldap_entry{object_name=DN}]}} =
+ eldap:search(H,
+ #eldap_search{base = BasePath,
+ filter = eldap:substrings("sn", [{any, "a"}]),
+ scope = eldap:singleLevel()}),
+
+ %% Modify but keep the old "cn" attr:
+ ok = eldap:modify_dn(H, DN, NewRDN, false, ""),
+
+ %% Check that DN was modified and the old CN entry is not deleted:
+ {ok,NewAttrs} = attributes(H, NewDN),
+ CN_orig = proplists:get_value("cn",OriginalAttrs),
+ CN_new = proplists:get_value("cn",NewAttrs),
+ Expected = lists:sort([NewCN|CN_orig]),
+ Expected = lists:sort(CN_new),
+
+ %% Restore db:
+ ok = eldap:delete(H, NewDN),
+ restore_original_object(H, DN, OriginalAttrs).
+
+%%%----------------------------------------------------------------
+%%% Test that start_tls on an already upgraded connection makes no noise
+start_tls_twice_should_fail(Config) ->
+ {ok,H} = open_bind(Config),
+ {error,tls_already_started} = eldap:start_tls(H, []),
eldap:close(H).
-start_tls_twice(doc) -> "Test that start_tls on an already upgraded connection fails";
-start_tls_twice(suite) -> [];
-start_tls_twice(Config) ->
- {Host,Port} = proplists:get_value(ldap_server, Config),
- {ok, H} = eldap:open([Host], [{port,Port}]),
- ok = eldap:start_tls(H, []),
+%%%----------------------------------------------------------------
+%%% Test that start_tls on an ldaps connection fails
+start_tls_on_ssl_should_fail(Config) ->
+ {ok,H} = open_bind(Config),
{error,tls_already_started} = eldap:start_tls(H, []),
- do_api_checks(H, Config),
eldap:close(H).
+%%%----------------------------------------------------------------
+encode(_Config) ->
+ {ok,Bin} = 'ELDAPv3':encode('AddRequest', #'AddRequest'{entry="hejHopp" ,attributes=[]} ),
+ Expected = <<104,11,4,7,104,101,106,72,111,112,112,48,0>>,
+ case Bin of
+ Expected -> ok;
+ _ -> ct:log("Encoded erroneously to:~n~p~nExpected:~n~p",[Bin,Expected]),
+ {fail, "Bad encode"}
+ end.
+
+%%%----------------------------------------------------------------
+decode(_Config) ->
+ {ok,Res} = 'ELDAPv3':decode('AddRequest', <<104,11,4,7,104,101,106,72,111,112,112,48,0>>),
+ ct:log("Res = ~p", [Res]),
+ Expected = #'AddRequest'{entry = "hejHopp",attributes = []},
+ case Res of
+ Expected -> ok;
+ #'AddRequest'{entry= <<"hejHopp">>, attributes=[]} ->
+ {fail, "decoded to (correct) binary!!"};
+ _ ->
+ {fail, "Bad decode"}
+ end.
+
-start_tls_on_ssl(doc) -> "Test that start_tls on an ldaps connection fails";
-start_tls_on_ssl(suite) -> [];
-start_tls_on_ssl(Config) ->
- {Host,Port} = proplists:get_value(ldaps_server, Config),
- {ok, H} = eldap:open([Host], [{port,Port}, {ssl,true}]),
- {error,tls_already_started} = eldap:start_tls(H, []),
- do_api_checks(H, Config),
- eldap:close(H).
+%%%****************************************************************
+%%% Private
-%%%--------------------------------------------------------------------------------
-chk_config(Key, Default, Config) ->
- case catch ct:get_config(ldap_server, undefined) of
- undefined -> [{Key,Default} | Config ];
- {'EXIT',_} -> [{Key,Default} | Config ];
- Value -> [{Key,Value} | Config]
+attributes(H, DN) ->
+ case eldap:search(H,
+ #eldap_search{base = DN,
+ filter= eldap:present("objectclass"),
+ scope = eldap:wholeSubtree()}) of
+ {ok, #eldap_search_result{entries=[#eldap_entry{object_name=DN,
+ attributes=OriginalAttrs}]}} ->
+ {ok, OriginalAttrs};
+ Other ->
+ Other
end.
+restore_original_object(H, DN, Attrs) ->
+ eldap:delete(H, DN),
+ ok = eldap:add(H, DN, Attrs).
+
+
+find_first_server(UseSSL, [{config,Key}|Ss]) ->
+ case ct:get_config(Key) of
+ {Host,Port} ->
+ ct:log("find_first_server config ~p -> ~p",[Key,{Host,Port}]),
+ find_first_server(UseSSL, [{Host,Port}|Ss]);
+ undefined ->
+ ct:log("find_first_server config ~p is undefined",[Key]),
+ find_first_server(UseSSL, Ss)
+ end;
+find_first_server(UseSSL, [{Host,Port}|Ss]) ->
+ case eldap:open([Host],[{port,Port},{ssl,UseSSL}]) of
+ {ok,H} when UseSSL==false, Ss=/=[] ->
+ case eldap:start_tls(H,[]) of
+ ok ->
+ ct:log("find_first_server ~p UseSSL=~p -> ok",[{Host,Port},UseSSL]),
+ eldap:close(H),
+ {Host,Port};
+ Res ->
+ ct:log("find_first_server ~p UseSSL=~p failed with~n~p~nSave as spare host.",[{Host,Port},UseSSL,Res]),
+ eldap:close(H),
+ find_first_server(UseSSL, Ss++[{spare_host,Host,Port}])
+ end;
+ {ok,H} ->
+ ct:log("find_first_server ~p UseSSL=~p -> ok",[{Host,Port},UseSSL]),
+ eldap:close(H),
+ {Host,Port};
+ Res ->
+ ct:log("find_first_server ~p UseSSL=~p failed with~n~p",[{Host,Port},UseSSL,Res]),
+ find_first_server(UseSSL, Ss)
+ end;
+find_first_server(false, [{spare_host,Host,Port}|_]) ->
+ ct:log("find_first_server can't find start_tls host, use the spare non-start_tls host for plain ldap: ~p",[{Host,Port}]),
+ {Host,Port};
+find_first_server(_, []) ->
+ ct:log("find_first_server, nothing left to try",[]),
+ undefined.
+
+initialize_db(Config) ->
+ case {open_bind(Config), inet:gethostname()} of
+ {{ok,H}, {ok,MyHost}} ->
+ Path = "dc="++MyHost++",dc=ericsson,dc=se",
+ delete_old_contents(H, Path),
+ add_new_contents(H, Path, MyHost),
+ eldap:close(H),
+ [{eldap_path,Path}|Config];
+ Other ->
+ ct:fail("initialize_db failed: ~p",[Other])
+ end.
+clear_db(Config) ->
+ {ok,H} = open_bind(Config),
+ Path = ?config(eldap_path, Config),
+ delete_old_contents(H, Path),
+ eldap:close(H),
+ Config.
-do_api_checks(H, Config) ->
- BasePath = proplists:get_value(eldap_path, Config),
+delete_old_contents(H, Path) ->
+ case eldap:search(H, [{base, Path},
+ {filter, eldap:present("objectclass")},
+ {scope, eldap:wholeSubtree()}])
+ of
+ {ok, #eldap_search_result{entries=Entries}} ->
+ [ok = eldap:delete(H,DN) || #eldap_entry{object_name=DN} <- Entries];
+ _Res ->
+ ignore
+ end.
- All = fun(Where) ->
- eldap:search(H, #eldap_search{base=Where,
- filter=eldap:present("objectclass"),
- scope= eldap:wholeSubtree()})
- end,
- {ok, #eldap_search_result{entries=[_XYZ]}} = All(BasePath),
-%% ct:log("XYZ=~p",[_XYZ]),
- {error, noSuchObject} = All("cn=Bar,"++BasePath),
+add_new_contents(H, Path, MyHost) ->
+ ok(eldap:add(H,"dc=ericsson,dc=se",
+ [{"objectclass", ["dcObject", "organization"]},
+ {"dc", ["ericsson"]},
+ {"o", ["Testing"]}])),
+ ok(eldap:add(H,Path,
+ [{"objectclass", ["dcObject", "organization"]},
+ {"dc", [MyHost]},
+ {"o", ["Test machine"]}])).
- {error, _} = eldap:add(H, "cn=Jonas Jonsson," ++ BasePath,
- [{"objectclass", ["person"]},
- {"cn", ["Jonas Jonsson"]}, {"sn", ["Jonsson"]}]),
- eldap:simple_bind(H, "cn=Manager,dc=ericsson,dc=se", "hejsan"),
- chk_add(H, BasePath),
- {ok,FB} = chk_search(H, BasePath),
- chk_modify(H, FB),
- chk_modify_password(H, FB),
- chk_delete(H, BasePath),
- chk_modify_dn(H, FB).
+ok({error,entryAlreadyExists}) -> ok;
+ok(X) -> ok=X.
-chk_add(H, BasePath) ->
- ok = eldap:add(H, "cn=Jonas Jonsson," ++ BasePath,
- [{"objectclass", ["person"]},
- {"cn", ["Jonas Jonsson"]}, {"sn", ["Jonsson"]}]),
- {error, entryAlreadyExists} = eldap:add(H, "cn=Jonas Jonsson," ++ BasePath,
- [{"objectclass", ["person"]},
- {"cn", ["Jonas Jonsson"]}, {"sn", ["Jonsson"]}]),
- ok = eldap:add(H, "cn=Foo Bar," ++ BasePath,
- [{"objectclass", ["person"]},
- {"cn", ["Foo Bar"]}, {"sn", ["Bar"]}, {"telephoneNumber", ["555-1232", "555-5432"]}]),
- ok = eldap:add(H, "ou=Team," ++ BasePath,
- [{"objectclass", ["organizationalUnit"]},
- {"ou", ["Team"]}]).
-chk_search(H, BasePath) ->
- Search = fun(Filter) ->
- eldap:search(H, #eldap_search{base=BasePath,
- filter=Filter,
- scope=eldap:singleLevel()})
- end,
- JJSR = {ok, #eldap_search_result{entries=[#eldap_entry{}]}} = Search(eldap:equalityMatch("sn", "Jonsson")),
- JJSR = Search(eldap:substrings("sn", [{any, "ss"}])),
- FBSR = {ok, #eldap_search_result{entries=[#eldap_entry{object_name=FB}]}} =
- Search(eldap:substrings("sn", [{any, "a"}])),
- FBSR = Search(eldap:substrings("sn", [{initial, "B"}])),
- FBSR = Search(eldap:substrings("sn", [{final, "r"}])),
- F_AND = eldap:'and'([eldap:present("objectclass"), eldap:present("ou")]),
- {ok, #eldap_search_result{entries=[#eldap_entry{}]}} = Search(F_AND),
- F_NOT = eldap:'and'([eldap:present("objectclass"), eldap:'not'(eldap:present("ou"))]),
- {ok, #eldap_search_result{entries=[#eldap_entry{}, #eldap_entry{}]}} = Search(F_NOT),
- {ok, #eldap_search_result{entries=[#eldap_entry{}]}} = Search(eldap:extensibleMatch("Bar",[{type,"sn"},{matchingRule,"caseExactMatch"}])),
- {ok, #eldap_search_result{entries=[#eldap_entry{}]}} = Search(eldap:extensibleMatch("Bar",[{type,"sn"},{matchingRule,"2.5.13.5"}])),
- {ok, #eldap_search_result{entries=[#eldap_entry{}]}} = Search(eldap:extensibleMatch("Bar",[{type,"sn"},{matchingRule,"caseIgnoreMatch"}])),
- {ok, #eldap_search_result{entries=[#eldap_entry{}]}} = Search(eldap:extensibleMatch("bar",[{type,"sn"},{matchingRule,"caseIgnoreMatch"}])),
- {ok, #eldap_search_result{entries=[]}} = Search(eldap:extensibleMatch("bar",[{type,"sn"},{matchingRule,"gluffgluff"}])),
- {ok, #eldap_search_result{entries=[]}} = Search(eldap:extensibleMatch("bar",[{type,"sn"},{matchingRule,"caseExactMatch"}])),
- {ok,FB}. %% FIXME
-
-chk_modify(H, FB) ->
- Mod = [eldap:mod_replace("telephoneNumber", ["555-12345"]),
- eldap:mod_add("description", ["Nice guy"])],
- %% io:format("MOD ~p ~p ~n",[FB, Mod]),
- ok = eldap:modify(H, FB, Mod),
- %% DELETE ATTR
- ok = eldap:modify(H, FB, [eldap:mod_delete("telephoneNumber", [])]).
+cond_start_tls(H, Config) ->
+ case ?config(start_tls,Config) of
+ true -> start_tls(H,Config);
+ _ -> Config
+ end.
-chk_modify_password(H, FB) ->
- %% Change password, and ensure we can bind with it.
- ok = eldap:simple_bind(H, "cn=Manager,dc=ericsson,dc=se", "hejsan"),
- ok = eldap:modify_password(H, FB, "example"),
- ok = eldap:simple_bind(H, FB, "example"),
- %% Change password to a server generated value.
+start_tls(H, Config) ->
+ KeyFile = filename:join([?config(data_dir,Config),
+ "certs/client/key.pem"
+ ]),
+ case eldap:start_tls(H, [{keyfile, KeyFile}]) of
+ ok ->
+ [{start_tls_success,true} | Config];
+ Error ->
+ ct:log("Start_tls on ~p failed: ~p",[?config(url,Config) ,Error]),
+ ct:fail("start_tls failed")
+ end.
+
+
+%%%----------------------------------------------------------------
+open_bind(Config) ->
+ {ok,H} = open(Config),
ok = eldap:simple_bind(H, "cn=Manager,dc=ericsson,dc=se", "hejsan"),
- {ok, Passwd} = eldap:modify_password(H, FB, []),
- ok = eldap:simple_bind(H, FB, Passwd),
- %% Change own password to server generated value.
- {ok, NewPasswd} = eldap:modify_password(H, [], [], Passwd),
- ok = eldap:simple_bind(H, FB, NewPasswd),
- %% Change own password to explicit value.
- ok = eldap:modify_password(H, [], "example", NewPasswd),
- ok = eldap:simple_bind(H, FB, "example"),
- %% Restore original binding.
- ok = eldap:simple_bind(H, "cn=Manager,dc=ericsson,dc=se", "hejsan").
-
-chk_delete(H, BasePath) ->
- {error, entryAlreadyExists} = eldap:add(H, "cn=Jonas Jonsson," ++ BasePath,
- [{"objectclass", ["person"]},
- {"cn", ["Jonas Jonsson"]}, {"sn", ["Jonsson"]}]),
- ok = eldap:delete(H, "cn=Jonas Jonsson," ++ BasePath),
- {error, noSuchObject} = eldap:delete(H, "cn=Jonas Jonsson," ++ BasePath).
-
-chk_modify_dn(H, FB) ->
- ok = eldap:modify_dn(H, FB, "cn=Niclas Andre", true, "").
- %%io:format("Res ~p~n ~p~n",[R, All(BasePath)]).
-
-
-%%%----------------
-add(H, Attr, Value, Path0, Attrs, Class) ->
- Path = case Path0 of
- [] -> Attr ++ "=" ++ Value;
- _ -> Attr ++ "=" ++ Value ++ "," ++ Path0
- end,
- case eldap:add(H, Path, [{"objectclass", Class}, {Attr, [Value]}] ++ Attrs)
- of
- ok -> {ok, Path};
- {error, E = entryAlreadyExists} -> {E, Path};
- R = {error, Reason} ->
- io:format("~p:~p: ~s,~s =>~n ~p~n",
- [?MODULE,?LINE, Attr, Value, R]),
- exit({ldap, add, Reason})
+ {ok,H}.
+
+open(Config) ->
+ {Host,Port} = ?config(server,Config),
+ SSLflag = ?config(ssl_flag,Config),
+ {ok,H} = eldap:open([Host], [{port,Port},{ssl,SSLflag}]),
+ cond_start_tls(H, Config),
+ {ok,H}.
+
+%%%----------------------------------------------------------------
+supported_extension(OID, Config) ->
+ {ok,H} = open_bind(Config),
+ case eldap:search(H, [{scope, eldap:baseObject()},
+ {filter, eldap:present("objectclass")},
+ {deref, eldap:neverDerefAliases()},
+ {attributes, ["+"]}]) of
+ {ok,R=#eldap_search_result{}} ->
+ eldap:close(H),
+ lists:member(OID,
+ [SE || EE <- R#eldap_search_result.entries,
+ {"supportedExtension",SEs} <- EE#eldap_entry.attributes,
+ SE<-SEs]);
+ _ ->
+ eldap:close(H),
+ false
end.
+%%%----------------------------------------------------------------
+client_timeout(Fun, Config) ->
+ Host = proplists:get_value(listen_host, Config),
+ Port = proplists:get_value(listen_port, Config),
+ Opts = proplists:get_value(tcp_connect_opts, Config),
+ T = 1000,
+ case eldap:open([Host], [{timeout,T},{port,Port}|Opts]) of
+ {ok,H} ->
+ T0 = now(),
+ {error,{gen_tcp_error,timeout}} = Fun(H),
+ T_op = diff(T0,now()),
+ ct:log("Time = ~p, Timeout spec = ~p",[T_op,T]),
+ if
+ T_op < T ->
+ {fail, "Timeout too early"};
+ true ->
+ ok
+ end;
+
+ Other -> ct:fail("eldap:open failed: ~p",[Other])
+ end.
+diff({M1,S1,U1},{M2,S2,U2}) ->
+ ( ((M2-M1)*1000 + (S2-S1))*1000 + (U2-U1) ).
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Develop
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-test() ->
- run().
-
-run() ->
- Cases = all(),
- run(Cases).
-
-run(Case) when is_atom(Case) ->
- run([Case]);
-run(Cases) when is_list(Cases) ->
- Run = fun(Test, Config0) ->
- Config = init_per_testcase(Test, Config0),
- try
- io:format("~nTest ~p ... ",[Test]),
- ?MODULE:Test(Config),
- end_per_testcase(Test, Config),
- io:format("ok~n",[])
- catch _:Reason ->
- io:format("~n FAIL (~p): ~p~n ~p~n",
- [Test, Reason, erlang:get_stacktrace()])
- end
- end,
- process_flag(trap_exit, true),
- Pid = spawn_link(fun() ->
- case init_per_suite([]) of
- {skip, Reason} -> io:format("Skip ~s~n",[Reason]);
- Config ->
- try
- [Run(Test, Config) || Test <- Cases]
- catch _:Err ->
- io:format("Error ~p in ~p~n",[Err, erlang:get_stacktrace()])
- end,
- end_per_suite(Config)
- end
- end),
- receive
- {'EXIT', Pid, normal} -> ok;
- Msg -> io:format("Received ~p (~p)~n",[Msg, Pid])
- after 100 -> ok end,
- process_flag(trap_exit, false),
- ok.
+%%%----------------------------------------------------------------
+init_ssl_certs_et_al(Config) ->
+ try ssl:start()
+ of
+ R when R==ok ; R=={error,{already_started,ssl}} ->
+ try make_certs:all("/dev/null",
+ filename:join(?config(data_dir,Config), "certs"))
+ of
+ {ok,_} -> true;
+ Other ->
+ ct:comment("make_certs failed"),
+ ct:log("make_certs failed ~p", [Other]),
+ false
+ catch
+ C:E ->
+ ct:comment("make_certs crashed"),
+ ct:log("make_certs failed ~p:~p", [C,E]),
+ false
+ end;
+ _ ->
+ false
+ catch
+ Error:Reason ->
+ ct:comment("ssl failed to start"),
+ ct:log("init_per_suite failed to start ssl Error=~p Reason=~p", [Error, Reason]),
+ false
+ end.
diff --git a/lib/eldap/test/eldap_basic_SUITE_data/RAND b/lib/eldap/test/eldap_basic_SUITE_data/RAND
new file mode 100644
index 0000000000..70997bd01f
--- /dev/null
+++ b/lib/eldap/test/eldap_basic_SUITE_data/RAND
Binary files differ
diff --git a/lib/eldap/test/eldap_connections_SUITE.erl b/lib/eldap/test/eldap_connections_SUITE.erl
deleted file mode 100644
index c5460fef09..0000000000
--- a/lib/eldap/test/eldap_connections_SUITE.erl
+++ /dev/null
@@ -1,147 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2012-2014. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
-
--module(eldap_connections_SUITE).
-
--compile(export_all).
-
--include_lib("common_test/include/ct.hrl").
-%-include_lib("eldap/include/eldap.hrl").
-
-
-all() ->
- [
- {group, v4},
- {group, v6}
- ].
-
-
-init_per_group(v4, Config) ->
- [{listen_opts, []},
- {listen_host, "localhost"},
- {connect_opts, []}
- | Config];
-init_per_group(v6, Config) ->
- {ok, Hostname} = inet:gethostname(),
- case lists:member(list_to_atom(Hostname), ct:get_config(ipv6_hosts,[])) of
- true ->
- [{listen_opts, [inet6]},
- {listen_host, "::"},
- {connect_opts, [{tcpopts,[inet6]}]}
- | Config];
- false ->
- {skip, io_lib:format("~p is not an ipv6_host",[Hostname])}
- end.
-
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-groups() ->
- [{v4, [], [tcp_connection, tcp_connection_option]},
- {v6, [], [tcp_connection, tcp_connection_option]}
- ].
-
-
-init_per_suite(Config) -> Config.
-
-
-end_per_suite(_Config) -> ok.
-
-
-init_per_testcase(_TestCase, Config) ->
- case gen_tcp:listen(0, proplists:get_value(listen_opts,Config)) of
- {ok,LSock} ->
- {ok,{_,Port}} = inet:sockname(LSock),
- [{listen_socket,LSock},
- {listen_port,Port}
- | Config];
- Other ->
- {fail, Other}
- end.
-
-
-end_per_testcase(_TestCase, Config) ->
- catch gen_tcp:close( proplists:get_value(listen_socket, Config) ).
-
-%%%================================================================
-%%%
-%%% Test cases
-%%%
-%%%----------------------------------------------------------------
-tcp_connection(Config) ->
- Host = proplists:get_value(listen_host, Config),
- Port = proplists:get_value(listen_port, Config),
- Opts = proplists:get_value(connect_opts, Config),
- case eldap:open([Host], [{port,Port}|Opts]) of
- {ok,_H} ->
- Sl = proplists:get_value(listen_socket, Config),
- case gen_tcp:accept(Sl,1000) of
- {ok,_S} -> ok;
- {error,timeout} -> ct:fail("server side accept timeout",[])
- end;
- Other -> ct:fail("eldap:open failed: ~p",[Other])
- end.
-
-
-%%%----------------------------------------------------------------
-tcp_connection_option(Config) ->
- Host = proplists:get_value(listen_host, Config),
- Port = proplists:get_value(listen_port, Config),
- Opts = proplists:get_value(connect_opts, Config),
- Sl = proplists:get_value(listen_socket, Config),
-
- %% Make an option value to test. The option must be implemented on all
- %% platforms that we test on. Must check what the default value is
- %% so we don't happen to choose that particular value.
- {ok,[{linger,DefaultLinger}]} = inet:getopts(Sl, [linger]),
- TestLinger = case DefaultLinger of
- {false,_} -> {true,5};
- {true,_} -> {false,0}
- end,
-
- case catch eldap:open([Host],
- [{port,Port},{tcpopts,[{linger,TestLinger}]}|Opts]) of
- {ok,H} ->
- case gen_tcp:accept(Sl,1000) of
- {ok,_} ->
- case eldap:getopts(H, [{tcpopts,[linger]}]) of
- {ok,[{tcpopts,[{linger,ActualLinger}]}]} ->
- case ActualLinger of
- TestLinger ->
- ok;
- DefaultLinger ->
- ct:fail("eldap:getopts: 'linger' didn't change,"
- " got ~p (=default) expected ~p",
- [ActualLinger,TestLinger]);
- _ ->
- ct:fail("eldap:getopts: bad 'linger', got ~p expected ~p",
- [ActualLinger,TestLinger])
- end;
- Other ->
- ct:fail("eldap:getopts: bad result ~p",[Other])
- end;
- {error,timeout} ->
- ct:fail("server side accept timeout",[])
- end;
-
- Other ->
- ct:fail("eldap:open failed: ~p",[Other])
- end.
diff --git a/lib/eldap/test/eldap_misc_SUITE.erl b/lib/eldap/test/eldap_misc_SUITE.erl
deleted file mode 100644
index ca810ee33c..0000000000
--- a/lib/eldap/test/eldap_misc_SUITE.erl
+++ /dev/null
@@ -1,51 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2012-2014. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
-
--module(eldap_misc_SUITE).
-
--compile(export_all). %% Use this only in test suites...
-
--include_lib("common_test/include/ct.hrl").
--include_lib("eldap/include/eldap.hrl").
--include_lib("eldap/ebin/ELDAPv3.hrl").
-
-all() ->
- [
- encode,
- decode
- ].
-
-
-encode(_Config) ->
- {ok,Bin} = 'ELDAPv3':encode('AddRequest', #'AddRequest'{entry="hejHopp" ,attributes=[]} ),
- Expected = <<104,11,4,7,104,101,106,72,111,112,112,48,0>>,
- Expected = Bin.
-
-decode(_Config) ->
- {ok,Res} = 'ELDAPv3':decode('AddRequest', <<104,11,4,7,104,101,106,72,111,112,112,48,0>>),
- ct:log("Res = ~p", [Res]),
- Expected = #'AddRequest'{entry = "hejHopp",attributes = []},
- case Res of
- Expected -> ok;
- #'AddRequest'{entry= <<"hejHopp">>, attributes=[]} ->
- {fail, "decoded to (correct) binary!!"};
- _ ->
- {fail, "Bad decode"}
- end.
-
diff --git a/lib/eldap/test/make_certs.erl b/lib/eldap/test/make_certs.erl
index f963af180d..15a7e118ff 100644
--- a/lib/eldap/test/make_certs.erl
+++ b/lib/eldap/test/make_certs.erl
@@ -1,41 +1,89 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
-module(make_certs).
+-compile([export_all]).
--export([all/2]).
+%-export([all/1, all/2, rootCA/2, intermediateCA/3, endusers/3, enduser/3, revoke/3, gencrl/2, verify/3]).
--record(dn, {commonName,
+-record(config, {commonName,
organizationalUnitName = "Erlang OTP",
organizationName = "Ericsson AB",
localityName = "Stockholm",
countryName = "SE",
- emailAddress = "[email protected]"}).
+ emailAddress = "[email protected]",
+ default_bits = 2048,
+ v2_crls = true,
+ ecc_certs = false,
+ issuing_distribution_point = false,
+ crl_port = 8000,
+ openssl_cmd = "openssl"}).
+
+
+default_config() ->
+ #config{}.
+
+make_config(Args) ->
+ make_config(Args, #config{}).
+
+make_config([], C) ->
+ C;
+make_config([{organizationalUnitName, Name}|T], C) when is_list(Name) ->
+ make_config(T, C#config{organizationalUnitName = Name});
+make_config([{organizationName, Name}|T], C) when is_list(Name) ->
+ make_config(T, C#config{organizationName = Name});
+make_config([{localityName, Name}|T], C) when is_list(Name) ->
+ make_config(T, C#config{localityName = Name});
+make_config([{countryName, Name}|T], C) when is_list(Name) ->
+ make_config(T, C#config{countryName = Name});
+make_config([{emailAddress, Name}|T], C) when is_list(Name) ->
+ make_config(T, C#config{emailAddress = Name});
+make_config([{default_bits, Bits}|T], C) when is_integer(Bits) ->
+ make_config(T, C#config{default_bits = Bits});
+make_config([{v2_crls, Bool}|T], C) when is_boolean(Bool) ->
+ make_config(T, C#config{v2_crls = Bool});
+make_config([{crl_port, Port}|T], C) when is_integer(Port) ->
+ make_config(T, C#config{crl_port = Port});
+make_config([{ecc_certs, Bool}|T], C) when is_boolean(Bool) ->
+ make_config(T, C#config{ecc_certs = Bool});
+make_config([{issuing_distribution_point, Bool}|T], C) when is_boolean(Bool) ->
+ make_config(T, C#config{issuing_distribution_point = Bool});
+make_config([{openssl_cmd, Cmd}|T], C) when is_list(Cmd) ->
+ make_config(T, C#config{openssl_cmd = Cmd}).
+
+
+all([DataDir, PrivDir]) ->
+ all(DataDir, PrivDir).
all(DataDir, PrivDir) ->
- OpenSSLCmd = "openssl",
+ all(DataDir, PrivDir, #config{}).
+
+all(DataDir, PrivDir, C) when is_list(C) ->
+ all(DataDir, PrivDir, make_config(C));
+all(DataDir, PrivDir, C = #config{}) ->
+ ok = filelib:ensure_dir(filename:join(PrivDir, "erlangCA")),
create_rnd(DataDir, PrivDir), % For all requests
- rootCA(PrivDir, OpenSSLCmd, "erlangCA"),
- intermediateCA(PrivDir, OpenSSLCmd, "otpCA", "erlangCA"),
- endusers(PrivDir, OpenSSLCmd, "otpCA", ["client", "server"]),
- collect_certs(PrivDir, ["erlangCA", "otpCA"], ["client", "server"]),
- %% Create keycert files
+ rootCA(PrivDir, "erlangCA", C),
+ intermediateCA(PrivDir, "otpCA", "erlangCA", C),
+ endusers(PrivDir, "otpCA", ["client", "server", "revoked"], C),
+ endusers(PrivDir, "erlangCA", ["localhost"], C),
+ %% Create keycert files
SDir = filename:join([PrivDir, "server"]),
SC = filename:join([SDir, "cert.pem"]),
SK = filename:join([SDir, "key.pem"]),
@@ -46,7 +94,14 @@ all(DataDir, PrivDir) ->
CK = filename:join([CDir, "key.pem"]),
CKC = filename:join([CDir, "keycert.pem"]),
append_files([CK, CC], CKC),
- remove_rnd(PrivDir).
+ RDir = filename:join([PrivDir, "revoked"]),
+ RC = filename:join([RDir, "cert.pem"]),
+ RK = filename:join([RDir, "key.pem"]),
+ RKC = filename:join([RDir, "keycert.pem"]),
+ revoke(PrivDir, "otpCA", "revoked", C),
+ append_files([RK, RC], RKC),
+ remove_rnd(PrivDir),
+ {ok, C}.
append_files(FileNames, ResultFileName) ->
{ok, ResultFile} = file:open(ResultFileName, [write]),
@@ -59,117 +114,182 @@ do_append_files([F|Fs], RF) ->
ok = file:write(RF, Data),
do_append_files(Fs, RF).
-rootCA(Root, OpenSSLCmd, Name) ->
- create_ca_dir(Root, Name, ca_cnf(Name)),
- DN = #dn{commonName = Name},
- create_self_signed_cert(Root, OpenSSLCmd, Name, req_cnf(DN)),
- ok.
+rootCA(Root, Name, C) ->
+ create_ca_dir(Root, Name, ca_cnf(C#config{commonName = Name})),
+ create_self_signed_cert(Root, Name, req_cnf(C#config{commonName = Name}), C),
+ file:copy(filename:join([Root, Name, "cert.pem"]), filename:join([Root, Name, "cacerts.pem"])),
+ gencrl(Root, Name, C).
-intermediateCA(Root, OpenSSLCmd, CA, ParentCA) ->
- CA = "otpCA",
- create_ca_dir(Root, CA, ca_cnf(CA)),
+intermediateCA(Root, CA, ParentCA, C) ->
+ create_ca_dir(Root, CA, ca_cnf(C#config{commonName = CA})),
CARoot = filename:join([Root, CA]),
- DN = #dn{commonName = CA},
CnfFile = filename:join([CARoot, "req.cnf"]),
- file:write_file(CnfFile, req_cnf(DN)),
- KeyFile = filename:join([CARoot, "private", "key.pem"]),
- ReqFile = filename:join([CARoot, "req.pem"]),
- create_req(Root, OpenSSLCmd, CnfFile, KeyFile, ReqFile),
+ file:write_file(CnfFile, req_cnf(C#config{commonName = CA})),
+ KeyFile = filename:join([CARoot, "private", "key.pem"]),
+ ReqFile = filename:join([CARoot, "req.pem"]),
+ create_req(Root, CnfFile, KeyFile, ReqFile, C),
CertFile = filename:join([CARoot, "cert.pem"]),
- sign_req(Root, OpenSSLCmd, ParentCA, "ca_cert", ReqFile, CertFile).
-
-endusers(Root, OpenSSLCmd, CA, Users) ->
- lists:foreach(fun(User) -> enduser(Root, OpenSSLCmd, CA, User) end, Users).
-
-enduser(Root, OpenSSLCmd, CA, User) ->
+ sign_req(Root, ParentCA, "ca_cert", ReqFile, CertFile, C),
+ CACertsFile = filename:join(CARoot, "cacerts.pem"),
+ file:copy(filename:join([Root, ParentCA, "cacerts.pem"]), CACertsFile),
+ %% append this CA's cert to the cacerts file
+ {ok, Bin} = file:read_file(CertFile),
+ {ok, FD} = file:open(CACertsFile, [append]),
+ file:write(FD, ["\n", Bin]),
+ file:close(FD),
+ gencrl(Root, CA, C).
+
+endusers(Root, CA, Users, C) ->
+ [enduser(Root, CA, User, C) || User <- Users].
+
+enduser(Root, CA, User, C) ->
UsrRoot = filename:join([Root, User]),
file:make_dir(UsrRoot),
CnfFile = filename:join([UsrRoot, "req.cnf"]),
- DN = #dn{commonName = User},
- file:write_file(CnfFile, req_cnf(DN)),
- KeyFile = filename:join([UsrRoot, "key.pem"]),
- ReqFile = filename:join([UsrRoot, "req.pem"]),
- create_req(Root, OpenSSLCmd, CnfFile, KeyFile, ReqFile),
+ file:write_file(CnfFile, req_cnf(C#config{commonName = User})),
+ KeyFile = filename:join([UsrRoot, "key.pem"]),
+ ReqFile = filename:join([UsrRoot, "req.pem"]),
+ create_req(Root, CnfFile, KeyFile, ReqFile, C),
+ %create_req(Root, CnfFile, KeyFile, ReqFile),
CertFileAllUsage = filename:join([UsrRoot, "cert.pem"]),
- sign_req(Root, OpenSSLCmd, CA, "user_cert", ReqFile, CertFileAllUsage),
+ sign_req(Root, CA, "user_cert", ReqFile, CertFileAllUsage, C),
CertFileDigitalSigOnly = filename:join([UsrRoot, "digital_signature_only_cert.pem"]),
- sign_req(Root, OpenSSLCmd, CA, "user_cert_digital_signature_only", ReqFile, CertFileDigitalSigOnly).
-
-collect_certs(Root, CAs, Users) ->
- Bins = lists:foldr(
- fun(CA, Acc) ->
- File = filename:join([Root, CA, "cert.pem"]),
- {ok, Bin} = file:read_file(File),
- [Bin, "\n" | Acc]
- end, [], CAs),
- lists:foreach(
- fun(User) ->
- File = filename:join([Root, User, "cacerts.pem"]),
- file:write_file(File, Bins)
- end, Users).
+ sign_req(Root, CA, "user_cert_digital_signature_only", ReqFile, CertFileDigitalSigOnly, C),
+ CACertsFile = filename:join(UsrRoot, "cacerts.pem"),
+ file:copy(filename:join([Root, CA, "cacerts.pem"]), CACertsFile),
+ ok.
-create_self_signed_cert(Root, OpenSSLCmd, CAName, Cnf) ->
+revoke(Root, CA, User, C) ->
+ UsrCert = filename:join([Root, User, "cert.pem"]),
+ CACnfFile = filename:join([Root, CA, "ca.cnf"]),
+ Cmd = [C#config.openssl_cmd, " ca"
+ " -revoke ", UsrCert,
+ [" -crl_reason keyCompromise" || C#config.v2_crls ],
+ " -config ", CACnfFile],
+ Env = [{"ROOTDIR", filename:absname(Root)}],
+ cmd(Cmd, Env),
+ gencrl(Root, CA, C).
+
+gencrl(Root, CA, C) ->
+ CACnfFile = filename:join([Root, CA, "ca.cnf"]),
+ CACRLFile = filename:join([Root, CA, "crl.pem"]),
+ Cmd = [C#config.openssl_cmd, " ca"
+ " -gencrl ",
+ " -crlhours 24",
+ " -out ", CACRLFile,
+ " -config ", CACnfFile],
+ Env = [{"ROOTDIR", filename:absname(Root)}],
+ cmd(Cmd, Env).
+
+verify(Root, CA, User, C) ->
+ CAFile = filename:join([Root, User, "cacerts.pem"]),
+ CACRLFile = filename:join([Root, CA, "crl.pem"]),
+ CertFile = filename:join([Root, User, "cert.pem"]),
+ Cmd = [C#config.openssl_cmd, " verify"
+ " -CAfile ", CAFile,
+ " -CRLfile ", CACRLFile, %% this is undocumented, but seems to work
+ " -crl_check ",
+ CertFile],
+ Env = [{"ROOTDIR", filename:absname(Root)}],
+ try cmd(Cmd, Env) catch
+ exit:{eval_cmd, _, _} ->
+ invalid
+ end.
+
+create_self_signed_cert(Root, CAName, Cnf, C = #config{ecc_certs = true}) ->
CARoot = filename:join([Root, CAName]),
CnfFile = filename:join([CARoot, "req.cnf"]),
file:write_file(CnfFile, Cnf),
- KeyFile = filename:join([CARoot, "private", "key.pem"]),
- CertFile = filename:join([CARoot, "cert.pem"]),
- Cmd = [OpenSSLCmd, " req"
+ KeyFile = filename:join([CARoot, "private", "key.pem"]),
+ CertFile = filename:join([CARoot, "cert.pem"]),
+ Cmd = [C#config.openssl_cmd, " ecparam"
+ " -out ", KeyFile,
+ " -name secp521r1 ",
+ %" -name sect283k1 ",
+ " -genkey "],
+ Env = [{"ROOTDIR", filename:absname(Root)}],
+ cmd(Cmd, Env),
+
+ Cmd2 = [C#config.openssl_cmd, " req"
+ " -new"
+ " -x509"
+ " -config ", CnfFile,
+ " -key ", KeyFile,
+ " -outform PEM ",
+ " -out ", CertFile],
+ cmd(Cmd2, Env);
+create_self_signed_cert(Root, CAName, Cnf, C) ->
+ CARoot = filename:join([Root, CAName]),
+ CnfFile = filename:join([CARoot, "req.cnf"]),
+ file:write_file(CnfFile, Cnf),
+ KeyFile = filename:join([CARoot, "private", "key.pem"]),
+ CertFile = filename:join([CARoot, "cert.pem"]),
+ Cmd = [C#config.openssl_cmd, " req"
" -new"
" -x509"
" -config ", CnfFile,
" -keyout ", KeyFile,
- " -out ", CertFile],
- Env = [{"ROOTDIR", Root}],
- cmd(Cmd, Env),
- fix_key_file(OpenSSLCmd, KeyFile).
-
-% openssl 1.0 generates key files in pkcs8 format by default and we don't handle this format
-fix_key_file(OpenSSLCmd, KeyFile) ->
- KeyFileTmp = KeyFile ++ ".tmp",
- Cmd = [OpenSSLCmd, " rsa",
- " -in ",
- KeyFile,
- " -out ",
- KeyFileTmp],
- cmd(Cmd, []),
- ok = file:rename(KeyFileTmp, KeyFile).
+ " -outform PEM",
+ " -out ", CertFile],
+ Env = [{"ROOTDIR", filename:absname(Root)}],
+ cmd(Cmd, Env).
+
create_ca_dir(Root, CAName, Cnf) ->
CARoot = filename:join([Root, CAName]),
+ ok = filelib:ensure_dir(CARoot),
file:make_dir(CARoot),
create_dirs(CARoot, ["certs", "crl", "newcerts", "private"]),
create_rnd(Root, filename:join([CAName, "private"])),
create_files(CARoot, [{"serial", "01\n"},
+ {"crlnumber", "01"},
{"index.txt", ""},
{"ca.cnf", Cnf}]).
-create_req(Root, OpenSSLCmd, CnfFile, KeyFile, ReqFile) ->
- Cmd = [OpenSSLCmd, " req"
+create_req(Root, CnfFile, KeyFile, ReqFile, C = #config{ecc_certs = true}) ->
+ Cmd = [C#config.openssl_cmd, " ecparam"
+ " -out ", KeyFile,
+ " -name secp521r1 ",
+ %" -name sect283k1 ",
+ " -genkey "],
+ Env = [{"ROOTDIR", filename:absname(Root)}],
+ cmd(Cmd, Env),
+ Cmd2 = [C#config.openssl_cmd, " req"
+ " -new ",
+ " -key ", KeyFile,
+ " -outform PEM ",
+ " -out ", ReqFile,
+ " -config ", CnfFile],
+ cmd(Cmd2, Env);
+ %fix_key_file(KeyFile).
+create_req(Root, CnfFile, KeyFile, ReqFile, C) ->
+ Cmd = [C#config.openssl_cmd, " req"
" -new"
" -config ", CnfFile,
- " -keyout ", KeyFile,
- " -out ", ReqFile],
- Env = [{"ROOTDIR", Root}],
- cmd(Cmd, Env),
- fix_key_file(OpenSSLCmd, KeyFile).
+ " -outform PEM ",
+ " -keyout ", KeyFile,
+ " -out ", ReqFile],
+ Env = [{"ROOTDIR", filename:absname(Root)}],
+ cmd(Cmd, Env).
+ %fix_key_file(KeyFile).
+
-sign_req(Root, OpenSSLCmd, CA, CertType, ReqFile, CertFile) ->
+sign_req(Root, CA, CertType, ReqFile, CertFile, C) ->
CACnfFile = filename:join([Root, CA, "ca.cnf"]),
- Cmd = [OpenSSLCmd, " ca"
+ Cmd = [C#config.openssl_cmd, " ca"
" -batch"
" -notext"
- " -config ", CACnfFile,
+ " -config ", CACnfFile,
" -extensions ", CertType,
- " -in ", ReqFile,
+ " -in ", ReqFile,
" -out ", CertFile],
- Env = [{"ROOTDIR", Root}],
+ Env = [{"ROOTDIR", filename:absname(Root)}],
cmd(Cmd, Env).
-
+
%%
%% Misc
%%
-
+
create_dirs(Root, Dirs) ->
lists:foreach(fun(Dir) ->
file:make_dir(filename:join([Root, Dir])) end,
@@ -192,30 +312,30 @@ remove_rnd(Dir) ->
cmd(Cmd, Env) ->
FCmd = lists:flatten(Cmd),
- Port = open_port({spawn, FCmd}, [stream, eof, exit_status, stderr_to_stdout,
+ Port = open_port({spawn, FCmd}, [stream, eof, exit_status, stderr_to_stdout,
{env, Env}]),
- eval_cmd(Port).
+ eval_cmd(Port, FCmd).
-eval_cmd(Port) ->
- receive
+eval_cmd(Port, Cmd) ->
+ receive
{Port, {data, _}} ->
- eval_cmd(Port);
+ eval_cmd(Port, Cmd);
{Port, eof} ->
ok
end,
receive
{Port, {exit_status, Status}} when Status /= 0 ->
%% io:fwrite("exit status: ~w~n", [Status]),
- exit({eval_cmd, Status})
+ exit({eval_cmd, Cmd, Status})
after 0 ->
ok
end.
%%
-%% Contents of configuration files
+%% Contents of configuration files
%%
-req_cnf(DN) ->
+req_cnf(C) ->
["# Purpose: Configuration for requests (end users and CAs)."
"\n"
"ROOTDIR = $ENV::ROOTDIR\n"
@@ -224,10 +344,10 @@ req_cnf(DN) ->
"[req]\n"
"input_password = secret\n"
"output_password = secret\n"
- "default_bits = 1024\n"
+ "default_bits = ", integer_to_list(C#config.default_bits), "\n"
"RANDFILE = $ROOTDIR/RAND\n"
"encrypt_key = no\n"
- "default_md = sha1\n"
+ "default_md = md5\n"
"#string_mask = pkix\n"
"x509_extensions = ca_ext\n"
"prompt = no\n"
@@ -235,12 +355,12 @@ req_cnf(DN) ->
"\n"
"[name]\n"
- "commonName = ", DN#dn.commonName, "\n"
- "organizationalUnitName = ", DN#dn.organizationalUnitName, "\n"
- "organizationName = ", DN#dn.organizationName, "\n"
- "localityName = ", DN#dn.localityName, "\n"
- "countryName = ", DN#dn.countryName, "\n"
- "emailAddress = ", DN#dn.emailAddress, "\n"
+ "commonName = ", C#config.commonName, "\n"
+ "organizationalUnitName = ", C#config.organizationalUnitName, "\n"
+ "organizationName = ", C#config.organizationName, "\n"
+ "localityName = ", C#config.localityName, "\n"
+ "countryName = ", C#config.countryName, "\n"
+ "emailAddress = ", C#config.emailAddress, "\n"
"\n"
"[ca_ext]\n"
@@ -249,8 +369,7 @@ req_cnf(DN) ->
"subjectKeyIdentifier = hash\n"
"subjectAltName = email:copy\n"].
-
-ca_cnf(CA) ->
+ca_cnf(C) ->
["# Purpose: Configuration for CAs.\n"
"\n"
"ROOTDIR = $ENV::ROOTDIR\n"
@@ -258,21 +377,23 @@ ca_cnf(CA) ->
"\n"
"[ca]\n"
- "dir = $ROOTDIR/", CA, "\n"
+ "dir = $ROOTDIR/", C#config.commonName, "\n"
"certs = $dir/certs\n"
"crl_dir = $dir/crl\n"
"database = $dir/index.txt\n"
"new_certs_dir = $dir/newcerts\n"
"certificate = $dir/cert.pem\n"
"serial = $dir/serial\n"
- "crl = $dir/crl.pem\n"
+ "crl = $dir/crl.pem\n",
+ ["crlnumber = $dir/crlnumber\n" || C#config.v2_crls],
"private_key = $dir/private/key.pem\n"
"RANDFILE = $dir/private/RAND\n"
"\n"
- "x509_extensions = user_cert\n"
+ "x509_extensions = user_cert\n",
+ ["crl_extensions = crl_ext\n" || C#config.v2_crls],
"unique_subject = no\n"
"default_days = 3600\n"
- "default_md = sha1\n"
+ "default_md = md5\n"
"preserve = no\n"
"policy = policy_match\n"
"\n"
@@ -286,6 +407,13 @@ ca_cnf(CA) ->
"emailAddress = supplied\n"
"\n"
+ "[crl_ext]\n"
+ "authorityKeyIdentifier=keyid:always,issuer:always\n",
+ ["issuingDistributionPoint=critical, @idpsec\n" || C#config.issuing_distribution_point],
+
+ "[idpsec]\n"
+ "fullname=URI:http://localhost:8000/",C#config.commonName,"/crl.pem\n"
+
"[user_cert]\n"
"basicConstraints = CA:false\n"
"keyUsage = nonRepudiation, digitalSignature, keyEncipherment\n"
@@ -293,6 +421,12 @@ ca_cnf(CA) ->
"authorityKeyIdentifier = keyid,issuer:always\n"
"subjectAltName = email:copy\n"
"issuerAltName = issuer:copy\n"
+ "crlDistributionPoints=@crl_section\n"
+
+ "[crl_section]\n"
+ %% intentionally invalid
+ "URI.1=http://localhost/",C#config.commonName,"/crl.pem\n"
+ "URI.2=http://localhost:",integer_to_list(C#config.crl_port),"/",C#config.commonName,"/crl.pem\n"
"\n"
"[user_cert_digital_signature_only]\n"
@@ -310,4 +444,7 @@ ca_cnf(CA) ->
"subjectKeyIdentifier = hash\n"
"authorityKeyIdentifier = keyid:always,issuer:always\n"
"subjectAltName = email:copy\n"
- "issuerAltName = issuer:copy\n"].
+ "issuerAltName = issuer:copy\n"
+ "crlDistributionPoints=@crl_section\n"
+ ].
+
diff --git a/lib/erl_docgen/doc/src/notes.xml b/lib/erl_docgen/doc/src/notes.xml
index f194fb6d6c..c2f81dfcc1 100644
--- a/lib/erl_docgen/doc/src/notes.xml
+++ b/lib/erl_docgen/doc/src/notes.xml
@@ -30,7 +30,23 @@
</header>
<p>This document describes the changes made to the <em>erl_docgen</em> application.</p>
- <section><title>Erl_Docgen 0.3.6</title>
+ <section><title>Erl_Docgen 0.3.7</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Maps: Properly align union typed assoc values in
+ documentation</p>
+ <p>
+ Own Id: OTP-12190</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erl_Docgen 0.3.6</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
diff --git a/lib/erl_docgen/vsn.mk b/lib/erl_docgen/vsn.mk
index 8bfcc08698..8957d6ac40 100644
--- a/lib/erl_docgen/vsn.mk
+++ b/lib/erl_docgen/vsn.mk
@@ -1 +1 @@
-ERL_DOCGEN_VSN = 0.3.6
+ERL_DOCGEN_VSN = 0.3.7
diff --git a/lib/erl_interface/doc/src/notes.xml b/lib/erl_interface/doc/src/notes.xml
index a055e854e3..29a9d71041 100644
--- a/lib/erl_interface/doc/src/notes.xml
+++ b/lib/erl_interface/doc/src/notes.xml
@@ -30,6 +30,42 @@
</header>
<p>This document describes the changes made to the Erl_interface application.</p>
+<section><title>Erl_Interface 3.7.20</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Use C99 function isfinite() instead of finite() when
+ available on non GCC compilers.</p>
+ <p>
+ Own Id: OTP-12268</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Distribute <c>autoconf</c> helpers to applications at
+ build time instead of having multiple identical copies
+ committed in the repository.</p>
+ <p>
+ Own Id: OTP-12348</p>
+ </item>
+ <item>
+ <p>
+ Added an .appup file for the application.</p>
+ <p>
+ Own Id: OTP-12358 Aux Id: OTP-12178 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Erl_Interface 3.7.19</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/erl_interface/src/Makefile.in b/lib/erl_interface/src/Makefile.in
index 7d914a02ca..7c09b605fa 100644
--- a/lib/erl_interface/src/Makefile.in
+++ b/lib/erl_interface/src/Makefile.in
@@ -43,10 +43,13 @@ include $(ERL_TOP)/make/output.mk
EBINDIR=../ebin
APP_FILE= erl_interface.app
-
APP_SRC= $(APP_FILE).src
APP_TARGET= $(EBINDIR)/$(APP_FILE)
+APPUP_FILE= erl_interface.appup
+APPUP_SRC= $(APPUP_FILE).src
+APPUP_TARGET= $(EBINDIR)/$(APPUP_FILE)
+
USING_MINGW=@MIXED_CYGWIN_MINGW@
USING_MSYS_VC==@MIXED_MSYS_VC@
USING_CYGWIN_VC==@MIXED_MSYS_VC@
@@ -220,7 +223,8 @@ ifeq ($(USING_VC),yes)
TARGETS = \
$(OBJ_TARGETS) \
$(EXE_TARGETS) \
- $(APP_TARGET)
+ $(APP_TARGET) \
+ $(APPUP_TARGET)
OBJ_TARGETS = \
$(MT_EILIB) \
@@ -250,7 +254,8 @@ ifeq ($USING_MINGW,yes)
TARGETS = \
$(OBJ_TARGETS) \
$(EXE_TARGETS) \
- $(APP_TARGET)
+ $(APP_TARGET) \
+ $(APPUP_TARGET)
OBJ_TARGETS = \
$(MD_EILIB) \
@@ -269,7 +274,8 @@ ifdef THR_DEFS
TARGETS = \
$(OBJ_TARGETS) \
$(EXE_TARGETS) \
- $(APP_TARGET)
+ $(APP_TARGET) \
+ $(APPUP_TARGET)
OBJ_TARGETS = \
$(ST_EILIB) \
@@ -292,7 +298,8 @@ else
TARGETS = \
$(OBJ_TARGETS) \
$(EXE_TARGETS) \
- $(APP_TARGET)
+ $(APP_TARGET) \
+ $(APPUP_TARGET)
OBJ_TARGETS = \
$(ST_EILIB) \
@@ -558,6 +565,8 @@ clean:
rm -f $(MDD_EIOBJECTS) $(MDD_ERLOBJECTS) $(MDD_EILIB) $(MDD_ERLLIB)
rm -f $(ERL_CALL)
rm -f $(FAKE_TARGETS)
+ rm -f $(APP_TARGET)
+ rm -f $(APPUP_TARGET)
distclean: clean
rm -f config.h config.log config.status configure
@@ -616,6 +625,8 @@ _create_dirs := $(shell mkdir -p $(EBINDIR) $(BINDIR) $(OBJDIR) $(ST_OBJDIR) $(M
$(APP_TARGET): $(APP_SRC) ../vsn.mk
$(vsn_verbose)sed -e 's;%VSN%;$(ERL_INTERFACE_VSN);' $< > $@
+$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
+ $(vsn_verbose)sed -e 's;%VSN%;$(ERL_INTERFACE_VSN);' $< > $@
ifeq ($(TARGET),win32)
@@ -884,6 +895,7 @@ release: opt
$(INSTALL_DIR) "$(RELEASE_PATH)/usr/include"
$(INSTALL_DIR) "$(RELEASE_PATH)/usr/lib"
$(INSTALL_DATA) $(APP_TARGET) "$(RELSYSDIR)/ebin/$(APP_FILE)"
+ $(INSTALL_DATA) $(APPUP_TARGET) "$(RELSYSDIR)/ebin/$(APPUP_FILE)"
$(INSTALL_DATA) $(HEADERS) "$(RELSYSDIR)/include"
$(INSTALL_DATA) $(HEADERS) "$(RELEASE_PATH)/usr/include"
$(INSTALL_DATA) $(OBJ_TARGETS) "$(RELSYSDIR)/lib"
diff --git a/lib/erl_interface/src/erl_interface.appup.src b/lib/erl_interface/src/erl_interface.appup.src
new file mode 100644
index 0000000000..d267e3d3d5
--- /dev/null
+++ b/lib/erl_interface/src/erl_interface.appup.src
@@ -0,0 +1,18 @@
+%% -*- erlang -*-
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2014. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+{"%VSN%", [], []}.
diff --git a/lib/erl_interface/vsn.mk b/lib/erl_interface/vsn.mk
index e39aa4f514..c809d5421e 100644
--- a/lib/erl_interface/vsn.mk
+++ b/lib/erl_interface/vsn.mk
@@ -1,2 +1,2 @@
-EI_VSN = 3.7.19
+EI_VSN = 3.7.20
ERL_INTERFACE_VSN = $(EI_VSN)
diff --git a/lib/eunit/doc/src/notes.xml b/lib/eunit/doc/src/notes.xml
index e5a190e3e9..6b76e097b6 100644
--- a/lib/eunit/doc/src/notes.xml
+++ b/lib/eunit/doc/src/notes.xml
@@ -32,6 +32,28 @@
</header>
<p>This document describes the changes made to the EUnit application.</p>
+<section><title>Eunit 2.2.9</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Make sure to install .hrl files when needed</p>
+ <p>
+ Own Id: OTP-12197</p>
+ </item>
+ <item>
+ <p>
+ Make sure the clean rule for ssh, ssl, eunit and otp_mibs
+ actually removes generated files.</p>
+ <p>
+ Own Id: OTP-12200</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Eunit 2.2.8</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/eunit/vsn.mk b/lib/eunit/vsn.mk
index 855e1dac88..dca8b3ece0 100644
--- a/lib/eunit/vsn.mk
+++ b/lib/eunit/vsn.mk
@@ -1 +1 @@
-EUNIT_VSN = 2.2.8
+EUNIT_VSN = 2.2.9
diff --git a/lib/hipe/doc/src/notes.xml b/lib/hipe/doc/src/notes.xml
index 2962e4a9ac..2d6fd245f7 100644
--- a/lib/hipe/doc/src/notes.xml
+++ b/lib/hipe/doc/src/notes.xml
@@ -30,6 +30,22 @@
</header>
<p>This document describes the changes made to HiPE.</p>
+<section><title>Hipe 3.11.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed internal elf_format hrl file to contain valid
+ erlang</p>
+ <p>
+ Own Id: OTP-12322</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Hipe 3.11.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/hipe/rtl/hipe_rtl_binary_match.erl b/lib/hipe/rtl/hipe_rtl_binary_match.erl
index 8831199244..af8903904b 100644
--- a/lib/hipe/rtl/hipe_rtl_binary_match.erl
+++ b/lib/hipe/rtl/hipe_rtl_binary_match.erl
@@ -990,19 +990,19 @@ unsigned_bignum(Dst1, Src, TrueLblName) ->
hipe_tagscheme:unsafe_mk_big(Dst1, Src, unsigned),
hipe_rtl:mk_goto(TrueLblName)].
-load_bytes(Dst, Base, Offset, {Signedness, _Endianess},1) ->
+load_bytes(Dst, Base, Offset, {Signedness, _Endianness},1) ->
[hipe_rtl:mk_load(Dst, Base, Offset, byte, Signedness),
hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1))];
-load_bytes(Dst, Base, Offset, {Signedness, Endianess},2) ->
- case Endianess of
+load_bytes(Dst, Base, Offset, {Signedness, Endianness},2) ->
+ case Endianness of
big ->
hipe_rtl_arch:load_big_2(Dst, Base, Offset, Signedness);
little ->
hipe_rtl_arch:load_little_2(Dst, Base, Offset, Signedness)
end;
-load_bytes(Dst, Base, Offset, {Signedness, Endianess},3) ->
+load_bytes(Dst, Base, Offset, {Signedness, Endianness},3) ->
Tmp1 = hipe_rtl:mk_new_reg(),
- case Endianess of
+ case Endianness of
big ->
[hipe_rtl:mk_load(Dst, Base, Offset, byte, Signedness),
hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1)),
@@ -1026,18 +1026,18 @@ load_bytes(Dst, Base, Offset, {Signedness, Endianess},3) ->
hipe_rtl:mk_alu(Dst, Dst, 'or', Tmp1),
hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1))]
end;
-load_bytes(Dst, Base, Offset, {Signedness, Endianess}, 4) ->
- case Endianess of
+load_bytes(Dst, Base, Offset, {Signedness, Endianness}, 4) ->
+ case Endianness of
big ->
hipe_rtl_arch:load_big_4(Dst, Base, Offset, Signedness);
little ->
hipe_rtl_arch:load_little_4(Dst, Base, Offset, Signedness)
end;
-load_bytes(Dst, Base, Offset, {Signedness, Endianess}, X) when X > 1 ->
+load_bytes(Dst, Base, Offset, {Signedness, Endianness}, X) when X > 1 ->
[LoopLbl, EndLbl] = create_lbls(2),
[Tmp1, Limit, TmpOffset] = create_regs(3),
- case Endianess of
+ case Endianness of
big ->
[hipe_rtl:mk_alu(Limit, Offset, add, hipe_rtl:mk_imm(X)),
hipe_rtl:mk_load(Dst, Base, Offset, byte, Signedness),
diff --git a/lib/hipe/vsn.mk b/lib/hipe/vsn.mk
index cf1976d8d6..4cf09830cb 100644
--- a/lib/hipe/vsn.mk
+++ b/lib/hipe/vsn.mk
@@ -1 +1 @@
-HIPE_VSN = 3.11.1
+HIPE_VSN = 3.11.2
diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml
index 921de8e490..fb7034498c 100644
--- a/lib/inets/doc/src/notes.xml
+++ b/lib/inets/doc/src/notes.xml
@@ -32,7 +32,37 @@
<file>notes.xml</file>
</header>
- <section><title>Inets 5.10.3</title>
+ <section><title>Inets 5.10.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed a spelling mistake in httpc documentation.</p>
+ <p>
+ Own Id: OTP-12221</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Add option {ftp_extension, boolean} to enable use of
+ extended commands EPSV and EPRT, as specified in RFC
+ 2428, for IPv4 instead of using the legacy commands. Ipv6
+ can not be supported without the extended commands.</p>
+ <p>
+ Own Id: OTP-12255</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Inets 5.10.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
diff --git a/lib/inets/src/http_client/httpc_handler.erl b/lib/inets/src/http_client/httpc_handler.erl
index 0a42e7210c..7f7328f1d9 100644
--- a/lib/inets/src/http_client/httpc_handler.erl
+++ b/lib/inets/src/http_client/httpc_handler.erl
@@ -316,8 +316,9 @@ handle_call(#request{address = Addr} = Request, _,
{reply, ok, State}
end;
{error, Reason} ->
- ?hcri("failed sending request", [{reason, Reason}]),
- {reply, {pipeline_failed, Reason}, State0}
+ ?hcri("failed sending request", [{reason, Reason}]),
+ NewPipeline = queue:in(Request, State0#state.pipeline),
+ {stop, shutdown, {pipeline_failed, Reason}, State0#state{pipeline = NewPipeline}}
end;
handle_call(#request{address = Addr} = Request, _,
@@ -355,25 +356,25 @@ handle_call(#request{address = Addr} = Request, _,
?hcrd("no current request", []),
cancel_timer(Timers#timers.queue_timer,
timeout_queue),
+ NewTimers = Timers#timers{queue_timer = undefined},
+ State1 = State0#state{timers = NewTimers},
Address = handle_proxy(Addr, Proxy),
case httpc_request:send(Address, Session, Request) of
ok ->
?hcrd("request sent", []),
%% Activate the request time out for the new request
- State1 =
- activate_request_timeout(State0#state{request = Request}),
- NewTimers = State1#state.timers,
+ State2 =
+ activate_request_timeout(State1#state{request = Request}),
NewSession =
Session#session{queue_length = 1,
client_close = ClientClose},
insert_session(NewSession, ProfileName),
- State = init_wait_for_response_state(Request, State1#state{session = NewSession,
- timers = NewTimers}),
+ State = init_wait_for_response_state(Request, State2#state{session = NewSession}),
{reply, ok, State};
{error, Reason} ->
?hcri("failed sending request", [{reason, Reason}]),
- {reply, {request_failed, Reason}, State0}
+ {stop, shutdown, {keepalive_failed, Reason}, State1}
end
end;
@@ -1329,7 +1330,7 @@ handle_keep_alive_queue(#state{status = keep_alive,
Session, <<>>,
State#state{keep_alive = KeepAlive});
{error, Reason} ->
- {reply, {keep_alive_failed, Reason}, State}
+ {stop, shutdown, {keepalive_failed, Reason}, State}
end
end
end.
diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl
index c535d59b9f..63f8bc5bc6 100644
--- a/lib/inets/test/httpc_SUITE.erl
+++ b/lib/inets/test/httpc_SUITE.erl
@@ -28,6 +28,7 @@
-include_lib("common_test/include/ct.hrl").
-include("inets_test_lib.hrl").
-include("http_internal.hrl").
+-include("httpc_internal.hrl").
%% Note: This directive should only be used in test suites.
-compile(export_all).
@@ -105,6 +106,7 @@ only_simulated() ->
empty_response_header,
remote_socket_close,
remote_socket_close_async,
+ process_leak_on_keepalive,
transfer_encoding,
transfer_encoding_identity,
redirect_loop,
@@ -900,6 +902,33 @@ remote_socket_close_async(Config) when is_list(Config) ->
%%-------------------------------------------------------------------------
+process_leak_on_keepalive(Config) ->
+ {ok, ClosedSocket} = gen_tcp:listen(6666, [{active, false}]),
+ ok = gen_tcp:close(ClosedSocket),
+ Request = {url(group_name(Config), "/dummy.html", Config), []},
+ HttpcHandlers0 = supervisor:which_children(httpc_handler_sup),
+ {ok, {{_, 200, _}, _, Body}} = httpc:request(get, Request, [], []),
+ HttpcHandlers1 = supervisor:which_children(httpc_handler_sup),
+ ChildrenCount = supervisor:count_children(httpc_handler_sup),
+ %% Assuming that the new handler will be selected for keep_alive
+ %% which could not be the case if other handlers existed
+ [{undefined, Pid, worker, [httpc_handler]}] =
+ ordsets:to_list(
+ ordsets:subtract(ordsets:from_list(HttpcHandlers1),
+ ordsets:from_list(HttpcHandlers0))),
+ sys:replace_state(
+ Pid, fun (State) ->
+ Session = element(3, State),
+ setelement(3, State, Session#session{socket=ClosedSocket})
+ end),
+ {ok, {{_, 200, _}, _, Body}} = httpc:request(get, Request, [], []),
+ %% bad handler with the closed socket should get replaced by
+ %% the new one, so children count should stay the same
+ ChildrenCount = supervisor:count_children(httpc_handler_sup),
+ ok.
+
+%%-------------------------------------------------------------------------
+
stream_to_pid(Config) when is_list(Config) ->
ReceiverPid = create_receiver(pid),
Receiver = ReceiverPid,
diff --git a/lib/jinterface/doc/src/notes.xml b/lib/jinterface/doc/src/notes.xml
index 46d89f0cdb..fc5f8be53e 100644
--- a/lib/jinterface/doc/src/notes.xml
+++ b/lib/jinterface/doc/src/notes.xml
@@ -30,6 +30,40 @@
</header>
<p>This document describes the changes made to the Jinterface application.</p>
+<section><title>Jinterface 1.5.12</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ handle empty .erlang.cookie without crashing and
+ OtpErlangList.clone must not return null</p>
+ <p>
+ Own Id: OTP-12210</p>
+ </item>
+ <item>
+ <p>
+ This fixes all the compilation warnings in the Java code</p>
+ <p>
+ Own Id: OTP-12211</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Added an .appup file for the application.</p>
+ <p>
+ Own Id: OTP-12358 Aux Id: OTP-12178 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Jinterface 1.5.11</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/Makefile b/lib/jinterface/java_src/com/ericsson/otp/erlang/Makefile
index fd923f85ae..ea3ab770ce 100644
--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/Makefile
+++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/Makefile
@@ -37,10 +37,13 @@ VSN=$(JINTERFACE_VSN)
EBINDIR=$(ERL_TOP)/lib/jinterface/ebin
APP_FILE= jinterface.app
-
APP_SRC= $(APP_FILE).src
APP_TARGET= $(EBINDIR)/$(APP_FILE)
+APPUP_FILE= jinterface.appup
+APPUP_SRC= $(APPUP_FILE).src
+APPUP_TARGET= $(EBINDIR)/$(APPUP_FILE)
+
# ----------------------------------------------------
# Release directory specification
# ----------------------------------------------------
@@ -54,7 +57,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/jinterface-$(VSN)
# all java sourcefiles listed in common include file
include $(ERL_TOP)/lib/jinterface/java_src/$(JAVA_CLASS_SUBDIR)/java_files
-TARGET_FILES= $(JAVA_FILES:%=$(JAVA_DEST_ROOT)$(JAVA_CLASS_SUBDIR)%.class) $(APP_TARGET)
+TARGET_FILES= $(JAVA_FILES:%=$(JAVA_DEST_ROOT)$(JAVA_CLASS_SUBDIR)%.class) $(APP_TARGET) $(APPUP_TARGET)
JAVA_SRC= $(JAVA_FILES:%=%.java)
JARFILE= OtpErlang.jar
@@ -90,6 +93,8 @@ endif
$(APP_TARGET): $(APP_SRC) $(ERL_TOP)/lib/jinterface/vsn.mk
$(vsn_verbose)sed -e 's;%VSN%;$(JINTERFACE_VSN);' $< > $@
+$(APPUP_TARGET): $(APPUP_SRC) $(ERL_TOP)/lib/jinterface/vsn.mk
+ $(vsn_verbose)sed -e 's;%VSN%;$(JINTERFACE_VSN);' $< > $@
debug opt: make_dirs $(JAVA_DEST_ROOT)$(JARFILE)
@@ -120,6 +125,7 @@ release_spec: opt
$(V_at)$(INSTALL_DATA) $(JAVA_DEST_ROOT)$(JARFILE) "$(RELSYSDIR)/priv"
$(V_at)$(INSTALL_DIR) "$(RELSYSDIR)/ebin"
$(V_at)$(INSTALL_DATA) $(APP_TARGET) "$(RELSYSDIR)/ebin/$(APP_FILE)"
+ $(V_at)$(INSTALL_DATA) $(APPUP_TARGET) "$(RELSYSDIR)/ebin/$(APPUP_FILE)"
release_docs_spec:
diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/jinterface.appup.src b/lib/jinterface/java_src/com/ericsson/otp/erlang/jinterface.appup.src
new file mode 100644
index 0000000000..d267e3d3d5
--- /dev/null
+++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/jinterface.appup.src
@@ -0,0 +1,18 @@
+%% -*- erlang -*-
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2014. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+{"%VSN%", [], []}.
diff --git a/lib/jinterface/vsn.mk b/lib/jinterface/vsn.mk
index eea83c2f3f..72ad316333 100644
--- a/lib/jinterface/vsn.mk
+++ b/lib/jinterface/vsn.mk
@@ -1 +1 @@
-JINTERFACE_VSN = 1.5.11
+JINTERFACE_VSN = 1.5.12
diff --git a/lib/kernel/doc/src/notes.xml b/lib/kernel/doc/src/notes.xml
index 7eaf2d4a44..1ef106e17a 100644
--- a/lib/kernel/doc/src/notes.xml
+++ b/lib/kernel/doc/src/notes.xml
@@ -30,6 +30,59 @@
</header>
<p>This document describes the changes made to the Kernel application.</p>
+<section><title>Kernel 3.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Make sure to install .hrl files when needed</p>
+ <p>
+ Own Id: OTP-12197</p>
+ </item>
+ <item>
+ <p>
+ Removed the undocumented application environment variable
+ 'raw_files' from the kernel application. This variable
+ was checked (by call to application:get_env/2) each time
+ a raw file was to be opened in the file module.</p>
+ <p>
+ Own Id: OTP-12276</p>
+ </item>
+ <item>
+ <p>
+ A bug has been fixed when using the netns option to
+ gen_udp, which accidentally only worked if it was the
+ last option.</p>
+ <p>
+ Own Id: OTP-12314</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Updated documentation for inet buffer size options.</p>
+ <p>
+ Own Id: OTP-12296</p>
+ </item>
+ <item>
+ <p>
+ Introduce new option 'raw' in file_info and link_info
+ functions. This option allows the caller not to go
+ through the file server for information about files
+ guaranteed to be local.</p>
+ <p>
+ Own Id: OTP-12325</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Kernel 3.0.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/kernel/vsn.mk b/lib/kernel/vsn.mk
index be633a304a..15820a0182 100644
--- a/lib/kernel/vsn.mk
+++ b/lib/kernel/vsn.mk
@@ -1 +1 @@
-KERNEL_VSN = 3.0.3
+KERNEL_VSN = 3.1
diff --git a/lib/megaco/doc/src/notes.xml b/lib/megaco/doc/src/notes.xml
index 9a260c3878..fd654af051 100644
--- a/lib/megaco/doc/src/notes.xml
+++ b/lib/megaco/doc/src/notes.xml
@@ -36,7 +36,24 @@
section is the version number of Megaco.</p>
- <section><title>Megaco 3.17.2</title>
+ <section><title>Megaco 3.17.3</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Distribute <c>autoconf</c> helpers to applications at
+ build time instead of having multiple identical copies
+ committed in the repository.</p>
+ <p>
+ Own Id: OTP-12348</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Megaco 3.17.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
diff --git a/lib/megaco/src/app/megaco.appup.src b/lib/megaco/src/app/megaco.appup.src
index a3a2e2ea9c..92504e8e87 100644
--- a/lib/megaco/src/app/megaco.appup.src
+++ b/lib/megaco/src/app/megaco.appup.src
@@ -180,11 +180,15 @@
%% |
%% v
%% 3.17.2
+%% |
+%% v
+%% 3.17.3
%%
%%
{"%VSN%",
[
+ {"3.17.2", []},
{"3.17.1", [{restart_application,megaco}]},
{"3.17.0.3", [{restart_application,megaco}]},
{"3.17.0.2", []},
@@ -198,6 +202,7 @@
}
],
[
+ {"3.17.2", []},
{"3.17.1", [{restart_application,megaco}]},
{"3.17.0.3", [{restart_application,megaco}]},
{"3.17.0.2", []},
diff --git a/lib/megaco/vsn.mk b/lib/megaco/vsn.mk
index 1f4e3b8e95..8687d622e9 100644
--- a/lib/megaco/vsn.mk
+++ b/lib/megaco/vsn.mk
@@ -18,6 +18,6 @@
# %CopyrightEnd%
APPLICATION = megaco
-MEGACO_VSN = 3.17.2
+MEGACO_VSN = 3.17.3
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(MEGACO_VSN)$(PRE_VSN)"
diff --git a/lib/mnesia/doc/src/notes.xml b/lib/mnesia/doc/src/notes.xml
index e5c7d87f52..18f72f4faf 100644
--- a/lib/mnesia/doc/src/notes.xml
+++ b/lib/mnesia/doc/src/notes.xml
@@ -38,7 +38,30 @@
thus constitutes one section in this document. The title of each
section is the version number of Mnesia.</p>
- <section><title>Mnesia 4.12.3</title>
+ <section><title>Mnesia 4.12.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed a spelling mistake in mnesia documentation.</p>
+ <p>
+ Own Id: OTP-12278</p>
+ </item>
+ <item>
+ <p>
+ Matching data with <c>mnesia:match_object/1</c> did not
+ work as expected in some cases, when data was written in
+ the same transaction before the matching was invoked.</p>
+ <p>
+ Own Id: OTP-12304 Aux Id: Seq12745 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Mnesia 4.12.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
diff --git a/lib/mnesia/vsn.mk b/lib/mnesia/vsn.mk
index d5b96c5c76..94eb360591 100644
--- a/lib/mnesia/vsn.mk
+++ b/lib/mnesia/vsn.mk
@@ -1 +1 @@
-MNESIA_VSN = 4.12.3
+MNESIA_VSN = 4.12.4
diff --git a/lib/observer/doc/src/notes.xml b/lib/observer/doc/src/notes.xml
index 658ac2c7cf..11729078c2 100644
--- a/lib/observer/doc/src/notes.xml
+++ b/lib/observer/doc/src/notes.xml
@@ -31,6 +31,22 @@
<p>This document describes the changes made to the Observer
application.</p>
+<section><title>Observer 2.0.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ A note saying only R15B nodes can be observed is removed
+ from the user guide.</p>
+ <p>
+ Own Id: OTP-12078</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Observer 2.0.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/observer/vsn.mk b/lib/observer/vsn.mk
index dbbbde1467..c8a6023b4f 100644
--- a/lib/observer/vsn.mk
+++ b/lib/observer/vsn.mk
@@ -1 +1 @@
-OBSERVER_VSN = 2.0.2
+OBSERVER_VSN = 2.0.3
diff --git a/lib/odbc/doc/src/notes.xml b/lib/odbc/doc/src/notes.xml
index 495a675631..7a7658b092 100644
--- a/lib/odbc/doc/src/notes.xml
+++ b/lib/odbc/doc/src/notes.xml
@@ -31,7 +31,46 @@
<p>This document describes the changes made to the odbc application.
</p>
- <section><title>ODBC 2.10.21</title>
+ <section><title>ODBC 2.10.22</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ OS X Mavericks is based on Darwin version 13.x, and
+ Yosemite on 14.x. Change the ODBC configure.in script to
+ recognize these versions.</p>
+ <p>
+ Own Id: OTP-12260</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ The commands longer than 127 chars sent to odbc server
+ crashed it, e.g. a connection string with driver path and
+ some additional parameters.</p>
+ <p>
+ Own Id: OTP-12346</p>
+ </item>
+ <item>
+ <p>
+ Distribute <c>autoconf</c> helpers to applications at
+ build time instead of having multiple identical copies
+ committed in the repository.</p>
+ <p>
+ Own Id: OTP-12348</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>ODBC 2.10.21</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
diff --git a/lib/odbc/vsn.mk b/lib/odbc/vsn.mk
index b374e42d15..52c84429ec 100644
--- a/lib/odbc/vsn.mk
+++ b/lib/odbc/vsn.mk
@@ -1 +1 @@
-ODBC_VSN = 2.10.21
+ODBC_VSN = 2.10.22
diff --git a/lib/orber/src/cdr_decode.erl b/lib/orber/src/cdr_decode.erl
index 36ef6ce02f..9aec64892e 100644
--- a/lib/orber/src/cdr_decode.erl
+++ b/lib/orber/src/cdr_decode.erl
@@ -193,7 +193,7 @@ dec_message_header(TypeCodes, Message, Bytes) ->
%% Args:
%% The message as a byte sequence.
%% Returns:
-%% A tuple {Endianess, Rest} where Endianess is big or little.
+%% A tuple {Endianness, Rest} where Endianness is big or little.
%% Rest is the remaining message byte sequence.
%%-----------------------------------------------------------------
dec_byte_order(<<0:8,T/binary>>) ->
@@ -206,7 +206,7 @@ dec_byte_order(<<1:8,T/binary>>) ->
%% Args:
%% The message as a byte sequence.
%% Returns:
-%% A tuple {Endianess, Rest} where Endianess is big or little.
+%% A tuple {Endianness, Rest} where Endianness is big or little.
%% Rest is the remaining message byte sequence.
%%-----------------------------------------------------------------
dec_byte_order_list([0|T]) ->
diff --git a/lib/otp_mibs/doc/src/notes.xml b/lib/otp_mibs/doc/src/notes.xml
index 391c82b1c5..c61978c99e 100644
--- a/lib/otp_mibs/doc/src/notes.xml
+++ b/lib/otp_mibs/doc/src/notes.xml
@@ -31,6 +31,22 @@
<p>This document describes the changes made to the OTP_Mibs
application.</p>
+<section><title>Otp_Mibs 1.0.10</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Make sure the clean rule for ssh, ssl, eunit and otp_mibs
+ actually removes generated files.</p>
+ <p>
+ Own Id: OTP-12200</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Otp_Mibs 1.0.9</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/otp_mibs/vsn.mk b/lib/otp_mibs/vsn.mk
index 98db21c132..2ff59431f4 100644
--- a/lib/otp_mibs/vsn.mk
+++ b/lib/otp_mibs/vsn.mk
@@ -1,4 +1,4 @@
-OTP_MIBS_VSN = 1.0.9
+OTP_MIBS_VSN = 1.0.10
# Note: The branch 'otp_mibs' is defunct as of otp_mibs-1.0.4 and
# should NOT be used again.
diff --git a/lib/parsetools/doc/src/notes.xml b/lib/parsetools/doc/src/notes.xml
index a8368740da..c8cb70b6d2 100644
--- a/lib/parsetools/doc/src/notes.xml
+++ b/lib/parsetools/doc/src/notes.xml
@@ -30,6 +30,24 @@
</header>
<p>This document describes the changes made to the Parsetools application.</p>
+<section><title>Parsetools 2.0.12</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The line counter becomes invalid when rules with linewrap
+ are used. This issue appears because the parsing FSM does
+ not roll back the line counter after attempting such a
+ rule.</p>
+ <p>
+ Own Id: OTP-12238</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Parsetools 2.0.11</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/parsetools/vsn.mk b/lib/parsetools/vsn.mk
index 8fd7422c1c..dd9cc2991c 100644
--- a/lib/parsetools/vsn.mk
+++ b/lib/parsetools/vsn.mk
@@ -1 +1 @@
-PARSETOOLS_VSN = 2.0.11
+PARSETOOLS_VSN = 2.0.12
diff --git a/lib/percept/doc/src/notes.xml b/lib/percept/doc/src/notes.xml
index bae999ed1a..b51c8fcb4d 100644
--- a/lib/percept/doc/src/notes.xml
+++ b/lib/percept/doc/src/notes.xml
@@ -32,6 +32,21 @@
</header>
<p>This document describes the changes made to the Percept application.</p>
+<section><title>Percept 0.8.10</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Make sure to install .hrl files when needed</p>
+ <p>
+ Own Id: OTP-12197</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Percept 0.8.9</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/percept/vsn.mk b/lib/percept/vsn.mk
index 935a9d1336..4451354e21 100644
--- a/lib/percept/vsn.mk
+++ b/lib/percept/vsn.mk
@@ -1 +1 @@
-PERCEPT_VSN = 0.8.9
+PERCEPT_VSN = 0.8.10
diff --git a/lib/runtime_tools/doc/src/notes.xml b/lib/runtime_tools/doc/src/notes.xml
index 9b026aee11..2877355718 100644
--- a/lib/runtime_tools/doc/src/notes.xml
+++ b/lib/runtime_tools/doc/src/notes.xml
@@ -31,6 +31,23 @@
<p>This document describes the changes made to the Runtime_Tools
application.</p>
+<section><title>Runtime_Tools 1.8.15</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Add <c>nif_version</c> to <c>erlang:system_info/1</c> in
+ order to get the NIF API version of the runtime system in
+ a way similar to <c>driver_version</c>.</p>
+ <p>
+ Own Id: OTP-12298</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Runtime_Tools 1.8.14</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/runtime_tools/vsn.mk b/lib/runtime_tools/vsn.mk
index 32953dfc5a..c1df23d2a2 100644
--- a/lib/runtime_tools/vsn.mk
+++ b/lib/runtime_tools/vsn.mk
@@ -1 +1 @@
-RUNTIME_TOOLS_VSN = 1.8.14
+RUNTIME_TOOLS_VSN = 1.8.15
diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml
index f3db05192e..3aa61aa9ec 100644
--- a/lib/ssh/doc/src/notes.xml
+++ b/lib/ssh/doc/src/notes.xml
@@ -29,6 +29,100 @@
<file>notes.xml</file>
</header>
+<section><title>Ssh 3.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Make sure the clean rule for ssh, ssl, eunit and otp_mibs
+ actually removes generated files.</p>
+ <p>
+ Own Id: OTP-12200</p>
+ </item>
+ <item>
+ <p>
+ Improved Property Tests (Thanks to Thomas, John and
+ Tobias at QuviQ)</p>
+ <p>
+ Own Id: OTP-12256</p>
+ </item>
+ <item>
+ <p>
+ Correct typo of renegotiate that could cause rekeying to
+ fail</p>
+ <p>
+ Own Id: OTP-12277 Aux Id: seq12736 </p>
+ </item>
+ <item>
+ <p>
+ The {timeout, Timeout} option passed to
+ ssh_sftp:start_channel was not applied to the early
+ phases of the SSH protocol. This patch passes the Timeout
+ through to ssh:connect. In case the timeout occurs during
+ these phases, {error, timeout} is returned. (Thanks to
+ Simon Cornish)</p>
+ <p>
+ Own Id: OTP-12306</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Added API functions ptty_alloc/3 and ptty_alloc/4, to
+ allocate a pseudo tty.</p>
+ <p>
+ Own Id: OTP-11542 Aux Id: seq12493, OTP-11631 </p>
+ </item>
+ <item>
+ <p>
+ Supports tar file creation on other media than file
+ systems mounted on the local machine.</p>
+ <p>
+ The <c>erl_tar</c> api is extended with
+ <c>erl_tar:init/3</c> that enables usage of user provided
+ media storage routines. A ssh-specific set of such
+ routines is hidden in the new function
+ <c>ssh_sftp:open_tar/3</c> to simplify creating a tar
+ archive on a remote ssh server.</p>
+ <p>
+ A chunked file reading option is added to
+ <c>erl_tar:add/3,4</c> to save memory on e.g small
+ embedded systems. The size of the slices read from a file
+ in that case can be specified.</p>
+ <p>
+ Own Id: OTP-12180 Aux Id: seq12715 </p>
+ </item>
+ <item>
+ <p>
+ Always send SSH_DISCONNECT protocol messages when peer
+ sends corrupt messages.</p>
+ <p>
+ Own Id: OTP-12185</p>
+ </item>
+ <item>
+ <p>
+ Hooks for funs that can change binaries sent to remote
+ sites from erl_tar for renote tar file creation are
+ added. See <c>ssh_sftp:open_tar/3,4</c> for details. The
+ hooks could also be used to read remote tar files that
+ need transformation before file extraction.</p>
+ <p>
+ Those hooks are intended for encryption and decryption of
+ tar files. Effort is put into memory, disk and network
+ resource economy.</p>
+ <p>
+ Own Id: OTP-12312 Aux Id: OTP-12180 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Ssh 3.0.8</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/ssh/doc/src/ssh_connection.xml b/lib/ssh/doc/src/ssh_connection.xml
index ff72cf7ee0..5e2926dfa6 100644
--- a/lib/ssh/doc/src/ssh_connection.xml
+++ b/lib/ssh/doc/src/ssh_connection.xml
@@ -62,6 +62,7 @@
<p><c>ssh_request_status() = success | failure</c></p>
<p><c>event() = {ssh_cm, ssh_connection_ref(), ssh_event_msg()} </c></p>
<p><c>ssh_event_msg() = data_events() | status_events() | terminal_events() </c></p>
+ <p><c>reason() = timeout | closed </c></p>
<taglist>
<tag><b>data_events()</b></tag>
@@ -218,7 +219,7 @@
</func>
<func>
- <name>exec(ConnectionRef, ChannelId, Command, TimeOut) -> ssh_request_status() </name>
+ <name>exec(ConnectionRef, ChannelId, Command, TimeOut) -> ssh_request_status() | {error, reason()} </name>
<fsummary>Request that the server start the execution of the given command. </fsummary>
<type>
<v> ConnectionRef = ssh_connection_ref() </v>
@@ -274,7 +275,8 @@
</func>
<func>
- <name>ptty_alloc(ConnectionRef, ChannelId, Options, Timeout) -> success | failure</name>
+ <name>ptty_alloc(ConnectionRef, ChannelId, Options) -> </name>
+ <name>ptty_alloc(ConnectionRef, ChannelId, Options, Timeout) -> > ssh_request_status() | {error, reason()} </name>
<fsummary>Send status replies to requests that want such replies. </fsummary>
<type>
<v> ConnectionRef = ssh_connection_ref() </v>
@@ -374,7 +376,7 @@
<func>
<name>session_channel(ConnectionRef, Timeout) -> </name>
<name>session_channel(ConnectionRef, InitialWindowSize,
- MaxPacketSize, Timeout) -> {ok, ssh_channel_id()} | {error, Reason}</name>
+ MaxPacketSize, Timeout) -> {ok, ssh_channel_id()} | {error, reason()}</name>
<fsummary>Opens a channel for a ssh session. </fsummary>
<type>
<v> ConnectionRef = ssh_connection_ref()</v>
@@ -391,7 +393,7 @@
</func>
<func>
- <name>setenv(ConnectionRef, ChannelId, Var, Value, TimeOut) -> ssh_request_status()</name>
+ <name>setenv(ConnectionRef, ChannelId, Var, Value, TimeOut) -> ssh_request_status() | {error, reason()} </name>
<fsummary> Environment variables may be passed to the
shell/command to be started later.</fsummary>
<type>
@@ -409,7 +411,7 @@
</func>
<func>
- <name>shell(ConnectionRef, ChannelId) -> ssh_request_status()
+ <name>shell(ConnectionRef, ChannelId) -> ssh_request_status() | {error, closed}
</name>
<fsummary> Requests that the user's default shell (typically
defined in /etc/passwd in UNIX systems) shall be executed at the server
@@ -426,7 +428,7 @@
</func>
<func>
- <name>subsystem(ConnectionRef, ChannelId, Subsystem, Timeout) -> ssh_request_status()</name>
+ <name>subsystem(ConnectionRef, ChannelId, Subsystem, Timeout) -> ssh_request_status() | {error, reason()} </name>
<fsummary> </fsummary>
<type>
<v> ConnectionRef = ssh_connection_ref() </v>
diff --git a/lib/ssh/src/ssh.app.src b/lib/ssh/src/ssh.app.src
index 4ad55b34ca..bc01c539e0 100644
--- a/lib/ssh/src/ssh.app.src
+++ b/lib/ssh/src/ssh.app.src
@@ -40,7 +40,7 @@
{applications, [kernel, stdlib, crypto, public_key]},
{env, []},
{mod, {ssh_app, []}},
- {runtime_dependencies, ["stdlib-2.0","public_key-0.22","kernel-3.0",
+ {runtime_dependencies, ["stdlib-2.3","public_key-0.22","kernel-3.0",
"erts-6.0","crypto-3.3"]}]}.
diff --git a/lib/ssh/src/ssh.appup.src b/lib/ssh/src/ssh.appup.src
index 70f1cc487c..b2b2994eed 100644
--- a/lib/ssh/src/ssh.appup.src
+++ b/lib/ssh/src/ssh.appup.src
@@ -20,7 +20,7 @@
{"%VSN%",
[
{"3.0.8", [{load_module, ssh_connection, soft_purge, soft_purge, [ssh_connection_handler]},
- {load_module, ssh_sftp, soft_purge, soft_purge, [erl_tar,ssh_xfer]},
+ {load_module, ssh_sftp, soft_purge, soft_purge, [ssh_xfer]},
{load_module, ssh_connection_handler, soft_purge, soft_purge, []},
{load_module, ssh, soft_purge, soft_purge, [ssh_connection_handler]},
{load_module, ssh_xfer, soft_purge, soft_purge, []}
diff --git a/lib/ssh/src/ssh_connection.erl b/lib/ssh/src/ssh_connection.erl
index 593443e11c..c66f810948 100644
--- a/lib/ssh/src/ssh_connection.erl
+++ b/lib/ssh/src/ssh_connection.erl
@@ -56,8 +56,8 @@
%%--------------------------------------------------------------------
%%--------------------------------------------------------------------
--spec session_channel(pid(), timeout()) -> {ok, channel_id()} | {error, term()}.
--spec session_channel(pid(), integer(), integer(), timeout()) -> {ok, channel_id()} | {error, term()}.
+-spec session_channel(pid(), timeout()) -> {ok, channel_id()} | {error, timeout | closed}.
+-spec session_channel(pid(), integer(), integer(), timeout()) -> {ok, channel_id()} | {error, timeout | closed}.
%% Description: Opens a channel for a ssh session. A session is a
%% remote execution of a program. The program may be a shell, an
@@ -81,7 +81,8 @@ session_channel(ConnectionHandler, InitialWindowSize,
end.
%%--------------------------------------------------------------------
--spec exec(pid(), channel_id(), string(), timeout()) -> success | failure.
+-spec exec(pid(), channel_id(), string(), timeout()) ->
+ success | failure | {error, timeout | closed}.
%% Description: Will request that the server start the
%% execution of the given command.
@@ -101,21 +102,15 @@ shell(ConnectionHandler, ChannelId) ->
ssh_connection_handler:request(ConnectionHandler, self(), ChannelId,
"shell", false, <<>>, 0).
%%--------------------------------------------------------------------
--spec subsystem(pid(), channel_id(), string(), timeout()) ->
- success | failure | {error, timeout}.
+-spec subsystem(pid(), channel_id(), string(), timeout()) ->
+ success | failure | {error, timeout | closed}.
%%
%% Description: Executes a predefined subsystem.
%%--------------------------------------------------------------------
subsystem(ConnectionHandler, ChannelId, SubSystem, TimeOut) ->
- case ssh_connection_handler:request(ConnectionHandler, self(),
- ChannelId, "subsystem",
- true, [?string(SubSystem)], TimeOut) of
- success -> success;
- failure -> failure;
- {error,timeout} -> {error,timeout};
- _ -> failure
- end.
-
+ ssh_connection_handler:request(ConnectionHandler, self(),
+ ChannelId, "subsystem",
+ true, [?string(SubSystem)], TimeOut).
%%--------------------------------------------------------------------
-spec send(pid(), channel_id(), iodata()) ->
ok | {error, closed}.
@@ -148,7 +143,7 @@ send_eof(ConnectionHandler, Channel) ->
ssh_connection_handler:send_eof(ConnectionHandler, Channel).
%%--------------------------------------------------------------------
--spec adjust_window(pid(), channel_id(), integer()) -> ok.
+-spec adjust_window(pid(), channel_id(), integer()) -> ok | {error, closed}.
%%
%%
%% Description: Adjusts the ssh flowcontrol window.
@@ -157,7 +152,8 @@ adjust_window(ConnectionHandler, Channel, Bytes) ->
ssh_connection_handler:adjust_window(ConnectionHandler, Channel, Bytes).
%%--------------------------------------------------------------------
--spec setenv(pid(), channel_id(), string(), string(), timeout()) -> success | failure.
+-spec setenv(pid(), channel_id(), string(), string(), timeout()) ->
+ success | failure | {error, timeout | closed}.
%%
%%
%% Description: Environment variables may be passed to the shell/command to be
@@ -189,7 +185,11 @@ reply_request(_,false, _, _) ->
ok.
%%--------------------------------------------------------------------
--spec ptty_alloc(pid(), channel_id(), proplists:proplist()) -> success | failiure.
+-spec ptty_alloc(pid(), channel_id(), proplists:proplist()) ->
+ success | failiure | {error, closed}.
+-spec ptty_alloc(pid(), channel_id(), proplists:proplist(), timeout()) ->
+ success | failiure | {error, timeout} | {error, closed}.
+
%%
%%
%% Description: Sends a ssh connection protocol pty_req.
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index fdb9d3b3e6..915060c426 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -289,8 +289,13 @@ renegotiate_data(ConnectionHandler) ->
-spec close(pid(), channel_id()) -> ok.
%%--------------------------------------------------------------------
close(ConnectionHandler, ChannelId) ->
- sync_send_all_state_event(ConnectionHandler, {close, ChannelId}).
-
+ case sync_send_all_state_event(ConnectionHandler, {close, ChannelId}) of
+ ok ->
+ ok;
+ {error, closed} ->
+ ok
+ end.
+
%%--------------------------------------------------------------------
-spec stop(pid()) -> ok | {error, term()}.
%%--------------------------------------------------------------------
@@ -1204,7 +1209,11 @@ sync_send_all_state_event(FsmPid, Event) ->
sync_send_all_state_event(FsmPid, Event, infinity).
sync_send_all_state_event(FsmPid, Event, Timeout) ->
- try gen_fsm:sync_send_all_state_event(FsmPid, Event, Timeout)
+ try gen_fsm:sync_send_all_state_event(FsmPid, Event, Timeout) of
+ {closed, _Channel} ->
+ {error, closed};
+ Result ->
+ Result
catch
exit:{noproc, _} ->
{error, closed};
diff --git a/lib/ssh/test/ssh_connection_SUITE.erl b/lib/ssh/test/ssh_connection_SUITE.erl
index 553d0f5720..e3871b3feb 100644
--- a/lib/ssh/test/ssh_connection_SUITE.erl
+++ b/lib/ssh/test/ssh_connection_SUITE.erl
@@ -37,7 +37,6 @@
all() ->
[
{group, openssh},
- start_subsystem_on_closed_channel,
interrupted_send,
start_shell,
start_shell_exec,
@@ -46,7 +45,8 @@ all() ->
gracefull_invalid_start,
gracefull_invalid_long_start,
gracefull_invalid_long_start_no_nl,
- stop_listener
+ stop_listener,
+ start_subsystem_on_closed_channel
].
groups() ->
[{openssh, [], payload() ++ ptty()}].
@@ -286,32 +286,7 @@ ptty_alloc_pixel(Config) when is_list(Config) ->
ssh:close(ConnectionRef).
%%--------------------------------------------------------------------
-start_subsystem_on_closed_channel(Config) ->
- PrivDir = ?config(priv_dir, Config),
- UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth
- file:make_dir(UserDir),
- SysDir = ?config(data_dir, Config),
- {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir},
- {user_dir, UserDir},
- {password, "morot"},
- {subsystems, [{"echo_n", {ssh_echo_server, [4000000]}}]}]),
-
- ConnectionRef = ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
- {user, "foo"},
- {password, "morot"},
- {user_interaction, false},
- {user_dir, UserDir}]),
-
- {ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity),
-
- ok = ssh_connection:close(ConnectionRef, ChannelId),
-
- failure = ssh_connection:subsystem(ConnectionRef, ChannelId, "echo_n", infinity),
-
- ssh:close(ConnectionRef),
- ssh:stop_daemon(Pid).
-%%--------------------------------------------------------------------
interrupted_send() ->
[{doc, "Use a subsystem that echos n char and then sends eof to cause a channel exit partway through a large send."}].
@@ -601,6 +576,31 @@ stop_listener(Config) when is_list(Config) ->
ct:fail({unexpected, Error})
end.
+start_subsystem_on_closed_channel(Config) ->
+ PrivDir = ?config(priv_dir, Config),
+ UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth
+ file:make_dir(UserDir),
+ SysDir = ?config(data_dir, Config),
+ {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir},
+ {user_dir, UserDir},
+ {password, "morot"},
+ {subsystems, [{"echo_n", {ssh_echo_server, [4000000]}}]}]),
+
+ ConnectionRef = ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
+ {user, "foo"},
+ {password, "morot"},
+ {user_interaction, false},
+ {user_dir, UserDir}]),
+
+ {ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity),
+
+ ok = ssh_connection:close(ConnectionRef, ChannelId),
+
+ {error, closed} = ssh_connection:subsystem(ConnectionRef, ChannelId, "echo_n", infinity),
+
+ ssh:close(ConnectionRef),
+ ssh:stop_daemon(Pid).
+
%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
diff --git a/lib/ssl/doc/src/notes.xml b/lib/ssl/doc/src/notes.xml
index 62e9bd0165..4349e5a456 100644
--- a/lib/ssl/doc/src/notes.xml
+++ b/lib/ssl/doc/src/notes.xml
@@ -25,7 +25,36 @@
<file>notes.xml</file>
</header>
<p>This document describes the changes made to the SSL application.</p>
- <section><title>SSL 5.3.7</title>
+ <section><title>SSL 5.3.8</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Make sure the clean rule for ssh, ssl, eunit and otp_mibs
+ actually removes generated files.</p>
+ <p>
+ Own Id: OTP-12200</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Change code to reflect that state data may be secret to
+ avoid breaking dialyzer contracts.</p>
+ <p>
+ Own Id: OTP-12341</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SSL 5.3.7</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
diff --git a/lib/stdlib/doc/src/ets.xml b/lib/stdlib/doc/src/ets.xml
index aa16e4e3db..902a921fbf 100644
--- a/lib/stdlib/doc/src/ets.xml
+++ b/lib/stdlib/doc/src/ets.xml
@@ -1593,6 +1593,21 @@ true</pre>
</desc>
</func>
<func>
+ <name name="take" arity="2"/>
+ <fsummary>Return and remove all objects with a given key from an ETS
+ table.</fsummary>
+ <desc>
+ <p>Returns a list of all objects with the key <c><anno>Key</anno></c> in
+ the table <c><anno>Tab</anno></c> and removes.</p>
+ <p>The given <c><anno>Key</anno></c> is used to identify the object by
+ either <em>comparing equal</em> the key of an object in an
+ <c>ordered_set</c> table, or <em>matching</em> in other types of
+ tables (see <seealso marker="#lookup/2">lookup/2</seealso> and
+ <seealso marker="#new/2">new/2</seealso> for details on the
+ difference).</p>
+ </desc>
+ </func>
+ <func>
<name name="to_dets" arity="2"/>
<fsummary>Fill a Dets table with objects from an ETS table.</fsummary>
<desc>
diff --git a/lib/stdlib/doc/src/notes.xml b/lib/stdlib/doc/src/notes.xml
index ebc750a399..8582bfc9f9 100644
--- a/lib/stdlib/doc/src/notes.xml
+++ b/lib/stdlib/doc/src/notes.xml
@@ -30,6 +30,109 @@
</header>
<p>This document describes the changes made to the STDLIB application.</p>
+<section><title>STDLIB 2.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The documentation of string:tokens/2 now explicitly
+ specifies that adjacent separator characters do not give
+ any empty strings in the resulting list of tokens.</p>
+ <p>
+ Own Id: OTP-12036</p>
+ </item>
+ <item>
+ <p>
+ Fix broken deprecation warnings in ssh application</p>
+ <p>
+ Own Id: OTP-12187</p>
+ </item>
+ <item>
+ <p>
+ Maps: Properly align union typed assoc values in
+ documentation</p>
+ <p>
+ Own Id: OTP-12190</p>
+ </item>
+ <item>
+ <p>
+ Fix filelib:wildcard/2 when 'Cwd' ends with a dot</p>
+ <p>
+ Own Id: OTP-12212</p>
+ </item>
+ <item>
+ <p>
+ Allow <c>Name/Arity</c> syntax in maps values inside
+ attributes.</p>
+ <p>
+ Own Id: OTP-12213</p>
+ </item>
+ <item>
+ <p>
+ Fix edlin to correctly save text killed with ctrl-u.
+ Prior to this fix, entering text into the Erlang shell
+ and then killing it with ctrl-u followed by yanking it
+ back with ctrl-y would result in the yanked text being
+ the reverse of the original killed text.</p>
+ <p>
+ Own Id: OTP-12224</p>
+ </item>
+ <item>
+ <p>
+ If a callback function was terminated with exit/1, there
+ would be no stack trace in the ERROR REPORT produced by
+ gen_server. This has been corrected.</p>
+ <p>
+ To keep the backwards compatibility, the actual exit
+ reason for the process is not changed.</p>
+ <p>
+ Own Id: OTP-12263 Aux Id: seq12733 </p>
+ </item>
+ <item>
+ <p>
+ Warnings produced by <c>ms_transform</c> could point out
+ the wrong line number.</p>
+ <p>
+ Own Id: OTP-12264</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Supports tar file creation on other media than file
+ systems mounted on the local machine.</p>
+ <p>
+ The <c>erl_tar</c> api is extended with
+ <c>erl_tar:init/3</c> that enables usage of user provided
+ media storage routines. A ssh-specific set of such
+ routines is hidden in the new function
+ <c>ssh_sftp:open_tar/3</c> to simplify creating a tar
+ archive on a remote ssh server.</p>
+ <p>
+ A chunked file reading option is added to
+ <c>erl_tar:add/3,4</c> to save memory on e.g small
+ embedded systems. The size of the slices read from a file
+ in that case can be specified.</p>
+ <p>
+ Own Id: OTP-12180 Aux Id: seq12715 </p>
+ </item>
+ <item>
+ <p>
+ I/O requests are optimized for long message queues in the
+ calling process.</p>
+ <p>
+ Own Id: OTP-12315</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>STDLIB 2.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/stdlib/src/binary.erl b/lib/stdlib/src/binary.erl
index b94829892d..de26784ead 100644
--- a/lib/stdlib/src/binary.erl
+++ b/lib/stdlib/src/binary.erl
@@ -89,9 +89,9 @@ copy(_, _) ->
decode_unsigned(_) ->
erlang:nif_error(undef).
--spec decode_unsigned(Subject, Endianess) -> Unsigned when
+-spec decode_unsigned(Subject, Endianness) -> Unsigned when
Subject :: binary(),
- Endianess :: big | little,
+ Endianness :: big | little,
Unsigned :: non_neg_integer().
decode_unsigned(_, _) ->
@@ -103,9 +103,9 @@ decode_unsigned(_, _) ->
encode_unsigned(_) ->
erlang:nif_error(undef).
--spec encode_unsigned(Unsigned, Endianess) -> binary() when
+-spec encode_unsigned(Unsigned, Endianness) -> binary() when
Unsigned :: non_neg_integer(),
- Endianess :: big | little.
+ Endianness :: big | little.
encode_unsigned(_, _) ->
erlang:nif_error(undef).
diff --git a/lib/stdlib/src/ets.erl b/lib/stdlib/src/ets.erl
index d3a6a21416..26b0393b35 100644
--- a/lib/stdlib/src/ets.erl
+++ b/lib/stdlib/src/ets.erl
@@ -71,6 +71,7 @@
rename/2, safe_fixtable/2, select/1, select/2, select/3,
select_count/2, select_delete/2, select_reverse/1,
select_reverse/2, select_reverse/3, setopts/2, slot/2,
+ take/2,
update_counter/3, update_element/3]).
-spec all() -> [Tab] when
@@ -403,6 +404,14 @@ setopts(_, _) ->
slot(_, _) ->
erlang:nif_error(undef).
+-spec take(Tab, Key) -> [Object] when
+ Tab :: tab(),
+ Key :: term(),
+ Object :: tuple().
+
+take(_, _) ->
+ erlang:nif_error(undef).
+
-spec update_counter(Tab, Key, UpdateOp) -> Result when
Tab :: tab(),
Key :: term(),
diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl
index 8dc8b2c291..2674f6886f 100644
--- a/lib/stdlib/test/ets_SUITE.erl
+++ b/lib/stdlib/test/ets_SUITE.erl
@@ -77,6 +77,7 @@
-export([otp_10182/1]).
-export([ets_all/1]).
-export([memory_check_summary/1]).
+-export([take/1]).
-export([init_per_testcase/2, end_per_testcase/2]).
%% Convenience for manual testing
@@ -153,6 +154,7 @@ all() ->
otp_9932,
otp_9423,
ets_all,
+ take,
memory_check_summary]. % MUST BE LAST
@@ -5582,6 +5584,43 @@ ets_all_run() ->
ets_all_run().
+take(Config) when is_list(Config) ->
+ %% Simple test for set tables.
+ T1 = ets_new(a, [set]),
+ [] = ets:take(T1, foo),
+ ets:insert(T1, {foo,bar}),
+ [] = ets:take(T1, bar),
+ [{foo,bar}] = ets:take(T1, foo),
+ [] = ets:tab2list(T1),
+ %% Non-immediate key.
+ ets:insert(T1, {{'not',<<"immediate">>},ok}),
+ [{{'not',<<"immediate">>},ok}] = ets:take(T1, {'not',<<"immediate">>}),
+ %% Same with ordered tables.
+ T2 = ets_new(b, [ordered_set]),
+ [] = ets:take(T2, foo),
+ ets:insert(T2, {foo,bar}),
+ [] = ets:take(T2, bar),
+ [{foo,bar}] = ets:take(T2, foo),
+ [] = ets:tab2list(T2),
+ ets:insert(T2, {{'not',<<"immediate">>},ok}),
+ [{{'not',<<"immediate">>},ok}] = ets:take(T2, {'not',<<"immediate">>}),
+ %% Arithmetically-equal keys.
+ ets:insert(T2, [{1.0,float},{2,integer}]),
+ [{1.0,float}] = ets:take(T2, 1),
+ [{2,integer}] = ets:take(T2, 2.0),
+ [] = ets:tab2list(T2),
+ %% Same with bag.
+ T3 = ets_new(c, [bag]),
+ ets:insert(T3, [{1,1},{1,2},{3,3}]),
+ [{1,1},{1,2}] = ets:take(T3, 1),
+ [{3,3}] = ets:take(T3, 3),
+ [] = ets:tab2list(T3),
+ ets:delete(T1),
+ ets:delete(T2),
+ ets:delete(T3),
+ ok.
+
+
%
% Utility functions:
%
diff --git a/lib/stdlib/vsn.mk b/lib/stdlib/vsn.mk
index b522c3ea3c..5be130bac9 100644
--- a/lib/stdlib/vsn.mk
+++ b/lib/stdlib/vsn.mk
@@ -1 +1 @@
-STDLIB_VSN = 2.2
+STDLIB_VSN = 2.3
diff --git a/lib/syntax_tools/doc/src/notes.xml b/lib/syntax_tools/doc/src/notes.xml
index 8384af53b0..b0f11bb243 100644
--- a/lib/syntax_tools/doc/src/notes.xml
+++ b/lib/syntax_tools/doc/src/notes.xml
@@ -31,6 +31,27 @@
<p>This document describes the changes made to the Syntax_Tools
application.</p>
+<section><title>Syntax_Tools 1.6.17</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Teach Maps to erl_syntax</p>
+ <p>
+ Affected functions: <list>
+ <item>erl_syntax:abstract/1</item>
+ <item>erl_syntax:concrete/1</item>
+ <item>erl_syntax:is_leaf/1</item>
+ <item>erl_syntax:is_literal/1</item> </list></p>
+ <p>
+ Own Id: OTP-12265</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Syntax_Tools 1.6.16</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/syntax_tools/vsn.mk b/lib/syntax_tools/vsn.mk
index 6a80734f83..673362d01d 100644
--- a/lib/syntax_tools/vsn.mk
+++ b/lib/syntax_tools/vsn.mk
@@ -1 +1 @@
-SYNTAX_TOOLS_VSN = 1.6.16
+SYNTAX_TOOLS_VSN = 1.6.17
diff --git a/lib/test_server/doc/src/notes.xml b/lib/test_server/doc/src/notes.xml
index a801a87725..68dc1fec88 100644
--- a/lib/test_server/doc/src/notes.xml
+++ b/lib/test_server/doc/src/notes.xml
@@ -32,6 +32,47 @@
<file>notes.xml</file>
</header>
+<section><title>Test_Server 3.7.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The source code to html code generator in Test Server
+ (and Common Test) would fail to generate anchors in the
+ html code for functions with non-expandable macros,
+ resulting in bad html links to such functions. This
+ correction lets the code generator ignore macros that
+ can't be expanded (i.e. not pre-process them), so that
+ correct anchors will always be produced.</p>
+ <p>
+ Own Id: OTP-11766 Aux Id: seq12556 </p>
+ </item>
+ <item>
+ <p>
+ Make sure to install .hrl files when needed</p>
+ <p>
+ Own Id: OTP-12197</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Distribute <c>autoconf</c> helpers to applications at
+ build time instead of having multiple identical copies
+ committed in the repository.</p>
+ <p>
+ Own Id: OTP-12348</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Test_Server 3.7.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/test_server/vsn.mk b/lib/test_server/vsn.mk
index 9e1ac8fd12..18d7583c35 100644
--- a/lib/test_server/vsn.mk
+++ b/lib/test_server/vsn.mk
@@ -1 +1 @@
-TEST_SERVER_VSN = 3.7.1
+TEST_SERVER_VSN = 3.7.2
diff --git a/lib/tools/doc/src/notes.xml b/lib/tools/doc/src/notes.xml
index faee5efd43..6f9563bb68 100644
--- a/lib/tools/doc/src/notes.xml
+++ b/lib/tools/doc/src/notes.xml
@@ -30,6 +30,41 @@
</header>
<p>This document describes the changes made to the Tools application.</p>
+<section><title>Tools 2.7.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed a typo in erlang-mode comment.</p>
+ <p>
+ Own Id: OTP-12214</p>
+ </item>
+ <item>
+ <p>
+ Add a skeleton for -spec in Erlang mode for Emacs</p>
+ <p>
+ Own Id: OTP-12283</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Cover no longer crashes when compiling <c>receive</c> and
+ the like with just an <c>after</c> clause. Thanks to
+ José Valim for providing a fix.</p>
+ <p>
+ Own Id: OTP-12328</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Tools 2.7</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/tools/vsn.mk b/lib/tools/vsn.mk
index 3acb8d38e2..d9651c30e3 100644
--- a/lib/tools/vsn.mk
+++ b/lib/tools/vsn.mk
@@ -1 +1 @@
-TOOLS_VSN = 2.7
+TOOLS_VSN = 2.7.1
diff --git a/lib/wx/doc/src/notes.xml b/lib/wx/doc/src/notes.xml
index 5a9c53e3b6..52087398e7 100644
--- a/lib/wx/doc/src/notes.xml
+++ b/lib/wx/doc/src/notes.xml
@@ -31,6 +31,35 @@
<p>This document describes the changes made to the wxErlang
application.</p>
+<section><title>Wx 1.3.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed a minor typo in the graphicsContext example.</p>
+ <p>
+ Own Id: OTP-12259</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Distribute <c>autoconf</c> helpers to applications at
+ build time instead of having multiple identical copies
+ committed in the repository.</p>
+ <p>
+ Own Id: OTP-12348</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Wx 1.3.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/wx/vsn.mk b/lib/wx/vsn.mk
index 24e8c2ed11..78c24ec093 100644
--- a/lib/wx/vsn.mk
+++ b/lib/wx/vsn.mk
@@ -1 +1 @@
-WX_VSN = 1.3.1
+WX_VSN = 1.3.2