aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--OTP_VERSION2
-rw-r--r--erts/doc/src/erl_ext_dist.xml251
-rw-r--r--erts/doc/src/notes.xml72
-rw-r--r--erts/emulator/beam/beam_emu.c15
-rw-r--r--erts/emulator/beam/erl_proc_sig_queue.c18
-rw-r--r--erts/emulator/beam/erl_process.c3
-rw-r--r--erts/emulator/beam/msg_instrs.tab1
-rw-r--r--erts/emulator/sys/common/erl_check_io.c6
-rw-r--r--erts/emulator/sys/unix/sys_drivers.c4
-rw-r--r--erts/emulator/test/dirty_bif_SUITE.erl54
-rw-r--r--erts/emulator/test/process_SUITE.erl42
-rw-r--r--erts/vsn.mk2
-rw-r--r--lib/common_test/doc/src/notes.xml15
-rw-r--r--lib/common_test/src/test_server_node.erl103
-rw-r--r--lib/common_test/vsn.mk2
-rw-r--r--lib/crypto/c_src/otp_test_engine.c4
-rw-r--r--lib/crypto/doc/src/notes.xml16
-rw-r--r--lib/crypto/vsn.mk2
-rw-r--r--lib/erl_interface/doc/src/notes.xml36
-rw-r--r--lib/erl_interface/src/Makefile.in34
-rw-r--r--lib/erl_interface/src/depend.mk1133
-rw-r--r--lib/erl_interface/src/prog/ei_fake_prog.c11
-rw-r--r--lib/erl_interface/src/prog/erl_call.c54
-rw-r--r--lib/erl_interface/src/prog/erl_start.c2
-rw-r--r--lib/erl_interface/test/Makefile1
-rw-r--r--lib/erl_interface/test/erl_call_SUITE.erl96
-rw-r--r--lib/erl_interface/vsn.mk2
-rw-r--r--lib/kernel/doc/src/notes.xml15
-rw-r--r--lib/kernel/src/kernel.appup.src8
-rw-r--r--lib/kernel/src/raw_file_io_inflate.erl2
-rw-r--r--lib/kernel/vsn.mk2
-rw-r--r--lib/public_key/asn1/OTP-PKIX.asn18
-rw-r--r--lib/snmp/include/snmp_types.hrl5
-rw-r--r--lib/snmp/src/agent/depend.mk19
-rw-r--r--lib/snmp/src/agent/modules.mk26
-rw-r--r--lib/snmp/src/agent/snmp_view_based_acm_mib.erl16
-rw-r--r--lib/snmp/src/agent/snmpa_agent.erl1136
-rw-r--r--lib/snmp/src/agent/snmpa_app.erl4
-rw-r--r--lib/snmp/src/agent/snmpa_get.erl1150
-rw-r--r--lib/snmp/src/agent/snmpa_get_lib.erl254
-rw-r--r--lib/snmp/src/agent/snmpa_get_mechanism.erl79
-rw-r--r--lib/snmp/src/agent/snmpa_set_lib.erl2
-rw-r--r--lib/snmp/src/agent/snmpa_supervisor.erl64
-rw-r--r--lib/snmp/src/agent/snmpa_trap.erl2
-rw-r--r--lib/snmp/src/app/snmp.app.src3
-rw-r--r--lib/snmp/src/app/snmp.config1
-rw-r--r--lib/snmp/src/app/snmp.erl24
-rw-r--r--lib/snmp/test/modules.mk1
-rw-r--r--lib/snmp/test/snmp_agent_test_get.erl58
-rw-r--r--lib/snmp/test/snmp_agent_test_lib.erl1
-rw-r--r--lib/snmp/test/snmp_manager_test.erl7
-rw-r--r--lib/ssh/doc/src/notes.xml25
-rw-r--r--lib/ssh/src/ssh.erl2
-rw-r--r--lib/ssh/src/ssh_channel.erl4
-rw-r--r--lib/ssh/vsn.mk2
-rw-r--r--lib/ssl/doc/src/notes.xml24
-rw-r--r--lib/ssl/doc/src/ssl.xml25
-rw-r--r--lib/ssl/src/ssl.erl77
-rw-r--r--lib/ssl/src/ssl_connection.hrl1
-rw-r--r--lib/ssl/src/tls_connection.erl29
-rw-r--r--lib/ssl/src/tls_socket.erl10
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl2
-rw-r--r--lib/ssl/vsn.mk2
-rw-r--r--lib/stdlib/doc/src/notes.xml15
-rw-r--r--lib/stdlib/src/erl_tar.erl4
-rw-r--r--lib/stdlib/src/stdlib.appup.src8
-rw-r--r--lib/stdlib/vsn.mk2
-rw-r--r--lib/xmerl/doc/src/notes.xml22
-rw-r--r--lib/xmerl/src/xmerl_scan.erl15
-rw-r--r--lib/xmerl/vsn.mk2
-rw-r--r--make/otp_patch_solve_forward_merge_version2
-rw-r--r--make/otp_version_tickets80
-rw-r--r--make/otp_version_tickets_in_merge9
-rw-r--r--otp_versions.table4
74 files changed, 2657 insertions, 2577 deletions
diff --git a/OTP_VERSION b/OTP_VERSION
index 8e5954eb6f..cc4d727a5d 100644
--- a/OTP_VERSION
+++ b/OTP_VERSION
@@ -1 +1 @@
-21.3
+21.3.4
diff --git a/erts/doc/src/erl_ext_dist.xml b/erts/doc/src/erl_ext_dist.xml
index b7090d0472..5813af1d57 100644
--- a/erts/doc/src/erl_ext_dist.xml
+++ b/erts/doc/src/erl_ext_dist.xml
@@ -386,44 +386,6 @@
</section>
<section>
- <marker id="REFERENCE_EXT"/>
- <title>REFERENCE_EXT</title>
- <table align="left">
- <row>
- <cell align="center">1</cell>
- <cell align="center">N</cell>
- <cell align="center">4</cell>
- <cell align="center">1</cell>
- </row>
- <row>
- <cell align="center"><c>101</c></cell>
- <cell align="center"><c>Node</c></cell>
- <cell align="center"><c>ID</c></cell>
- <cell align="center"><c>Creation</c></cell>
- </row>
- <tcaption>REFERENCE_EXT</tcaption></table>
- <p>
- Encodes a reference object (an object generated with
- <seealso marker="erlang:make_ref/0">erlang:make_ref/0</seealso>).
- The <c>Node</c> term is an encoded atom, that is,
- <seealso marker="#ATOM_UTF8_EXT"><c>ATOM_UTF8_EXT</c></seealso>,
- <seealso marker="#SMALL_ATOM_UTF8_EXT"><c>SMALL_ATOM_UTF8_EXT</c></seealso>, or
- <seealso marker="#ATOM_CACHE_REF"><c>ATOM_CACHE_REF</c></seealso>.
- The <c>ID</c> field contains a big-endian unsigned integer,
- but <em>is to be regarded as uninterpreted data</em>,
- as this field is node-specific.
- <c>Creation</c> is a byte containing a node serial number, which
- makes it possible to separate old (crashed) nodes from a new one.
- </p>
- <p>
- In <c>ID</c>, only 18 bits are significant; the rest are to be 0.
- In <c>Creation</c>, only two bits are significant; the rest are to be 0.
- See <seealso marker="#NEW_REFERENCE_EXT">
- <c>NEW_REFERENCE_EXT</c></seealso>.
- </p>
- </section>
-
- <section>
<marker id="PORT_EXT"/>
<title>PORT_EXT</title>
<table align="left">
@@ -441,13 +403,46 @@
</row>
<tcaption>PORT_EXT</tcaption></table>
<p>
- Encodes a port object (obtained from
- <seealso marker="erlang:open_port/2">
- <c>erlang:open_port/2</c></seealso>).
- The <c>ID</c> is a node-specific identifier for a local port.
+ Same as <seealso marker="#NEW_PORT_EXT"><c>NEW_PORT_EXT</c></seealso>
+ except the <c>Creation</c> field is only one byte and only two
+ bits are significant, the rest are to be 0.
+ </p>
+ </section>
+
+ <section>
+ <marker id="NEW_PORT_EXT"/>
+ <title>NEW_PORT_EXT</title>
+ <table align="left">
+ <row>
+ <cell align="center">1</cell>
+ <cell align="center">N</cell>
+ <cell align="center">4</cell>
+ <cell align="center">4</cell>
+ </row>
+ <row>
+ <cell align="center"><c>89</c></cell>
+ <cell align="center"><c>Node</c></cell>
+ <cell align="center"><c>ID</c></cell>
+ <cell align="center"><c>Creation</c></cell>
+ </row>
+ <tcaption>NEW_PORT_EXT</tcaption></table>
+ <p>
+ Encodes a port identifier (obtained from
+ <seealso marker="erlang#open_port/2"><c>erlang:open_port/2</c></seealso>).
+ <c>Node</c> is an encoded atom, that is,
+ <seealso marker="#ATOM_UTF8_EXT"><c>ATOM_UTF8_EXT</c></seealso>,
+ <seealso marker="#SMALL_ATOM_UTF8_EXT"><c>SMALL_ATOM_UTF8_EXT</c></seealso>
+ or <seealso marker="#ATOM_CACHE_REF"><c>ATOM_CACHE_REF</c></seealso>.
+ <c>ID</c> is a 32-bit big endian unsigned integer. Only 28 bits are
+ significant; the rest are to be 0. The <c>Creation</c> works just like in
+ <seealso marker="#NEW_PID_EXT"><c>NEW_PID_EXT</c></seealso>.
Port operations are not allowed across node boundaries.
- The <c>Creation</c> works just like in
- <seealso marker="#REFERENCE_EXT"><c>REFERENCE_EXT</c></seealso>.
+ </p>
+ <p>Introduced in OTP 19, but only to be decoded and echoed back. Not
+ encoded for local ports. Planned to supersede <seealso marker="#PORT_EXT">
+ <c>PORT_EXT</c></seealso> in OTP 23 when
+ <seealso marker="erl_dist_protocol#dflags"><c>DFLAG_BIG_CREATON</c></seealso>
+ becomes mandatory.
</p>
</section>
@@ -471,12 +466,65 @@
</row>
<tcaption>PID_EXT</tcaption></table>
<p>
- Encodes a process identifier object (obtained from
- <seealso marker="erlang:spawn/3"><c>erlang:spawn/3</c></seealso> or
- friends). The <c>ID</c> and <c>Creation</c> fields works just like in
- <seealso marker="#REFERENCE_EXT"><c>REFERENCE_EXT</c></seealso>, while
- the <c>Serial</c> field is used to improve safety.
- In <c>ID</c>, only 15 bits are significant; the rest are to be 0.
+ Same as <seealso marker="#NEW_PID_EXT"><c>NEW_PID_EXT</c></seealso>
+ except the <c>Creation</c> field is only one byte and only two
+ bits are significant, the rest are to be 0.
+ </p>
+ </section>
+
+ <section>
+ <marker id="NEW_PID_EXT"/>
+ <title>NEW_PID_EXT</title>
+ <table align="left">
+ <row>
+ <cell align="center">1</cell>
+ <cell align="center">N</cell>
+ <cell align="center">4</cell>
+ <cell align="center">4</cell>
+ <cell align="center">4</cell>
+ </row>
+ <row>
+ <cell align="center"><c>88</c></cell>
+ <cell align="center"><c>Node</c></cell>
+ <cell align="center"><c>ID</c></cell>
+ <cell align="center"><c>Serial</c></cell>
+ <cell align="center"><c>Creation</c></cell>
+ </row>
+ <tcaption>NEW_PID_EXT</tcaption></table>
+ <p>
+ Encodes an Erlang process identifier object.
+ </p>
+ <taglist>
+ <tag><c>Node</c></tag>
+ <item><p>The name of the originating node, encoded using
+ <seealso marker="#ATOM_UTF8_EXT"><c>ATOM_UTF8_EXT</c></seealso>,
+ <seealso marker="#SMALL_ATOM_UTF8_EXT"><c>SMALL_ATOM_UTF8_EXT</c></seealso>
+ or <seealso
+ marker="#ATOM_CACHE_REF"><c>ATOM_CACHE_REF</c></seealso>.</p>
+ </item>
+ <tag><c>ID</c></tag>
+ <item><p>A 32-bit big endian unsigned integer. Only 15 bits are
+ significant; the rest are to be 0.</p>
+ </item>
+ <tag><c>Serial</c></tag>
+ <item><p>A 32-bit big endian unsigned integer. Only 13 bits are
+ significant; the rest are to be 0.</p>
+ </item>
+ <tag><c>Creation</c></tag>
+ <item><p>A 32-bit big endian unsigned integer. All identifiers
+ originating from the same node incarnation must have identical <c>Creation</c>
+ values. This makes it possible to separate identifiers from old
+ (crashed) nodes from a new one. The value zero should be avoided for
+ normal operations as it is used as a wild card for debug purpose
+ (like a pid returned by <seealso marker="erts:erlang#list_to_pid/1">
+ erlang:list_to_pid/1</seealso>).</p>
+ </item>
+ </taglist>
+ <p>Introduced in OTP 19, but only to be decoded and echoed back. Not
+ encoded for local processes. Planned to supersede <seealso marker="#PID_EXT">
+ <c>PID_EXT</c></seealso> in OTP 23 when
+ <seealso marker="erl_dist_protocol#dflags"><c>DFLAG_BIG_CREATON</c></seealso>
+ becomes mandatory.
</p>
</section>
@@ -700,6 +748,30 @@
</section>
<section>
+ <marker id="REFERENCE_EXT"/>
+ <title>REFERENCE_EXT (deprecated)</title>
+ <table align="left">
+ <row>
+ <cell align="center">1</cell>
+ <cell align="center">N</cell>
+ <cell align="center">4</cell>
+ <cell align="center">1</cell>
+ </row>
+ <row>
+ <cell align="center"><c>101</c></cell>
+ <cell align="center"><c>Node</c></cell>
+ <cell align="center"><c>ID</c></cell>
+ <cell align="center"><c>Creation</c></cell>
+ </row>
+ <tcaption>REFERENCE_EXT</tcaption></table>
+ <p>
+ The same as <seealso marker="#NEW_REFERENCE_EXT">
+ <c>NEW_REFERENCE_EXT</c></seealso> except <c>ID</c> is only one word
+ (<c>Len</c> = 1).
+ </p>
+ </section>
+
+ <section>
<marker id="NEW_REFERENCE_EXT"/>
<title>NEW_REFERENCE_EXT</title>
<table align="left">
@@ -719,29 +791,68 @@
</row>
<tcaption>NEW_REFERENCE_EXT</tcaption></table>
<p>
- <c>Node</c> and <c>Creation</c> are as in
- <seealso marker="#REFERENCE_EXT"><c>REFERENCE_EXT</c></seealso>.
- </p>
- <p>
- <c>ID</c> contains a sequence of big-endian unsigned integers
- (4 bytes each, so <c>N'</c> is a multiple of 4),
- but is to be regarded as uninterpreted data.
- </p>
- <p>
- <c>N'</c> = 4 * <c>Len</c>.
- </p>
- <p>
- In the first word (4 bytes) of <c>ID</c>, only 18 bits are
- significant, the rest are to be 0.
- In <c>Creation</c>, only two bits are significant,
- the rest are to be 0.
+ The same as <seealso marker="#NEWER_REFERENCE_EXT">
+ <c>NEWER_REFERENCE_EXT</c></seealso> <em>except</em>:
</p>
+ <taglist>
+ <tag><c>ID</c></tag>
+ <item><p>In the first word (4 bytes) of <c>ID</c>, only 18 bits are
+ significant, the rest must be 0.</p>
+ </item>
+ <tag><c>Creation</c></tag>
+ <item><p>Only one byte long and only two bits are significant, the rest must be 0.</p>
+ </item>
+ </taglist>
+ </section>
+
+ <section>
+ <marker id="NEWER_REFERENCE_EXT"/>
+ <title>NEWER_REFERENCE_EXT</title>
+ <table align="left">
+ <row>
+ <cell align="center">1</cell>
+ <cell align="center">2</cell>
+ <cell align="center">N</cell>
+ <cell align="center">4</cell>
+ <cell align="center">N'</cell>
+ </row>
+ <row>
+ <cell align="center"><c>90</c></cell>
+ <cell align="center"><c>Len</c></cell>
+ <cell align="center"><c>Node</c></cell>
+ <cell align="center"><c>Creation</c></cell>
+ <cell align="center"><c>ID ...</c></cell>
+ </row>
+ <tcaption>NEWER_REFERENCE_EXT</tcaption></table>
<p>
- <c>NEW_REFERENCE_EXT</c> was introduced with distribution version 4.
- In version 4, <c>N'</c> is to be at most 12.
+ Encodes a reference term generated with
+ <seealso marker="erts:erlang#make_ref/0">erlang:make_ref/0</seealso>.
</p>
- <p>
- See <seealso marker="#REFERENCE_EXT"><c>REFERENCE_EXT</c></seealso>.
+ <taglist>
+ <tag><c>Node</c></tag>
+ <item><p>The name of the originating node, encoded using
+ <seealso marker="#ATOM_UTF8_EXT"><c>ATOM_UTF8_EXT</c></seealso>,
+ <seealso marker="#SMALL_ATOM_UTF8_EXT"><c>SMALL_ATOM_UTF8_EXT</c></seealso>
+ or <seealso marker="#ATOM_CACHE_REF"><c>ATOM_CACHE_REF</c></seealso>.</p>
+ </item>
+ <tag><c>Len</c></tag>
+ <item><p>A 16-bit big endian unsigned integer not larger than 3.</p>
+ </item>
+ <tag><c>ID</c></tag>
+ <item><p>A sequence of <c>Len</c> big-endian unsigned integers
+ (4 bytes each, so <c>N'</c>&nbsp;=&nbsp;4&nbsp;*&nbsp;<c>Len</c>),
+ but is to be regarded as uninterpreted data.</p>
+ </item>
+ <tag><c>Creation</c></tag>
+ <item><p>Works just like in
+ <seealso marker="#NEW_PID_EXT"><c>NEW_PID_EXT</c></seealso>.</p>
+ </item>
+ </taglist>
+ <p>Introduced in OTP 19, but only to be decoded and echoed back. Not
+ encoded for local references. Planned to supersede <seealso marker="#NEW_REFERENCE_EXT">
+ <c>NEW_REFERENCE_EXT</c></seealso> in OTP 23 when
+ <seealso marker="erl_dist_protocol#dflags"><c>DFLAG_BIG_CREATON</c></seealso>
+ becomes mandatory.
</p>
</section>
diff --git a/erts/doc/src/notes.xml b/erts/doc/src/notes.xml
index 5c45f8d83b..d77235782b 100644
--- a/erts/doc/src/notes.xml
+++ b/erts/doc/src/notes.xml
@@ -31,6 +31,78 @@
</header>
<p>This document describes the changes made to the ERTS application.</p>
+<section><title>Erts 10.3.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix <c>erlang:open_port/2</c> with the <c>fd</c> option
+ to correctly cleanup the pollset when the port is closed.
+ Before this fix there would be error printouts sent to
+ logger when the same fd was reused in a new port.</p>
+ <p>
+ Own Id: OTP-15753 Aux Id: ERL-900 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 10.3.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fixed a bug in <c>seq_trace:reset_trace/0</c> that
+ could crash the emulator.</p>
+ <p>
+ Own Id: OTP-15704</p>
+ </item>
+ <item>
+ <p>
+ Fixed bug in <c>process_info(reductions)</c> causing it
+ to sometimes return invalid results.</p>
+ <p>
+ Own Id: OTP-15709 Aux Id: ERIERL-337 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 10.3.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>If a suspend/resume signal pair was sent to a process
+ while it was executing dirty, the receiving process could
+ later end up in a suspended state indefinitely. This bug
+ was introduced in ERTS version 10.0 (OTP 21.0).</p>
+ <p>Suspend/resume signals are sent from <seealso
+ marker="erts:erlang#suspend_process/1"><c>erlang:suspend_process()</c></seealso>/<seealso
+ marker="erts:erlang#resume_process/1"><c>erlang:resume_process()</c></seealso>.
+ The <seealso
+ marker="runtime_tools:dbg"><c>dbg</c></seealso> trace
+ tool utilize this functionality and could thus trigger
+ this bug.</p>
+ <p>
+ Own Id: OTP-15688</p>
+ </item>
+ <item>
+ <p>
+ Fix a possible deadlock when terminating the ERTS caused
+ by a dirty scheduler not releasing it's run-queue lock
+ when terminating.</p>
+ <p>
+ Own Id: OTP-15690 Aux Id: PR-2172 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Erts 10.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c
index 4351dda5a7..10d70a96e8 100644
--- a/erts/emulator/beam/beam_emu.c
+++ b/erts/emulator/beam/beam_emu.c
@@ -3261,20 +3261,23 @@ erts_is_builtin(Eterm Mod, Eterm Name, int arity)
/*
- * Return the current number of reductions for the given process.
+ * Return the current number of reductions consumed by the given process.
* To get the total number of reductions, p->reds must be added.
*/
Uint
-erts_current_reductions(Process *current, Process *p)
+erts_current_reductions(Process *c_p, Process *p)
{
- if (current != p) {
+ Sint reds_left;
+ if (c_p != p || !(erts_atomic32_read_nob(&c_p->state)
+ & ERTS_PSFLG_RUNNING)) {
return 0;
- } else if (current->fcalls < 0 && ERTS_PROC_GET_SAVED_CALLS_BUF(current)) {
- return current->fcalls + CONTEXT_REDS;
+ } else if (c_p->fcalls < 0 && ERTS_PROC_GET_SAVED_CALLS_BUF(c_p)) {
+ reds_left = c_p->fcalls + CONTEXT_REDS;
} else {
- return REDS_IN(current) - current->fcalls;
+ reds_left = c_p->fcalls;
}
+ return REDS_IN(c_p) - reds_left;
}
int
diff --git a/erts/emulator/beam/erl_proc_sig_queue.c b/erts/emulator/beam/erl_proc_sig_queue.c
index 18418a76e1..d475a0a634 100644
--- a/erts/emulator/beam/erl_proc_sig_queue.c
+++ b/erts/emulator/beam/erl_proc_sig_queue.c
@@ -3247,9 +3247,15 @@ erts_proc_sig_handle_incoming(Process *c_p, erts_aint32_t *statep,
erts_nif_demonitored((ErtsResource *) tmon->other.ptr);
cnt++;
break;
- case ERTS_MON_TYPE_SUSPEND:
- erts_resume(c_p, ERTS_PROC_LOCK_MAIN);
+ case ERTS_MON_TYPE_SUSPEND: {
+ ErtsMonitorSuspend *msp;
+ erts_aint_t mstate;
+ msp = (ErtsMonitorSuspend *) erts_monitor_to_data(tmon);
+ mstate = erts_atomic_read_acqb(&msp->state);
+ if (mstate & ERTS_MSUSPEND_STATE_FLG_ACTIVE)
+ erts_resume(c_p, ERTS_PROC_LOCK_MAIN);
break;
+ }
default:
break;
}
@@ -3784,6 +3790,9 @@ clear_seq_trace_token(ErtsMessage *sig)
case ERTS_MON_TYPE_PROC:
case ERTS_MON_TYPE_DIST_PROC:
case ERTS_MON_TYPE_NODE:
+ case ERTS_MON_TYPE_NODES:
+ case ERTS_MON_TYPE_SUSPEND:
+ case ERTS_MON_TYPE_TIME_OFFSET:
break;
default:
ERTS_INTERNAL_ERROR("Unexpected sig type");
@@ -3800,6 +3809,11 @@ clear_seq_trace_token(ErtsMessage *sig)
case ERTS_SIG_Q_OP_LINK:
case ERTS_SIG_Q_OP_UNLINK:
case ERTS_SIG_Q_OP_TRACE_CHANGE_STATE:
+ case ERTS_SIG_Q_OP_GROUP_LEADER:
+ case ERTS_SIG_Q_OP_IS_ALIVE:
+ case ERTS_SIG_Q_OP_PROCESS_INFO:
+ case ERTS_SIG_Q_OP_SYNC_SUSPEND:
+ case ERTS_SIG_Q_OP_RPC:
break;
default:
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index cc02fbad1e..1f464e2e5a 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -9474,6 +9474,7 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls)
if (!is_normal_sched & !!(flags & ERTS_RUNQ_FLG_HALTING)) {
/* Wait for emulator to terminate... */
+ erts_runq_unlock(rq);
while (1)
erts_milli_sleep(1000*1000);
}
@@ -13081,10 +13082,10 @@ void erts_halt(int code)
if (-1 == erts_atomic32_cmpxchg_acqb(&erts_halt_progress,
erts_no_schedulers,
-1)) {
+ notify_reap_ports_relb();
ERTS_RUNQ_FLGS_SET(ERTS_DIRTY_CPU_RUNQ, ERTS_RUNQ_FLG_HALTING);
ERTS_RUNQ_FLGS_SET(ERTS_DIRTY_IO_RUNQ, ERTS_RUNQ_FLG_HALTING);
erts_halt_code = code;
- notify_reap_ports_relb();
}
}
diff --git a/erts/emulator/beam/msg_instrs.tab b/erts/emulator/beam/msg_instrs.tab
index 9bf3aefaca..a6a0dec451 100644
--- a/erts/emulator/beam/msg_instrs.tab
+++ b/erts/emulator/beam/msg_instrs.tab
@@ -105,6 +105,7 @@ i_loop_rec(Dest) {
$SET_CP_I_ABS(I);
c_p->arity = 0;
c_p->current = NULL;
+ c_p->fcalls = FCALLS;
FCALLS -= erts_proc_sig_receive_helper(c_p, FCALLS, neg_o_reds,
&msgp, &get_out);
SWAPIN;
diff --git a/erts/emulator/sys/common/erl_check_io.c b/erts/emulator/sys/common/erl_check_io.c
index c39cd01e1c..c77a535105 100644
--- a/erts/emulator/sys/common/erl_check_io.c
+++ b/erts/emulator/sys/common/erl_check_io.c
@@ -752,6 +752,8 @@ driver_select(ErlDrvPort ix, ErlDrvEvent e, int mode, int on)
ret = 0;
goto done_unknown;
}
+ /* For some reason (don't know why), we do not clean all
+ events when doing ERL_DRV_USE_NO_CALLBACK. */
else if ((mode&ERL_DRV_USE_NO_CALLBACK) == ERL_DRV_USE) {
mode |= (ERL_DRV_READ | ERL_DRV_WRITE);
}
@@ -2439,6 +2441,10 @@ drvmode2str(int mode) {
case ERL_DRV_WRITE|ERL_DRV_USE: return "WRITE|USE";
case ERL_DRV_READ|ERL_DRV_WRITE|ERL_DRV_USE: return "READ|WRITE|USE";
case ERL_DRV_USE: return "USE";
+ case ERL_DRV_READ|ERL_DRV_USE_NO_CALLBACK: return "READ|USE_NO_CB";
+ case ERL_DRV_WRITE|ERL_DRV_USE_NO_CALLBACK: return "WRITE|USE_NO_CB";
+ case ERL_DRV_READ|ERL_DRV_WRITE|ERL_DRV_USE_NO_CALLBACK: return "READ|WRITE|USE_NO_CB";
+ case ERL_DRV_USE_NO_CALLBACK: return "USE_NO_CB";
case ERL_DRV_READ: return "READ";
case ERL_DRV_WRITE: return "WRITE";
case ERL_DRV_READ|ERL_DRV_WRITE: return "READ|WRITE";
diff --git a/erts/emulator/sys/unix/sys_drivers.c b/erts/emulator/sys/unix/sys_drivers.c
index 042a091db1..664d677ebd 100644
--- a/erts/emulator/sys/unix/sys_drivers.c
+++ b/erts/emulator/sys/unix/sys_drivers.c
@@ -1006,10 +1006,8 @@ static void clear_fd_data(ErtsSysFdData *fdd)
static void nbio_stop_fd(ErlDrvPort prt, ErtsSysFdData *fdd, int use)
{
- driver_select(prt, abs(fdd->fd), use ? ERL_DRV_USE_NO_CALLBACK : 0|DO_READ|DO_WRITE, 0);
clear_fd_data(fdd);
SET_BLOCKING(abs(fdd->fd));
-
}
static void fd_stop(ErlDrvData ev) /* Does not close the fds */
@@ -1026,10 +1024,12 @@ static void fd_stop(ErlDrvData ev) /* Does not close the fds */
if (dd->ifd) {
sz += sizeof(ErtsSysFdData);
+ driver_select(prt, abs(dd->ifd->fd), ERL_DRV_USE_NO_CALLBACK|DO_READ|DO_WRITE, 0);
nbio_stop_fd(prt, dd->ifd, 1);
}
if (dd->ofd && dd->ofd != dd->ifd) {
sz += sizeof(ErtsSysFdData);
+ driver_select(prt, abs(dd->ofd->fd), ERL_DRV_USE_NO_CALLBACK|DO_WRITE, 0);
nbio_stop_fd(prt, dd->ofd, 1);
}
diff --git a/erts/emulator/test/dirty_bif_SUITE.erl b/erts/emulator/test/dirty_bif_SUITE.erl
index 46eb0cba58..4f5ad0295a 100644
--- a/erts/emulator/test/dirty_bif_SUITE.erl
+++ b/erts/emulator/test/dirty_bif_SUITE.erl
@@ -38,7 +38,8 @@
dirty_process_info/1,
dirty_process_register/1,
dirty_process_trace/1,
- code_purge/1]).
+ code_purge/1,
+ otp_15688/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
@@ -64,7 +65,8 @@ all() ->
dirty_process_info,
dirty_process_register,
dirty_process_trace,
- code_purge].
+ code_purge,
+ otp_15688].
init_per_suite(Config) ->
case erlang:system_info(dirty_cpu_schedulers) of
@@ -498,10 +500,58 @@ code_purge(Config) when is_list(Config) ->
true = Time =< 1000,
ok.
+otp_15688(Config) when is_list(Config) ->
+ ImBack = make_ref(),
+ {See, SeeMon} = spawn_monitor(fun () ->
+ erts_debug:dirty_io(wait, 2000),
+ exit(ImBack)
+ end),
+ wait_until(fun () ->
+ [{current_function, {erts_debug, dirty_io, 2}},
+ {status, running}]
+ == process_info(See,
+ [current_function, status])
+ end),
+ {Ser1, Ser1Mon} = spawn_monitor(fun () ->
+ erlang:suspend_process(See,
+ [asynchronous])
+ end),
+ erlang:suspend_process(See, [asynchronous]),
+ receive {'DOWN', Ser1Mon, process, Ser1, normal} -> ok end,
+
+ %% Verify that we sent the suspend request while it was executing dirty...
+ [{current_function, {erts_debug, dirty_io, 2}},
+ {status, running}] = process_info(See, [current_function, status]),
+
+ wait_until(fun () ->
+ {status, suspended} == process_info(See, status)
+ end),
+ erlang:resume_process(See),
+
+ receive
+ {'DOWN', SeeMon, process, See, Reason} ->
+ ImBack = Reason
+ after 4000 ->
+ %% Resume bug seems to have hit us...
+ PI = process_info(See),
+ exit(See, kill),
+ ct:fail({suspendee_stuck, PI})
+ end.
+
+
%%
%% Internal...
%%
+wait_until(Fun) ->
+ case Fun() of
+ true ->
+ ok;
+ _ ->
+ receive after 100 -> ok end,
+ wait_until(Fun)
+ end.
+
access_dirty_process(Config, Start, Test, Finish) ->
{ok, Node} = start_node(Config, ""),
[ok] = mcall(Node,
diff --git a/erts/emulator/test/process_SUITE.erl b/erts/emulator/test/process_SUITE.erl
index b23f77a0b2..0cb0d6c1e2 100644
--- a/erts/emulator/test/process_SUITE.erl
+++ b/erts/emulator/test/process_SUITE.erl
@@ -44,6 +44,7 @@
process_info_garbage_collection/1,
process_info_smoke_all/1,
process_info_status_handled_signal/1,
+ process_info_reductions/1,
bump_reductions/1, low_prio/1, binary_owner/1, yield/1, yield2/1,
otp_4725/1, bad_register/1, garbage_collect/1, otp_6237/1,
process_info_messages/1, process_flag_badarg/1, process_flag_heap_size/1,
@@ -84,6 +85,7 @@ all() ->
process_info_garbage_collection,
process_info_smoke_all,
process_info_status_handled_signal,
+ process_info_reductions,
bump_reductions, low_prio, yield, yield2, otp_4725,
bad_register, garbage_collect, process_info_messages,
process_flag_badarg, process_flag_heap_size,
@@ -1084,6 +1086,46 @@ process_info_status_handled_signal(Config) when is_list(Config) ->
false = erlang:is_process_alive(P),
ok.
+%% OTP-15709
+%% Provoke a bug where process_info(reductions) returned wrong result
+%% because REDS_IN (def_arg_reg[5]) is read when the process in not running.
+process_info_reductions(Config) when is_list(Config) ->
+ pi_reductions_tester(spawn_link(fun() -> pi_reductions_spinnloop() end)),
+ pi_reductions_tester(spawn_link(fun() -> pi_reductions_recvloop() end)),
+ ok.
+
+pi_reductions_tester(Pid) ->
+ {_, DiffList} =
+ lists:foldl(fun(_, {Prev, Acc}) ->
+ %% Add another item that force sending the request
+ %% as a signal, like 'current_function'.
+ PI = process_info(Pid, [reductions, current_function]),
+ [{reductions,Reds}, {current_function,_}] = PI,
+ Diff = Reds - Prev,
+ {Diff, true} = {Diff, (Diff >= 0)},
+ {Diff, true} = {Diff, (Diff =< 1000*1000)},
+ {Reds, [Diff | Acc]}
+ end,
+ {0, []},
+ lists:seq(1,10)),
+ unlink(Pid),
+ exit(Pid,kill),
+ io:format("Reduction diffs: ~p\n", [DiffList]),
+ ok.
+
+pi_reductions_spinnloop() ->
+ %% 6 args to make use of def_arg_reg[5] which is also used as REDS_IN
+ pi_reductions_spinnloop(1, atom, "hej", self(), make_ref(), 3.14).
+
+pi_reductions_spinnloop(A,B,C,D,E,F) ->
+ pi_reductions_spinnloop(B,C,D,E,F,A).
+
+pi_reductions_recvloop() ->
+ receive
+ "a free lunch" -> false
+ end.
+
+
%% Tests erlang:bump_reductions/1.
bump_reductions(Config) when is_list(Config) ->
erlang:garbage_collect(),
diff --git a/erts/vsn.mk b/erts/vsn.mk
index fac608ed4e..785c7626e7 100644
--- a/erts/vsn.mk
+++ b/erts/vsn.mk
@@ -18,7 +18,7 @@
# %CopyrightEnd%
#
-VSN = 10.3
+VSN = 10.3.3
# Port number 4365 in 4.2
# Port number 4366 in 4.3
diff --git a/lib/common_test/doc/src/notes.xml b/lib/common_test/doc/src/notes.xml
index 8b40173e8a..018bb910a1 100644
--- a/lib/common_test/doc/src/notes.xml
+++ b/lib/common_test/doc/src/notes.xml
@@ -33,6 +33,21 @@
<file>notes.xml</file>
</header>
+<section><title>Common_Test 1.17.1</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ OTP internal test improvements.</p>
+ <p>
+ Own Id: OTP-15716</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Common_Test 1.17</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/common_test/src/test_server_node.erl b/lib/common_test/src/test_server_node.erl
index ea7ad8538e..3ae4a047d8 100644
--- a/lib/common_test/src/test_server_node.erl
+++ b/lib/common_test/src/test_server_node.erl
@@ -656,9 +656,19 @@ find_release({unix,linux}, Rel) ->
find_release(_, _) -> none.
find_rel_linux(Rel) ->
- case suse_release() of
- none -> [];
- SuseRel -> find_rel_suse(Rel, SuseRel)
+ try
+ case ubuntu_release() of
+ none -> none;
+ [UbuntuRel |_] -> throw(find_rel_ubuntu(Rel, UbuntuRel))
+ end,
+ case suse_release() of
+ none -> none;
+ SuseRel -> throw(find_rel_suse(Rel, SuseRel))
+ end,
+ []
+ catch
+ throw:Result ->
+ Result
end.
find_rel_suse(Rel, SuseRel) ->
@@ -735,6 +745,93 @@ suse_release(Fd) ->
end
end.
+find_rel_ubuntu(_Rel, UbuntuRel) when is_integer(UbuntuRel), UbuntuRel < 16 ->
+ [];
+find_rel_ubuntu(Rel, UbuntuRel) when is_integer(UbuntuRel) ->
+ Root = "/usr/local/otp/releases/ubuntu",
+ lists:foldl(fun (ChkUbuntuRel, Acc) ->
+ find_rel_ubuntu_aux1(Rel, Root++integer_to_list(ChkUbuntuRel))
+ ++ Acc
+ end,
+ [],
+ lists:seq(16, UbuntuRel)).
+
+find_rel_ubuntu_aux1(Rel, RootWc) ->
+ case erlang:system_info(wordsize) of
+ 4 ->
+ find_rel_ubuntu_aux2(Rel, RootWc++"_32");
+ 8 ->
+ find_rel_ubuntu_aux2(Rel, RootWc++"_64") ++
+ find_rel_ubuntu_aux2(Rel, RootWc++"_32")
+ end.
+
+find_rel_ubuntu_aux2(Rel, RootWc) ->
+ RelDir = filename:dirname(RootWc),
+ Pat = filename:basename(RootWc ++ "_" ++ Rel) ++ ".*",
+ case file:list_dir(RelDir) of
+ {ok,Dirs} ->
+ case lists:filter(fun(Dir) ->
+ case re:run(Dir, Pat, [unicode]) of
+ nomatch -> false;
+ _ -> true
+ end
+ end, Dirs) of
+ [] ->
+ [];
+ [R|_] ->
+ [filename:join([RelDir,R,"bin","erl"])]
+ end;
+ _ ->
+ []
+ end.
+
+ubuntu_release() ->
+ case file:open("/etc/lsb-release", [read]) of
+ {ok,Fd} ->
+ try
+ ubuntu_release(Fd, undefined, undefined)
+ after
+ file:close(Fd)
+ end;
+ {error,_} -> none
+ end.
+
+ubuntu_release(_Fd, DistrId, Rel) when DistrId /= undefined,
+ Rel /= undefined ->
+ Ubuntu = case DistrId of
+ "Ubuntu" -> true;
+ "ubuntu" -> true;
+ _ -> false
+ end,
+ case Ubuntu of
+ false -> none;
+ true -> Rel
+ end;
+ubuntu_release(Fd, DistroId, Rel) ->
+ case io:get_line(Fd, '') of
+ eof ->
+ none;
+ Line when is_list(Line) ->
+ case re:run(Line, "^DISTRIB_ID=(\\w+)$",
+ [{capture,all_but_first,list}]) of
+ {match,[NewDistroId]} ->
+ ubuntu_release(Fd, NewDistroId, Rel);
+ nomatch ->
+ case re:run(Line, "^DISTRIB_RELEASE=(\\d+(?:\\.\\d+)*)$",
+ [{capture,all_but_first,list}]) of
+ {match,[RelList]} ->
+ NewRel = lists:map(fun (N) ->
+ list_to_integer(N)
+ end,
+ string:lexemes(RelList, ".")),
+ ubuntu_release(Fd, DistroId, NewRel);
+ nomatch ->
+ ubuntu_release(Fd, DistroId, Rel)
+ end
+ end
+ end.
+
+
unpack(Bin) ->
{One,Term} = split_binary(Bin, 1),
case binary_to_list(One) of
diff --git a/lib/common_test/vsn.mk b/lib/common_test/vsn.mk
index 23eb8d9656..14a3622a00 100644
--- a/lib/common_test/vsn.mk
+++ b/lib/common_test/vsn.mk
@@ -1 +1 @@
-COMMON_TEST_VSN = 1.17
+COMMON_TEST_VSN = 1.17.1
diff --git a/lib/crypto/c_src/otp_test_engine.c b/lib/crypto/c_src/otp_test_engine.c
index 2c8cce094e..f452fb2d0c 100644
--- a/lib/crypto/c_src/otp_test_engine.c
+++ b/lib/crypto/c_src/otp_test_engine.c
@@ -375,7 +375,7 @@ int test_rsa_sign(int dtype,
} */
if ((sizeof(fake_flag) == m_len)
- && bcmp(m,fake_flag,m_len) == 0) {
+ && memcmp(m,fake_flag,m_len) == 0) {
printf("To be faked\r\n");
/* To be faked */
slen = RSA_size(rsa);
@@ -397,7 +397,7 @@ int test_rsa_verify(int dtype,
printf("test_rsa_verify (dtype=%i) called m_len=%u siglen=%u\r\n", dtype, m_len, siglen);
if ((sizeof(fake_flag) == m_len)
- && bcmp(m,fake_flag,m_len) == 0) {
+ && memcmp(m,fake_flag,m_len) == 0) {
printf("To be faked\r\n");
return (siglen == RSA_size(rsa))
&& chk_test_data(sigret, siglen);
diff --git a/lib/crypto/doc/src/notes.xml b/lib/crypto/doc/src/notes.xml
index c0b302734e..195c9d029d 100644
--- a/lib/crypto/doc/src/notes.xml
+++ b/lib/crypto/doc/src/notes.xml
@@ -31,6 +31,22 @@
</header>
<p>This document describes the changes made to the Crypto application.</p>
+<section><title>Crypto 4.4.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed build link error on Windows. Unresolved symbol
+ 'bcmp'.</p>
+ <p>
+ Own Id: OTP-15750 Aux Id: ERL-905 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Crypto 4.4.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/crypto/vsn.mk b/lib/crypto/vsn.mk
index deba17fb66..0a3d9f45e4 100644
--- a/lib/crypto/vsn.mk
+++ b/lib/crypto/vsn.mk
@@ -1 +1 @@
-CRYPTO_VSN = 4.4.1
+CRYPTO_VSN = 4.4.2
diff --git a/lib/erl_interface/doc/src/notes.xml b/lib/erl_interface/doc/src/notes.xml
index b686cfbf33..5ad0e2499b 100644
--- a/lib/erl_interface/doc/src/notes.xml
+++ b/lib/erl_interface/doc/src/notes.xml
@@ -31,6 +31,42 @@
</header>
<p>This document describes the changes made to the Erl_interface application.</p>
+<section><title>Erl_Interface 3.11.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix handling of Makefile dependencies so that parallel
+ make works properly.</p>
+ <p>
+ Own Id: OTP-15757</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erl_Interface 3.11.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed two bugs in the <c>erl_call</c> program. A missing
+ initialization (introduced in <c>erl_interface-3.11</c>)
+ which either caused a crash or failure to connect to or
+ start a node, and an incorrectly calculated timeout which
+ could cause failure to start an erlang node. These bugs
+ only caused failures on some platforms.</p>
+ <p>
+ Own Id: OTP-15676 Aux Id: OTP-15442, ERL-881 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Erl_Interface 3.11</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/erl_interface/src/Makefile.in b/lib/erl_interface/src/Makefile.in
index b0bb9bfadf..2c1a8252ae 100644
--- a/lib/erl_interface/src/Makefile.in
+++ b/lib/erl_interface/src/Makefile.in
@@ -780,29 +780,31 @@ $(MDD_OBJDIR)/ei_fake_prog_mdd_cxx$(EXE): prog/ei_fake_prog.c $(MDD_EILIB)
# Create dependency file using gcc -MM
###########################################################################
-depend:
+depend: $(TARGET)/depend.mk
+
+$(TARGET)/depend.mk: $(TARGET)/config.h
$(gen_verbose)
- $(V_colon)@echo "Generating dependency file depend.mk..."
- @echo "# Generated dependency rules" > depend.mk; \
- $(V_CC) $(CFLAGS) -MM $(SOURCES) | \
+ $(V_colon)echo "Generating dependency file depend.mk..."
+ @echo "# Generated dependency rules" > $@
+ $(V_CC) $(CFLAGS) -MM $(SOURCES) | \
sed 's&$(TARGET)&\$$\(TARGET\)&g' | \
- sed 's/^.*:/\$$\(ST_OBJDIR\)\/&/' >> depend.mk; \
- echo >> depend.mk; \
- $(CC) $(CFLAGS) -MM $(SOURCES) | \
+ sed 's/^.*:/\$$\(ST_OBJDIR\)\/&/' >> $@
+ @echo >> $@
+ $(V_CC) $(CFLAGS) -MM $(SOURCES) | \
sed 's&$(TARGET)&\$$\(TARGET\)&g' | \
- sed 's/^.*:/\$$\(MT_OBJDIR\)\/&/' >> depend.mk; \
- echo >> depend.mk; \
- $(CC) $(CFLAGS) -MM $(SOURCES) | \
+ sed 's/^.*:/\$$\(MT_OBJDIR\)\/&/' >> $@
+ @echo >> $@
+ $(V_CC) $(CFLAGS) -MM $(SOURCES) | \
sed 's&$(TARGET)&\$$\(TARGET\)&g' | \
- sed 's/^.*:/\$$\(MD_OBJDIR\)\/&/' >> depend.mk; \
- echo >> depend.mk; \
- $(CC) $(CFLAGS) -MM $(SOURCES) | \
+ sed 's/^.*:/\$$\(MD_OBJDIR\)\/&/' >> $@
+ @echo >> $@
+ $(V_CC) $(CFLAGS) -MM $(SOURCES) | \
sed 's&$(TARGET)&\$$\(TARGET\)&g' | \
- sed 's/^.*:/\$$\(MDD_OBJDIR\)\/&/' >> depend.mk; \
- echo >> depend.mk
+ sed 's/^.*:/\$$\(MDD_OBJDIR\)\/&/' >> $@
+ @echo >> $@
# For some reason this has to be after 'opt' target
-include depend.mk
+-include $(TARGET)/depend.mk
# ----------------------------------------------------
# Release Target
diff --git a/lib/erl_interface/src/depend.mk b/lib/erl_interface/src/depend.mk
deleted file mode 100644
index af753046e5..0000000000
--- a/lib/erl_interface/src/depend.mk
+++ /dev/null
@@ -1,1133 +0,0 @@
-# Generated dependency rules
-$(ST_OBJDIR)/ei_connect.o: connect/ei_connect.c $(TARGET)/config.h \
- misc/eidef.h ../include/ei.h misc/eiext.h misc/ei_portio.h \
- misc/ei_internal.h connect/ei_connect_int.h misc/ei_locking.h \
- connect/eisend.h connect/eirecv.h misc/eimd5.h misc/putget.h \
- connect/ei_resolve.h epmd/ei_epmd.h
-$(ST_OBJDIR)/ei_resolve.o: connect/ei_resolve.c $(TARGET)/config.h \
- misc/eidef.h ../include/ei.h connect/ei_resolve.h misc/ei_locking.h
-$(ST_OBJDIR)/eirecv.o: connect/eirecv.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h connect/eirecv.h misc/ei_portio.h \
- misc/ei_internal.h misc/putget.h misc/ei_trace.h misc/show_msg.h
-$(ST_OBJDIR)/send.o: connect/send.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h connect/eisend.h misc/putget.h \
- connect/ei_connect_int.h misc/ei_internal.h misc/ei_trace.h \
- misc/show_msg.h
-$(ST_OBJDIR)/send_exit.o: connect/send_exit.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/ei_connect_int.h misc/ei_trace.h \
- misc/ei_internal.h misc/putget.h misc/show_msg.h
-$(ST_OBJDIR)/send_reg.o: connect/send_reg.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h connect/eisend.h misc/putget.h \
- connect/ei_connect_int.h misc/ei_internal.h misc/ei_trace.h \
- misc/show_msg.h
-$(ST_OBJDIR)/decode_atom.o: decode/decode_atom.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_big.o: decode/decode_big.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_bignum.o: decode/decode_bignum.c $(TARGET)/config.h
-$(ST_OBJDIR)/decode_binary.o: decode/decode_binary.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_boolean.o: decode/decode_boolean.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_char.o: decode/decode_char.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_double.o: decode/decode_double.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_fun.o: decode/decode_fun.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/ei_malloc.h decode/decode_skip.h misc/putget.h
-$(ST_OBJDIR)/decode_intlist.o: decode/decode_intlist.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_list_header.o: decode/decode_list_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_long.o: decode/decode_long.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_pid.o: decode/decode_pid.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_port.o: decode/decode_port.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_ref.o: decode/decode_ref.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_skip.o: decode/decode_skip.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- decode/decode_skip.h
-$(ST_OBJDIR)/decode_string.o: decode/decode_string.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_trace.o: decode/decode_trace.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/putget.h
-$(ST_OBJDIR)/decode_tuple_header.o: decode/decode_tuple_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_ulong.o: decode/decode_ulong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_version.o: decode/decode_version.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_longlong.o: decode/decode_longlong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_ulonglong.o: decode/decode_ulonglong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_atom.o: encode/encode_atom.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_bignum.o: encode/encode_bignum.c $(TARGET)/config.h
-$(ST_OBJDIR)/encode_binary.o: encode/encode_binary.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_boolean.o: encode/encode_boolean.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_char.o: encode/encode_char.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_double.o: encode/encode_double.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_fun.o: encode/encode_fun.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_list_header.o: encode/encode_list_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_long.o: encode/encode_long.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_pid.o: encode/encode_pid.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_port.o: encode/encode_port.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_ref.o: encode/encode_ref.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_string.o: encode/encode_string.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_trace.o: encode/encode_trace.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/putget.h
-$(ST_OBJDIR)/encode_tuple_header.o: encode/encode_tuple_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_ulong.o: encode/encode_ulong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_version.o: encode/encode_version.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_longlong.o: encode/encode_longlong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h misc/ei_x_encode.h
-$(ST_OBJDIR)/encode_ulonglong.o: encode/encode_ulonglong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h misc/ei_x_encode.h
-$(ST_OBJDIR)/epmd_port.o: epmd/epmd_port.c misc/ei_internal.h epmd/ei_epmd.h \
- misc/putget.h
-$(ST_OBJDIR)/epmd_publish.o: epmd/epmd_publish.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/ei_internal.h \
- misc/putget.h ../include/erl_interface.h epmd/ei_epmd.h
-$(ST_OBJDIR)/epmd_unpublish.o: epmd/epmd_unpublish.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/ei_internal.h \
- misc/putget.h ../include/erl_interface.h epmd/ei_epmd.h
-$(ST_OBJDIR)/ei_decode_term.o: misc/ei_decode_term.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/ei_decode_term.h misc/putget.h
-$(ST_OBJDIR)/ei_format.o: misc/ei_format.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/ei_malloc.h misc/ei_format.h
-$(ST_OBJDIR)/ei_locking.o: misc/ei_locking.c $(TARGET)/config.h \
- misc/ei_malloc.h misc/ei_locking.h
-$(ST_OBJDIR)/ei_malloc.o: misc/ei_malloc.c misc/ei_malloc.h
-$(ST_OBJDIR)/ei_portio.o: misc/ei_portio.c misc/ei_portio.h misc/ei_internal.h
-$(ST_OBJDIR)/ei_printterm.o: misc/ei_printterm.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/ei_printterm.h misc/ei_malloc.h
-$(ST_OBJDIR)/ei_pthreads.o: misc/ei_pthreads.c $(TARGET)/config.h \
- ../include/ei.h misc/ei_locking.h
-$(ST_OBJDIR)/ei_trace.o: misc/ei_trace.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/ei_trace.h
-$(ST_OBJDIR)/ei_x_encode.o: misc/ei_x_encode.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/ei_x_encode.h \
- misc/ei_malloc.h
-$(ST_OBJDIR)/eimd5.o: misc/eimd5.c misc/eimd5.h
-$(ST_OBJDIR)/get_type.o: misc/get_type.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h misc/putget.h
-$(ST_OBJDIR)/show_msg.o: misc/show_msg.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h misc/putget.h misc/ei_printterm.h \
- misc/ei_internal.h misc/show_msg.h
-$(ST_OBJDIR)/ei_compat.o: misc/ei_compat.c ../include/ei.h misc/ei_internal.h
-$(ST_OBJDIR)/hash_dohash.o: registry/hash_dohash.c registry/hash.h ../include/ei.h
-$(ST_OBJDIR)/hash_foreach.o: registry/hash_foreach.c registry/hash.h ../include/ei.h
-$(ST_OBJDIR)/hash_freetab.o: registry/hash_freetab.c registry/hash.h ../include/ei.h
-$(ST_OBJDIR)/hash_insert.o: registry/hash_insert.c registry/hash.h ../include/ei.h
-$(ST_OBJDIR)/hash_isprime.o: registry/hash_isprime.c registry/hash.h ../include/ei.h
-$(ST_OBJDIR)/hash_lookup.o: registry/hash_lookup.c registry/hash.h ../include/ei.h
-$(ST_OBJDIR)/hash_newtab.o: registry/hash_newtab.c registry/hash.h ../include/ei.h
-$(ST_OBJDIR)/hash_remove.o: registry/hash_remove.c registry/hash.h ../include/ei.h
-$(ST_OBJDIR)/hash_resize.o: registry/hash_resize.c registry/hash.h ../include/ei.h
-$(ST_OBJDIR)/hash_rlookup.o: registry/hash_rlookup.c registry/hash.h ../include/ei.h
-$(ST_OBJDIR)/reg_close.o: registry/reg_close.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_delete.o: registry/reg_delete.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_dirty.o: registry/reg_dirty.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_dump.o: registry/reg_dump.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- registry/reg.h registry/hash.h connect/eisend.h connect/eirecv.h \
- connect/ei_connect_int.h
-$(ST_OBJDIR)/reg_free.o: registry/reg_free.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_get.o: registry/reg_get.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_getf.o: registry/reg_getf.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_geti.o: registry/reg_geti.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_getp.o: registry/reg_getp.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_gets.o: registry/reg_gets.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_make.o: registry/reg_make.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_open.o: registry/reg_open.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_purge.o: registry/reg_purge.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_resize.o: registry/reg_resize.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_restore.o: registry/reg_restore.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- registry/reg.h registry/hash.h connect/eisend.h connect/eirecv.h \
- connect/ei_connect_int.h
-$(ST_OBJDIR)/reg_set.o: registry/reg_set.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_setf.o: registry/reg_setf.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_seti.o: registry/reg_seti.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_setp.o: registry/reg_setp.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_sets.o: registry/reg_sets.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_stat.o: registry/reg_stat.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_tabstat.o: registry/reg_tabstat.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/decode_term.o: legacy/decode_term.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h ../include/erl_interface.h
-$(ST_OBJDIR)/encode_term.o: legacy/encode_term.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h misc/ei_x_encode.h ../include/erl_interface.h \
- legacy/erl_marshal.h legacy/erl_eterm.h legacy/portability.h
-$(ST_OBJDIR)/erl_connect.o: legacy/erl_connect.c $(TARGET)/config.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_config.h \
- legacy/erl_connect.h legacy/erl_eterm.h legacy/portability.h \
- legacy/erl_malloc.h misc/putget.h connect/ei_connect_int.h \
- misc/ei_locking.h epmd/ei_epmd.h misc/ei_internal.h
-$(ST_OBJDIR)/erl_error.o: legacy/erl_error.c $(TARGET)/config.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_error.h
-$(ST_OBJDIR)/erl_eterm.o: legacy/erl_eterm.c misc/ei_locking.h \
- $(TARGET)/config.h connect/ei_resolve.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_eterm.h \
- legacy/portability.h legacy/erl_malloc.h legacy/erl_marshal.h \
- legacy/erl_error.h legacy/erl_internal.h misc/ei_internal.h
-$(ST_OBJDIR)/erl_fix_alloc.o: legacy/erl_fix_alloc.c $(TARGET)/config.h \
- misc/ei_locking.h ../include/erl_interface.h ../include/ei.h \
- legacy/erl_error.h legacy/erl_malloc.h legacy/erl_fix_alloc.h \
- legacy/erl_eterm.h legacy/portability.h
-$(ST_OBJDIR)/erl_format.o: legacy/erl_format.c ../include/erl_interface.h \
- ../include/ei.h legacy/erl_eterm.h legacy/portability.h \
- legacy/erl_malloc.h legacy/erl_error.h legacy/erl_internal.h
-$(ST_OBJDIR)/erl_malloc.o: legacy/erl_malloc.c ../include/erl_interface.h \
- ../include/ei.h legacy/erl_fix_alloc.h legacy/erl_malloc.h \
- legacy/erl_internal.h legacy/erl_eterm.h legacy/portability.h \
- misc/ei_malloc.h
-$(ST_OBJDIR)/erl_marshal.o: legacy/erl_marshal.c $(TARGET)/config.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_marshal.h \
- legacy/erl_eterm.h legacy/portability.h legacy/erl_malloc.h \
- legacy/erl_error.h legacy/erl_internal.h misc/eiext.h misc/putget.h
-$(ST_OBJDIR)/erl_timeout.o: legacy/erl_timeout.c $(TARGET)/config.h \
- legacy/erl_timeout.h
-$(ST_OBJDIR)/global_names.o: legacy/global_names.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
- ../include/erl_interface.h legacy/erl_connect.h
-$(ST_OBJDIR)/global_register.o: legacy/global_register.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h ../include/erl_interface.h
-$(ST_OBJDIR)/global_unregister.o: legacy/global_unregister.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
- ../include/erl_interface.h legacy/erl_connect.h
-$(ST_OBJDIR)/global_whereis.o: legacy/global_whereis.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
- ../include/erl_interface.h legacy/erl_connect.h
-
-$(MT_OBJDIR)/ei_connect.o: connect/ei_connect.c $(TARGET)/config.h \
- misc/eidef.h ../include/ei.h misc/eiext.h misc/ei_portio.h \
- misc/ei_internal.h connect/ei_connect_int.h misc/ei_locking.h \
- connect/eisend.h connect/eirecv.h misc/eimd5.h misc/putget.h \
- connect/ei_resolve.h epmd/ei_epmd.h
-$(MT_OBJDIR)/ei_resolve.o: connect/ei_resolve.c $(TARGET)/config.h \
- misc/eidef.h ../include/ei.h connect/ei_resolve.h misc/ei_locking.h
-$(MT_OBJDIR)/eirecv.o: connect/eirecv.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h connect/eirecv.h misc/ei_portio.h \
- misc/ei_internal.h misc/putget.h misc/ei_trace.h misc/show_msg.h
-$(MT_OBJDIR)/send.o: connect/send.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h connect/eisend.h misc/putget.h \
- connect/ei_connect_int.h misc/ei_internal.h misc/ei_trace.h \
- misc/show_msg.h
-$(MT_OBJDIR)/send_exit.o: connect/send_exit.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/ei_connect_int.h misc/ei_trace.h \
- misc/ei_internal.h misc/putget.h misc/show_msg.h
-$(MT_OBJDIR)/send_reg.o: connect/send_reg.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h connect/eisend.h misc/putget.h \
- connect/ei_connect_int.h misc/ei_internal.h misc/ei_trace.h \
- misc/show_msg.h
-$(MT_OBJDIR)/decode_atom.o: decode/decode_atom.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_big.o: decode/decode_big.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_bignum.o: decode/decode_bignum.c $(TARGET)/config.h
-$(MT_OBJDIR)/decode_binary.o: decode/decode_binary.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_boolean.o: decode/decode_boolean.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_char.o: decode/decode_char.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_double.o: decode/decode_double.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_fun.o: decode/decode_fun.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/ei_malloc.h decode/decode_skip.h misc/putget.h
-$(MT_OBJDIR)/decode_intlist.o: decode/decode_intlist.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_list_header.o: decode/decode_list_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_long.o: decode/decode_long.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_pid.o: decode/decode_pid.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_port.o: decode/decode_port.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_ref.o: decode/decode_ref.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_skip.o: decode/decode_skip.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- decode/decode_skip.h
-$(MT_OBJDIR)/decode_string.o: decode/decode_string.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_trace.o: decode/decode_trace.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/putget.h
-$(MT_OBJDIR)/decode_tuple_header.o: decode/decode_tuple_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_ulong.o: decode/decode_ulong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_version.o: decode/decode_version.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_longlong.o: decode/decode_longlong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_ulonglong.o: decode/decode_ulonglong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_atom.o: encode/encode_atom.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_bignum.o: encode/encode_bignum.c $(TARGET)/config.h
-$(MT_OBJDIR)/encode_binary.o: encode/encode_binary.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_boolean.o: encode/encode_boolean.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_char.o: encode/encode_char.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_double.o: encode/encode_double.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_fun.o: encode/encode_fun.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_list_header.o: encode/encode_list_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_long.o: encode/encode_long.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_pid.o: encode/encode_pid.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_port.o: encode/encode_port.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_ref.o: encode/encode_ref.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_string.o: encode/encode_string.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_trace.o: encode/encode_trace.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/putget.h
-$(MT_OBJDIR)/encode_tuple_header.o: encode/encode_tuple_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_ulong.o: encode/encode_ulong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_version.o: encode/encode_version.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_longlong.o: encode/encode_longlong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h misc/ei_x_encode.h
-$(MT_OBJDIR)/encode_ulonglong.o: encode/encode_ulonglong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h misc/ei_x_encode.h
-$(MT_OBJDIR)/epmd_port.o: epmd/epmd_port.c misc/ei_internal.h epmd/ei_epmd.h \
- misc/putget.h
-$(MT_OBJDIR)/epmd_publish.o: epmd/epmd_publish.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/ei_internal.h \
- misc/putget.h ../include/erl_interface.h epmd/ei_epmd.h
-$(MT_OBJDIR)/epmd_unpublish.o: epmd/epmd_unpublish.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/ei_internal.h \
- misc/putget.h ../include/erl_interface.h epmd/ei_epmd.h
-$(MT_OBJDIR)/ei_decode_term.o: misc/ei_decode_term.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/ei_decode_term.h misc/putget.h
-$(MT_OBJDIR)/ei_format.o: misc/ei_format.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/ei_malloc.h misc/ei_format.h
-$(MT_OBJDIR)/ei_locking.o: misc/ei_locking.c $(TARGET)/config.h \
- misc/ei_malloc.h misc/ei_locking.h
-$(MT_OBJDIR)/ei_malloc.o: misc/ei_malloc.c misc/ei_malloc.h
-$(MT_OBJDIR)/ei_portio.o: misc/ei_portio.c misc/ei_portio.h misc/ei_internal.h
-$(MT_OBJDIR)/ei_printterm.o: misc/ei_printterm.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/ei_printterm.h misc/ei_malloc.h
-$(MT_OBJDIR)/ei_pthreads.o: misc/ei_pthreads.c $(TARGET)/config.h \
- ../include/ei.h misc/ei_locking.h
-$(MT_OBJDIR)/ei_trace.o: misc/ei_trace.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/ei_trace.h
-$(MT_OBJDIR)/ei_x_encode.o: misc/ei_x_encode.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/ei_x_encode.h \
- misc/ei_malloc.h
-$(MT_OBJDIR)/eimd5.o: misc/eimd5.c misc/eimd5.h
-$(MT_OBJDIR)/get_type.o: misc/get_type.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h misc/putget.h
-$(MT_OBJDIR)/show_msg.o: misc/show_msg.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h misc/putget.h misc/ei_printterm.h \
- misc/ei_internal.h misc/show_msg.h
-$(MT_OBJDIR)/ei_compat.o: misc/ei_compat.c ../include/ei.h misc/ei_internal.h
-$(MT_OBJDIR)/hash_dohash.o: registry/hash_dohash.c registry/hash.h ../include/ei.h
-$(MT_OBJDIR)/hash_foreach.o: registry/hash_foreach.c registry/hash.h ../include/ei.h
-$(MT_OBJDIR)/hash_freetab.o: registry/hash_freetab.c registry/hash.h ../include/ei.h
-$(MT_OBJDIR)/hash_insert.o: registry/hash_insert.c registry/hash.h ../include/ei.h
-$(MT_OBJDIR)/hash_isprime.o: registry/hash_isprime.c registry/hash.h ../include/ei.h
-$(MT_OBJDIR)/hash_lookup.o: registry/hash_lookup.c registry/hash.h ../include/ei.h
-$(MT_OBJDIR)/hash_newtab.o: registry/hash_newtab.c registry/hash.h ../include/ei.h
-$(MT_OBJDIR)/hash_remove.o: registry/hash_remove.c registry/hash.h ../include/ei.h
-$(MT_OBJDIR)/hash_resize.o: registry/hash_resize.c registry/hash.h ../include/ei.h
-$(MT_OBJDIR)/hash_rlookup.o: registry/hash_rlookup.c registry/hash.h ../include/ei.h
-$(MT_OBJDIR)/reg_close.o: registry/reg_close.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_delete.o: registry/reg_delete.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_dirty.o: registry/reg_dirty.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_dump.o: registry/reg_dump.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- registry/reg.h registry/hash.h connect/eisend.h connect/eirecv.h \
- connect/ei_connect_int.h
-$(MT_OBJDIR)/reg_free.o: registry/reg_free.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_get.o: registry/reg_get.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_getf.o: registry/reg_getf.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_geti.o: registry/reg_geti.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_getp.o: registry/reg_getp.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_gets.o: registry/reg_gets.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_make.o: registry/reg_make.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_open.o: registry/reg_open.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_purge.o: registry/reg_purge.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_resize.o: registry/reg_resize.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_restore.o: registry/reg_restore.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- registry/reg.h registry/hash.h connect/eisend.h connect/eirecv.h \
- connect/ei_connect_int.h
-$(MT_OBJDIR)/reg_set.o: registry/reg_set.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_setf.o: registry/reg_setf.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_seti.o: registry/reg_seti.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_setp.o: registry/reg_setp.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_sets.o: registry/reg_sets.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_stat.o: registry/reg_stat.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_tabstat.o: registry/reg_tabstat.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/decode_term.o: legacy/decode_term.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h ../include/erl_interface.h
-$(MT_OBJDIR)/encode_term.o: legacy/encode_term.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h misc/ei_x_encode.h ../include/erl_interface.h \
- legacy/erl_marshal.h legacy/erl_eterm.h legacy/portability.h
-$(MT_OBJDIR)/erl_connect.o: legacy/erl_connect.c $(TARGET)/config.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_config.h \
- legacy/erl_connect.h legacy/erl_eterm.h legacy/portability.h \
- legacy/erl_malloc.h misc/putget.h connect/ei_connect_int.h \
- misc/ei_locking.h epmd/ei_epmd.h misc/ei_internal.h
-$(MT_OBJDIR)/erl_error.o: legacy/erl_error.c $(TARGET)/config.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_error.h
-$(MT_OBJDIR)/erl_eterm.o: legacy/erl_eterm.c misc/ei_locking.h \
- $(TARGET)/config.h connect/ei_resolve.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_eterm.h \
- legacy/portability.h legacy/erl_malloc.h legacy/erl_marshal.h \
- legacy/erl_error.h legacy/erl_internal.h misc/ei_internal.h
-$(MT_OBJDIR)/erl_fix_alloc.o: legacy/erl_fix_alloc.c $(TARGET)/config.h \
- misc/ei_locking.h ../include/erl_interface.h ../include/ei.h \
- legacy/erl_error.h legacy/erl_malloc.h legacy/erl_fix_alloc.h \
- legacy/erl_eterm.h legacy/portability.h
-$(MT_OBJDIR)/erl_format.o: legacy/erl_format.c ../include/erl_interface.h \
- ../include/ei.h legacy/erl_eterm.h legacy/portability.h \
- legacy/erl_malloc.h legacy/erl_error.h legacy/erl_internal.h
-$(MT_OBJDIR)/erl_malloc.o: legacy/erl_malloc.c ../include/erl_interface.h \
- ../include/ei.h legacy/erl_fix_alloc.h legacy/erl_malloc.h \
- legacy/erl_internal.h legacy/erl_eterm.h legacy/portability.h \
- misc/ei_malloc.h
-$(MT_OBJDIR)/erl_marshal.o: legacy/erl_marshal.c $(TARGET)/config.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_marshal.h \
- legacy/erl_eterm.h legacy/portability.h legacy/erl_malloc.h \
- legacy/erl_error.h legacy/erl_internal.h misc/eiext.h misc/putget.h
-$(MT_OBJDIR)/erl_timeout.o: legacy/erl_timeout.c $(TARGET)/config.h \
- legacy/erl_timeout.h
-$(MT_OBJDIR)/global_names.o: legacy/global_names.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
- ../include/erl_interface.h legacy/erl_connect.h
-$(MT_OBJDIR)/global_register.o: legacy/global_register.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h ../include/erl_interface.h
-$(MT_OBJDIR)/global_unregister.o: legacy/global_unregister.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
- ../include/erl_interface.h legacy/erl_connect.h
-$(MT_OBJDIR)/global_whereis.o: legacy/global_whereis.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
- ../include/erl_interface.h legacy/erl_connect.h
-
-$(MD_OBJDIR)/ei_connect.o: connect/ei_connect.c $(TARGET)/config.h \
- misc/eidef.h ../include/ei.h misc/eiext.h misc/ei_portio.h \
- misc/ei_internal.h connect/ei_connect_int.h misc/ei_locking.h \
- connect/eisend.h connect/eirecv.h misc/eimd5.h misc/putget.h \
- connect/ei_resolve.h epmd/ei_epmd.h
-$(MD_OBJDIR)/ei_resolve.o: connect/ei_resolve.c $(TARGET)/config.h \
- misc/eidef.h ../include/ei.h connect/ei_resolve.h misc/ei_locking.h
-$(MD_OBJDIR)/eirecv.o: connect/eirecv.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h connect/eirecv.h misc/ei_portio.h \
- misc/ei_internal.h misc/putget.h misc/ei_trace.h misc/show_msg.h
-$(MD_OBJDIR)/send.o: connect/send.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h connect/eisend.h misc/putget.h \
- connect/ei_connect_int.h misc/ei_internal.h misc/ei_trace.h \
- misc/show_msg.h
-$(MD_OBJDIR)/send_exit.o: connect/send_exit.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/ei_connect_int.h misc/ei_trace.h \
- misc/ei_internal.h misc/putget.h misc/show_msg.h
-$(MD_OBJDIR)/send_reg.o: connect/send_reg.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h connect/eisend.h misc/putget.h \
- connect/ei_connect_int.h misc/ei_internal.h misc/ei_trace.h \
- misc/show_msg.h
-$(MD_OBJDIR)/decode_atom.o: decode/decode_atom.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_big.o: decode/decode_big.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_bignum.o: decode/decode_bignum.c $(TARGET)/config.h
-$(MD_OBJDIR)/decode_binary.o: decode/decode_binary.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_boolean.o: decode/decode_boolean.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_char.o: decode/decode_char.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_double.o: decode/decode_double.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_fun.o: decode/decode_fun.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/ei_malloc.h decode/decode_skip.h misc/putget.h
-$(MD_OBJDIR)/decode_intlist.o: decode/decode_intlist.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_list_header.o: decode/decode_list_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_long.o: decode/decode_long.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_pid.o: decode/decode_pid.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_port.o: decode/decode_port.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_ref.o: decode/decode_ref.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_skip.o: decode/decode_skip.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- decode/decode_skip.h
-$(MD_OBJDIR)/decode_string.o: decode/decode_string.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_trace.o: decode/decode_trace.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/putget.h
-$(MD_OBJDIR)/decode_tuple_header.o: decode/decode_tuple_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_ulong.o: decode/decode_ulong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_version.o: decode/decode_version.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_longlong.o: decode/decode_longlong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_ulonglong.o: decode/decode_ulonglong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_atom.o: encode/encode_atom.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_bignum.o: encode/encode_bignum.c $(TARGET)/config.h
-$(MD_OBJDIR)/encode_binary.o: encode/encode_binary.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_boolean.o: encode/encode_boolean.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_char.o: encode/encode_char.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_double.o: encode/encode_double.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_fun.o: encode/encode_fun.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_list_header.o: encode/encode_list_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_long.o: encode/encode_long.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_pid.o: encode/encode_pid.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_port.o: encode/encode_port.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_ref.o: encode/encode_ref.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_string.o: encode/encode_string.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_trace.o: encode/encode_trace.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/putget.h
-$(MD_OBJDIR)/encode_tuple_header.o: encode/encode_tuple_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_ulong.o: encode/encode_ulong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_version.o: encode/encode_version.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_longlong.o: encode/encode_longlong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h misc/ei_x_encode.h
-$(MD_OBJDIR)/encode_ulonglong.o: encode/encode_ulonglong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h misc/ei_x_encode.h
-$(MD_OBJDIR)/epmd_port.o: epmd/epmd_port.c misc/ei_internal.h epmd/ei_epmd.h \
- misc/putget.h
-$(MD_OBJDIR)/epmd_publish.o: epmd/epmd_publish.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/ei_internal.h \
- misc/putget.h ../include/erl_interface.h epmd/ei_epmd.h
-$(MD_OBJDIR)/epmd_unpublish.o: epmd/epmd_unpublish.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/ei_internal.h \
- misc/putget.h ../include/erl_interface.h epmd/ei_epmd.h
-$(MD_OBJDIR)/ei_decode_term.o: misc/ei_decode_term.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/ei_decode_term.h misc/putget.h
-$(MD_OBJDIR)/ei_format.o: misc/ei_format.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/ei_malloc.h misc/ei_format.h
-$(MD_OBJDIR)/ei_locking.o: misc/ei_locking.c $(TARGET)/config.h \
- misc/ei_malloc.h misc/ei_locking.h
-$(MD_OBJDIR)/ei_malloc.o: misc/ei_malloc.c misc/ei_malloc.h
-$(MD_OBJDIR)/ei_portio.o: misc/ei_portio.c misc/ei_portio.h misc/ei_internal.h
-$(MD_OBJDIR)/ei_printterm.o: misc/ei_printterm.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/ei_printterm.h misc/ei_malloc.h
-$(MD_OBJDIR)/ei_pthreads.o: misc/ei_pthreads.c $(TARGET)/config.h \
- ../include/ei.h misc/ei_locking.h
-$(MD_OBJDIR)/ei_trace.o: misc/ei_trace.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/ei_trace.h
-$(MD_OBJDIR)/ei_x_encode.o: misc/ei_x_encode.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/ei_x_encode.h \
- misc/ei_malloc.h
-$(MD_OBJDIR)/eimd5.o: misc/eimd5.c misc/eimd5.h
-$(MD_OBJDIR)/get_type.o: misc/get_type.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h misc/putget.h
-$(MD_OBJDIR)/show_msg.o: misc/show_msg.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h misc/putget.h misc/ei_printterm.h \
- misc/ei_internal.h misc/show_msg.h
-$(MD_OBJDIR)/ei_compat.o: misc/ei_compat.c ../include/ei.h misc/ei_internal.h
-$(MD_OBJDIR)/hash_dohash.o: registry/hash_dohash.c registry/hash.h ../include/ei.h
-$(MD_OBJDIR)/hash_foreach.o: registry/hash_foreach.c registry/hash.h ../include/ei.h
-$(MD_OBJDIR)/hash_freetab.o: registry/hash_freetab.c registry/hash.h ../include/ei.h
-$(MD_OBJDIR)/hash_insert.o: registry/hash_insert.c registry/hash.h ../include/ei.h
-$(MD_OBJDIR)/hash_isprime.o: registry/hash_isprime.c registry/hash.h ../include/ei.h
-$(MD_OBJDIR)/hash_lookup.o: registry/hash_lookup.c registry/hash.h ../include/ei.h
-$(MD_OBJDIR)/hash_newtab.o: registry/hash_newtab.c registry/hash.h ../include/ei.h
-$(MD_OBJDIR)/hash_remove.o: registry/hash_remove.c registry/hash.h ../include/ei.h
-$(MD_OBJDIR)/hash_resize.o: registry/hash_resize.c registry/hash.h ../include/ei.h
-$(MD_OBJDIR)/hash_rlookup.o: registry/hash_rlookup.c registry/hash.h ../include/ei.h
-$(MD_OBJDIR)/reg_close.o: registry/reg_close.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_delete.o: registry/reg_delete.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_dirty.o: registry/reg_dirty.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_dump.o: registry/reg_dump.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- registry/reg.h registry/hash.h connect/eisend.h connect/eirecv.h \
- connect/ei_connect_int.h
-$(MD_OBJDIR)/reg_free.o: registry/reg_free.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_get.o: registry/reg_get.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_getf.o: registry/reg_getf.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_geti.o: registry/reg_geti.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_getp.o: registry/reg_getp.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_gets.o: registry/reg_gets.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_make.o: registry/reg_make.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_open.o: registry/reg_open.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_purge.o: registry/reg_purge.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_resize.o: registry/reg_resize.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_restore.o: registry/reg_restore.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- registry/reg.h registry/hash.h connect/eisend.h connect/eirecv.h \
- connect/ei_connect_int.h
-$(MD_OBJDIR)/reg_set.o: registry/reg_set.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_setf.o: registry/reg_setf.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_seti.o: registry/reg_seti.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_setp.o: registry/reg_setp.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_sets.o: registry/reg_sets.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_stat.o: registry/reg_stat.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_tabstat.o: registry/reg_tabstat.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/decode_term.o: legacy/decode_term.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h ../include/erl_interface.h
-$(MD_OBJDIR)/encode_term.o: legacy/encode_term.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h misc/ei_x_encode.h ../include/erl_interface.h \
- legacy/erl_marshal.h legacy/erl_eterm.h legacy/portability.h
-$(MD_OBJDIR)/erl_connect.o: legacy/erl_connect.c $(TARGET)/config.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_config.h \
- legacy/erl_connect.h legacy/erl_eterm.h legacy/portability.h \
- legacy/erl_malloc.h misc/putget.h connect/ei_connect_int.h \
- misc/ei_locking.h epmd/ei_epmd.h misc/ei_internal.h
-$(MD_OBJDIR)/erl_error.o: legacy/erl_error.c $(TARGET)/config.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_error.h
-$(MD_OBJDIR)/erl_eterm.o: legacy/erl_eterm.c misc/ei_locking.h \
- $(TARGET)/config.h connect/ei_resolve.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_eterm.h \
- legacy/portability.h legacy/erl_malloc.h legacy/erl_marshal.h \
- legacy/erl_error.h legacy/erl_internal.h misc/ei_internal.h
-$(MD_OBJDIR)/erl_fix_alloc.o: legacy/erl_fix_alloc.c $(TARGET)/config.h \
- misc/ei_locking.h ../include/erl_interface.h ../include/ei.h \
- legacy/erl_error.h legacy/erl_malloc.h legacy/erl_fix_alloc.h \
- legacy/erl_eterm.h legacy/portability.h
-$(MD_OBJDIR)/erl_format.o: legacy/erl_format.c ../include/erl_interface.h \
- ../include/ei.h legacy/erl_eterm.h legacy/portability.h \
- legacy/erl_malloc.h legacy/erl_error.h legacy/erl_internal.h
-$(MD_OBJDIR)/erl_malloc.o: legacy/erl_malloc.c ../include/erl_interface.h \
- ../include/ei.h legacy/erl_fix_alloc.h legacy/erl_malloc.h \
- legacy/erl_internal.h legacy/erl_eterm.h legacy/portability.h \
- misc/ei_malloc.h
-$(MD_OBJDIR)/erl_marshal.o: legacy/erl_marshal.c $(TARGET)/config.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_marshal.h \
- legacy/erl_eterm.h legacy/portability.h legacy/erl_malloc.h \
- legacy/erl_error.h legacy/erl_internal.h misc/eiext.h misc/putget.h
-$(MD_OBJDIR)/erl_timeout.o: legacy/erl_timeout.c $(TARGET)/config.h \
- legacy/erl_timeout.h
-$(MD_OBJDIR)/global_names.o: legacy/global_names.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
- ../include/erl_interface.h legacy/erl_connect.h
-$(MD_OBJDIR)/global_register.o: legacy/global_register.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h ../include/erl_interface.h
-$(MD_OBJDIR)/global_unregister.o: legacy/global_unregister.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
- ../include/erl_interface.h legacy/erl_connect.h
-$(MD_OBJDIR)/global_whereis.o: legacy/global_whereis.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
- ../include/erl_interface.h legacy/erl_connect.h
-
-$(MDD_OBJDIR)/ei_connect.o: connect/ei_connect.c $(TARGET)/config.h \
- misc/eidef.h ../include/ei.h misc/eiext.h misc/ei_portio.h \
- misc/ei_internal.h connect/ei_connect_int.h misc/ei_locking.h \
- connect/eisend.h connect/eirecv.h misc/eimd5.h misc/putget.h \
- connect/ei_resolve.h epmd/ei_epmd.h
-$(MDD_OBJDIR)/ei_resolve.o: connect/ei_resolve.c $(TARGET)/config.h \
- misc/eidef.h ../include/ei.h connect/ei_resolve.h misc/ei_locking.h
-$(MDD_OBJDIR)/eirecv.o: connect/eirecv.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h connect/eirecv.h misc/ei_portio.h \
- misc/ei_internal.h misc/putget.h misc/ei_trace.h misc/show_msg.h
-$(MDD_OBJDIR)/send.o: connect/send.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h connect/eisend.h misc/putget.h \
- connect/ei_connect_int.h misc/ei_internal.h misc/ei_trace.h \
- misc/show_msg.h
-$(MDD_OBJDIR)/send_exit.o: connect/send_exit.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/ei_connect_int.h misc/ei_trace.h \
- misc/ei_internal.h misc/putget.h misc/show_msg.h
-$(MDD_OBJDIR)/send_reg.o: connect/send_reg.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h connect/eisend.h misc/putget.h \
- connect/ei_connect_int.h misc/ei_internal.h misc/ei_trace.h \
- misc/show_msg.h
-$(MDD_OBJDIR)/decode_atom.o: decode/decode_atom.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_big.o: decode/decode_big.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_bignum.o: decode/decode_bignum.c $(TARGET)/config.h
-$(MDD_OBJDIR)/decode_binary.o: decode/decode_binary.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_boolean.o: decode/decode_boolean.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_char.o: decode/decode_char.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_double.o: decode/decode_double.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_fun.o: decode/decode_fun.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/ei_malloc.h decode/decode_skip.h misc/putget.h
-$(MDD_OBJDIR)/decode_intlist.o: decode/decode_intlist.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_list_header.o: decode/decode_list_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_long.o: decode/decode_long.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_pid.o: decode/decode_pid.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_port.o: decode/decode_port.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_ref.o: decode/decode_ref.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_skip.o: decode/decode_skip.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- decode/decode_skip.h
-$(MDD_OBJDIR)/decode_string.o: decode/decode_string.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_trace.o: decode/decode_trace.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/putget.h
-$(MDD_OBJDIR)/decode_tuple_header.o: decode/decode_tuple_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_ulong.o: decode/decode_ulong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_version.o: decode/decode_version.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_longlong.o: decode/decode_longlong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_ulonglong.o: decode/decode_ulonglong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_atom.o: encode/encode_atom.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_bignum.o: encode/encode_bignum.c $(TARGET)/config.h
-$(MDD_OBJDIR)/encode_binary.o: encode/encode_binary.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_boolean.o: encode/encode_boolean.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_char.o: encode/encode_char.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_double.o: encode/encode_double.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_fun.o: encode/encode_fun.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_list_header.o: encode/encode_list_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_long.o: encode/encode_long.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_pid.o: encode/encode_pid.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_port.o: encode/encode_port.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_ref.o: encode/encode_ref.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_string.o: encode/encode_string.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_trace.o: encode/encode_trace.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/putget.h
-$(MDD_OBJDIR)/encode_tuple_header.o: encode/encode_tuple_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_ulong.o: encode/encode_ulong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_version.o: encode/encode_version.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_longlong.o: encode/encode_longlong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h misc/ei_x_encode.h
-$(MDD_OBJDIR)/encode_ulonglong.o: encode/encode_ulonglong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h misc/ei_x_encode.h
-$(MDD_OBJDIR)/epmd_port.o: epmd/epmd_port.c misc/ei_internal.h epmd/ei_epmd.h \
- misc/putget.h
-$(MDD_OBJDIR)/epmd_publish.o: epmd/epmd_publish.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/ei_internal.h \
- misc/putget.h ../include/erl_interface.h epmd/ei_epmd.h
-$(MDD_OBJDIR)/epmd_unpublish.o: epmd/epmd_unpublish.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/ei_internal.h \
- misc/putget.h ../include/erl_interface.h epmd/ei_epmd.h
-$(MDD_OBJDIR)/ei_decode_term.o: misc/ei_decode_term.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/ei_decode_term.h misc/putget.h
-$(MDD_OBJDIR)/ei_format.o: misc/ei_format.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/ei_malloc.h misc/ei_format.h
-$(MDD_OBJDIR)/ei_locking.o: misc/ei_locking.c $(TARGET)/config.h \
- misc/ei_malloc.h misc/ei_locking.h
-$(MDD_OBJDIR)/ei_malloc.o: misc/ei_malloc.c misc/ei_malloc.h
-$(MDD_OBJDIR)/ei_portio.o: misc/ei_portio.c misc/ei_portio.h misc/ei_internal.h
-$(MDD_OBJDIR)/ei_printterm.o: misc/ei_printterm.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/ei_printterm.h misc/ei_malloc.h
-$(MDD_OBJDIR)/ei_pthreads.o: misc/ei_pthreads.c $(TARGET)/config.h \
- ../include/ei.h misc/ei_locking.h
-$(MDD_OBJDIR)/ei_trace.o: misc/ei_trace.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/ei_trace.h
-$(MDD_OBJDIR)/ei_x_encode.o: misc/ei_x_encode.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/ei_x_encode.h \
- misc/ei_malloc.h
-$(MDD_OBJDIR)/eimd5.o: misc/eimd5.c misc/eimd5.h
-$(MDD_OBJDIR)/get_type.o: misc/get_type.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h misc/putget.h
-$(MDD_OBJDIR)/show_msg.o: misc/show_msg.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h misc/putget.h misc/ei_printterm.h \
- misc/ei_internal.h misc/show_msg.h
-$(MDD_OBJDIR)/ei_compat.o: misc/ei_compat.c ../include/ei.h misc/ei_internal.h
-$(MDD_OBJDIR)/hash_dohash.o: registry/hash_dohash.c registry/hash.h ../include/ei.h
-$(MDD_OBJDIR)/hash_foreach.o: registry/hash_foreach.c registry/hash.h ../include/ei.h
-$(MDD_OBJDIR)/hash_freetab.o: registry/hash_freetab.c registry/hash.h ../include/ei.h
-$(MDD_OBJDIR)/hash_insert.o: registry/hash_insert.c registry/hash.h ../include/ei.h
-$(MDD_OBJDIR)/hash_isprime.o: registry/hash_isprime.c registry/hash.h ../include/ei.h
-$(MDD_OBJDIR)/hash_lookup.o: registry/hash_lookup.c registry/hash.h ../include/ei.h
-$(MDD_OBJDIR)/hash_newtab.o: registry/hash_newtab.c registry/hash.h ../include/ei.h
-$(MDD_OBJDIR)/hash_remove.o: registry/hash_remove.c registry/hash.h ../include/ei.h
-$(MDD_OBJDIR)/hash_resize.o: registry/hash_resize.c registry/hash.h ../include/ei.h
-$(MDD_OBJDIR)/hash_rlookup.o: registry/hash_rlookup.c registry/hash.h ../include/ei.h
-$(MDD_OBJDIR)/reg_close.o: registry/reg_close.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_delete.o: registry/reg_delete.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_dirty.o: registry/reg_dirty.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_dump.o: registry/reg_dump.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- registry/reg.h registry/hash.h connect/eisend.h connect/eirecv.h \
- connect/ei_connect_int.h
-$(MDD_OBJDIR)/reg_free.o: registry/reg_free.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_get.o: registry/reg_get.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_getf.o: registry/reg_getf.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_geti.o: registry/reg_geti.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_getp.o: registry/reg_getp.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_gets.o: registry/reg_gets.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_make.o: registry/reg_make.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_open.o: registry/reg_open.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_purge.o: registry/reg_purge.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_resize.o: registry/reg_resize.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_restore.o: registry/reg_restore.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- registry/reg.h registry/hash.h connect/eisend.h connect/eirecv.h \
- connect/ei_connect_int.h
-$(MDD_OBJDIR)/reg_set.o: registry/reg_set.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_setf.o: registry/reg_setf.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_seti.o: registry/reg_seti.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_setp.o: registry/reg_setp.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_sets.o: registry/reg_sets.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_stat.o: registry/reg_stat.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_tabstat.o: registry/reg_tabstat.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/decode_term.o: legacy/decode_term.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h ../include/erl_interface.h
-$(MDD_OBJDIR)/encode_term.o: legacy/encode_term.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h misc/ei_x_encode.h ../include/erl_interface.h \
- legacy/erl_marshal.h legacy/erl_eterm.h legacy/portability.h
-$(MDD_OBJDIR)/erl_connect.o: legacy/erl_connect.c $(TARGET)/config.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_config.h \
- legacy/erl_connect.h legacy/erl_eterm.h legacy/portability.h \
- legacy/erl_malloc.h misc/putget.h connect/ei_connect_int.h \
- misc/ei_locking.h epmd/ei_epmd.h misc/ei_internal.h
-$(MDD_OBJDIR)/erl_error.o: legacy/erl_error.c $(TARGET)/config.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_error.h
-$(MDD_OBJDIR)/erl_eterm.o: legacy/erl_eterm.c misc/ei_locking.h \
- $(TARGET)/config.h connect/ei_resolve.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_eterm.h \
- legacy/portability.h legacy/erl_malloc.h legacy/erl_marshal.h \
- legacy/erl_error.h legacy/erl_internal.h misc/ei_internal.h
-$(MDD_OBJDIR)/erl_fix_alloc.o: legacy/erl_fix_alloc.c $(TARGET)/config.h \
- misc/ei_locking.h ../include/erl_interface.h ../include/ei.h \
- legacy/erl_error.h legacy/erl_malloc.h legacy/erl_fix_alloc.h \
- legacy/erl_eterm.h legacy/portability.h
-$(MDD_OBJDIR)/erl_format.o: legacy/erl_format.c ../include/erl_interface.h \
- ../include/ei.h legacy/erl_eterm.h legacy/portability.h \
- legacy/erl_malloc.h legacy/erl_error.h legacy/erl_internal.h
-$(MDD_OBJDIR)/erl_malloc.o: legacy/erl_malloc.c ../include/erl_interface.h \
- ../include/ei.h legacy/erl_fix_alloc.h legacy/erl_malloc.h \
- legacy/erl_internal.h legacy/erl_eterm.h legacy/portability.h \
- misc/ei_malloc.h
-$(MDD_OBJDIR)/erl_marshal.o: legacy/erl_marshal.c $(TARGET)/config.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_marshal.h \
- legacy/erl_eterm.h legacy/portability.h legacy/erl_malloc.h \
- legacy/erl_error.h legacy/erl_internal.h misc/eiext.h misc/putget.h
-$(MDD_OBJDIR)/erl_timeout.o: legacy/erl_timeout.c $(TARGET)/config.h \
- legacy/erl_timeout.h
-$(MDD_OBJDIR)/global_names.o: legacy/global_names.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
- ../include/erl_interface.h legacy/erl_connect.h
-$(MDD_OBJDIR)/global_register.o: legacy/global_register.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h ../include/erl_interface.h
-$(MDD_OBJDIR)/global_unregister.o: legacy/global_unregister.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
- ../include/erl_interface.h legacy/erl_connect.h
-$(MDD_OBJDIR)/global_whereis.o: legacy/global_whereis.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
- ../include/erl_interface.h legacy/erl_connect.h
-
diff --git a/lib/erl_interface/src/prog/ei_fake_prog.c b/lib/erl_interface/src/prog/ei_fake_prog.c
index c7a16dc7c4..158464b385 100644
--- a/lib/erl_interface/src/prog/ei_fake_prog.c
+++ b/lib/erl_interface/src/prog/ei_fake_prog.c
@@ -98,11 +98,18 @@ int main(void)
EI_ULONGLONG ulonglongx = 0;
#endif
erlang_char_encoding enc;
+ ei_socket_callbacks cbs;
intx = erl_errno;
+ ei_init();
+
+ ei_close_connection(intx);
+
ei_connect_init(&xec, charp, charp, creation);
+ ei_connect_init_ussi(&xec, charp, charp, creation, &cbs, sizeof(cbs), NULL);
ei_connect_xinit (&xec, charp, charp, charp, thisipaddr, charp, creation);
+ ei_connect_xinit_ussi(&xec, charp, charp, charp, thisipaddr, charp, creation, &cbs, sizeof(cbs), NULL);
ei_connect(&xec, charp);
ei_xconnect (&xec, thisipaddr, charp);
@@ -121,6 +128,8 @@ int main(void)
ei_publish(&xec, intx);
ei_accept(&xec, intx, &conp);
ei_unpublish(&xec);
+ ei_listen(&xec, intp, intx);
+ ei_xlisten(&xec, thisipaddr, intp, intx);
ei_thisnodename(&xec);
ei_thishostname(&xec);
@@ -187,7 +196,7 @@ int main(void)
ei_decode_char(charp, intp, charp);
ei_decode_string(charp, intp, charp);
ei_decode_atom(charp, intp, charp);
- ei_decode_atom_as(charp, intp, charp, MAXATOMLEN_UTF8, ERLANG_WHATEVER, &enc, &enc);
+ ei_decode_atom_as(charp, intp, charp, MAXATOMLEN_UTF8, ERLANG_UTF8, &enc, &enc);
ei_decode_binary(charp, intp, (void *)0, longp);
ei_decode_fun(charp, intp, &efun);
free_fun(&efun);
diff --git a/lib/erl_interface/src/prog/erl_call.c b/lib/erl_interface/src/prog/erl_call.c
index 52ad6885e8..ab91157035 100644
--- a/lib/erl_interface/src/prog/erl_call.c
+++ b/lib/erl_interface/src/prog/erl_call.c
@@ -88,10 +88,6 @@
#include "ei_resolve.h"
#include "erl_start.h" /* FIXME remove dependency */
-#ifdef __WIN32__
-static void initWinSock(void);
-#endif
-
/*
* Some nice global variables
* (I don't think "nice" is the right word actually... -gordon)
@@ -157,6 +153,8 @@ int erl_call(int argc, char **argv)
char* progname = argv[0];
ei_cnode ec;
+ ei_init();
+
/* Get the command line options */
while (i < argc) {
if (argv[i][0] != '-') {
@@ -317,14 +315,6 @@ int erl_call(int argc, char **argv)
struct in_addr h_ipadr;
char* ct;
-#ifdef __WIN32__
- /*
- * FIXME Extremly ugly, but needed to get ei_gethostbyname() below
- * to work.
- */
- initWinSock();
-#endif
-
/* gethostname requires len to be max(hostname) + 1 */
if (gethostname(h_hostname, EI_MAXHOSTNAMELEN+1) < 0) {
fprintf(stderr,"erl_call: failed to get host name: %d\n", errno);
@@ -857,46 +847,6 @@ static void usage(const char *progname) {
exit(0);
}
-
-/***************************************************************************
- *
- * OS specific functions
- *
- ***************************************************************************/
-
-#ifdef __WIN32__
-/*
- * FIXME This should not be here. This is a quick fix to make erl_call
- * work at all on Windows NT.
- */
-static void initWinSock(void)
-{
- WORD wVersionRequested;
- WSADATA wsaData;
- int err;
- static int initialized;
-
- wVersionRequested = MAKEWORD(1, 1);
- if (!initialized) {
- initialized = 1;
- err = WSAStartup(wVersionRequested, &wsaData);
-
- if (err != 0) {
- fprintf(stderr,"erl_call: "
- "Can't initialize windows sockets: %d\n", err);
- }
-
- if ( LOBYTE( wsaData.wVersion ) != 1 ||
- HIBYTE( wsaData.wVersion ) != 1 ) {
- fprintf(stderr,"erl_call: This version of "
- "windows sockets not supported\n");
- WSACleanup();
- }
- }
-}
-#endif
-
-
/***************************************************************************
*
* Utility functions
diff --git a/lib/erl_interface/src/prog/erl_start.c b/lib/erl_interface/src/prog/erl_start.c
index 670a5900c9..c766f4780e 100644
--- a/lib/erl_interface/src/prog/erl_start.c
+++ b/lib/erl_interface/src/prog/erl_start.c
@@ -657,7 +657,7 @@ static int wait_for_erlang(int sockd, int magic, struct timeval *timeout)
gettimeofday(&now,NULL);
to.tv_sec = stop_time.tv_sec - now.tv_sec;
to.tv_usec = stop_time.tv_usec - now.tv_usec;
- while ((to.tv_usec <= 0) && (to.tv_sec >= 0)) {
+ while ((to.tv_usec < 0) && (to.tv_sec > 0)) {
to.tv_usec += 1000000;
to.tv_sec--;
}
diff --git a/lib/erl_interface/test/Makefile b/lib/erl_interface/test/Makefile
index 94f4b422d6..f8f2ef0156 100644
--- a/lib/erl_interface/test/Makefile
+++ b/lib/erl_interface/test/Makefile
@@ -33,6 +33,7 @@ MODULES= \
ei_format_SUITE \
ei_print_SUITE \
ei_tmo_SUITE \
+ erl_call_SUITE \
erl_connect_SUITE \
erl_global_SUITE \
erl_eterm_SUITE \
diff --git a/lib/erl_interface/test/erl_call_SUITE.erl b/lib/erl_interface/test/erl_call_SUITE.erl
new file mode 100644
index 0000000000..9e2b2e4251
--- /dev/null
+++ b/lib/erl_interface/test/erl_call_SUITE.erl
@@ -0,0 +1,96 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+-module(erl_call_SUITE).
+
+-include_lib("common_test/include/ct.hrl").
+
+-export([all/0, smoke/1]).
+
+all() ->
+ [smoke].
+
+smoke(Config) when is_list(Config) ->
+ ErlCall = find_erl_call(),
+ NameSwitch = case net_kernel:longnames() of
+ true ->
+ "-name";
+ false ->
+ "-sname"
+ end,
+ Name = atom_to_list(?MODULE)
+ ++ "-"
+ ++ integer_to_list(erlang:system_time(microsecond)),
+
+ ArgsList = ["-s", "-a", "erlang node", NameSwitch, Name],
+ io:format("erl_call: \"~ts\"\n~nargs list: ~p~n", [ErlCall, ArgsList]),
+ CmdRes = get_smoke_port_res(open_port({spawn_executable, ErlCall},
+ [{args, ArgsList}, eof]), []),
+ io:format("CmdRes: ~p~n", [CmdRes]),
+
+ [_, Hostname] = string:lexemes(atom_to_list(node()), "@"),
+ NodeName = list_to_atom(Name ++ "@" ++ Hostname),
+ io:format("NodeName: ~p~n~n", [NodeName]),
+
+ pong = net_adm:ping(NodeName),
+ rpc:cast(NodeName, erlang, halt, []),
+ NodeName = list_to_atom(string:trim(CmdRes, both, "'")),
+ ok.
+
+%
+% Utility functions...
+%
+
+find_erl_call() ->
+ ErlCallName = case os:type() of
+ {win32, _} -> "erl_call.exe";
+ _ -> "erl_call"
+ end,
+ LibDir = code:lib_dir(erl_interface),
+ InstalledErlCall = filename:join([LibDir, "bin", ErlCallName]),
+ TargetDir = erlang:system_info(system_architecture),
+ TargetErlCall = filename:join([LibDir, "bin", TargetDir, ErlCallName]),
+
+ try
+ lists:foreach(fun (F) ->
+ io:format("Checking: \"~ts\"~n", [F]),
+ case file:read_file_info(F) of
+ {ok, _} ->
+ throw(F);
+ _ ->
+ ok
+ end
+ end,
+ [InstalledErlCall, TargetErlCall]),
+ exit({missing, erl_call})
+ catch
+ throw:ErlCall ->
+ ErlCall
+ end.
+
+get_smoke_port_res(Port, Acc) when is_port(Port) ->
+ receive
+ {Port, {data, Data}} ->
+ get_smoke_port_res(Port, [Acc|Data]);
+ {Port, eof} ->
+ lists:flatten(Acc)
+ end.
+
diff --git a/lib/erl_interface/vsn.mk b/lib/erl_interface/vsn.mk
index 0ed5c07bca..5e63f75ab5 100644
--- a/lib/erl_interface/vsn.mk
+++ b/lib/erl_interface/vsn.mk
@@ -1,2 +1,2 @@
-EI_VSN = 3.11
+EI_VSN = 3.11.2
ERL_INTERFACE_VSN = $(EI_VSN)
diff --git a/lib/kernel/doc/src/notes.xml b/lib/kernel/doc/src/notes.xml
index 0c187eb19f..61bd598145 100644
--- a/lib/kernel/doc/src/notes.xml
+++ b/lib/kernel/doc/src/notes.xml
@@ -31,6 +31,21 @@
</header>
<p>This document describes the changes made to the Kernel application.</p>
+<section><title>Kernel 6.3.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fixed a performance regression when reading files
+ opened with the <c>compressed</c> flag.</p>
+ <p>
+ Own Id: OTP-15706 Aux Id: ERIERL-336 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Kernel 6.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/kernel/src/kernel.appup.src b/lib/kernel/src/kernel.appup.src
index 8fa3f5c588..aca3247c8f 100644
--- a/lib/kernel/src/kernel.appup.src
+++ b/lib/kernel/src/kernel.appup.src
@@ -43,7 +43,9 @@
{<<"^6\\.1\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
{<<"^6\\.2$">>,[restart_new_emulator]},
{<<"^6\\.2\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
- {<<"^6\\.2\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}],
+ {<<"^6\\.2\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
+ {<<"^6\\.3$">>,[restart_new_emulator]},
+ {<<"^6\\.3\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}],
[{<<"^5\\.3$">>,[restart_new_emulator]},
{<<"^5\\.3\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
{<<"^5\\.3\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
@@ -60,4 +62,6 @@
{<<"^6\\.1\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
{<<"^6\\.2$">>,[restart_new_emulator]},
{<<"^6\\.2\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
- {<<"^6\\.2\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}]}.
+ {<<"^6\\.2\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
+ {<<"^6\\.3$">>,[restart_new_emulator]},
+ {<<"^6\\.3\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}]}.
diff --git a/lib/kernel/src/raw_file_io_inflate.erl b/lib/kernel/src/raw_file_io_inflate.erl
index 7e9780310c..d3ed02dd03 100644
--- a/lib/kernel/src/raw_file_io_inflate.erl
+++ b/lib/kernel/src/raw_file_io_inflate.erl
@@ -26,7 +26,7 @@
-include("file_int.hrl").
--define(INFLATE_CHUNK_SIZE, (1 bsl 10)).
+-define(INFLATE_CHUNK_SIZE, (8 bsl 10)).
-define(GZIP_WBITS, (16 + 15)).
callback_mode() -> state_functions.
diff --git a/lib/kernel/vsn.mk b/lib/kernel/vsn.mk
index 7bebe1ba70..b1ae513223 100644
--- a/lib/kernel/vsn.mk
+++ b/lib/kernel/vsn.mk
@@ -1 +1 @@
-KERNEL_VSN = 6.3
+KERNEL_VSN = 6.3.1
diff --git a/lib/public_key/asn1/OTP-PKIX.asn1 b/lib/public_key/asn1/OTP-PKIX.asn1
index 9bcd99fba3..ff3250b383 100644
--- a/lib/public_key/asn1/OTP-PKIX.asn1
+++ b/lib/public_key/asn1/OTP-PKIX.asn1
@@ -233,9 +233,13 @@ countryName ATTRIBUTE-TYPE-AND-VALUE-CLASS ::= {
-- regarding how to handle and sometimes accept incorrect certificates
-- we define and use the type below instead of X520countryName
+ -- We accept utf8String encoding of the US-ASCII
+ -- country name code and the mix up with other country code systems
+ -- that uses three characters instead of two.
+
OTP-X520countryname ::= CHOICE {
- printableString PrintableString (SIZE (2)),
- utf8String UTF8String (SIZE (2))
+ printableString PrintableString (SIZE (2..3)),
+ utf8String UTF8String (SIZE (2..3))
}
serialNumber ATTRIBUTE-TYPE-AND-VALUE-CLASS ::= {
diff --git a/lib/snmp/include/snmp_types.hrl b/lib/snmp/include/snmp_types.hrl
index ffe30996dc..eff17a13a3 100644
--- a/lib/snmp/include/snmp_types.hrl
+++ b/lib/snmp/include/snmp_types.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -349,6 +349,9 @@
-define(view_included, 1).
-define(view_excluded, 2).
+-define(view_wildcard, 0).
+-define(view_exact, 1).
+
%%-----------------------------------------------------------------
%% From SNMPv2-SMI
diff --git a/lib/snmp/src/agent/depend.mk b/lib/snmp/src/agent/depend.mk
index 8eba50fa3b..49c7669e41 100644
--- a/lib/snmp/src/agent/depend.mk
+++ b/lib/snmp/src/agent/depend.mk
@@ -2,7 +2,7 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2016. All Rights Reserved.
+# Copyright Ericsson AB 2004-2019. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -24,6 +24,9 @@ $(EBIN)/snmpa_authentication_service.$(EMULATOR): \
$(EBIN)/snmpa_error_report.$(EMULATOR): \
snmpa_error_report.erl
+$(EBIN)/snmpa_get_mechanism.$(EMULATOR): \
+ snmpa_get_mechanism.erl
+
$(EBIN)/snmpa_network_interface.$(EMULATOR): \
snmpa_network_interface.erl
@@ -78,6 +81,20 @@ $(EBIN)/snmpa_error_logger.$(EMULATOR): \
snmpa_error_report.erl \
snmpa_error_logger.erl
+$(EBIN)/snmpa_set.$(EMULATOR): \
+ snmpa_set_mechanism.erl \
+ snmpa_set.erl \
+ ../misc/snmp_verbosity.hrl
+
+$(EBIN)/snmpa_get.$(EMULATOR): \
+ snmpa_get_mechanism.erl \
+ snmpa_get.erl \
+ ../misc/snmp_verbosity.hrl
+
+$(EBIN)/snmpa_get_lib.$(EMULATOR): \
+ snmpa_get_lib.erl \
+ ../misc/snmp_verbosity.hrl
+
$(EBIN)/snmpa_local_db.$(EMULATOR): \
snmpa_local_db.erl \
../misc/snmp_debug.hrl \
diff --git a/lib/snmp/src/agent/modules.mk b/lib/snmp/src/agent/modules.mk
index 0f8615588a..49cc158c2e 100644
--- a/lib/snmp/src/agent/modules.mk
+++ b/lib/snmp/src/agent/modules.mk
@@ -2,7 +2,7 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2016. All Rights Reserved.
+# Copyright Ericsson AB 2004-2019. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@ BEHAVIOUR_MODULES = \
snmpa_authentication_service \
snmpa_discovery_handler \
snmpa_error_report \
+ snmpa_get_mechanism \
snmpa_mib_storage \
snmpa_mib_data \
snmpa_network_interface \
@@ -30,12 +31,24 @@ BEHAVIOUR_MODULES = \
snmpa_notification_filter \
snmpa_set_mechanism
+MIB_MODULES = \
+ snmp_community_mib \
+ snmp_framework_mib \
+ snmp_notification_mib \
+ snmp_standard_mib \
+ snmp_target_mib \
+ snmp_user_based_sm_mib \
+ snmp_view_based_acm_mib
+
# snmpa is "plain" interface module but also defines some agent specific types
# and therefor must be compiled before the modules that use them, including
# the behaviour modules...
+# Some of the MIB modules also define types used elsewhere and therefor
+# has to be built before the other mods.
# snmpa_mib_data_ttln
MODULES = \
snmpa \
+ $(MIB_MODULES) \
$(BEHAVIOUR_MODULES) \
snmpa_acm \
snmpa_agent \
@@ -46,6 +59,8 @@ MODULES = \
snmpa_error \
snmpa_error_io \
snmpa_error_logger \
+ snmpa_get \
+ snmpa_get_lib \
snmpa_local_db \
snmpa_mib_storage_ets \
snmpa_mib_storage_dets \
@@ -66,17 +81,10 @@ MODULES = \
snmpa_trap \
snmpa_usm \
snmpa_vacm \
- snmp_community_mib \
- snmp_framework_mib \
snmp_generic \
snmp_generic_mnesia \
snmp_index \
- snmp_notification_mib \
- snmp_shadow_table \
- snmp_standard_mib \
- snmp_target_mib \
- snmp_user_based_sm_mib \
- snmp_view_based_acm_mib
+ snmp_shadow_table
INTERNAL_HRL_FILES = \
diff --git a/lib/snmp/src/agent/snmp_view_based_acm_mib.erl b/lib/snmp/src/agent/snmp_view_based_acm_mib.erl
index 02415e8036..c6eeb7cea2 100644
--- a/lib/snmp/src/agent/snmp_view_based_acm_mib.erl
+++ b/lib/snmp/src/agent/snmp_view_based_acm_mib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -37,6 +37,12 @@
%%
-export([emask2imask/1]).
+-export_type([
+ mibview/0,
+ internal_view_mask/0,
+ internal_view_mask_element/0,
+ internal_view_type/0
+ ]).
-include("snmp_types.hrl").
-include("SNMPv2-TC.hrl").
@@ -53,7 +59,13 @@
-type internal_view_mask() :: null | [internal_view_mask_element()].
--type internal_view_mask_element() :: 0 | 1.
+-type internal_view_mask_element() :: ?view_wildcard |
+ ?view_exact.
+-type internal_view_type() :: ?view_included | ?view_excluded.
+
+-type mibview() :: [{SubTree :: snmp:oid(),
+ Mask :: internal_view_mask(),
+ Type :: internal_view_type()}].
-type external_view_mask() :: octet_string(). % At most length of 16 octet
-type octet_string() :: [octet()].
diff --git a/lib/snmp/src/agent/snmpa_agent.erl b/lib/snmp/src/agent/snmpa_agent.erl
index 458b88359b..a521b3773b 100644
--- a/lib/snmp/src/agent/snmpa_agent.erl
+++ b/lib/snmp/src/agent/snmpa_agent.erl
@@ -28,7 +28,8 @@
%% External exports
-export([start_link/4, start_link/5, stop/1]).
--export([subagent_set/2,
+-export([subagent_get/3, subagent_get_next/3,
+ subagent_set/2,
load_mibs/3, unload_mibs/3,
which_mibs/1, whereis_mib/2, info/1,
register_subagent/3, unregister_subagent/2,
@@ -362,12 +363,19 @@ do_init(Prio, Parent, Ref, Options) ->
"~n Options: ~p",[Prio, Parent, Ref, Options]),
Mibs = get_mibs(Options),
+
SetModule = get_set_mechanism(Options),
put(set_module, SetModule),
+ ?vtrace("set-module: ~w", [SetModule]),
+
+ GetModule = get_get_mechanism(Options),
+ put(get_module, GetModule),
+ ?vtrace("get-module: ~w", [GetModule]),
%% OTP-3324. For AXD301.
AuthModule = get_authentication_service(Options),
put(auth_module, AuthModule),
+ ?vtrace("auth-module: ~w", [AuthModule]),
MultiT = get_multi_threaded(Options),
Vsns = get_versions(Options),
@@ -1133,7 +1141,7 @@ handle_call({subagent_get_next, MibView, Varbinds, PduData}, _From, S) ->
"~n PduData: ~p",
[MibView,Varbinds,PduData]),
put_pdu_data(PduData),
- {reply, do_get_next(MibView, Varbinds, infinity), S};
+ {reply, do_get_next(MibView, Varbinds), S};
handle_call({subagent_set, Arguments, PduData}, _From, S) ->
?vlog("[handle_call] subagent set:"
"~n Arguments: ~p"
@@ -1174,7 +1182,7 @@ handle_call({get_next, Vars, Context}, _From, S) ->
?vdebug("Varbinds: ~p",[Varbinds]),
MibView = snmpa_acm:get_root_mib_view(),
Reply =
- case do_get_next(MibView, Varbinds, infinity) of
+ case do_get_next(MibView, Varbinds) of
{noError, 0, NewVarbinds} ->
Vbs = lists:keysort(#varbind.org_index, NewVarbinds),
[{Oid,Val} || #varbind{oid = Oid, value = Val} <- Vbs];
@@ -2559,7 +2567,7 @@ process_pdu(#pdu{type = 'get-next-request', request_id = ReqId, varbinds = Vbs},
"~n ReqId: ~p"
"~n Vbs: ~p"
"~n MibView: ~p",[ReqId, Vbs, MibView]),
- Res = get_err(do_get_next(MibView, Vbs, infinity)),
+ Res = get_err(do_get_next(MibView, Vbs)),
?vtrace("get-next result: "
"~n ~p",[Res]),
{ErrStatus, ErrIndex, ResVarbinds} =
@@ -2650,8 +2658,7 @@ validate_next_v1_2([Vb | _Vbs], _MibView, _Res)
{noSuchName, Vb#varbind.org_index};
validate_next_v1_2([Vb | Vbs], MibView, Res)
when Vb#varbind.variabletype =:= 'Counter64' ->
- case validate_next_v1(
- do_get_next(MibView, [mk_next_oid(Vb)], infinity), MibView) of
+ case validate_next_v1( do_get_next(MibView, [mk_next_oid(Vb)]), MibView) of
{noError, 0, [NVb]} ->
validate_next_v1_2(Vbs, MibView, [NVb | Res]);
{Error, Index, _OrgVb} ->
@@ -2693,6 +2700,20 @@ mk_next_oid(Vb) ->
%%%-----------------------------------------------------------------
%%-----------------------------------------------------------------
+%% Func: do_get/2
+%% Purpose: Handles all VBs in a request that is inside the
+%% mibview (local).
+%% Returns: {noError, 0, ListOfNewVarbinds} |
+%% {ErrorStatus, ErrorIndex, []}
+%%-----------------------------------------------------------------
+
+do_get(UnsortedVarbinds, IsNotification) ->
+ Extra = get(net_if_data),
+ GetModule = get(get_module),
+ GetModule:do_get(UnsortedVarbinds, IsNotification, Extra).
+
+
+%%-----------------------------------------------------------------
%% Func: do_get/3
%% Purpose: do_get handles "getRequests".
%% Pre: incoming varbinds have type == 'NULL', value == unSpecified
@@ -2700,390 +2721,24 @@ mk_next_oid(Vb) ->
%% {ErrorStatus, ErrorIndex, []}
%%-----------------------------------------------------------------
-%% If this function is called from a worker-process, we *may*
-%% need to tunnel into the master-agent and let it do the
-%% work
+%% If this function is called from a worker-process (or other process),
+%% we *may* need to tunnel into the master-agent and let it do the work.
do_get(MibView, UnsortedVarbinds, IsNotification) ->
- do_get(MibView, UnsortedVarbinds, IsNotification, false).
+ Extra = get(net_if_data),
+ GetModule = get(get_module),
+ GetModule:do_get(MibView, UnsortedVarbinds, IsNotification, Extra).
do_get(MibView, UnsortedVarbinds, IsNotification, ForceMaster) ->
- ?vtrace("do_get -> entry with"
- "~n MibView: ~p"
- "~n UnsortedVarbinds: ~p"
- "~n IsNotification: ~p",
- [MibView, UnsortedVarbinds, IsNotification]),
case (whereis(snmp_master_agent) =:= self()) of
false when (ForceMaster =:= true) ->
- %% I am a lowly worker process, handoff to the master agent
PduData = get_pdu_data(),
call(snmp_master_agent,
{do_get, MibView, UnsortedVarbinds, IsNotification, PduData});
-
- _ ->
- %% This is me, the master, so go ahead
- {OutSideView, InSideView} =
- split_vbs_view(UnsortedVarbinds, MibView),
- {Error, Index, NewVbs} =
- do_get(InSideView, IsNotification),
- {Error, Index, NewVbs ++ OutSideView}
-
- end.
-
-
-split_vbs_view(Vbs, MibView) ->
- ?vtrace("split the varbinds view", []),
- split_vbs_view(Vbs, MibView, [], []).
-
-split_vbs_view([Vb | Vbs], MibView, Out, In) ->
- case snmpa_acm:validate_mib_view(Vb#varbind.oid, MibView) of
- true -> split_vbs_view(Vbs, MibView, Out, [Vb | In]);
- false -> split_vbs_view(Vbs, MibView,
- [Vb#varbind{value = noSuchObject} | Out], In)
- end;
-split_vbs_view([], _MibView, Out, In) ->
- {Out, In}.
-
-do_get(UnsortedVarbinds, IsNotification) ->
- {MyVarbinds, SubagentVarbinds} = sort_varbindlist(UnsortedVarbinds),
- case do_get_local(MyVarbinds, [], IsNotification) of
- {noError, 0, NewMyVarbinds} ->
- case do_get_subagents(SubagentVarbinds, IsNotification) of
- {noError, 0, NewSubagentVarbinds} ->
- {noError, 0, NewMyVarbinds ++ NewSubagentVarbinds};
- {ErrorStatus, ErrorIndex, _} ->
- {ErrorStatus, ErrorIndex, []}
- end;
- {ErrorStatus, ErrorIndex, _} ->
- {ErrorStatus, ErrorIndex, []}
+ _ ->
+ do_get(MibView, UnsortedVarbinds, IsNotification)
end.
-%%-----------------------------------------------------------------
-%% Func: do_get_local/3
-%% Purpose: Loop the variablebindings list. We know that each varbind
-%% in that list belongs to us.
-%% Returns: {noError, 0, ListOfNewVarbinds} |
-%% {ErrorStatus, ErrorIndex, []}
-%%-----------------------------------------------------------------
-do_get_local([Vb | Vbs], Res, IsNotification) ->
- case try_get(Vb, IsNotification) of
- NewVb when is_record(NewVb, varbind) ->
- do_get_local(Vbs, [NewVb | Res], IsNotification);
- ListOfNewVb when is_list(ListOfNewVb) ->
- do_get_local(Vbs, lists:append(ListOfNewVb, Res), IsNotification);
- {error, Error, OrgIndex} ->
- {Error, OrgIndex, []}
- end;
-do_get_local([], Res, _IsNotification) ->
- {noError, 0, Res}.
-
-%%-----------------------------------------------------------------
-%% Func: do_get_subagents/2
-%% Purpose: Loop the list of varbinds for different subagents.
-%% For each of them, call sub_agent_get to retreive
-%% the values for them.
-%% Returns: {noError, 0, ListOfNewVarbinds} |
-%% {ErrorStatus, ErrorIndex, []}
-%%-----------------------------------------------------------------
-do_get_subagents(SubagentVarbinds, IsNotification) ->
- do_get_subagents(SubagentVarbinds, [], IsNotification).
-do_get_subagents([{SubAgentPid, SAVbs} | Tail], Res, IsNotification) ->
- {_SAOids, Vbs} = sa_split(SAVbs),
- case catch subagent_get(SubAgentPid, Vbs, IsNotification) of
- {noError, 0, NewVbs} ->
- do_get_subagents(Tail, lists:append(NewVbs, Res), IsNotification);
- {ErrorStatus, ErrorIndex, _} ->
- {ErrorStatus, ErrorIndex, []};
- {'EXIT', Reason} ->
- user_err("Lost contact with subagent (get) ~w. Using genErr",
- [Reason]),
- {genErr, 0, []}
- end;
-do_get_subagents([], Res, _IsNotification) ->
- {noError, 0, Res}.
-
-
-%%-----------------------------------------------------------------
-%% Func: try_get/2
-%% Returns: {error, ErrorStatus, OrgIndex} |
-%% #varbind |
-%% List of #varbind
-%%-----------------------------------------------------------------
-try_get(IVb, IsNotification) when is_record(IVb, ivarbind) ->
- ?vtrace("try_get(ivarbind) -> entry with"
- "~n IVb: ~p", [IVb]),
- get_var_value_from_ivb(IVb, IsNotification);
-try_get({TableOid, TableVbs}, IsNotification) ->
- ?vtrace("try_get(table) -> entry with"
- "~n TableOid: ~p"
- "~n TableVbs: ~p", [TableOid, TableVbs]),
- [#ivarbind{mibentry = MibEntry}|_] = TableVbs,
- {NoAccessVbs, AccessVbs} =
- check_all_table_vbs(TableVbs, IsNotification, [], []),
- case get_tab_value_from_mib(MibEntry, TableOid, AccessVbs) of
- {error, ErrorStatus, OrgIndex} ->
- {error, ErrorStatus, OrgIndex};
- NVbs ->
- NVbs ++ NoAccessVbs
- end.
-
-%%-----------------------------------------------------------------
-%% Make sure all requested columns are accessible.
-%%-----------------------------------------------------------------
-check_all_table_vbs([IVb| IVbs], IsNotification, NoA, A) ->
- #ivarbind{mibentry = Me, varbind = Vb} = IVb,
- case Me#me.access of
- 'not-accessible' ->
- NNoA = [Vb#varbind{value = noSuchInstance} | NoA],
- check_all_table_vbs(IVbs, IsNotification, NNoA, A);
- 'accessible-for-notify' when IsNotification =:= false ->
- NNoA = [Vb#varbind{value = noSuchInstance} | NoA],
- check_all_table_vbs(IVbs, IsNotification, NNoA, A);
- 'write-only' ->
- NNoA = [Vb#varbind{value = noSuchInstance} | NoA],
- check_all_table_vbs(IVbs, IsNotification, NNoA, A);
- _ ->
- check_all_table_vbs(IVbs, IsNotification, NoA, [IVb | A])
- end;
-check_all_table_vbs([], _IsNotification, NoA, A) -> {NoA, A}.
-
-%%-----------------------------------------------------------------
-%% Returns: {error, ErrorStatus, OrgIndex} |
-%% #varbind
-%%-----------------------------------------------------------------
-get_var_value_from_ivb(IVb, IsNotification)
- when IVb#ivarbind.status =:= noError ->
- ?vtrace("get_var_value_from_ivb(noError) -> entry", []),
- #ivarbind{mibentry = Me, varbind = Vb} = IVb,
- #varbind{org_index = OrgIndex, oid = Oid} = Vb,
- case Me#me.access of
- 'not-accessible' ->
- Vb#varbind{value = noSuchInstance};
- 'accessible-for-notify' when IsNotification =:= false ->
- Vb#varbind{value = noSuchInstance};
- 'write-only' ->
- Vb#varbind{value = noSuchInstance};
- _ ->
- case get_var_value_from_mib(Me, Oid) of
- {value, Type, Value} ->
- Vb#varbind{variabletype = Type, value = Value};
- {error, ErrorStatus} ->
- {error, ErrorStatus, OrgIndex}
- end
- end;
-get_var_value_from_ivb(#ivarbind{status = Status, varbind = Vb}, _) ->
- ?vtrace("get_var_value_from_ivb(~p) -> entry", [Status]),
- Vb#varbind{value = Status}.
-
-%%-----------------------------------------------------------------
-%% Func: get_var_value_from_mib/1
-%% Purpose:
-%% Returns: {error, ErrorStatus} |
-%% {value, Type, Value}
-%%-----------------------------------------------------------------
-%% Pre: Oid is a correct instance Oid (lookup checked that).
-%% Returns: A correct return value (see make_value_a_correct_value)
-get_var_value_from_mib(#me{entrytype = variable,
- asn1_type = ASN1Type,
- mfa = {Mod, Func, Args}},
- _Oid) ->
- ?vtrace("get_var_value_from_mib(variable) -> entry when"
- "~n Mod: ~p"
- "~n Func: ~p"
- "~n Args: ~p", [Mod, Func, Args]),
- Result = (catch dbg_apply(Mod, Func, [get | Args])),
- % mib shall return {value, <a-nice-value-within-range>} |
- % {noValue, noSuchName} (v1) |
- % {noValue, noSuchObject | noSuchInstance} (v2, v1)
- % everything else (including 'genErr') will generate 'genErr'.
- make_value_a_correct_value(Result, ASN1Type, {Mod, Func, Args});
-
-get_var_value_from_mib(#me{entrytype = table_column,
- oid = MeOid,
- asn1_type = ASN1Type,
- mfa = {Mod, Func, Args}},
- Oid) ->
- ?vtrace("get_var_value_from_mib(table_column) -> entry when"
- "~n MeOid: ~p"
- "~n Mod: ~p"
- "~n Func: ~p"
- "~n Args: ~p"
- "~n Oid: ~p", [MeOid, Mod, Func, Args, Oid]),
- Col = lists:last(MeOid),
- Indexes = snmp_misc:diff(Oid, MeOid),
- [Result] = (catch dbg_apply(Mod, Func, [get, Indexes, [Col] | Args])),
- make_value_a_correct_value(Result, ASN1Type,
- {Mod, Func, Args, Indexes, Col}).
-
-
-%% For table operations we need to pass RestOid down to the table-function.
-%% Its up to the table-function to check for noSuchInstance (ex: a
-%% non-existing row).
-%% Returns: {error, ErrorStatus, OrgIndex} |
-%% {value, Type, Value}
-get_tab_value_from_mib(#me{mfa = {Mod, Func, Args}}, TableOid, TableVbs) ->
- ?vtrace("get_tab_value_from_mib -> entry when"
- "~n Mod: ~p"
- "~n Func: ~p"
- "~n Args: ~p", [Mod, Func, Args]),
- TableOpsWithShortOids = deletePrefixes(TableOid, TableVbs),
- SortedVBsRows = snmpa_svbl:sort_varbinds_rows(TableOpsWithShortOids),
- case get_value_all_rows(SortedVBsRows, Mod, Func, Args, []) of
- {Error, Index} ->
- #ivarbind{varbind = Vb} = lists:nth(Index, TableVbs),
- {error, Error, Vb#varbind.org_index};
- ListOfValues ->
- merge_varbinds_and_value(TableVbs, ListOfValues)
- end.
-
-%%-----------------------------------------------------------------
-%% Values is a scrambled list of {CorrectValue, Index}, where Index
-%% is index into the #ivarbind list. So for each Value, we must
-%% find the corresponding #ivarbind, and merge them into a new
-%% #varbind.
-%% The Values list comes from validate_tab_res.
-%%-----------------------------------------------------------------
-merge_varbinds_and_value(IVbs, [{{value, Type, Value}, Index} | Values]) ->
- #ivarbind{varbind = Vb} = lists:nth(Index, IVbs),
- [Vb#varbind{variabletype = Type, value = Value} |
- merge_varbinds_and_value(IVbs, Values)];
-merge_varbinds_and_value(_, []) -> [].
-
-get_value_all_rows([{[], OrgCols} | Rows], Mod, Func, Args, Res) ->
- ?vtrace("get_value_all_rows -> entry when"
- "~n OrgCols: ~p", [OrgCols]),
- Cols = [{{value, noValue, noSuchInstance}, Index} ||
- {_Col, _ASN1Type, Index} <- OrgCols],
- NewRes = lists:append(Cols, Res),
- get_value_all_rows(Rows, Mod, Func, Args, NewRes);
-get_value_all_rows([{RowIndex, OrgCols} | Rows], Mod, Func, Args, Res) ->
- ?vtrace("get_value_all_rows -> entry when"
- "~n RowIndex: ~p"
- "~n OrgCols: ~p", [RowIndex, OrgCols]),
- {DOrgCols, Dup} = remove_duplicates(OrgCols),
- Cols = delete_index(DOrgCols),
- Result = (catch dbg_apply(Mod, Func, [get, RowIndex, Cols | Args])),
- case validate_tab_res(Result, DOrgCols, {Mod, Func, Args}) of
- Values when is_list(Values) ->
- NVals = restore_duplicates(Dup, Values),
- NewRes = lists:append(NVals, Res),
- get_value_all_rows(Rows, Mod, Func, Args, NewRes);
- {error, ErrorStatus, Index} ->
- validate_err(row_set, {ErrorStatus, Index}, {Mod, Func, Args})
- end;
-get_value_all_rows([], _Mod, _Func, _Args, Res) ->
- ?vtrace("get_value_all_rows -> entry when done"
- "~n Res: ~p", [Res]),
- Res.
-
-%%-----------------------------------------------------------------
-%% Returns: list of {ShortOid, ASN1TYpe}
-%%-----------------------------------------------------------------
-deletePrefixes(Prefix, [#ivarbind{varbind = Varbind, mibentry = ME} | Vbs]) ->
- #varbind{oid = Oid} = Varbind,
- [{snmp_misc:diff(Oid, Prefix), ME#me.asn1_type} |
- deletePrefixes(Prefix, Vbs)];
-deletePrefixes(_Prefix, []) -> [].
-
-%%-----------------------------------------------------------------
-%% Args: {RowIndex, list of {ShortOid, ASN1Type}}
-%% Returns: list of Col
-%%-----------------------------------------------------------------
-delete_index([{Col, _Val, _OrgIndex} | T]) ->
- [Col | delete_index(T)];
-delete_index([]) -> [].
-
-%%-----------------------------------------------------------------
-%% This function is called before 'get' on a table, and removes
-%% any duplicate columns. It returns {Cols, DupInfo}. The Cols
-%% are the unique columns. The instrumentation function is
-%% called to get the values. These values, together with the
-%% DupInfo, is later passed to restore_duplicates, which uses
-%% the retrieved values to reconstruct the original column list,
-%% but with the retrieved value for each column.
-%%-----------------------------------------------------------------
-remove_duplicates(Cols) ->
- remove_duplicates(Cols, [], []).
-
-
-remove_duplicates([{Col, V1, OrgIdx1}, {Col, V2, OrgIdx2} | T], NCols, Dup) ->
- remove_duplicates([{Col, V1, OrgIdx1} | T], NCols,
- [{Col, V2, OrgIdx2} | Dup]);
-remove_duplicates([Col | T], NCols, Dup) ->
- remove_duplicates(T, [Col | NCols], Dup);
-remove_duplicates([], NCols, Dup) ->
- {lists:reverse(NCols), lists:reverse(Dup)}.
-
-restore_duplicates([], Cols) ->
- [{Val, OrgIndex} || {_Col, Val, OrgIndex} <- Cols];
-restore_duplicates([{Col, _Val2, OrgIndex2} | Dup],
- [{Col, NVal, OrgIndex1} | Cols]) ->
- [{NVal, OrgIndex2} |
- restore_duplicates(Dup, [{Col, NVal, OrgIndex1} | Cols])];
-restore_duplicates(Dup, [{_Col, Val, OrgIndex} | T]) ->
- [{Val, OrgIndex} | restore_duplicates(Dup, T)].
-
-%% Maps the column number to Index.
-% col_to_index(0, _) -> 0;
-% col_to_index(Col, [{Col, _, Index}|_]) ->
-% Index;
-% col_to_index(Col, [_|Cols]) ->
-% col_to_index(Col, Cols).
-
-%%-----------------------------------------------------------------
-%% Three cases:
-%% 1) All values ok
-%% 2) table_func returned {Error, ...}
-%% 3) Some value in Values list is erroneous.
-%% Args: Value is a list of values from table_func(get..)
-%% OrgCols is a list with {Col, ASN1Type, OrgIndex}
-%% each element in Values and OrgCols correspond to each
-%% other.
-%%-----------------------------------------------------------------
-validate_tab_res(Values, OrgCols, Mfa) when is_list(Values) ->
- {_Col, _ASN1Type, OneIdx} = hd(OrgCols),
- validate_tab_res(Values, OrgCols, Mfa, [], OneIdx);
-validate_tab_res({noValue, Error}, OrgCols, Mfa) ->
- Values = lists:duplicate(length(OrgCols), {noValue, Error}),
- validate_tab_res(Values, OrgCols, Mfa);
-validate_tab_res({genErr, Col}, OrgCols, Mfa) ->
- case lists:keysearch(Col, 1, OrgCols) of
- {value, {_Col, _ASN1Type, Index}} ->
- {error, genErr, Index};
- _ ->
- user_err("Invalid column in {genErr, ~w} from ~w (get)",
- [Col, Mfa]),
- [{_Col, _ASN1Type, Index} | _] = OrgCols,
- {error, genErr, Index}
- end;
-validate_tab_res(genErr, [{_Col, __ASN1Type, Index} | _OrgCols], _Mfa) ->
- {error, genErr, Index};
-validate_tab_res(Error, [{_Col, _ASN1Type, Index} | _OrgCols], Mfa) ->
- user_err("Invalid return value ~w from ~w (get)",[Error, Mfa]),
- {error, genErr, Index}.
-
-validate_tab_res([Value | Values],
- [{Col, ASN1Type, Index} | OrgCols],
- Mfa, Res, I) ->
- %% This one makes it possible to return a list of genErr, which
- %% is not allowed according to the manual. But that's ok, as
- %% everything else will generate a genErr! (the only problem is
- %% that it won't generate a user_error).
- case make_value_a_correct_value(Value, ASN1Type, Mfa) of
- {error, ErrorStatus} ->
- {error, ErrorStatus, Index};
- CorrectValue ->
- NewRes = [{Col, CorrectValue, Index} | Res],
- validate_tab_res(Values, OrgCols, Mfa, NewRes, I)
- end;
-validate_tab_res([], [], _Mfa, Res, _I) ->
- lists:reverse(Res);
-validate_tab_res([], [{_Col, _ASN1Type, Index}|_], Mfa, _Res, _I) ->
- user_err("Too few values returned from ~w (get)", [Mfa]),
- {error, genErr, Index};
-validate_tab_res(_TooMany, [], Mfa, _Res, I) ->
- user_err("Too many values returned from ~w (get)", [Mfa]),
- {error, genErr, I}.
%%%-----------------------------------------------------------------
@@ -3125,491 +2780,12 @@ validate_tab_res(_TooMany, [], Mfa, _Res, I) ->
%% subagent must be considered to be very rare.
%%-----------------------------------------------------------------
-%% It may be a bit agressive to check this already,
-%% but since it is a security measure, it makes sense.
-do_get_next(_MibView, UnsortedVarbinds, GbMaxVBs)
- when (is_integer(GbMaxVBs) andalso (length(UnsortedVarbinds) > GbMaxVBs)) ->
- {tooBig, 0, []}; % What is the correct index in this case?
-do_get_next(MibView, UnsortedVBs, GbMaxVBs) ->
- ?vt("do_get_next -> entry when"
- "~n MibView: ~p"
- "~n UnsortedVBs: ~p", [MibView, UnsortedVBs]),
- SortedVBs = oid_sort_vbs(UnsortedVBs),
- ?vt("do_get_next -> "
- "~n SortedVBs: ~p", [SortedVBs]),
- next_loop_varbinds([], SortedVBs, MibView, [], [], GbMaxVBs).
-
-oid_sort_vbs(Vbs) ->
- lists:keysort(#varbind.oid, Vbs).
-
-next_loop_varbinds(_, Vbs, _MibView, Res, _LAVb, GbMaxVBs)
- when (is_integer(GbMaxVBs) andalso
- ((length(Vbs) + length(Res)) > GbMaxVBs)) ->
- {tooBig, 0, []}; % What is the correct index in this case?
-
-%% LAVb is Last Accessible Vb
-next_loop_varbinds([], [Vb | Vbs], MibView, Res, LAVb, GbMaxVBs) ->
- ?vt("next_loop_varbinds -> entry when"
- "~n Vb: ~p"
- "~n MibView: ~p", [Vb, MibView]),
- case varbind_next(Vb, MibView) of
- endOfMibView ->
- ?vt("next_loop_varbind -> endOfMibView", []),
- RVb = if LAVb =:= [] -> Vb;
- true -> LAVb
- end,
- NewVb = RVb#varbind{variabletype = 'NULL', value = endOfMibView},
- next_loop_varbinds([], Vbs, MibView, [NewVb | Res], [], GbMaxVBs);
-
- {variable, ME, VarOid} when ((ME#me.access =/= 'not-accessible') andalso
- (ME#me.access =/= 'write-only') andalso
- (ME#me.access =/= 'accessible-for-notify')) ->
- ?vt("next_loop_varbind -> variable: "
- "~n ME: ~p"
- "~n VarOid: ~p", [ME, VarOid]),
- case try_get_instance(Vb, ME) of
- {value, noValue, _NoSuchSomething} ->
- ?vt("next_loop_varbind -> noValue", []),
- %% Try next one
- NewVb = Vb#varbind{oid = VarOid,
- value = 'NULL'},
- next_loop_varbinds([], [NewVb | Vbs], MibView, Res, [],
- GbMaxVBs);
- {value, Type, Value} ->
- ?vt("next_loop_varbind -> value"
- "~n Type: ~p"
- "~n Value: ~p", [Type, Value]),
- NewVb = Vb#varbind{oid = VarOid,
- variabletype = Type,
- value = Value},
- next_loop_varbinds([], Vbs, MibView, [NewVb | Res], [],
- GbMaxVBs);
- {error, ErrorStatus} ->
- ?vdebug("next loop varbinds:"
- "~n ErrorStatus: ~p",[ErrorStatus]),
- {ErrorStatus, Vb#varbind.org_index, []}
- end;
- {variable, _ME, VarOid} ->
- ?vt("next_loop_varbind -> variable: "
- "~n VarOid: ~p", [VarOid]),
- RVb = if LAVb =:= [] -> Vb;
- true -> LAVb
- end,
- NewVb = Vb#varbind{oid = VarOid, value = 'NULL'},
- next_loop_varbinds([], [NewVb | Vbs], MibView, Res, RVb, GbMaxVBs);
- {table, TableOid, TableRestOid, ME} ->
- ?vt("next_loop_varbind -> table: "
- "~n TableOid: ~p"
- "~n TableRestOid: ~p"
- "~n ME: ~p", [TableOid, TableRestOid, ME]),
- next_loop_varbinds({table, TableOid, ME,
- [{tab_oid(TableRestOid), Vb}]},
- Vbs, MibView, Res, [], GbMaxVBs);
- {subagent, SubAgentPid, SAOid} ->
- ?vt("next_loop_varbind -> subagent: "
- "~n SubAgentPid: ~p"
- "~n SAOid: ~p", [SubAgentPid, SAOid]),
- NewVb = Vb#varbind{variabletype = 'NULL', value = 'NULL'},
- next_loop_varbinds({subagent, SubAgentPid, SAOid, [NewVb]},
- Vbs, MibView, Res, [], GbMaxVBs)
- end;
-next_loop_varbinds({table, TableOid, ME, TabOids},
- [Vb | Vbs], MibView, Res, _LAVb, GbMaxVBs) ->
- ?vt("next_loop_varbinds(table) -> entry with"
- "~n TableOid: ~p"
- "~n Vb: ~p", [TableOid, Vb]),
- case varbind_next(Vb, MibView) of
- {table, TableOid, TableRestOid, _ME} ->
- next_loop_varbinds({table, TableOid, ME,
- [{tab_oid(TableRestOid), Vb} | TabOids]},
- Vbs, MibView, Res, [], GbMaxVBs);
- _ ->
- case get_next_table(ME, TableOid, TabOids, MibView) of
- {ok, TabRes, TabEndOfTabVbs} ->
- NewVbs = lists:append(TabEndOfTabVbs, [Vb | Vbs]),
- NewRes = lists:append(TabRes, Res),
- next_loop_varbinds([], NewVbs, MibView, NewRes, [],
- GbMaxVBs);
- {ErrorStatus, OrgIndex} ->
- ?vdebug("next loop varbinds: next varbind"
- "~n ErrorStatus: ~p"
- "~n OrgIndex: ~p",
- [ErrorStatus,OrgIndex]),
- {ErrorStatus, OrgIndex, []}
- end
- end;
-next_loop_varbinds({table, TableOid, ME, TabOids},
- [], MibView, Res, _LAVb, GbMaxVBs) ->
- ?vt("next_loop_varbinds(table) -> entry with"
- "~n TableOid: ~p", [TableOid]),
- case get_next_table(ME, TableOid, TabOids, MibView) of
- {ok, TabRes, TabEndOfTabVbs} ->
- ?vt("next_loop_varbinds(table) -> get_next_table result:"
- "~n TabRes: ~p"
- "~n TabEndOfTabVbs: ~p", [TabRes, TabEndOfTabVbs]),
- NewRes = lists:append(TabRes, Res),
- next_loop_varbinds([], TabEndOfTabVbs, MibView, NewRes, [],
- GbMaxVBs);
- {ErrorStatus, OrgIndex} ->
- ?vdebug("next loop varbinds: next table"
- "~n ErrorStatus: ~p"
- "~n OrgIndex: ~p",
- [ErrorStatus,OrgIndex]),
- {ErrorStatus, OrgIndex, []}
- end;
-next_loop_varbinds({subagent, SAPid, SAOid, SAVbs},
- [Vb | Vbs], MibView, Res, _LAVb, GbMaxVBs) ->
- ?vt("next_loop_varbinds(subagent) -> entry with"
- "~n SAPid: ~p"
- "~n SAOid: ~p"
- "~n Vb: ~p", [SAPid, SAOid, Vb]),
- case varbind_next(Vb, MibView) of
- {subagent, _SubAgentPid, SAOid} ->
- next_loop_varbinds({subagent, SAPid, SAOid,
- [Vb | SAVbs]},
- Vbs, MibView, Res, [], GbMaxVBs);
- _ ->
- case get_next_sa(SAPid, SAOid, SAVbs, MibView) of
- {ok, SARes, SAEndOfMibViewVbs} ->
- NewVbs = lists:append(SAEndOfMibViewVbs, [Vb | Vbs]),
- NewRes = lists:append(SARes, Res),
- next_loop_varbinds([], NewVbs, MibView, NewRes, [],
- GbMaxVBs);
- {noSuchName, OrgIndex} ->
- %% v1 reply, treat this Vb as endOfMibView, and try again
- %% for the others.
- case lists:keysearch(OrgIndex, #varbind.org_index, SAVbs) of
- {value, EVb} ->
- NextOid = next_oid(SAOid),
- EndOfVb =
- EVb#varbind{oid = NextOid,
- value = {endOfMibView, NextOid}},
- case lists:delete(EVb, SAVbs) of
- [] ->
- next_loop_varbinds([], [EndOfVb, Vb | Vbs],
- MibView, Res, [],
- GbMaxVBs);
- TryAgainVbs ->
- next_loop_varbinds({subagent, SAPid, SAOid,
- TryAgainVbs},
- [EndOfVb, Vb | Vbs],
- MibView, Res, [],
- GbMaxVBs)
- end;
- false ->
- %% bad index from subagent
- {genErr, (hd(SAVbs))#varbind.org_index, []}
- end;
- {ErrorStatus, OrgIndex} ->
- ?vdebug("next loop varbinds: next subagent"
- "~n Vb: ~p"
- "~n ErrorStatus: ~p"
- "~n OrgIndex: ~p",
- [Vb,ErrorStatus,OrgIndex]),
- {ErrorStatus, OrgIndex, []}
- end
- end;
-next_loop_varbinds({subagent, SAPid, SAOid, SAVbs},
- [], MibView, Res, _LAVb, GbMaxVBs) ->
- ?vt("next_loop_varbinds(subagent) -> entry with"
- "~n SAPid: ~p"
- "~n SAOid: ~p", [SAPid, SAOid]),
- case get_next_sa(SAPid, SAOid, SAVbs, MibView) of
- {ok, SARes, SAEndOfMibViewVbs} ->
- NewRes = lists:append(SARes, Res),
- next_loop_varbinds([], SAEndOfMibViewVbs, MibView, NewRes, [],
- GbMaxVBs);
- {noSuchName, OrgIndex} ->
- %% v1 reply, treat this Vb as endOfMibView, and try again for
- %% the others.
- case lists:keysearch(OrgIndex, #varbind.org_index, SAVbs) of
- {value, EVb} ->
- NextOid = next_oid(SAOid),
- EndOfVb = EVb#varbind{oid = NextOid,
- value = {endOfMibView, NextOid}},
- case lists:delete(EVb, SAVbs) of
- [] ->
- next_loop_varbinds([], [EndOfVb], MibView, Res, [],
- GbMaxVBs);
- TryAgainVbs ->
- next_loop_varbinds({subagent, SAPid, SAOid,
- TryAgainVbs},
- [EndOfVb], MibView, Res, [],
- GbMaxVBs)
- end;
- false ->
- %% bad index from subagent
- {genErr, (hd(SAVbs))#varbind.org_index, []}
- end;
- {ErrorStatus, OrgIndex} ->
- ?vdebug("next loop varbinds: next subagent"
- "~n ErrorStatus: ~p"
- "~n OrgIndex: ~p",
- [ErrorStatus,OrgIndex]),
- {ErrorStatus, OrgIndex, []}
- end;
-next_loop_varbinds([], [], _MibView, Res, _LAVb, _GbMaxVBs) ->
- ?vt("next_loop_varbinds -> entry when done", []),
- {noError, 0, Res}.
-
-try_get_instance(_Vb, #me{mfa = {M, F, A}, asn1_type = ASN1Type}) ->
- ?vtrace("try_get_instance -> entry with"
- "~n M: ~p"
- "~n F: ~p"
- "~n A: ~p", [M,F,A]),
- Result = (catch dbg_apply(M, F, [get | A])),
- % mib shall return {value, <a-nice-value-within-range>} |
- % {noValue, noSuchName} (v1) |
- % {noValue, noSuchObject | noSuchInstance} (v2, v1)
- % everything else (including 'genErr') will generate 'genErr'.
- make_value_a_correct_value(Result, ASN1Type, {M, F, A}).
-
-tab_oid([]) -> [0];
-tab_oid(X) -> X.
-
-
-%%-----------------------------------------------------------------
-%% Perform a next, using the varbinds Oid if value is simple
-%% value. If value is {endOf<something>, NextOid}, use NextOid.
-%% This case happens when a table has returned endOfTable, or
-%% a subagent has returned endOfMibView.
-%%-----------------------------------------------------------------
-varbind_next(#varbind{value = Value, oid = Oid}, MibView) ->
- ?vt("varbind_next -> entry with"
- "~n Value: ~p"
- "~n Oid: ~p"
- "~n MibView: ~p", [Value, Oid, MibView]),
- case Value of
- {endOfTable, NextOid} ->
- snmpa_mib:next(get(mibserver), NextOid, MibView);
- {endOfMibView, NextOid} ->
- snmpa_mib:next(get(mibserver), NextOid, MibView);
- _ ->
- snmpa_mib:next(get(mibserver), Oid, MibView)
- end.
-
-get_next_table(#me{mfa = {M, F, A}}, TableOid, TableOids, MibView) ->
- % We know that all TableOids have at least a column number as oid
- ?vt("get_next_table -> entry with"
- "~n M: ~p"
- "~n F: ~p"
- "~n A: ~p"
- "~n TableOid: ~p"
- "~n TableOids: ~p"
- "~n MibView: ~p", [M, F, A, TableOid, TableOids, MibView]),
- Sorted = snmpa_svbl:sort_varbinds_rows(TableOids),
- case get_next_values_all_rows(Sorted, M,F,A, [], TableOid) of
- NewVbs when is_list(NewVbs) ->
- ?vt("get_next_table -> "
- "~n NewVbs: ~p", [NewVbs]),
- % We must now check each Vb for endOfTable and that it is
- % in the MibView. If not, it becomes a endOfTable. We
- % collect all of these together.
- transform_tab_next_result(NewVbs, {[], []}, MibView);
- {ErrorStatus, OrgIndex} ->
- {ErrorStatus, OrgIndex}
- end.
-
-get_next_values_all_rows([Row | Rows], M, F, A, Res, TabOid) ->
- {RowIndex, TableOids} = Row,
- Cols = delete_index(TableOids),
- ?vt("get_next_values_all_rows -> "
- "~n Cols: ~p", [Cols]),
- Result = (catch dbg_apply(M, F, [get_next, RowIndex, Cols | A])),
- ?vt("get_next_values_all_rows -> "
- "~n Result: ~p", [Result]),
- case validate_tab_next_res(Result, TableOids, {M, F, A}, TabOid) of
- Values when is_list(Values) ->
- ?vt("get_next_values_all_rows -> "
- "~n Values: ~p", [Values]),
- NewRes = lists:append(Values, Res),
- get_next_values_all_rows(Rows, M, F, A, NewRes, TabOid);
- {ErrorStatus, OrgIndex} ->
- {ErrorStatus, OrgIndex}
- end;
-get_next_values_all_rows([], _M, _F, _A, Res, _TabOid) ->
- Res.
-
-transform_tab_next_result([Vb | Vbs], {Res, EndOfs}, MibView) ->
- case Vb#varbind.value of
- {endOfTable, _} ->
-%% ?vtrace("transform_tab_next_result -> endOfTable: "
-%% "split varbinds",[]),
-%% R = split_varbinds(Vbs, Res, [Vb | EndOfs]),
-%% ?vtrace("transform_tab_next_result -> "
-%% "~n R: ~p", [R]),
-%% R;
- split_varbinds(Vbs, Res, [Vb | EndOfs]);
- _ ->
- case snmpa_acm:validate_mib_view(Vb#varbind.oid, MibView) of
- true ->
- transform_tab_next_result(Vbs, {[Vb|Res], EndOfs},MibView);
- _ ->
- Oid = Vb#varbind.oid,
- NewEndOf = Vb#varbind{value = {endOfTable, Oid}},
- transform_tab_next_result(Vbs, {Res, [NewEndOf | EndOfs]},
- MibView)
- end
- end;
-transform_tab_next_result([], {Res, EndOfs}, _MibView) ->
- ?vt("transform_tab_next_result -> entry with: "
- "~n Res: ~p"
- "~n EndIfs: ~p",[Res, EndOfs]),
- {ok, Res, EndOfs}.
-
-%%-----------------------------------------------------------------
-%% Three cases:
-%% 1) All values ok
-%% 2) table_func returned {Error, ...}
-%% 3) Some value in Values list is erroneous.
-%% Args: Value is a list of values from table_func(get_next, ...)
-%% TableOids is a list of {TabRestOid, OrgVb}
-%% each element in Values and TableOids correspond to each
-%% other.
-%% Returns: List of NewVarbinds |
-%% {ErrorStatus, OrgIndex}
-%% (In the NewVarbinds list, the value may be endOfTable)
-%%-----------------------------------------------------------------
-validate_tab_next_res(Values, TableOids, Mfa, TabOid) ->
- ?vt("validate_tab_next_res -> entry with: "
- "~n Values: ~p"
- "~n TableOids: ~p"
- "~n Mfa: ~p"
- "~n TabOid: ~p", [Values, TableOids, Mfa, TabOid]),
- {_Col, _ASN1Type, OneIdx} = hd(TableOids),
- validate_tab_next_res(Values, TableOids, Mfa, [], TabOid,
- next_oid(TabOid), OneIdx).
-validate_tab_next_res([{NextOid, Value} | Values],
- [{_ColNo, OrgVb, _Index} | TableOids],
- Mfa, Res, TabOid, TabNextOid, I) ->
- ?vt("validate_tab_next_res -> entry with: "
- "~n NextOid: ~p"
- "~n Value: ~p"
- "~n Values: ~p"
- "~n TableOids: ~p"
- "~n Mfa: ~p"
- "~n TabOid: ~p",
- [NextOid, Value, Values, TableOids, Mfa, TabOid]),
- #varbind{org_index = OrgIndex} = OrgVb,
- ?vt("validate_tab_next_res -> OrgIndex: ~p", [OrgIndex]),
- NextCompleteOid = lists:append(TabOid, NextOid),
- case snmpa_mib:lookup(get(mibserver), NextCompleteOid) of
- {table_column, #me{asn1_type = ASN1Type}, _TableEntryOid} ->
- ?vt("validate_tab_next_res -> ASN1Type: ~p", [ASN1Type]),
- case make_value_a_correct_value({value, Value}, ASN1Type, Mfa) of
- {error, ErrorStatus} ->
- ?vt("validate_tab_next_res -> "
- "~n ErrorStatus: ~p", [ErrorStatus]),
- {ErrorStatus, OrgIndex};
- {value, Type, NValue} ->
- ?vt("validate_tab_next_res -> "
- "~n Type: ~p"
- "~n NValue: ~p", [Type, NValue]),
- NewVb = OrgVb#varbind{oid = NextCompleteOid,
- variabletype = Type, value = NValue},
- validate_tab_next_res(Values, TableOids, Mfa,
- [NewVb | Res], TabOid, TabNextOid, I)
- end;
- Error ->
- user_err("Invalid oid ~w from ~w (get_next). Using genErr => ~p",
- [NextOid, Mfa, Error]),
- {genErr, OrgIndex}
- end;
-validate_tab_next_res([endOfTable | Values],
- [{_ColNo, OrgVb, _Index} | TableOids],
- Mfa, Res, TabOid, TabNextOid, I) ->
- ?vt("validate_tab_next_res(endOfTable) -> entry with: "
- "~n Values: ~p"
- "~n OrgVb: ~p"
- "~n TableOids: ~p"
- "~n Mfa: ~p"
- "~n Res: ~p"
- "~n TabOid: ~p"
- "~n TabNextOid: ~p"
- "~n I: ~p",
- [Values, OrgVb, TableOids, Mfa, Res, TabOid, TabNextOid, I]),
- NewVb = OrgVb#varbind{value = {endOfTable, TabNextOid}},
- validate_tab_next_res(Values, TableOids, Mfa, [NewVb | Res],
- TabOid, TabNextOid, I);
-validate_tab_next_res([], [], _Mfa, Res, _TabOid, _TabNextOid, _I) ->
- Res;
-validate_tab_next_res([], [{_Col, _OrgVb, Index}|_], Mfa, _Res, _, _, _I) ->
- user_err("Too few values returned from ~w (get_next)", [Mfa]),
- {genErr, Index};
-validate_tab_next_res({genErr, ColNumber}, OrgCols,
- Mfa, _Res, _TabOid, _TabNextOid, _I) ->
- OrgIndex = snmpa_svbl:col_to_orgindex(ColNumber, OrgCols),
- validate_err(table_next, {genErr, OrgIndex}, Mfa);
-validate_tab_next_res({error, Reason}, [{_ColNo, OrgVb, _Index} | _TableOids],
- Mfa, _Res, _TabOid, _TabNextOid, _I) ->
- #varbind{org_index = OrgIndex} = OrgVb,
- user_err("Erroneous return value ~w from ~w (get_next)",
- [Reason, Mfa]),
- {genErr, OrgIndex};
-validate_tab_next_res(Error, [{_ColNo, OrgVb, _Index} | _TableOids],
- Mfa, _Res, _TabOid, _TabNextOid, _I) ->
- #varbind{org_index = OrgIndex} = OrgVb,
- user_err("Invalid return value ~w from ~w (get_next)",
- [Error, Mfa]),
- {genErr, OrgIndex};
-validate_tab_next_res(TooMany, [], Mfa, _Res, _, _, I) ->
- user_err("Too many values ~w returned from ~w (get_next)",
- [TooMany, Mfa]),
- {genErr, I}.
-
-%%-----------------------------------------------------------------
-%% Func: get_next_sa/4
-%% Purpose: Loop the list of varbinds for the subagent.
-%% Call subagent_get_next to retreive
-%% the next varbinds.
-%% Returns: {ok, ListOfNewVbs, ListOfEndOfMibViewsVbs} |
-%% {ErrorStatus, ErrorIndex}
-%%-----------------------------------------------------------------
-get_next_sa(SAPid, SAOid, SAVbs, MibView) ->
- case catch subagent_get_next(SAPid, MibView, SAVbs) of
- {noError, 0, NewVbs} ->
- NewerVbs = transform_sa_next_result(NewVbs,SAOid,next_oid(SAOid)),
- split_varbinds(NewerVbs, [], []);
- {ErrorStatus, ErrorIndex, _} ->
- {ErrorStatus, ErrorIndex};
- {'EXIT', Reason} ->
- user_err("Lost contact with subagent (next) ~w. Using genErr",
- [Reason]),
- {genErr, 0}
- end.
-%%-----------------------------------------------------------------
-%% Check for wrong prefix returned or endOfMibView, and convert
-%% into {endOfMibView, SANextOid}.
-%%-----------------------------------------------------------------
-transform_sa_next_result([Vb | Vbs], SAOid, SANextOid)
- when Vb#varbind.value =:= endOfMibView ->
- [Vb#varbind{value = {endOfMibView, SANextOid}} |
- transform_sa_next_result(Vbs, SAOid, SANextOid)];
-transform_sa_next_result([Vb | Vbs], SAOid, SANextOid) ->
- case lists:prefix(SAOid, Vb#varbind.oid) of
- true ->
- [Vb | transform_sa_next_result(Vbs, SAOid, SANextOid)];
- _ ->
- [Vb#varbind{oid = SANextOid, value = {endOfMibView, SANextOid}} |
- transform_sa_next_result(Vbs, SAOid, SANextOid)]
- end;
-transform_sa_next_result([], _SAOid, _SANextOid) ->
- [].
-
-split_varbinds([Vb | Vbs], Res, EndOfs) ->
- case Vb#varbind.value of
- {endOfMibView, _} -> split_varbinds(Vbs, Res, [Vb | EndOfs]);
- {endOfTable, _} -> split_varbinds(Vbs, Res, [Vb | EndOfs]);
- _ -> split_varbinds(Vbs, [Vb | Res], EndOfs)
- end;
-split_varbinds([], Res, EndOfs) -> {ok, Res, EndOfs}.
+do_get_next(MibView, UnsortedVarbinds) ->
+ Extra = get(net_if_data),
+ GetModule = get(get_module),
+ GetModule:do_get_next(MibView, UnsortedVarbinds, Extra).
-next_oid(Oid) ->
- case lists:reverse(Oid) of
- [H | T] -> lists:reverse([H+1 | T]);
- [] -> []
- end.
%%%-----------------------------------------------------------------
@@ -3623,200 +2799,12 @@ next_oid(Oid) ->
%%%-----------------------------------------------------------------
do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds, GbMaxVBs) ->
- ?vtrace("do_get_bulk -> entry with"
- "~n MibView: ~p"
- "~n NonRepeaters: ~p"
- "~n MaxRepetitions: ~p"
- "~n PduMS: ~p"
- "~n Varbinds: ~p"
- "~n GbMaxVBs: ~p",
- [MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds, GbMaxVBs]),
- {NonRepVbs, RestVbs} = split_vbs(NonRepeaters, Varbinds, []),
- ?vt("do_get_bulk -> split: "
- "~n NonRepVbs: ~p"
- "~n RestVbs: ~p", [NonRepVbs, RestVbs]),
- case do_get_next(MibView, NonRepVbs, GbMaxVBs) of
- {noError, 0, UResNonRepVbs} ->
- ?vt("do_get_bulk -> next noError: "
- "~n UResNonRepVbs: ~p", [UResNonRepVbs]),
- ResNonRepVbs = lists:keysort(#varbind.org_index, UResNonRepVbs),
- %% Decode the first varbinds, produce a reversed list of
- %% listOfBytes.
- case (catch enc_vbs(PduMS - ?empty_pdu_size, ResNonRepVbs)) of
- {error, Idx, Reason} ->
- user_err("failed encoding varbind ~w:~n~p", [Idx, Reason]),
- {genErr, Idx, []};
- {SizeLeft, Res} when is_integer(SizeLeft) and is_list(Res) ->
- ?vtrace("do_get_bulk -> encoded: "
- "~n SizeLeft: ~p"
- "~n Res: ~w", [SizeLeft, Res]),
- case (catch do_get_rep(SizeLeft, MibView, MaxRepetitions,
- RestVbs, Res,
- length(UResNonRepVbs), GbMaxVBs)) of
- {error, Idx, Reason} ->
- user_err("failed encoding varbind ~w:~n~p",
- [Idx, Reason]),
- {genErr, Idx, []};
- Res when is_list(Res) ->
- ?vtrace("do get bulk -> Res: "
- "~n ~w", [Res]),
- {noError, 0, conv_res(Res)};
- {noError, 0, Data} = OK ->
- ?vtrace("do get bulk -> OK: "
- "~n length(Data): ~w", [length(Data)]),
- OK;
- Else ->
- ?vtrace("do get bulk -> Else: "
- "~n ~w", [Else]),
- Else
- end;
- Res when is_list(Res) ->
- {noError, 0, conv_res(Res)}
- end;
+ Extra = get(net_if_data),
+ GetModule = get(get_module),
+ GetModule:do_get_bulk(MibView, NonRepeaters, MaxRepetitions,
+ PduMS, Varbinds, GbMaxVBs,
+ Extra).
- {ErrorStatus, Index, _} ->
- ?vdebug("do get bulk: "
- "~n ErrorStatus: ~p"
- "~n Index: ~p",[ErrorStatus, Index]),
- {ErrorStatus, Index, []}
- end.
-
-% sz(L) when list(L) -> length(L);
-% sz(B) when binary(B) -> size(B);
-% sz(_) -> unknown.
-
-split_vbs(N, Varbinds, Res) when N =< 0 -> {Res, Varbinds};
-split_vbs(N, [H | T], Res) -> split_vbs(N-1, T, [H | Res]);
-split_vbs(_N, [], Res) -> {Res, []}.
-
-enc_vbs(SizeLeft, Vbs) ->
- ?vt("enc_vbs -> entry with"
- "~n SizeLeft: ~w", [SizeLeft]),
- Fun = fun(Vb, {Sz, Res}) when Sz > 0 ->
- ?vt("enc_vbs -> (fun) entry with"
- "~n Vb: ~p"
- "~n Sz: ~p"
- "~n Res: ~w", [Vb, Sz, Res]),
- case (catch snmp_pdus:enc_varbind(Vb)) of
- {'EXIT', Reason} ->
- ?vtrace("enc_vbs -> encode failed: "
- "~n Reason: ~p", [Reason]),
- throw({error, Vb#varbind.org_index, Reason});
- X ->
- ?vt("enc_vbs -> X: ~w", [X]),
- Lx = length(X),
- ?vt("enc_vbs -> Lx: ~w", [Lx]),
- if
- Lx < Sz ->
- {Sz - length(X), [X | Res]};
- true ->
- throw(Res)
- end
- end;
- (_Vb, {_Sz, [_H | T]}) ->
- ?vt("enc_vbs -> (fun) entry with"
- "~n T: ~p", [T]),
- throw(T);
- (_Vb, {_Sz, []}) ->
- ?vt("enc_vbs -> (fun) entry", []),
- throw([])
- end,
- lists:foldl(Fun, {SizeLeft, []}, Vbs).
-
-do_get_rep(Sz, MibView, MaxRepetitions, Varbinds, Res, GbNumVBs, GbMaxVBs)
- when MaxRepetitions >= 0 ->
- do_get_rep(Sz, MibView, 0, MaxRepetitions, Varbinds, Res,
- GbNumVBs, GbMaxVBs);
-do_get_rep(Sz, MibView, _MaxRepetitions, Varbinds, Res, GbNumVBs, GbMaxVBs) ->
- do_get_rep(Sz, MibView, 0, 0, Varbinds, Res, GbNumVBs, GbMaxVBs).
-
-conv_res(ResVarbinds) ->
- conv_res(ResVarbinds, []).
-conv_res([VbListOfBytes | T], Bytes) ->
- conv_res(T, VbListOfBytes ++ Bytes);
-conv_res([], Bytes) ->
- Bytes.
-
-%% The only other value, then a positive integer, is infinity.
-do_get_rep(_Sz, _MibView, Count, Max, _, _Res, GbNumVBs, GbMaxVBs)
- when (is_integer(GbMaxVBs) andalso (GbNumVBs > GbMaxVBs)) ->
- ?vinfo("Max Get-BULK VBs limit (~w) exceeded (~w) when:"
- "~n Count: ~p"
- "~n Max: ~p", [GbMaxVBs, GbNumVBs, Count, Max]),
- {tooBig, 0, []};
-do_get_rep(_Sz, _MibView, Max, Max, _, Res, _GbNumVBs, _GbMaxVBs) ->
- ?vt("do_get_rep -> done when: "
- "~n Res: ~p", [Res]),
- {noError, 0, conv_res(Res)};
-do_get_rep(Sz, MibView, Count, Max, Varbinds, Res, GbNumVBs, GbMaxVBs) ->
- ?vt("do_get_rep -> entry when: "
- "~n Sz: ~p"
- "~n Count: ~p"
- "~n Res: ~w", [Sz, Count, Res]),
- case try_get_bulk(Sz, MibView, Varbinds, GbMaxVBs) of
- {noError, NextVarbinds, SizeLeft, Res2} ->
- ?vt("do_get_rep -> noError: "
- "~n SizeLeft: ~p"
- "~n Res2: ~p", [SizeLeft, Res2]),
- do_get_rep(SizeLeft, MibView, Count+1, Max, NextVarbinds,
- Res2 ++ Res,
- GbNumVBs + length(Varbinds), GbMaxVBs);
- {endOfMibView, _NextVarbinds, _SizeLeft, Res2} ->
- ?vt("do_get_rep -> endOfMibView: "
- "~n Res2: ~p", [Res2]),
- {noError, 0, conv_res(Res2 ++ Res)};
- {ErrorStatus, Index} ->
- ?vtrace("do_get_rep -> done when error: "
- "~n ErrorStatus: ~p"
- "~n Index: ~p", [ErrorStatus, Index]),
- {ErrorStatus, Index, []}
- end.
-
-org_index_sort_vbs(Vbs) ->
- lists:keysort(#varbind.org_index, Vbs).
-
-try_get_bulk(Sz, MibView, Varbinds, GbMaxVBs) ->
- ?vt("try_get_bulk -> entry with"
- "~n Sz: ~w"
- "~n MibView: ~w"
- "~n Varbinds: ~w", [Sz, MibView, Varbinds]),
- case do_get_next(MibView, Varbinds, GbMaxVBs) of
- {noError, 0, UNextVarbinds} ->
- ?vt("try_get_bulk -> noError: "
- "~n UNextVarbinds: ~p", [UNextVarbinds]),
- NextVarbinds = org_index_sort_vbs(UNextVarbinds),
- case (catch enc_vbs(Sz, NextVarbinds)) of
- {error, Idx, Reason} ->
- user_err("failed encoding varbind ~w:~n~p", [Idx, Reason]),
- ?vtrace("try_get_bulk -> encode error: "
- "~n Idx: ~p"
- "~n Reason: ~p", [Idx, Reason]),
- {genErr, Idx};
- {SizeLeft, Res} when is_integer(SizeLeft) andalso
- is_list(Res) ->
- ?vt("try get bulk -> encode ok: "
- "~n SizeLeft: ~w"
- "~n Res: ~w", [SizeLeft, Res]),
- {check_end_of_mibview(NextVarbinds),
- NextVarbinds, SizeLeft, Res};
- Res when is_list(Res) ->
- ?vt("try get bulk -> Res: "
- "~n ~w", [Res]),
- {endOfMibView, [], 0, Res}
- end;
- {ErrorStatus, Index, _} ->
- ?vt("try_get_bulk -> error: "
- "~n ErrorStatus: ~p"
- "~n Index: ~p", [ErrorStatus, Index]),
- {ErrorStatus, Index}
- end.
-
-%% If all variables in this pass are endOfMibView,
-%% there is no reason to continue.
-check_end_of_mibview([#varbind{value = endOfMibView} | T]) ->
- check_end_of_mibview(T);
-check_end_of_mibview([]) -> endOfMibView;
-check_end_of_mibview(_) -> noError.
%%%--------------------------------------------------
@@ -3834,14 +2822,11 @@ do_subagent_set(Arguments) ->
SetModule = get(set_module),
apply(SetModule, do_subagent_set, [Arguments]).
+
+
%%%-----------------------------------------------------------------
%%% 7. Misc functions
%%%-----------------------------------------------------------------
-sort_varbindlist(Varbinds) ->
- snmpa_svbl:sort_varbindlist(get(mibserver), Varbinds).
-
-sa_split(SubagentVarbinds) ->
- snmpa_svbl:sa_split(SubagentVarbinds).
make_response_pdu(ReqId, ErrStatus, ErrIndex, OrgVarbinds, _ResponseVarbinds)
when ErrIndex =/= 0 ->
@@ -4139,6 +3124,7 @@ report_err(Val, Mfa, Err) ->
user_err("Got ~p from ~w. Using ~w", [Val, Mfa, Err]),
{error, Err}.
+
is_valid_pdu_type('get-request') -> true;
is_valid_pdu_type('get-next-request') -> true;
is_valid_pdu_type('get-bulk-request') -> true;
@@ -4176,33 +3162,8 @@ mapfoldl(F, Eas, Accu0, [Hd|Tail]) ->
mapfoldl(_F, _Eas, Accu, []) -> {Accu,[]}.
-%%-----------------------------------------------------------------
-%% Runtime debugging of the agent.
-%%-----------------------------------------------------------------
-
-dbg_apply(M,F,A) ->
- case get(verbosity) of
- silence ->
- apply(M,F,A);
- _ ->
- ?vlog("~n apply: ~w,~w,~p~n", [M,F,A]),
- Res = (catch apply(M,F,A)),
- case Res of
- {'EXIT', Reason} ->
- ?vinfo("Call to: "
- "~n Module: ~p"
- "~n Function: ~p"
- "~n Args: ~p"
- "~n"
- "~nresulted in an exit"
- "~n"
- "~n ~p", [M, F, A, Reason]);
- _ ->
- ?vlog("~n returned: ~p", [Res])
- end,
- Res
- end.
+%% ---------------------------------------------------------------------
short_name(none) -> ma;
short_name(_Pid) -> sa.
@@ -4450,6 +3411,9 @@ get_mib_storage(Opts) ->
get_set_mechanism(Opts) ->
get_option(set_mechanism, Opts, snmpa_set).
+get_get_mechanism(Opts) ->
+ get_option(get_mechanism, Opts, snmpa_get).
+
get_authentication_service(Opts) ->
get_option(authentication_service, Opts, snmpa_acm).
diff --git a/lib/snmp/src/agent/snmpa_app.erl b/lib/snmp/src/agent/snmpa_app.erl
index 86ff145e93..c00929c334 100644
--- a/lib/snmp/src/agent/snmpa_app.erl
+++ b/lib/snmp/src/agent/snmpa_app.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -67,6 +67,7 @@ convert_config(Opts) ->
SaVerb = get_sub_agent_verbosity(Opts),
[{agent_type, AgentType},
{agent_verbosity, SaVerb},
+ {get_mechanism, snmpa_get},
{set_mechanism, SetModule},
{authentication_service, AuthModule},
{priority, Prio},
@@ -97,6 +98,7 @@ convert_config(Opts) ->
{verbosity, ConfVerb}],
[{agent_type, AgentType},
{agent_verbosity, MaVerb},
+ {get_mechanism, snmpa_get},
{set_mechanism, SetModule},
{authentication_service, AuthModule},
{db_dir, DbDir},
diff --git a/lib/snmp/src/agent/snmpa_get.erl b/lib/snmp/src/agent/snmpa_get.erl
new file mode 100644
index 0000000000..e67975a67d
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_get.erl
@@ -0,0 +1,1150 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019-2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(snmpa_get).
+
+-behaviour(snmpa_get_mechanism).
+
+
+%%%-----------------------------------------------------------------
+%%% snmpa_get_mechanism exports
+%%%-----------------------------------------------------------------
+
+-export([
+ do_get/3, do_get/4,
+ do_get_next/3,
+ do_get_bulk/7
+ ]).
+
+-define(VMODULE,"GET").
+-include("snmpa_internal.hrl").
+-include("snmp_types.hrl").
+-include("snmp_debug.hrl").
+-include("snmp_verbosity.hrl").
+
+-ifndef(default_verbosity).
+-define(default_verbosity,silence).
+-endif.
+
+-define(empty_pdu_size, 21).
+
+-ifdef(snmp_extended_verbosity).
+-define(vt(F,A), ?vtrace(F, A)).
+-else.
+-define(vt(_F, _A), ok).
+-endif.
+
+
+-define(AGENT, snmpa_agent).
+-define(LIB, snmpa_get_lib).
+
+
+
+%%%-----------------------------------------------------------------
+%%% 3. GET REQUEST
+%%% --------------
+%%% According to RFC1157, section 4.1.2 and RFC1905, section 4.2.1.
+%%% In rfc1157:4.1.2 it isn't specified if noSuchName should be
+%%% returned even if some other varbind generates a genErr.
+%%% In rfc1905:4.2.1 this is not a problem since exceptions are
+%%% used, and thus a genErr will be returned anyway.
+%%%-----------------------------------------------------------------
+
+%%-----------------------------------------------------------------
+%% Func: do_get/2
+%% Purpose: Handles all VBs in a request that is inside the
+%% mibview (local).
+%% Returns: {noError, 0, ListOfNewVarbinds} |
+%% {ErrorStatus, ErrorIndex, []}
+%%-----------------------------------------------------------------
+
+do_get(UnsortedVarbinds, IsNotification, _Extra) ->
+ {MyVarbinds, SubagentVarbinds} = ?LIB:agent_sort_vbs(UnsortedVarbinds),
+ case do_get_local(MyVarbinds, IsNotification) of
+ {noError, 0, NewMyVarbinds} ->
+ case do_get_subagents(SubagentVarbinds, IsNotification) of
+ {noError, 0, NewSubagentVarbinds} ->
+ {noError, 0, NewMyVarbinds ++ NewSubagentVarbinds};
+ {ErrorStatus, ErrorIndex, _} ->
+ {ErrorStatus, ErrorIndex, []}
+ end;
+ {ErrorStatus, ErrorIndex, _} ->
+ {ErrorStatus, ErrorIndex, []}
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Func: do_get/3
+%% Purpose: do_get handles "getRequests".
+%% Pre: incoming varbinds have type == 'NULL', value == unSpecified
+%% Returns: {noError, 0, ListOfNewVarbinds} |
+%% {ErrorStatus, ErrorIndex, []}
+%%-----------------------------------------------------------------
+
+do_get(MibView, UnsortedVarbinds, IsNotification, Extra) ->
+ ?vtrace("do_get -> entry with"
+ "~n MibView: ~p"
+ "~n UnsortedVarbinds: ~p"
+ "~n IsNotification: ~p",
+ [MibView, UnsortedVarbinds, IsNotification]),
+ %% This is me, the master, so go ahead
+ {OutSideView, InSideView} = ?LIB:split_vbs_view(UnsortedVarbinds, MibView),
+ {Error, Index, NewVbs} = do_get(InSideView, IsNotification, Extra),
+ {Error, Index, NewVbs ++ OutSideView}.
+
+
+
+%%-----------------------------------------------------------------
+%% Func: do_get_local/2,3
+%% Purpose: Loop the variablebindings list. We know that each varbind
+%% in that list belongs to us.
+%% Returns: {noError, 0, ListOfNewVarbinds} |
+%% {ErrorStatus, ErrorIndex, []}
+%%-----------------------------------------------------------------
+
+do_get_local(VBs, IsNotification) ->
+ do_get_local(VBs, [], IsNotification).
+
+do_get_local([Vb | Vbs], Res, IsNotification) ->
+ case try_get(Vb, IsNotification) of
+ NewVb when is_record(NewVb, varbind) ->
+ do_get_local(Vbs, [NewVb | Res], IsNotification);
+ ListOfNewVb when is_list(ListOfNewVb) ->
+ do_get_local(Vbs, lists:append(ListOfNewVb, Res), IsNotification);
+ {error, Error, OrgIndex} ->
+ {Error, OrgIndex, []}
+ end;
+do_get_local([], Res, _IsNotification) ->
+ {noError, 0, Res}.
+
+
+
+%%-----------------------------------------------------------------
+%% Func: do_get_subagents/2
+%% Purpose: Loop the list of varbinds for different subagents.
+%% For each of them, call sub_agent_get to retreive
+%% the values for them.
+%% Returns: {noError, 0, ListOfNewVarbinds} |
+%% {ErrorStatus, ErrorIndex, []}
+%%-----------------------------------------------------------------
+do_get_subagents(SubagentVarbinds, IsNotification) ->
+ do_get_subagents(SubagentVarbinds, [], IsNotification).
+do_get_subagents([{SubAgentPid, SAVbs} | Tail], Res, IsNotification) ->
+ {_SAOids, Vbs} = ?LIB:sa_split(SAVbs),
+ case catch ?AGENT:subagent_get(SubAgentPid, Vbs, IsNotification) of
+ {noError, 0, NewVbs} ->
+ do_get_subagents(Tail, lists:append(NewVbs, Res), IsNotification);
+ {ErrorStatus, ErrorIndex, _} ->
+ {ErrorStatus, ErrorIndex, []};
+ {'EXIT', Reason} ->
+ ?LIB:user_err("Lost contact with subagent (get) ~w. Using genErr",
+ [Reason]),
+ {genErr, 0, []}
+ end;
+do_get_subagents([], Res, _IsNotification) ->
+ {noError, 0, Res}.
+
+
+%%-----------------------------------------------------------------
+%% Func: try_get/2
+%% Returns: {error, ErrorStatus, OrgIndex} |
+%% #varbind |
+%% List of #varbind
+%%-----------------------------------------------------------------
+try_get(IVb, IsNotification) when is_record(IVb, ivarbind) ->
+ ?vtrace("try_get(ivarbind) -> entry with"
+ "~n IVb: ~p", [IVb]),
+ get_var_value_from_ivb(IVb, IsNotification);
+try_get({TableOid, TableVbs}, IsNotification) ->
+ ?vtrace("try_get(table) -> entry with"
+ "~n TableOid: ~p"
+ "~n TableVbs: ~p", [TableOid, TableVbs]),
+ [#ivarbind{mibentry = MibEntry}|_] = TableVbs,
+ {NoAccessVbs, AccessVbs} =
+ check_all_table_vbs(TableVbs, IsNotification, [], []),
+ case get_tab_value_from_mib(MibEntry, TableOid, AccessVbs) of
+ {error, ErrorStatus, OrgIndex} ->
+ {error, ErrorStatus, OrgIndex};
+ NVbs ->
+ NVbs ++ NoAccessVbs
+ end.
+
+%%-----------------------------------------------------------------
+%% Make sure all requested columns are accessible.
+%%-----------------------------------------------------------------
+check_all_table_vbs([IVb| IVbs], IsNotification, NoA, A) ->
+ #ivarbind{mibentry = Me, varbind = Vb} = IVb,
+ case Me#me.access of
+ 'not-accessible' ->
+ NNoA = [Vb#varbind{value = noSuchInstance} | NoA],
+ check_all_table_vbs(IVbs, IsNotification, NNoA, A);
+ 'accessible-for-notify' when IsNotification =:= false ->
+ NNoA = [Vb#varbind{value = noSuchInstance} | NoA],
+ check_all_table_vbs(IVbs, IsNotification, NNoA, A);
+ 'write-only' ->
+ NNoA = [Vb#varbind{value = noSuchInstance} | NoA],
+ check_all_table_vbs(IVbs, IsNotification, NNoA, A);
+ _ ->
+ check_all_table_vbs(IVbs, IsNotification, NoA, [IVb | A])
+ end;
+check_all_table_vbs([], _IsNotification, NoA, A) -> {NoA, A}.
+
+%%-----------------------------------------------------------------
+%% Returns: {error, ErrorStatus, OrgIndex} |
+%% #varbind
+%%-----------------------------------------------------------------
+get_var_value_from_ivb(IVb, IsNotification)
+ when IVb#ivarbind.status =:= noError ->
+ ?vtrace("get_var_value_from_ivb(noError) -> entry", []),
+ #ivarbind{mibentry = Me, varbind = Vb} = IVb,
+ #varbind{org_index = OrgIndex, oid = Oid} = Vb,
+ case Me#me.access of
+ 'not-accessible' ->
+ Vb#varbind{value = noSuchInstance};
+ 'accessible-for-notify' when IsNotification =:= false ->
+ Vb#varbind{value = noSuchInstance};
+ 'write-only' ->
+ Vb#varbind{value = noSuchInstance};
+ _ ->
+ case get_var_value_from_mib(Me, Oid) of
+ {value, Type, Value} ->
+ Vb#varbind{variabletype = Type, value = Value};
+ {error, ErrorStatus} ->
+ {error, ErrorStatus, OrgIndex}
+ end
+ end;
+get_var_value_from_ivb(#ivarbind{status = Status, varbind = Vb}, _) ->
+ ?vtrace("get_var_value_from_ivb(~p) -> entry", [Status]),
+ Vb#varbind{value = Status}.
+
+%%-----------------------------------------------------------------
+%% Func: get_var_value_from_mib/1
+%% Purpose:
+%% Returns: {error, ErrorStatus} |
+%% {value, Type, Value}
+%%-----------------------------------------------------------------
+%% Pre: Oid is a correct instance Oid (lookup checked that).
+%% Returns: A correct return value (see ?AGENT:make_value_a_correct_value)
+get_var_value_from_mib(#me{entrytype = variable,
+ asn1_type = ASN1Type,
+ mfa = {Mod, Func, Args}},
+ _Oid) ->
+ ?vtrace("get_var_value_from_mib(variable) -> entry when"
+ "~n Mod: ~p"
+ "~n Func: ~p"
+ "~n Args: ~p", [Mod, Func, Args]),
+ Result = (catch ?LIB:dbg_apply(Mod, Func, [get | Args])),
+ %% mib shall return {value, <a-nice-value-within-range>} |
+ %% {noValue, noSuchName} (v1) |
+ %% {noValue, noSuchObject | noSuchInstance} (v2, v1)
+ %% everything else (including 'genErr') will generate 'genErr'.
+ ?AGENT:make_value_a_correct_value(Result, ASN1Type, {Mod, Func, Args});
+
+get_var_value_from_mib(#me{entrytype = table_column,
+ oid = MeOid,
+ asn1_type = ASN1Type,
+ mfa = {Mod, Func, Args}},
+ Oid) ->
+ ?vtrace("get_var_value_from_mib(table_column) -> entry when"
+ "~n MeOid: ~p"
+ "~n Mod: ~p"
+ "~n Func: ~p"
+ "~n Args: ~p"
+ "~n Oid: ~p", [MeOid, Mod, Func, Args, Oid]),
+ Col = lists:last(MeOid),
+ Indexes = snmp_misc:diff(Oid, MeOid),
+ [Result] = (catch ?LIB:dbg_apply(Mod, Func, [get, Indexes, [Col] | Args])),
+ ?AGENT:make_value_a_correct_value(Result, ASN1Type,
+ {Mod, Func, Args, Indexes, Col}).
+
+
+%% For table operations we need to pass RestOid down to the table-function.
+%% Its up to the table-function to check for noSuchInstance (ex: a
+%% non-existing row).
+%% Returns: {error, ErrorStatus, OrgIndex} |
+%% {value, Type, Value}
+get_tab_value_from_mib(#me{mfa = {Mod, Func, Args}}, TableOid, TableVbs) ->
+ ?vtrace("get_tab_value_from_mib -> entry when"
+ "~n Mod: ~p"
+ "~n Func: ~p"
+ "~n Args: ~p", [Mod, Func, Args]),
+ TableOpsWithShortOids = ?LIB:delete_prefixes(TableOid, TableVbs),
+ SortedVBsRows = snmpa_svbl:sort_varbinds_rows(TableOpsWithShortOids),
+ case get_value_all_rows(SortedVBsRows, Mod, Func, Args, []) of
+ {Error, Index} ->
+ #ivarbind{varbind = Vb} = lists:nth(Index, TableVbs),
+ {error, Error, Vb#varbind.org_index};
+ ListOfValues ->
+ merge_varbinds_and_value(TableVbs, ListOfValues)
+ end.
+
+%%-----------------------------------------------------------------
+%% Values is a scrambled list of {CorrectValue, Index}, where Index
+%% is index into the #ivarbind list. So for each Value, we must
+%% find the corresponding #ivarbind, and merge them into a new
+%% #varbind.
+%% The Values list comes from validate_tab_res.
+%%-----------------------------------------------------------------
+merge_varbinds_and_value(IVbs, [{{value, Type, Value}, Index} | Values]) ->
+ #ivarbind{varbind = Vb} = lists:nth(Index, IVbs),
+ [Vb#varbind{variabletype = Type, value = Value} |
+ merge_varbinds_and_value(IVbs, Values)];
+merge_varbinds_and_value(_, []) -> [].
+
+get_value_all_rows([{[], OrgCols} | Rows], Mod, Func, Args, Res) ->
+ ?vtrace("get_value_all_rows -> entry when"
+ "~n OrgCols: ~p", [OrgCols]),
+ Cols = [{{value, noValue, noSuchInstance}, Index} ||
+ {_Col, _ASN1Type, Index} <- OrgCols],
+ NewRes = lists:append(Cols, Res),
+ get_value_all_rows(Rows, Mod, Func, Args, NewRes);
+get_value_all_rows([{RowIndex, OrgCols} | Rows], Mod, Func, Args, Res) ->
+ ?vtrace("get_value_all_rows -> entry when"
+ "~n RowIndex: ~p"
+ "~n OrgCols: ~p", [RowIndex, OrgCols]),
+ {DOrgCols, Dup} = remove_duplicates(OrgCols),
+ Cols = delete_index(DOrgCols),
+ Result = (catch ?LIB:dbg_apply(Mod, Func, [get, RowIndex, Cols | Args])),
+ case validate_tab_res(Result, DOrgCols, {Mod, Func, Args}) of
+ Values when is_list(Values) ->
+ NVals = restore_duplicates(Dup, Values),
+ NewRes = lists:append(NVals, Res),
+ get_value_all_rows(Rows, Mod, Func, Args, NewRes);
+ {error, ErrorStatus, Index} ->
+ ?AGENT:validate_err(row_set, {ErrorStatus, Index}, {Mod, Func, Args})
+ end;
+get_value_all_rows([], _Mod, _Func, _Args, Res) ->
+ ?vtrace("get_value_all_rows -> entry when done"
+ "~n Res: ~p", [Res]),
+ Res.
+
+%%-----------------------------------------------------------------
+%% Args: {RowIndex, list of {ShortOid, ASN1Type}}
+%% Returns: list of Col
+%%-----------------------------------------------------------------
+delete_index([{Col, _Val, _OrgIndex} | T]) ->
+ [Col | delete_index(T)];
+delete_index([]) -> [].
+
+%%-----------------------------------------------------------------
+%% This function is called before 'get' on a table, and removes
+%% any duplicate columns. It returns {Cols, DupInfo}. The Cols
+%% are the unique columns. The instrumentation function is
+%% called to get the values. These values, together with the
+%% DupInfo, is later passed to restore_duplicates, which uses
+%% the retrieved values to reconstruct the original column list,
+%% but with the retrieved value for each column.
+%%-----------------------------------------------------------------
+remove_duplicates(Cols) ->
+ remove_duplicates(Cols, [], []).
+
+
+remove_duplicates([{Col, V1, OrgIdx1}, {Col, V2, OrgIdx2} | T], NCols, Dup) ->
+ remove_duplicates([{Col, V1, OrgIdx1} | T], NCols,
+ [{Col, V2, OrgIdx2} | Dup]);
+remove_duplicates([Col | T], NCols, Dup) ->
+ remove_duplicates(T, [Col | NCols], Dup);
+remove_duplicates([], NCols, Dup) ->
+ {lists:reverse(NCols), lists:reverse(Dup)}.
+
+restore_duplicates([], Cols) ->
+ [{Val, OrgIndex} || {_Col, Val, OrgIndex} <- Cols];
+restore_duplicates([{Col, _Val2, OrgIndex2} | Dup],
+ [{Col, NVal, OrgIndex1} | Cols]) ->
+ [{NVal, OrgIndex2} |
+ restore_duplicates(Dup, [{Col, NVal, OrgIndex1} | Cols])];
+restore_duplicates(Dup, [{_Col, Val, OrgIndex} | T]) ->
+ [{Val, OrgIndex} | restore_duplicates(Dup, T)].
+
+
+
+%%-----------------------------------------------------------------
+%% Three cases:
+%% 1) All values ok
+%% 2) table_func returned {Error, ...}
+%% 3) Some value in Values list is erroneous.
+%% Args: Value is a list of values from table_func(get..)
+%% OrgCols is a list with {Col, ASN1Type, OrgIndex}
+%% each element in Values and OrgCols correspond to each
+%% other.
+%%-----------------------------------------------------------------
+validate_tab_res(Values, OrgCols, Mfa) when is_list(Values) ->
+ {_Col, _ASN1Type, OneIdx} = hd(OrgCols),
+ validate_tab_res(Values, OrgCols, Mfa, [], OneIdx);
+validate_tab_res({noValue, Error}, OrgCols, Mfa) ->
+ Values = lists:duplicate(length(OrgCols), {noValue, Error}),
+ validate_tab_res(Values, OrgCols, Mfa);
+validate_tab_res({genErr, Col}, OrgCols, Mfa) ->
+ case lists:keysearch(Col, 1, OrgCols) of
+ {value, {_Col, _ASN1Type, Index}} ->
+ {error, genErr, Index};
+ _ ->
+ ?LIB:user_err("Invalid column in {genErr, ~w} from ~w (get)",
+ [Col, Mfa]),
+ [{_Col, _ASN1Type, Index} | _] = OrgCols,
+ {error, genErr, Index}
+ end;
+validate_tab_res(genErr, [{_Col, __ASN1Type, Index} | _OrgCols], _Mfa) ->
+ {error, genErr, Index};
+validate_tab_res(Error, [{_Col, _ASN1Type, Index} | _OrgCols], Mfa) ->
+ ?LIB:user_err("Invalid return value ~w from ~w (get)",[Error, Mfa]),
+ {error, genErr, Index}.
+
+validate_tab_res([Value | Values],
+ [{Col, ASN1Type, Index} | OrgCols],
+ Mfa, Res, I) ->
+ %% This one makes it possible to return a list of genErr, which
+ %% is not allowed according to the manual. But that's ok, as
+ %% everything else will generate a genErr! (the only problem is
+ %% that it won't generate a user_error).
+ case ?AGENT:make_value_a_correct_value(Value, ASN1Type, Mfa) of
+ {error, ErrorStatus} ->
+ {error, ErrorStatus, Index};
+ CorrectValue ->
+ NewRes = [{Col, CorrectValue, Index} | Res],
+ validate_tab_res(Values, OrgCols, Mfa, NewRes, I)
+ end;
+validate_tab_res([], [], _Mfa, Res, _I) ->
+ lists:reverse(Res);
+validate_tab_res([], [{_Col, _ASN1Type, Index}|_], Mfa, _Res, _I) ->
+ ?LIB:user_err("Too few values returned from ~w (get)", [Mfa]),
+ {error, genErr, Index};
+validate_tab_res(_TooMany, [], Mfa, _Res, I) ->
+ ?LIB:user_err("Too many values returned from ~w (get)", [Mfa]),
+ {error, genErr, I}.
+
+
+
+%%%-----------------------------------------------------------------
+%%% 4. GET-NEXT REQUEST
+%%% --------------
+%%% According to RFC1157, section 4.1.3 and RFC1905, section 4.2.2.
+%%%-----------------------------------------------------------------
+%%-----------------------------------------------------------------
+%% Func: do_get_next/3
+%% Purpose: do_get_next handles "getNextRequests".
+%% Note: Even if it is SNMPv1, a varbind's value can be
+%% endOfMibView. This is converted to noSuchName in process_pdu.
+%% Returns: {noError, 0, ListOfNewVarbinds} |
+%% {ErrorStatus, ErrorIndex, []}
+%% Note2: ListOfNewVarbinds is not sorted in any order!!!
+%% Alg: First, the variables are sorted in OID order.
+%%
+%% Second, next in the MIB is performed for each OID, and
+%% the result is collected as: if next oid is a variable,
+%% perform a get to retrieve its value; if next oid is in a
+%% table, save this value and continue until we get an oid
+%% outside this table. Then perform get_next on the table,
+%% and continue with all endOfTables and the oid outside the
+%% table; if next oid is an subagent, save this value and
+%% continue as in the table case.
+%%
+%% Third, each response is checked for endOfMibView, or (for
+%% subagents) that the Oid returned has the correct prefix.
+%% (This is necessary since an SA can be registered under many
+%% separated subtrees, and if the last variable in the first
+%% subtree is requested in a next, the SA will return the first
+%% variable in the second subtree. This might be working, since
+%% there may be a variable in between these subtrees.) For each
+%% of these, a new get-next is performed, one at a time.
+%% This alg. might be optimised in several ways. The most
+%% striking one is that the same SA might be called several
+%% times, when one time should be enough. But it isn't clear
+%% that this really matters, since many nexts across the same
+%% subagent must be considered to be very rare.
+%%-----------------------------------------------------------------
+
+do_get_next(MibView, UnsortedVBs, _Extra) ->
+ do_get_next2(MibView, UnsortedVBs, infinity).
+
+%% The third argument is only used if we are called as result
+%% of a get-bulk request.
+do_get_next2(_MibView, UnsortedVarbinds, GbMaxVBs)
+ when (is_integer(GbMaxVBs) andalso (length(UnsortedVarbinds) > GbMaxVBs)) ->
+ {tooBig, 0, []}; % What is the correct index in this case?
+do_get_next2(MibView, UnsortedVBs, GbMaxVBs) ->
+ ?vt("do_get_next2 -> entry when"
+ "~n MibView: ~p"
+ "~n UnsortedVBs: ~p", [MibView, UnsortedVBs]),
+ SortedVBs = ?LIB:oid_sort_vbs(UnsortedVBs),
+ ?vt("do_get_next -> "
+ "~n SortedVBs: ~p", [SortedVBs]),
+ next_loop_varbinds([], SortedVBs, MibView, [], [], GbMaxVBs).
+
+next_loop_varbinds(_, Vbs, _MibView, Res, _LAVb, GbMaxVBs)
+ when (is_integer(GbMaxVBs) andalso
+ ((length(Vbs) + length(Res)) > GbMaxVBs)) ->
+ {tooBig, 0, []}; % What is the correct index in this case?
+
+%% LAVb is Last Accessible Vb
+next_loop_varbinds([], [Vb | Vbs], MibView, Res, LAVb, GbMaxVBs) ->
+ ?vt("next_loop_varbinds -> entry when"
+ "~n Vb: ~p"
+ "~n MibView: ~p", [Vb, MibView]),
+ case varbind_next(Vb, MibView) of
+ endOfMibView ->
+ ?vt("next_loop_varbind -> endOfMibView", []),
+ RVb = if LAVb =:= [] -> Vb;
+ true -> LAVb
+ end,
+ NewVb = RVb#varbind{variabletype = 'NULL', value = endOfMibView},
+ next_loop_varbinds([], Vbs, MibView, [NewVb | Res], [], GbMaxVBs);
+
+ {variable, ME, VarOid} when ((ME#me.access =/= 'not-accessible') andalso
+ (ME#me.access =/= 'write-only') andalso
+ (ME#me.access =/= 'accessible-for-notify')) ->
+ ?vt("next_loop_varbind -> variable: "
+ "~n ME: ~p"
+ "~n VarOid: ~p", [ME, VarOid]),
+ case try_get_instance(Vb, ME) of
+ {value, noValue, _NoSuchSomething} ->
+ ?vt("next_loop_varbind -> noValue", []),
+ %% Try next one
+ NewVb = Vb#varbind{oid = VarOid,
+ value = 'NULL'},
+ next_loop_varbinds([], [NewVb | Vbs], MibView, Res, [],
+ GbMaxVBs);
+ {value, Type, Value} ->
+ ?vt("next_loop_varbind -> value"
+ "~n Type: ~p"
+ "~n Value: ~p", [Type, Value]),
+ NewVb = Vb#varbind{oid = VarOid,
+ variabletype = Type,
+ value = Value},
+ next_loop_varbinds([], Vbs, MibView, [NewVb | Res], [],
+ GbMaxVBs);
+ {error, ErrorStatus} ->
+ ?vdebug("next loop varbinds:"
+ "~n ErrorStatus: ~p",[ErrorStatus]),
+ {ErrorStatus, Vb#varbind.org_index, []}
+ end;
+ {variable, _ME, VarOid} ->
+ ?vt("next_loop_varbind -> variable: "
+ "~n VarOid: ~p", [VarOid]),
+ RVb = if LAVb =:= [] -> Vb;
+ true -> LAVb
+ end,
+ NewVb = Vb#varbind{oid = VarOid, value = 'NULL'},
+ next_loop_varbinds([], [NewVb | Vbs], MibView, Res, RVb, GbMaxVBs);
+ {table, TableOid, TableRestOid, ME} ->
+ ?vt("next_loop_varbind -> table: "
+ "~n TableOid: ~p"
+ "~n TableRestOid: ~p"
+ "~n ME: ~p", [TableOid, TableRestOid, ME]),
+ next_loop_varbinds({table, TableOid, ME,
+ [{tab_oid(TableRestOid), Vb}]},
+ Vbs, MibView, Res, [], GbMaxVBs);
+ {subagent, SubAgentPid, SAOid} ->
+ ?vt("next_loop_varbind -> subagent: "
+ "~n SubAgentPid: ~p"
+ "~n SAOid: ~p", [SubAgentPid, SAOid]),
+ NewVb = Vb#varbind{variabletype = 'NULL', value = 'NULL'},
+ next_loop_varbinds({subagent, SubAgentPid, SAOid, [NewVb]},
+ Vbs, MibView, Res, [], GbMaxVBs)
+ end;
+next_loop_varbinds({table, TableOid, ME, TabOids},
+ [Vb | Vbs], MibView, Res, _LAVb, GbMaxVBs) ->
+ ?vt("next_loop_varbinds(table) -> entry with"
+ "~n TableOid: ~p"
+ "~n Vb: ~p", [TableOid, Vb]),
+ case varbind_next(Vb, MibView) of
+ {table, TableOid, TableRestOid, _ME} ->
+ next_loop_varbinds({table, TableOid, ME,
+ [{tab_oid(TableRestOid), Vb} | TabOids]},
+ Vbs, MibView, Res, [], GbMaxVBs);
+ _ ->
+ case get_next_table(ME, TableOid, TabOids, MibView) of
+ {ok, TabRes, TabEndOfTabVbs} ->
+ NewVbs = lists:append(TabEndOfTabVbs, [Vb | Vbs]),
+ NewRes = lists:append(TabRes, Res),
+ next_loop_varbinds([], NewVbs, MibView, NewRes, [],
+ GbMaxVBs);
+ {ErrorStatus, OrgIndex} ->
+ ?vdebug("next loop varbinds: next varbind"
+ "~n ErrorStatus: ~p"
+ "~n OrgIndex: ~p",
+ [ErrorStatus,OrgIndex]),
+ {ErrorStatus, OrgIndex, []}
+ end
+ end;
+next_loop_varbinds({table, TableOid, ME, TabOids},
+ [], MibView, Res, _LAVb, GbMaxVBs) ->
+ ?vt("next_loop_varbinds(table) -> entry with"
+ "~n TableOid: ~p", [TableOid]),
+ case get_next_table(ME, TableOid, TabOids, MibView) of
+ {ok, TabRes, TabEndOfTabVbs} ->
+ ?vt("next_loop_varbinds(table) -> get_next_table result:"
+ "~n TabRes: ~p"
+ "~n TabEndOfTabVbs: ~p", [TabRes, TabEndOfTabVbs]),
+ NewRes = lists:append(TabRes, Res),
+ next_loop_varbinds([], TabEndOfTabVbs, MibView, NewRes, [],
+ GbMaxVBs);
+ {ErrorStatus, OrgIndex} ->
+ ?vdebug("next loop varbinds: next table"
+ "~n ErrorStatus: ~p"
+ "~n OrgIndex: ~p",
+ [ErrorStatus,OrgIndex]),
+ {ErrorStatus, OrgIndex, []}
+ end;
+next_loop_varbinds({subagent, SAPid, SAOid, SAVbs},
+ [Vb | Vbs], MibView, Res, _LAVb, GbMaxVBs) ->
+ ?vt("next_loop_varbinds(subagent) -> entry with"
+ "~n SAPid: ~p"
+ "~n SAOid: ~p"
+ "~n Vb: ~p", [SAPid, SAOid, Vb]),
+ case varbind_next(Vb, MibView) of
+ {subagent, _SubAgentPid, SAOid} ->
+ next_loop_varbinds({subagent, SAPid, SAOid,
+ [Vb | SAVbs]},
+ Vbs, MibView, Res, [], GbMaxVBs);
+ _ ->
+ case get_next_sa(SAPid, SAOid, SAVbs, MibView) of
+ {ok, SARes, SAEndOfMibViewVbs} ->
+ NewVbs = lists:append(SAEndOfMibViewVbs, [Vb | Vbs]),
+ NewRes = lists:append(SARes, Res),
+ next_loop_varbinds([], NewVbs, MibView, NewRes, [],
+ GbMaxVBs);
+ {noSuchName, OrgIndex} ->
+ %% v1 reply, treat this Vb as endOfMibView, and try again
+ %% for the others.
+ case lists:keysearch(OrgIndex, #varbind.org_index, SAVbs) of
+ {value, EVb} ->
+ NextOid = next_oid(SAOid),
+ EndOfVb =
+ EVb#varbind{oid = NextOid,
+ value = {endOfMibView, NextOid}},
+ case lists:delete(EVb, SAVbs) of
+ [] ->
+ next_loop_varbinds([], [EndOfVb, Vb | Vbs],
+ MibView, Res, [],
+ GbMaxVBs);
+ TryAgainVbs ->
+ next_loop_varbinds({subagent, SAPid, SAOid,
+ TryAgainVbs},
+ [EndOfVb, Vb | Vbs],
+ MibView, Res, [],
+ GbMaxVBs)
+ end;
+ false ->
+ %% bad index from subagent
+ {genErr, (hd(SAVbs))#varbind.org_index, []}
+ end;
+ {ErrorStatus, OrgIndex} ->
+ ?vdebug("next loop varbinds: next subagent"
+ "~n Vb: ~p"
+ "~n ErrorStatus: ~p"
+ "~n OrgIndex: ~p",
+ [Vb,ErrorStatus,OrgIndex]),
+ {ErrorStatus, OrgIndex, []}
+ end
+ end;
+next_loop_varbinds({subagent, SAPid, SAOid, SAVbs},
+ [], MibView, Res, _LAVb, GbMaxVBs) ->
+ ?vt("next_loop_varbinds(subagent) -> entry with"
+ "~n SAPid: ~p"
+ "~n SAOid: ~p", [SAPid, SAOid]),
+ case get_next_sa(SAPid, SAOid, SAVbs, MibView) of
+ {ok, SARes, SAEndOfMibViewVbs} ->
+ NewRes = lists:append(SARes, Res),
+ next_loop_varbinds([], SAEndOfMibViewVbs, MibView, NewRes, [],
+ GbMaxVBs);
+ {noSuchName, OrgIndex} ->
+ %% v1 reply, treat this Vb as endOfMibView, and try again for
+ %% the others.
+ case lists:keysearch(OrgIndex, #varbind.org_index, SAVbs) of
+ {value, EVb} ->
+ NextOid = next_oid(SAOid),
+ EndOfVb = EVb#varbind{oid = NextOid,
+ value = {endOfMibView, NextOid}},
+ case lists:delete(EVb, SAVbs) of
+ [] ->
+ next_loop_varbinds([], [EndOfVb], MibView, Res, [],
+ GbMaxVBs);
+ TryAgainVbs ->
+ next_loop_varbinds({subagent, SAPid, SAOid,
+ TryAgainVbs},
+ [EndOfVb], MibView, Res, [],
+ GbMaxVBs)
+ end;
+ false ->
+ %% bad index from subagent
+ {genErr, (hd(SAVbs))#varbind.org_index, []}
+ end;
+ {ErrorStatus, OrgIndex} ->
+ ?vdebug("next loop varbinds: next subagent"
+ "~n ErrorStatus: ~p"
+ "~n OrgIndex: ~p",
+ [ErrorStatus,OrgIndex]),
+ {ErrorStatus, OrgIndex, []}
+ end;
+next_loop_varbinds([], [], _MibView, Res, _LAVb, _GbMaxVBs) ->
+ ?vt("next_loop_varbinds -> entry when done", []),
+ {noError, 0, Res}.
+
+try_get_instance(_Vb, #me{mfa = {M, F, A}, asn1_type = ASN1Type}) ->
+ ?vtrace("try_get_instance -> entry with"
+ "~n M: ~p"
+ "~n F: ~p"
+ "~n A: ~p", [M,F,A]),
+ Result = (catch ?LIB:dbg_apply(M, F, [get | A])),
+ % mib shall return {value, <a-nice-value-within-range>} |
+ % {noValue, noSuchName} (v1) |
+ % {noValue, noSuchObject | noSuchInstance} (v2, v1)
+ % everything else (including 'genErr') will generate 'genErr'.
+ ?AGENT:make_value_a_correct_value(Result, ASN1Type, {M, F, A}).
+
+tab_oid([]) -> [0];
+tab_oid(X) -> X.
+
+
+%%-----------------------------------------------------------------
+%% Perform a next, using the varbinds Oid if value is simple
+%% value. If value is {endOf<something>, NextOid}, use NextOid.
+%% This case happens when a table has returned endOfTable, or
+%% a subagent has returned endOfMibView.
+%%-----------------------------------------------------------------
+varbind_next(#varbind{value = Value, oid = Oid}, MibView) ->
+ ?vt("varbind_next -> entry with"
+ "~n Value: ~p"
+ "~n Oid: ~p"
+ "~n MibView: ~p", [Value, Oid, MibView]),
+ case Value of
+ {endOfTable, NextOid} ->
+ snmpa_mib:next(get(mibserver), NextOid, MibView);
+ {endOfMibView, NextOid} ->
+ snmpa_mib:next(get(mibserver), NextOid, MibView);
+ _ ->
+ snmpa_mib:next(get(mibserver), Oid, MibView)
+ end.
+
+get_next_table(#me{mfa = {M, F, A}}, TableOid, TableOids, MibView) ->
+ % We know that all TableOids have at least a column number as oid
+ ?vt("get_next_table -> entry with"
+ "~n M: ~p"
+ "~n F: ~p"
+ "~n A: ~p"
+ "~n TableOid: ~p"
+ "~n TableOids: ~p"
+ "~n MibView: ~p", [M, F, A, TableOid, TableOids, MibView]),
+ Sorted = snmpa_svbl:sort_varbinds_rows(TableOids),
+ case get_next_values_all_rows(Sorted, M,F,A, [], TableOid) of
+ NewVbs when is_list(NewVbs) ->
+ ?vt("get_next_table -> "
+ "~n NewVbs: ~p", [NewVbs]),
+ % We must now check each Vb for endOfTable and that it is
+ % in the MibView. If not, it becomes a endOfTable. We
+ % collect all of these together.
+ transform_tab_next_result(NewVbs, {[], []}, MibView);
+ {ErrorStatus, OrgIndex} ->
+ {ErrorStatus, OrgIndex}
+ end.
+
+get_next_values_all_rows([Row | Rows], M, F, A, Res, TabOid) ->
+ {RowIndex, TableOids} = Row,
+ Cols = delete_index(TableOids),
+ ?vt("get_next_values_all_rows -> "
+ "~n Cols: ~p", [Cols]),
+ Result = (catch ?LIB:dbg_apply(M, F, [get_next, RowIndex, Cols | A])),
+ ?vt("get_next_values_all_rows -> "
+ "~n Result: ~p", [Result]),
+ case validate_tab_next_res(Result, TableOids, {M, F, A}, TabOid) of
+ Values when is_list(Values) ->
+ ?vt("get_next_values_all_rows -> "
+ "~n Values: ~p", [Values]),
+ NewRes = lists:append(Values, Res),
+ get_next_values_all_rows(Rows, M, F, A, NewRes, TabOid);
+ {ErrorStatus, OrgIndex} ->
+ {ErrorStatus, OrgIndex}
+ end;
+get_next_values_all_rows([], _M, _F, _A, Res, _TabOid) ->
+ Res.
+
+transform_tab_next_result([Vb | Vbs], {Res, EndOfs}, MibView) ->
+ case Vb#varbind.value of
+ {endOfTable, _} ->
+ {ResVBs, EndOfVBs} = ?LIB:split_vbs(Vbs, Res, [Vb | EndOfs]),
+ {ok, ResVBs, EndOfVBs};
+ _ ->
+ case snmpa_acm:validate_mib_view(Vb#varbind.oid, MibView) of
+ true ->
+ transform_tab_next_result(Vbs, {[Vb|Res], EndOfs},MibView);
+ _ ->
+ Oid = Vb#varbind.oid,
+ NewEndOf = Vb#varbind{value = {endOfTable, Oid}},
+ transform_tab_next_result(Vbs, {Res, [NewEndOf | EndOfs]},
+ MibView)
+ end
+ end;
+transform_tab_next_result([], {Res, EndOfs}, _MibView) ->
+ ?vt("transform_tab_next_result -> entry with: "
+ "~n Res: ~p"
+ "~n EndIfs: ~p",[Res, EndOfs]),
+ {ok, Res, EndOfs}.
+
+
+
+%%-----------------------------------------------------------------
+%% Three cases:
+%% 1) All values ok
+%% 2) table_func returned {Error, ...}
+%% 3) Some value in Values list is erroneous.
+%% Args: Value is a list of values from table_func(get_next, ...)
+%% TableOids is a list of {TabRestOid, OrgVb}
+%% each element in Values and TableOids correspond to each
+%% other.
+%% Returns: List of NewVarbinds |
+%% {ErrorStatus, OrgIndex}
+%% (In the NewVarbinds list, the value may be endOfTable)
+%%-----------------------------------------------------------------
+validate_tab_next_res(Values, TableOids, Mfa, TabOid) ->
+ ?vt("validate_tab_next_res -> entry with: "
+ "~n Values: ~p"
+ "~n TableOids: ~p"
+ "~n Mfa: ~p"
+ "~n TabOid: ~p", [Values, TableOids, Mfa, TabOid]),
+ {_Col, _ASN1Type, OneIdx} = hd(TableOids),
+ validate_tab_next_res(Values, TableOids, Mfa, [], TabOid,
+ next_oid(TabOid), OneIdx).
+validate_tab_next_res([{NextOid, Value} | Values],
+ [{_ColNo, OrgVb, _Index} | TableOids],
+ Mfa, Res, TabOid, TabNextOid, I) ->
+ ?vt("validate_tab_next_res -> entry with: "
+ "~n NextOid: ~p"
+ "~n Value: ~p"
+ "~n Values: ~p"
+ "~n TableOids: ~p"
+ "~n Mfa: ~p"
+ "~n TabOid: ~p",
+ [NextOid, Value, Values, TableOids, Mfa, TabOid]),
+ #varbind{org_index = OrgIndex} = OrgVb,
+ ?vt("validate_tab_next_res -> OrgIndex: ~p", [OrgIndex]),
+ NextCompleteOid = lists:append(TabOid, NextOid),
+ case snmpa_mib:lookup(get(mibserver), NextCompleteOid) of
+ {table_column, #me{asn1_type = ASN1Type}, _TableEntryOid} ->
+ ?vt("validate_tab_next_res -> ASN1Type: ~p", [ASN1Type]),
+ case ?AGENT:make_value_a_correct_value({value, Value}, ASN1Type, Mfa) of
+ {error, ErrorStatus} ->
+ ?vt("validate_tab_next_res -> "
+ "~n ErrorStatus: ~p", [ErrorStatus]),
+ {ErrorStatus, OrgIndex};
+ {value, Type, NValue} ->
+ ?vt("validate_tab_next_res -> "
+ "~n Type: ~p"
+ "~n NValue: ~p", [Type, NValue]),
+ NewVb = OrgVb#varbind{oid = NextCompleteOid,
+ variabletype = Type, value = NValue},
+ validate_tab_next_res(Values, TableOids, Mfa,
+ [NewVb | Res], TabOid, TabNextOid, I)
+ end;
+ Error ->
+ ?LIB:user_err("Invalid oid ~w from ~w (get_next). Using genErr => ~p",
+ [NextOid, Mfa, Error]),
+ {genErr, OrgIndex}
+ end;
+validate_tab_next_res([endOfTable | Values],
+ [{_ColNo, OrgVb, _Index} | TableOids],
+ Mfa, Res, TabOid, TabNextOid, I) ->
+ ?vt("validate_tab_next_res(endOfTable) -> entry with: "
+ "~n Values: ~p"
+ "~n OrgVb: ~p"
+ "~n TableOids: ~p"
+ "~n Mfa: ~p"
+ "~n Res: ~p"
+ "~n TabOid: ~p"
+ "~n TabNextOid: ~p"
+ "~n I: ~p",
+ [Values, OrgVb, TableOids, Mfa, Res, TabOid, TabNextOid, I]),
+ NewVb = OrgVb#varbind{value = {endOfTable, TabNextOid}},
+ validate_tab_next_res(Values, TableOids, Mfa, [NewVb | Res],
+ TabOid, TabNextOid, I);
+validate_tab_next_res([], [], _Mfa, Res, _TabOid, _TabNextOid, _I) ->
+ Res;
+validate_tab_next_res([], [{_Col, _OrgVb, Index}|_], Mfa, _Res, _, _, _I) ->
+ ?LIB:user_err("Too few values returned from ~w (get_next)", [Mfa]),
+ {genErr, Index};
+validate_tab_next_res({genErr, ColNumber}, OrgCols,
+ Mfa, _Res, _TabOid, _TabNextOid, _I) ->
+ OrgIndex = snmpa_svbl:col_to_orgindex(ColNumber, OrgCols),
+ ?AGENT:validate_err(table_next, {genErr, OrgIndex}, Mfa);
+validate_tab_next_res({error, Reason}, [{_ColNo, OrgVb, _Index} | _TableOids],
+ Mfa, _Res, _TabOid, _TabNextOid, _I) ->
+ #varbind{org_index = OrgIndex} = OrgVb,
+ ?LIB:user_err("Erroneous return value ~w from ~w (get_next)",
+ [Reason, Mfa]),
+ {genErr, OrgIndex};
+validate_tab_next_res(Error, [{_ColNo, OrgVb, _Index} | _TableOids],
+ Mfa, _Res, _TabOid, _TabNextOid, _I) ->
+ #varbind{org_index = OrgIndex} = OrgVb,
+ ?LIB:user_err("Invalid return value ~w from ~w (get_next)",
+ [Error, Mfa]),
+ {genErr, OrgIndex};
+validate_tab_next_res(TooMany, [], Mfa, _Res, _, _, I) ->
+ ?LIB:user_err("Too many values ~w returned from ~w (get_next)",
+ [TooMany, Mfa]),
+ {genErr, I}.
+
+%%-----------------------------------------------------------------
+%% Func: get_next_sa/4
+%% Purpose: Loop the list of varbinds for the subagent.
+%% Call subagent_get_next to retreive
+%% the next varbinds.
+%% Returns: {ok, ListOfNewVbs, ListOfEndOfMibViewsVbs} |
+%% {ErrorStatus, ErrorIndex}
+%%-----------------------------------------------------------------
+get_next_sa(SAPid, SAOid, SAVbs, MibView) ->
+ case catch ?AGENT:subagent_get_next(SAPid, MibView, SAVbs) of
+ {noError, 0, NewVbs} ->
+ NewerVbs = transform_sa_next_result(NewVbs,SAOid,next_oid(SAOid)),
+ {ResVBs, EndOfVBs} = ?LIB:split_vbs(NewerVbs),
+ {ok, ResVBs, EndOfVBs};
+ {ErrorStatus, ErrorIndex, _} ->
+ {ErrorStatus, ErrorIndex};
+ {'EXIT', Reason} ->
+ ?LIB:user_err("Lost contact with subagent (next) ~w. Using genErr",
+ [Reason]),
+ {genErr, 0}
+ end.
+
+%%-----------------------------------------------------------------
+%% Check for wrong prefix returned or endOfMibView, and convert
+%% into {endOfMibView, SANextOid}.
+%%-----------------------------------------------------------------
+transform_sa_next_result([Vb | Vbs], SAOid, SANextOid)
+ when Vb#varbind.value =:= endOfMibView ->
+ [Vb#varbind{value = {endOfMibView, SANextOid}} |
+ transform_sa_next_result(Vbs, SAOid, SANextOid)];
+transform_sa_next_result([Vb | Vbs], SAOid, SANextOid) ->
+ case lists:prefix(SAOid, Vb#varbind.oid) of
+ true ->
+ [Vb | transform_sa_next_result(Vbs, SAOid, SANextOid)];
+ _ ->
+ [Vb#varbind{oid = SANextOid, value = {endOfMibView, SANextOid}} |
+ transform_sa_next_result(Vbs, SAOid, SANextOid)]
+ end;
+transform_sa_next_result([], _SAOid, _SANextOid) ->
+ [].
+
+
+next_oid(Oid) ->
+ case lists:reverse(Oid) of
+ [H | T] -> lists:reverse([H+1 | T]);
+ [] -> []
+ end.
+
+
+
+%%%-----------------------------------------------------------------
+%%% 5. GET-BULK REQUEST
+%%%
+%%% In order to prevent excesses in reply sizes there are two
+%%% preventive methods in place. One is to check that the encode
+%%% size does not exceed Max PDU size (this is mentioned in the
+%%% standard). The other is a simple VBs limit. That is, the
+%%% resulting response cannot contain more then this number of VBs.
+%%%-----------------------------------------------------------------
+
+do_get_bulk(MibView, NonRepeaters, MaxRepetitions,
+ PduMS, Varbinds, GbMaxVBs, _Extra) ->
+ ?vtrace("do_get_bulk -> entry with"
+ "~n MibView: ~p"
+ "~n NonRepeaters: ~p"
+ "~n MaxRepetitions: ~p"
+ "~n PduMS: ~p"
+ "~n Varbinds: ~p"
+ "~n GbMaxVBs: ~p",
+ [MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds, GbMaxVBs]),
+ {NonRepVbs, RestVbs} = ?LIB:split_vbs_gb(NonRepeaters, Varbinds),
+ ?vt("do_get_bulk -> split: "
+ "~n NonRepVbs: ~p"
+ "~n RestVbs: ~p", [NonRepVbs, RestVbs]),
+ case do_get_next2(MibView, NonRepVbs, GbMaxVBs) of
+ {noError, 0, UResNonRepVbs} ->
+ ?vt("do_get_bulk -> next noError: "
+ "~n UResNonRepVbs: ~p", [UResNonRepVbs]),
+ ResNonRepVbs = lists:keysort(#varbind.org_index, UResNonRepVbs),
+ %% Decode the first varbinds, produce a reversed list of
+ %% listOfBytes.
+ case (catch enc_vbs(PduMS - ?empty_pdu_size, ResNonRepVbs)) of
+ {error, Idx, Reason} ->
+ ?LIB:user_err("failed encoding varbind ~w:~n~p", [Idx, Reason]),
+ {genErr, Idx, []};
+ {SizeLeft, Res} when is_integer(SizeLeft) and is_list(Res) ->
+ ?vtrace("do_get_bulk -> encoded: "
+ "~n SizeLeft: ~p"
+ "~n Res: ~w", [SizeLeft, Res]),
+ case (catch do_get_rep(SizeLeft, MibView, MaxRepetitions,
+ RestVbs, Res,
+ length(UResNonRepVbs), GbMaxVBs)) of
+ {error, Idx, Reason} ->
+ ?LIB:user_err("failed encoding varbind ~w:~n~p",
+ [Idx, Reason]),
+ {genErr, Idx, []};
+ Res when is_list(Res) ->
+ ?vtrace("do get bulk -> Res: "
+ "~n ~w", [Res]),
+ {noError, 0, conv_res(Res)};
+ {noError, 0, Data} = OK ->
+ ?vtrace("do get bulk -> OK: "
+ "~n length(Data): ~w", [length(Data)]),
+ OK;
+ Else ->
+ ?vtrace("do get bulk -> Else: "
+ "~n ~w", [Else]),
+ Else
+ end;
+ Res when is_list(Res) ->
+ {noError, 0, conv_res(Res)}
+ end;
+
+ {ErrorStatus, Index, _} ->
+ ?vdebug("do get bulk: "
+ "~n ErrorStatus: ~p"
+ "~n Index: ~p",[ErrorStatus, Index]),
+ {ErrorStatus, Index, []}
+ end.
+
+enc_vbs(SizeLeft, Vbs) ->
+ ?vt("enc_vbs -> entry with"
+ "~n SizeLeft: ~w", [SizeLeft]),
+ Fun = fun(Vb, {Sz, Res}) when Sz > 0 ->
+ ?vt("enc_vbs -> (fun) entry with"
+ "~n Vb: ~p"
+ "~n Sz: ~p"
+ "~n Res: ~w", [Vb, Sz, Res]),
+ case (catch snmp_pdus:enc_varbind(Vb)) of
+ {'EXIT', Reason} ->
+ ?vtrace("enc_vbs -> encode failed: "
+ "~n Reason: ~p", [Reason]),
+ throw({error, Vb#varbind.org_index, Reason});
+ X ->
+ ?vt("enc_vbs -> X: ~w", [X]),
+ Lx = length(X),
+ ?vt("enc_vbs -> Lx: ~w", [Lx]),
+ if
+ Lx < Sz ->
+ {Sz - length(X), [X | Res]};
+ true ->
+ throw(Res)
+ end
+ end;
+ (_Vb, {_Sz, [_H | T]}) ->
+ ?vt("enc_vbs -> (fun) entry with"
+ "~n T: ~p", [T]),
+ throw(T);
+ (_Vb, {_Sz, []}) ->
+ ?vt("enc_vbs -> (fun) entry", []),
+ throw([])
+ end,
+ lists:foldl(Fun, {SizeLeft, []}, Vbs).
+
+do_get_rep(Sz, MibView, MaxRepetitions, Varbinds, Res, GbNumVBs, GbMaxVBs)
+ when MaxRepetitions >= 0 ->
+ do_get_rep(Sz, MibView, 0, MaxRepetitions, Varbinds, Res,
+ GbNumVBs, GbMaxVBs);
+do_get_rep(Sz, MibView, _MaxRepetitions, Varbinds, Res, GbNumVBs, GbMaxVBs) ->
+ do_get_rep(Sz, MibView, 0, 0, Varbinds, Res, GbNumVBs, GbMaxVBs).
+
+conv_res(ResVarbinds) ->
+ conv_res(ResVarbinds, []).
+conv_res([VbListOfBytes | T], Bytes) ->
+ conv_res(T, VbListOfBytes ++ Bytes);
+conv_res([], Bytes) ->
+ Bytes.
+
+%% The only other value, then a positive integer, is infinity.
+do_get_rep(_Sz, _MibView, Count, Max, _, _Res, GbNumVBs, GbMaxVBs)
+ when (is_integer(GbMaxVBs) andalso (GbNumVBs > GbMaxVBs)) ->
+ ?vinfo("Max Get-BULK VBs limit (~w) exceeded (~w) when:"
+ "~n Count: ~p"
+ "~n Max: ~p", [GbMaxVBs, GbNumVBs, Count, Max]),
+ {tooBig, 0, []};
+do_get_rep(_Sz, _MibView, Max, Max, _, Res, _GbNumVBs, _GbMaxVBs) ->
+ ?vt("do_get_rep -> done when: "
+ "~n Res: ~p", [Res]),
+ {noError, 0, conv_res(Res)};
+do_get_rep(Sz, MibView, Count, Max, Varbinds, Res, GbNumVBs, GbMaxVBs) ->
+ ?vt("do_get_rep -> entry when: "
+ "~n Sz: ~p"
+ "~n Count: ~p"
+ "~n Res: ~w", [Sz, Count, Res]),
+ case try_get_bulk(Sz, MibView, Varbinds, GbMaxVBs) of
+ {noError, NextVarbinds, SizeLeft, Res2} ->
+ ?vt("do_get_rep -> noError: "
+ "~n SizeLeft: ~p"
+ "~n Res2: ~p", [SizeLeft, Res2]),
+ do_get_rep(SizeLeft, MibView, Count+1, Max, NextVarbinds,
+ Res2 ++ Res,
+ GbNumVBs + length(Varbinds), GbMaxVBs);
+ {endOfMibView, _NextVarbinds, _SizeLeft, Res2} ->
+ ?vt("do_get_rep -> endOfMibView: "
+ "~n Res2: ~p", [Res2]),
+ {noError, 0, conv_res(Res2 ++ Res)};
+ {ErrorStatus, Index} ->
+ ?vtrace("do_get_rep -> done when error: "
+ "~n ErrorStatus: ~p"
+ "~n Index: ~p", [ErrorStatus, Index]),
+ {ErrorStatus, Index, []}
+ end.
+
+try_get_bulk(Sz, MibView, Varbinds, GbMaxVBs) ->
+ ?vt("try_get_bulk -> entry with"
+ "~n Sz: ~w"
+ "~n MibView: ~w"
+ "~n Varbinds: ~w", [Sz, MibView, Varbinds]),
+ case do_get_next2(MibView, Varbinds, GbMaxVBs) of
+ {noError, 0, UNextVarbinds} ->
+ ?vt("try_get_bulk -> noError: "
+ "~n UNextVarbinds: ~p", [UNextVarbinds]),
+ NextVarbinds = ?LIB:org_index_sort_vbs(UNextVarbinds),
+ case (catch enc_vbs(Sz, NextVarbinds)) of
+ {error, Idx, Reason} ->
+ ?LIB:user_err("failed encoding varbind ~w:~n~p", [Idx, Reason]),
+ ?vtrace("try_get_bulk -> encode error: "
+ "~n Idx: ~p"
+ "~n Reason: ~p", [Idx, Reason]),
+ {genErr, Idx};
+ {SizeLeft, Res} when is_integer(SizeLeft) andalso
+ is_list(Res) ->
+ ?vt("try get bulk -> encode ok: "
+ "~n SizeLeft: ~w"
+ "~n Res: ~w", [SizeLeft, Res]),
+ {check_end_of_mibview(NextVarbinds),
+ NextVarbinds, SizeLeft, Res};
+ Res when is_list(Res) ->
+ ?vt("try get bulk -> Res: "
+ "~n ~w", [Res]),
+ {endOfMibView, [], 0, Res}
+ end;
+ {ErrorStatus, Index, _} ->
+ ?vt("try_get_bulk -> error: "
+ "~n ErrorStatus: ~p"
+ "~n Index: ~p", [ErrorStatus, Index]),
+ {ErrorStatus, Index}
+ end.
+
+%% If all variables in this pass are endOfMibView,
+%% there is no reason to continue.
+check_end_of_mibview([#varbind{value = endOfMibView} | T]) ->
+ check_end_of_mibview(T);
+check_end_of_mibview([]) -> endOfMibView;
+check_end_of_mibview(_) -> noError.
+
+
+
diff --git a/lib/snmp/src/agent/snmpa_get_lib.erl b/lib/snmp/src/agent/snmpa_get_lib.erl
new file mode 100644
index 0000000000..eaf7fe2641
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_get_lib.erl
@@ -0,0 +1,254 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019-2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%% Note that most of these functions *assume* that they are executed
+%% by the agent. If they are not they may note work as they require
+%% some properties to be set in the process dictionary!
+%%
+
+-module(snmpa_get_lib).
+
+-export([
+ split_vbs/1, split_vbs/3,
+ split_vbs_view/2,
+ split_vbs_gb/2,
+
+ agent_sort_vbs/1,
+ oid_sort_vbs/1, org_index_sort_vbs/1,
+
+ sa_split/1,
+
+ delete_prefixes/2,
+
+ dbg_apply/3,
+
+ user_err/2
+ ]).
+
+-define(VMODULE,"GET-LIB").
+-include("snmpa_internal.hrl").
+-include("snmp_types.hrl").
+-include("snmp_debug.hrl").
+-include("snmp_verbosity.hrl").
+
+
+
+
+%%-----------------------------------------------------------------
+%% split_vbs/1,3
+%%
+%% Splits the list of varbinds (basically) into two lists. One
+%% of 'end of'-varbinds (mib view and tables) and then the rest
+%% of the varbinds.
+%%-----------------------------------------------------------------
+
+-spec split_vbs(VBs :: [snmp:varbind()]) ->
+ {ResVBs :: [snmp:varbind()],
+ EndOfVBs :: [snmp:varbind()]}.
+
+split_vbs(VBs) ->
+ split_vbs(VBs, [], []).
+
+-spec split_vbs(VBs :: [snmp:varbind()],
+ Res :: [snmp:varbind()],
+ EndOfs :: [snmp:varbind()]) ->
+ {ResVBs :: [snmp:varbind()],
+ EndOfVBs :: [snmp:varbind()]}.
+
+split_vbs([], ResVBs, EndOfVBs) ->
+ {ResVBs, EndOfVBs};
+split_vbs([VB | VBs], Res, EndOfs) ->
+ case VB#varbind.value of
+ {endOfMibView, _} -> split_vbs(VBs, Res, [VB | EndOfs]);
+ {endOfTable, _} -> split_vbs(VBs, Res, [VB | EndOfs]);
+ _ -> split_vbs(VBs, [VB | Res], EndOfs)
+ end.
+
+
+
+%%-----------------------------------------------------------------
+%% split_vbs_view/2
+%%
+%% Splits a list of varbinds into two lists based on the provided
+%% MibView. One list of varbinds inside the MibView and one of
+%% varbinds outside the MibView.
+%%-----------------------------------------------------------------
+
+-spec split_vbs_view(VBs :: [snmp:varbind()],
+ MibView :: snmp_view_based_acm_mib:mibview()) ->
+ {OutSideView :: [snmp:varbind()],
+ InSideView :: [snmp:varbind()]}.
+
+split_vbs_view(VBs, MibView) ->
+ ?vtrace("split the varbinds view", []),
+ split_vbs_view(VBs, MibView, [], []).
+
+split_vbs_view([], _MibView, Out, In) ->
+ {Out, In};
+split_vbs_view([VB | VBs], MibView, Out, In) ->
+ case snmpa_acm:validate_mib_view(VB#varbind.oid, MibView) of
+ true ->
+ split_vbs_view(VBs, MibView, Out, [VB | In]);
+ false ->
+ VB2 = VB#varbind{value = noSuchObject},
+ split_vbs_view(VBs, MibView, [VB2 | Out], In)
+ end.
+
+
+
+%%-----------------------------------------------------------------
+%% split_vbs_gb/2
+%%
+%% Performs a get-bulk split of the varbinds
+%%-----------------------------------------------------------------
+
+-spec split_vbs_gb(NonRepeaters :: integer(),
+ VBs :: [snmp:varbind()]) ->
+ {NonRepVBs :: [snmp:varbind()],
+ RestVBs :: [snmp:varbind()]}.
+
+split_vbs_gb(N, VBs) ->
+ split_vbs_gb(N, VBs, []).
+
+split_vbs_gb(N, Varbinds, Res) when N =< 0 ->
+ {Res, Varbinds};
+split_vbs_gb(N, [H | T], Res) ->
+ split_vbs_gb(N-1, T, [H | Res]);
+split_vbs_gb(_N, [], Res) ->
+ {Res, []}.
+
+
+
+%%-----------------------------------------------------------------
+%% agent_sort_vbs/1
+%%
+%% Sorts the varbinds into two categories. The first is varbinds
+%% belonging to "our" agent and the other is varbinds for
+%% subagents.
+%%-----------------------------------------------------------------
+
+-spec agent_sort_vbs(VBs :: [snmp:varbind()]) ->
+ {AgentVBs :: [snmp:varbind()],
+ SubAgentVBs :: [snmp:varbind()]}.
+
+agent_sort_vbs(VBs) ->
+ snmpa_svbl:sort_varbindlist(get(mibserver), VBs).
+
+
+%%-----------------------------------------------------------------
+%% oid_sort_vbs/1
+%%
+%% Sorts the varbinds based on their oid.
+%%-----------------------------------------------------------------
+
+-spec oid_sort_vbs(VBs :: [snmp:varbind()]) -> SortedVBs :: [snmp:varbind()].
+
+oid_sort_vbs(VBs) ->
+ lists:keysort(#varbind.oid, VBs).
+
+
+%%-----------------------------------------------------------------
+%% org_index_sort_vbs/1
+%%
+%% Sorts the varbinds based on their org_index.
+%%-----------------------------------------------------------------
+
+-spec org_index_sort_vbs(VBs :: [snmp:varbind()]) -> SortedVBs :: [snmp:varbind()].
+
+org_index_sort_vbs(Vbs) ->
+ lists:keysort(#varbind.org_index, Vbs).
+
+
+
+%%-----------------------------------------------------------------
+%% sa_split/1
+%%
+%% Splits a list of {oid(), varbind()} into two lists of oid()
+%% and varbind. The resulting lists are reversed!
+%%-----------------------------------------------------------------
+
+-spec sa_split(SAVBs :: [{SAOid :: snmp:oid(), snmp:varbind()}]) ->
+ {Oids :: [snmp:oid()], VBs :: [snmp:varbind()]}.
+
+sa_split(SAVBs) ->
+ snmpa_svbl:sa_split(SAVBs).
+
+
+
+%%-----------------------------------------------------------------
+%% delete_prefixes/2
+%%
+%% Takes an Oid prefix and a list of ivarbinds and produces a list
+%% of {ShortOid, ASN1Type}. The ShortOid is basically the oid with
+%% the OidPrefix removed.
+%%-----------------------------------------------------------------
+
+-spec delete_prefixes(OidPrefix :: snmp:oid(),
+ VBs :: [snmp:ivarbind()]) ->
+ [{ShortOid :: snmp:oid(),
+ ASN1Type :: snmp:asn1_type()}].
+
+delete_prefixes(OidPrefix, IVBs) ->
+ [{snmp_misc:diff(Oid, OidPrefix), ME#me.asn1_type} ||
+ #ivarbind{varbind = #varbind{oid = Oid}, mibentry = ME} <- IVBs].
+
+
+
+%%-----------------------------------------------------------------
+%% dbg_apply/3
+%%
+%% Call instrumentation functions, but allow for debug printing
+%% of useful debug info.
+%%-----------------------------------------------------------------
+
+-spec dbg_apply(M :: atom(), F :: atom(), A :: list()) ->
+ any().
+
+dbg_apply(M, F, A) ->
+ case get(verbosity) of
+ silence ->
+ apply(M,F,A);
+ _ ->
+ ?vlog("~n apply: ~w, ~w, ~p~n", [M,F,A]),
+ Res = (catch apply(M,F,A)),
+ case Res of
+ {'EXIT', Reason} ->
+ ?vinfo("Call to: "
+ "~n Module: ~p"
+ "~n Function: ~p"
+ "~n Args: ~p"
+ "~n"
+ "~nresulted in an exit"
+ "~n"
+ "~n ~p~n", [M, F, A, Reason]);
+ _ ->
+ ?vlog("~n returned: ~p~n", [Res])
+ end,
+ Res
+ end.
+
+
+%% ---------------------------------------------------------------------
+
+user_err(F, A) ->
+ snmpa_error:user_err(F, A).
+
+
diff --git a/lib/snmp/src/agent/snmpa_get_mechanism.erl b/lib/snmp/src/agent/snmpa_get_mechanism.erl
new file mode 100644
index 0000000000..744a6529e1
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_get_mechanism.erl
@@ -0,0 +1,79 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019-2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(snmpa_get_mechanism).
+
+%%
+%% This module defines the behaviour for the undocumented (hidden)
+%% get-mechanism feature. This allows for implementing your own
+%% handling of get, get-next and get-bulk requests.
+%% Probably only useful for special cases (e.g. optimization).
+%%
+
+
+
+%% ----------- do_get/2,3 -----------------------------------------------------
+
+%% Purpose: Handles all VBs in a request that is inside the
+%% mibview (local).
+
+-callback do_get(UnsortedVBs :: [snmp:varbind()],
+ IsNotification :: boolean(),
+ Extra :: term()) ->
+ {noError, 0, ResVBs :: [snmp:varbind()]} |
+ {ErrStatus :: snmp:error_status(), ErrIndex :: snmp:error_index(), []}.
+
+
+%% Purpose: Handles "get-requests".
+
+-callback do_get(MibView :: snmp_view_based_acm_mib:mibview(),
+ UnsortedVBs :: [snmp:varbind()],
+ IsNotification :: boolean(),
+ Extra :: term()) ->
+ {noError, 0, ResVBs :: [snmp:varbind()]} |
+ {ErrStatus :: snmp:error_status(), ErrIndex :: snmp:error_index(), []}.
+
+
+
+
+%% ----------- do_get_next/2 ------------------------------------------------
+
+%% Purpose: Handles "get-next-requests".
+
+-callback do_get_next(MibView :: snmp_view_based_acm_mib:mibview(),
+ UnsortedVBs :: [snmp:varbind()],
+ Extra :: term()) ->
+ {noError, 0, ResVBs :: [snmp:varbind()]} |
+ {ErrStatus :: snmp:error_status(), ErrIndex :: snmp:error_index(), []}.
+
+
+
+
+%% ----------- do_get_bulk/6 ------------------------------------------------
+
+-callback do_get_bulk(MibView :: snmp_view_based_acm_mib:mibview(),
+ NonRepeaters :: non_neg_integer(),
+ MaxRepetitions :: non_neg_integer(),
+ PduMS :: pos_integer(),
+ VBs :: [snmp:varbind()],
+ MaxVBs :: pos_integer(),
+ Extra :: term()) ->
+ {noError, 0, ResVBs :: [snmp:varbind()]} |
+ {ErrStatus :: snmp:error_status(), ErrIndex :: snmp:error_index(), []}.
diff --git a/lib/snmp/src/agent/snmpa_set_lib.erl b/lib/snmp/src/agent/snmpa_set_lib.erl
index 57507a36e8..3dcf49cbe6 100644
--- a/lib/snmp/src/agent/snmpa_set_lib.erl
+++ b/lib/snmp/src/agent/snmpa_set_lib.erl
@@ -390,7 +390,7 @@ dbg_apply(M,F,A) ->
{'EXIT', {function_clause, [{M, F, A} | _]}} ->
{'EXIT', {hook_function_clause, {M, F, A}}};
- % XYZ: Older format for compatibility
+ %% XYZ: Older format for compatibility
{'EXIT', {undef, {M, F, A}}} ->
{'EXIT', {hook_undef, {M, F, A}}};
{'EXIT', {function_clause, {M, F, A}}} ->
diff --git a/lib/snmp/src/agent/snmpa_supervisor.erl b/lib/snmp/src/agent/snmpa_supervisor.erl
index cdb5ca840d..2cb0556001 100644
--- a/lib/snmp/src/agent/snmpa_supervisor.erl
+++ b/lib/snmp/src/agent/snmpa_supervisor.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -193,36 +193,36 @@ init([AgentType, Opts]) ->
?vdebug("agent restart type: ~w", [Restart]),
%% -- Agent type --
- ets:insert(snmp_agent_table, {agent_type, AgentType}),
+ store(agent_type, AgentType),
%% -- Prio --
Prio = get_opt(priority, Opts, normal),
?vdebug("[agent table] store priority: ~p",[Prio]),
- ets:insert(snmp_agent_table, {priority, Prio}),
+ store(priority, Prio),
%% -- Versions --
Vsns = get_opt(versions, Opts, [v1,v2,v3]),
?vdebug("[agent table] store versions: ~p",[Vsns]),
- ets:insert(snmp_agent_table, {versions, Vsns}),
+ store(versions, Vsns),
%% -- Max number of VBs in a Get-BULK response --
GbMaxVBs = get_gb_max_vbs(Opts),
?vdebug("[agent table] Get-BULK max VBs: ~p", [GbMaxVBs]),
- ets:insert(snmp_agent_table, {gb_max_vbs, GbMaxVBs}),
+ store(gb_max_vbs, GbMaxVBs),
%% -- DB-directory --
DbDir = get_opt(db_dir, Opts),
?vdebug("[agent table] store db_dir: ~n ~p",[DbDir]),
- ets:insert(snmp_agent_table, {db_dir, filename:join([DbDir])}),
+ store(db_dir, filename:join([DbDir])),
DbInitError = get_opt(db_init_error, Opts, terminate),
?vdebug("[agent table] store db_init_error: ~n ~p",[DbInitError]),
- ets:insert(snmp_agent_table, {db_init_error, DbInitError}),
+ store(db_init_error, DbInitError),
%% -- Error report module --
ErrorReportMod = get_opt(error_report_mod, Opts, snmpa_error_logger),
?vdebug("[agent table] store error report module: ~w",[ErrorReportMod]),
- ets:insert(snmp_agent_table, {error_report_mod, ErrorReportMod}),
+ store(error_report_mod, ErrorReportMod),
%% -- mib storage --
%% MibStorage has only one mandatory part: module
@@ -320,31 +320,31 @@ init([AgentType, Opts]) ->
end,
?vdebug("[agent table] store mib storage: ~w", [MibStorage]),
- ets:insert(snmp_agent_table, {mib_storage, MibStorage}),
+ store(mib_storage, MibStorage),
%% -- Agent mib storage --
AgentMibStorage = get_opt(agent_mib_storage, Opts, persistent),
%% ?vdebug("[agent table] store agent mib storage: ~w",[AgentMibStorage]),
- ets:insert(snmp_agent_table, {agent_mib_storage, AgentMibStorage}),
+ store(agent_mib_storage, AgentMibStorage),
%% -- System start time --
?vdebug("[agent table] store system start time",[]),
- ets:insert(snmp_agent_table, {system_start_time, snmp_misc:now(cs)}),
+ store(system_start_time, snmp_misc:now(cs)),
%% -- Symbolic store options --
SsOpts = get_opt(symbolic_store, Opts, []),
?vdebug("[agent table] store symbolic store options: ~w",[SsOpts]),
- ets:insert(snmp_agent_table, {symbolic_store, SsOpts}),
+ store(symbolic_store, SsOpts),
%% -- Local DB options --
LdbOpts = get_opt(local_db, Opts, []),
?vdebug("[agent table] store local db options: ~w",[LdbOpts]),
- ets:insert(snmp_agent_table, {local_db, LdbOpts}),
+ store(local_db, LdbOpts),
%% -- Target cache options --
TargetCacheOpts = get_opt(target_cache, Opts, []),
?vdebug("[agent table] store target cache options: ~w",[TargetCacheOpts]),
- ets:insert(snmp_agent_table, {target_cache, TargetCacheOpts}),
+ store(target_cache, TargetCacheOpts),
%% -- Specs --
SupFlags = {one_for_all, 0, 3600},
@@ -377,7 +377,7 @@ init([AgentType, Opts]) ->
%% -- Config --
ConfOpts = get_opt(config, Opts, []),
?vdebug("[agent table] store config options: ~p", [ConfOpts]),
- ets:insert(snmp_agent_table, {config, ConfOpts}),
+ store(config, ConfOpts),
ConfigArgs = [Vsns, ConfOpts],
ConfigSpec =
@@ -390,43 +390,46 @@ init([AgentType, Opts]) ->
%% -- Discovery processing --
DiscoOpts = get_opt(discovery, Opts, []),
?vdebug("[agent table] store discovery options: ~p", [DiscoOpts]),
- ets:insert(snmp_agent_table, {discovery, DiscoOpts}),
+ store(discovery, DiscoOpts),
%% -- Mibs --
Mibs = get_mibs(get_opt(mibs, Opts, []), Vsns),
?vdebug("[agent table] store mibs: ~n ~p",[Mibs]),
- ets:insert(snmp_agent_table, {mibs, Mibs}),
+ store(mibs, Mibs),
Ref = make_ref(),
+ %% -- Get module --
+ GetModule = get_opt(get_mechanism, Opts, snmpa_get),
+ ?vdebug("[agent table] store get-module: ~p", [GetModule]),
+ store(get_mechanism, GetModule),
+
%% -- Set module --
SetModule = get_opt(set_mechanism, Opts, snmpa_set),
?vdebug("[agent table] store set-module: ~p",[SetModule]),
- ets:insert(snmp_agent_table, {set_mechanism, ConfOpts}),
+ store(set_mechanism, SetModule),
%% -- Authentication service --
AuthModule = get_opt(authentication_service, Opts, snmpa_acm),
?vdebug("[agent table] store authentication service: ~w",
[AuthModule]),
- ets:insert(snmp_agent_table,
- {authentication_service, AuthModule}),
+ store(authentication_service, AuthModule),
%% -- Multi-threaded --
MultiT = get_opt(multi_threaded, Opts, false),
- ?vdebug("[agent table] store multi-threaded: ~p",[MultiT]),
- ets:insert(snmp_agent_table, {multi_threaded, MultiT}),
+ ?vdebug("[agent table] store multi-threaded: ~p", [MultiT]),
+ store(multi_threaded, MultiT),
%% -- Audit trail log --
case get_opt(audit_trail_log, Opts, not_found) of
not_found ->
- ?vdebug("[agent table] no audit trail log",[]),
+ ?vdebug("[agent table] no audit trail log", []),
ok;
AtlOpts ->
?vdebug("[agent table] "
"store audit trail log options: ~p",
[AtlOpts]),
- ets:insert(snmp_agent_table,
- {audit_trail_log, AtlOpts}),
+ store(audit_trail_log, AtlOpts),
ok
end,
@@ -434,24 +437,25 @@ init([AgentType, Opts]) ->
MibsOpts = get_opt(mib_server, Opts, []),
?vdebug("[agent table] store mib-server options: "
"~n ~p", [MibsOpts]),
- ets:insert(snmp_agent_table, {mib_server, MibsOpts}),
+ store(mib_server, MibsOpts),
%% -- Network interface --
NiOpts = get_opt(net_if, Opts, []),
?vdebug("[agent table] store net-if options: "
"~n ~p", [NiOpts]),
- ets:insert(snmp_agent_table, {net_if, NiOpts}),
+ store(net_if, NiOpts),
%% -- Note store --
NsOpts = get_opt(note_store, Opts, []),
?vdebug("[agent table] store note-store options: "
"~n ~p",[NsOpts]),
- ets:insert(snmp_agent_table, {note_store, NsOpts}),
+ store(note_store, NsOpts),
AgentOpts =
[{verbosity, AgentVerb},
{mibs, Mibs},
{mib_storage, MibStorage},
+ {get_mechanism, GetModule},
{set_mechanism, SetModule},
{authentication_service, AuthModule},
{multi_threaded, MultiT},
@@ -480,6 +484,10 @@ init([AgentType, Opts]) ->
{ok, {SupFlags, [MiscSupSpec, SymStoreSpec, LocalDbSpec, TargetCacheSpec |
Rest]}}.
+
+store(Key, Value) ->
+ ets:insert(snmp_agent_table, {Key, Value}).
+
get_mibs(Mibs, Vsns) ->
MibDir = filename:join(code:priv_dir(snmp), "mibs"),
StdMib =
diff --git a/lib/snmp/src/agent/snmpa_trap.erl b/lib/snmp/src/agent/snmpa_trap.erl
index e75016f7ec..31805c3bee 100644
--- a/lib/snmp/src/agent/snmpa_trap.erl
+++ b/lib/snmp/src/agent/snmpa_trap.erl
@@ -917,7 +917,7 @@ do_send_v2_trap(Recvs, Vbs, ExtraInfo, NetIf) ->
TrapPdu = make_v2_notif_pdu(Vbs, 'snmpv2-trap'),
AddrCommunities = mk_addr_communities(Recvs),
lists:foreach(fun({Community, Addrs}) ->
- ?vtrace("~n send v2 trap to ~p",[Addrs]),
+ ?vtrace("send v2 trap to ~p",[Addrs]),
NetIf ! {send_pdu, 'version-2', TrapPdu,
{community, Community}, Addrs, ExtraInfo}
end, AddrCommunities),
diff --git a/lib/snmp/src/app/snmp.app.src b/lib/snmp/src/app/snmp.app.src
index d4bf0de61a..178309b488 100644
--- a/lib/snmp/src/app/snmp.app.src
+++ b/lib/snmp/src/app/snmp.app.src
@@ -49,6 +49,9 @@
snmpa_error_io,
snmpa_error_logger,
snmpa_error_report,
+ snmpa_get,
+ snmpa_get_lib,
+ snmpa_get_mechanism,
snmpa_local_db,
snmpa_mib,
snmpa_mib_data,
diff --git a/lib/snmp/src/app/snmp.config b/lib/snmp/src/app/snmp.config
index b66ef5d7df..f35a636157 100644
--- a/lib/snmp/src/app/snmp.config
+++ b/lib/snmp/src/app/snmp.config
@@ -8,6 +8,7 @@
%% {agent_verbosity, verbosity()} |
%% {versions, versions()} |
%% {priority, atom()} |
+%% {get_mechanism, module()} |
%% {set_mechanism, module()} |
%% {authentication_service, module()} |
%% {multi_threaded, bool()} |
diff --git a/lib/snmp/src/app/snmp.erl b/lib/snmp/src/app/snmp.erl
index 8a736f688b..216452afdd 100644
--- a/lib/snmp/src/app/snmp.erl
+++ b/lib/snmp/src/app/snmp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -116,7 +116,10 @@
pdu/0,
trappdu/0,
mib/0,
- mib_name/0,
+ mib_name/0,
+
+ error_status/0,
+ error_index/0,
void/0
]).
@@ -208,6 +211,23 @@
-type pdu() :: #pdu{}.
-type trappdu() :: #trappdu{}.
+%% We should really specify all of these, but they are so numerous...
+%% See the validate_err/1 function in the snmpa_agent.
+%% Here are a number of them:
+%% badValue |
+%% commitFailed |
+%% genErr |
+%% inconsistentName | inconsistentValue |
+%% noAccess | noCreation |
+%% noSuchInstance | noSuchName | noSuchObject |
+%% notWritable |
+%% resourceUnavailable |
+%% undoFailed |
+%% wrongValue
+
+-type error_status() :: atom().
+-type error_index() :: pos_integer().
+
-type void() :: term().
diff --git a/lib/snmp/test/modules.mk b/lib/snmp/test/modules.mk
index 0f54e67c65..8b6547f9a9 100644
--- a/lib/snmp/test/modules.mk
+++ b/lib/snmp/test/modules.mk
@@ -31,6 +31,7 @@ SUITE_MODULES = \
snmp_agent_mibs_test \
snmp_agent_nfilter_test \
snmp_agent_test \
+ snmp_agent_test_get \
snmp_agent_conf_test \
snmp_agent_test_lib \
snmp_manager_config_test \
diff --git a/lib/snmp/test/snmp_agent_test_get.erl b/lib/snmp/test/snmp_agent_test_get.erl
new file mode 100644
index 0000000000..517c71507a
--- /dev/null
+++ b/lib/snmp/test/snmp_agent_test_get.erl
@@ -0,0 +1,58 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019-2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(snmp_agent_test_get).
+
+-behaviour(snmpa_get_mechanism).
+
+
+%%%-----------------------------------------------------------------
+%%% snmpa_get_mechanism exports
+%%%-----------------------------------------------------------------
+
+-export([
+ do_get/3, do_get/4,
+ do_get_next/3,
+ do_get_bulk/7
+ ]).
+
+
+
+do_get(UnsortedVarbinds, IsNotification, Extra) ->
+ snmpa_get:do_get(UnsortedVarbinds, IsNotification, Extra).
+
+
+
+do_get(MibView, UnsortedVarbinds, IsNotification, Extra) ->
+ snmpa_get:do_get(MibView, UnsortedVarbinds, IsNotification, Extra).
+
+
+
+do_get_next(MibView, UnsortedVBs, Extra) ->
+ snmpa_get:do_get_next(MibView, UnsortedVBs, Extra).
+
+
+
+
+do_get_bulk(MibView, NonRepeaters, MaxRepetitions,
+ PduMS, Varbinds, GbMaxVBs, Extra) ->
+ snmpa_get:do_get_bulk(MibView, NonRepeaters, MaxRepetitions,
+ PduMS, Varbinds, GbMaxVBs,
+ Extra).
diff --git a/lib/snmp/test/snmp_agent_test_lib.erl b/lib/snmp/test/snmp_agent_test_lib.erl
index 66211d7105..c19c88528f 100644
--- a/lib/snmp/test/snmp_agent_test_lib.erl
+++ b/lib/snmp/test/snmp_agent_test_lib.erl
@@ -445,6 +445,7 @@ start_agent(Config, Vsns, Opts) ->
[{versions, Vsns},
{agent_type, master},
{agent_verbosity, trace},
+ {get_mechanism, snmp_agent_test_get},
{db_dir, AgentDbDir},
{audit_trail_log, [{type, read_write},
{dir, AgentLogDir},
diff --git a/lib/snmp/test/snmp_manager_test.erl b/lib/snmp/test/snmp_manager_test.erl
index 6ced55f0cc..bb9b05b89f 100644
--- a/lib/snmp/test/snmp_manager_test.erl
+++ b/lib/snmp/test/snmp_manager_test.erl
@@ -6179,7 +6179,12 @@ start_agent(Node, Vsns, Conf0, _Opts) ->
{mib_server, [{verbosity, MSV}]},
{note_store, [{verbosity, NSV}]},
{stymbolic_store, [{verbosity, SSV}]},
- {net_if, [{verbosity, NIV}]},
+ {net_if, [{verbosity, NIV},
+ %% On some linux "they" add a 127.0.1.1 or somthing
+ %% similar, so if we don't specify bind_to
+ %% we don't know which address will be selected
+ %% (which will cause problems for some test cases).
+ {options, [{bind_to, true}]}]},
{multi_threaded, true}],
?line ok = set_agent_env(Node, Env),
diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml
index 68a0afcbee..40ec19c701 100644
--- a/lib/ssh/doc/src/notes.xml
+++ b/lib/ssh/doc/src/notes.xml
@@ -30,6 +30,31 @@
<file>notes.xml</file>
</header>
+<section><title>Ssh 4.7.5</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The callback <c>ssh_channel:init/1</c> was missing in
+ OTP-21</p>
+ <p>
+ Own Id: OTP-15762</p>
+ </item>
+ <item>
+ <p>
+ If a client was connected to an server on an already open
+ socket, the callback <c>fun(PeerName,FingerPrint)</c> in
+ the <c>accept_callback</c> option passed the local name
+ in the argument PeerName instead of the remote name.</p>
+ <p>
+ Own Id: OTP-15763</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Ssh 4.7.4</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index 9281bf84a7..ff5aee14d7 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -127,7 +127,7 @@ connect(Socket, UserOptions, NegotiationTimeout) when is_port(Socket),
Options ->
case valid_socket_to_use(Socket, ?GET_OPT(transport,Options)) of
ok ->
- {ok, {Host,_Port}} = inet:sockname(Socket),
+ {ok, {Host,_Port}} = inet:peername(Socket),
Opts = ?PUT_INTERNAL_OPT([{user_pid,self()}, {host,Host}], Options),
ssh_connection_handler:start_connection(client, Socket, Opts, NegotiationTimeout);
{error,SockError} ->
diff --git a/lib/ssh/src/ssh_channel.erl b/lib/ssh/src/ssh_channel.erl
index 443bd05086..1d977e3bc9 100644
--- a/lib/ssh/src/ssh_channel.erl
+++ b/lib/ssh/src/ssh_channel.erl
@@ -58,6 +58,7 @@
State::term()}.
%%% API
-export([start/4, start/5, start_link/4, start_link/5, call/2, call/3,
+ init/1,
cast/2, reply/2, enter_loop/1]).
%%====================================================================
@@ -76,6 +77,9 @@ cast(ChannelPid, Msg) ->
reply(From, Msg) ->
ssh_client_channel:reply(From, Msg).
+init(Args) ->
+ ssh_client_channel:init(Args).
+
start(ConnectionManager, ChannelId, CallBack, CbInitArgs) ->
ssh_client_channel:start(ConnectionManager, ChannelId, CallBack, CbInitArgs).
diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk
index 0f9eee887c..2947f82556 100644
--- a/lib/ssh/vsn.mk
+++ b/lib/ssh/vsn.mk
@@ -1,4 +1,4 @@
#-*-makefile-*- ; force emacs to enter makefile-mode
-SSH_VSN = 4.7.4
+SSH_VSN = 4.7.5
APP_VSN = "ssh-$(SSH_VSN)"
diff --git a/lib/ssl/doc/src/notes.xml b/lib/ssl/doc/src/notes.xml
index 874c5dd11d..b036463e87 100644
--- a/lib/ssl/doc/src/notes.xml
+++ b/lib/ssl/doc/src/notes.xml
@@ -27,6 +27,30 @@
</header>
<p>This document describes the changes made to the SSL application.</p>
+<section><title>SSL 9.2.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The timeout for a passive receive was sometimes not
+ cancelled and later caused a server crash. This bug has
+ now been corrected.</p>
+ <p>
+ Own Id: OTP-14701 Aux Id: ERL-883, ERL-884 </p>
+ </item>
+ <item>
+ <p>
+ Add tag for passive message (active N) in cb_info to
+ retain transport transparency.</p>
+ <p>
+ Own Id: OTP-15679 Aux Id: ERL-861 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>SSL 9.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
index 90a9181ede..24d063e1bd 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -101,16 +101,21 @@
<datatype>
<name name="transport_option"/>
<desc>
- <p>Defaults to <c>{gen_tcp, tcp, tcp_closed, tcp_error}</c>
- for TLS and <c>{gen_udp, udp, udp_closed, udp_error}</c> for
- DTLS. Can be used to customize the transport layer. The tag
- values should be the values used by the underlying transport
- in its active mode messages. For TLS the callback module must implement a
- reliable transport protocol, behave as <c>gen_tcp</c>, and have functions
- corresponding to <c>inet:setopts/2</c>, <c>inet:getopts/2</c>,
- <c>inet:peername/1</c>, <c>inet:sockname/1</c>, and <c>inet:port/1</c>.
- The callback <c>gen_tcp</c> is treated specially and calls <c>inet</c>
- directly. For DTLS this feature must be considered exprimental.
+ <p>Defaults to <c>{gen_tcp, tcp, tcp_closed, tcp_error,
+ tcp_passive}</c> for TLS (for backward compatibility a four
+ tuple will be converted to a five tuple with the last element
+ "second_element"_passive) and <c>{gen_udp, udp, udp_closed,
+ udp_error}</c> for DTLS (might also be changed to five tuple in
+ the future). Can be used to customize the transport layer. The
+ tag values should be the values used by the underlying
+ transport in its active mode messages. For TLS the callback
+ module must implement a reliable transport protocol, behave as
+ <c>gen_tcp</c>, and have functions corresponding to
+ <c>inet:setopts/2</c>, <c>inet:getopts/2</c>,
+ <c>inet:peername/1</c>, <c>inet:sockname/1</c>, and
+ <c>inet:port/1</c>. The callback <c>gen_tcp</c> is treated
+ specially and calls <c>inet</c> directly. For DTLS this
+ feature must be considered exprimental.
</p>
</desc>
</datatype>
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index fb6b7ba8e8..7f8f1ec71c 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -94,7 +94,9 @@
-type active_msgs() :: {ssl, sslsocket(), Data::binary() | list()} | {ssl_closed, sslsocket()} |
{ssl_error, sslsocket(), Reason::term()} | {ssl_passive, sslsocket()}.
-type transport_option() :: {cb_info, {CallbackModule::atom(), DataTag::atom(),
- ClosedTag::atom(), ErrTag::atom()}}.
+ ClosedTag::atom(), ErrTag::atom()}} |
+ {cb_info, {CallbackModule::atom(), DataTag::atom(),
+ ClosedTag::atom(), ErrTag::atom(), PassiveTag::atom()}}.
-type host() :: hostname() | ip_address().
-type hostname() :: string().
-type ip_address() :: inet:ip_address().
@@ -400,9 +402,9 @@ connect(Socket, SslOptions) when is_port(Socket) ->
timeout() | list()) ->
{ok, #sslsocket{}} | {error, reason()}.
connect(Socket, SslOptions0, Timeout) when is_port(Socket),
- (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) ->
- {Transport,_,_,_} = proplists:get_value(cb_info, SslOptions0,
- {gen_tcp, tcp, tcp_closed, tcp_error}),
+ (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) ->
+ CbInfo = handle_option(cb_info, SslOptions0, default_cb_info(tls)),
+ Transport = element(1, CbInfo),
EmulatedOptions = tls_socket:emulated_options(),
{ok, SocketValues} = tls_socket:getopts(Transport, Socket, EmulatedOptions),
try handle_options(SslOptions0 ++ SocketValues, client) of
@@ -542,8 +544,8 @@ handshake(#sslsocket{pid = [Pid|_], fd = {_, _, _}} = Socket, SslOpts, Timeout)
end;
handshake(Socket, SslOptions, Timeout) when is_port(Socket),
(is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) ->
- {Transport,_,_,_} =
- proplists:get_value(cb_info, SslOptions, {gen_tcp, tcp, tcp_closed, tcp_error}),
+ CbInfo = handle_option(cb_info, SslOptions, default_cb_info(tls)),
+ Transport = element(1, CbInfo),
EmulatedOptions = tls_socket:emulated_options(),
{ok, SocketValues} = tls_socket:getopts(Transport, Socket, EmulatedOptions),
ConnetionCb = connection_cb(SslOptions),
@@ -595,7 +597,7 @@ close(#sslsocket{pid = [Pid|_]}) when is_pid(Pid) ->
ssl_connection:close(Pid, {close, ?DEFAULT_TIMEOUT});
close(#sslsocket{pid = {dtls, #config{dtls_handler = {Pid, _}}}}) ->
dtls_packet_demux:close(Pid);
-close(#sslsocket{pid = {ListenSocket, #config{transport_info={Transport,_, _, _}}}}) ->
+close(#sslsocket{pid = {ListenSocket, #config{transport_info={Transport,_,_,_,_}}}}) ->
Transport:close(ListenSocket).
%%--------------------------------------------------------------------
@@ -611,7 +613,7 @@ close(#sslsocket{pid = [TLSPid|_]},
close(#sslsocket{pid = [TLSPid|_]}, Timeout) when is_pid(TLSPid),
(is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) ->
ssl_connection:close(TLSPid, {close, Timeout});
-close(#sslsocket{pid = {ListenSocket, #config{transport_info={Transport,_, _, _}}}}, _) ->
+close(#sslsocket{pid = {ListenSocket, #config{transport_info={Transport,_,_,_,_}}}}, _) ->
Transport:close(ListenSocket).
%%--------------------------------------------------------------------
@@ -627,7 +629,8 @@ send(#sslsocket{pid = {_, #config{transport_info={_, udp, _, _}}}}, _) ->
{error,enotconn}; %% Emulate connection behaviour
send(#sslsocket{pid = {dtls,_}}, _) ->
{error,enotconn}; %% Emulate connection behaviour
-send(#sslsocket{pid = {ListenSocket, #config{transport_info={Transport, _, _, _}}}}, Data) ->
+send(#sslsocket{pid = {ListenSocket, #config{transport_info = Info}}}, Data) ->
+ Transport = element(1, Info),
Transport:send(ListenSocket, Data). %% {error,enotconn}
%%--------------------------------------------------------------------
@@ -645,7 +648,8 @@ recv(#sslsocket{pid = [Pid|_]}, Length, Timeout) when is_pid(Pid),
recv(#sslsocket{pid = {dtls,_}}, _, _) ->
{error,enotconn};
recv(#sslsocket{pid = {Listen,
- #config{transport_info = {Transport, _, _, _}}}}, _,_) when is_port(Listen)->
+ #config{transport_info = Info}}},_,_) when is_port(Listen)->
+ Transport = element(1, Info),
Transport:recv(Listen, 0). %% {error,enotconn}
%%--------------------------------------------------------------------
@@ -660,7 +664,7 @@ controlling_process(#sslsocket{pid = {dtls, _}},
NewOwner) when is_pid(NewOwner) ->
ok; %% Meaningless but let it be allowed to conform with TLS
controlling_process(#sslsocket{pid = {Listen,
- #config{transport_info = {Transport, _, _, _}}}},
+ #config{transport_info = {Transport,_,_,_,_}}}},
NewOwner) when is_port(Listen),
is_pid(NewOwner) ->
%% Meaningless but let it be allowed to conform with normal sockets
@@ -703,13 +707,13 @@ connection_information(#sslsocket{pid = [Pid|_]}, Items) when is_pid(Pid) ->
%%
%% Description: same as inet:peername/1.
%%--------------------------------------------------------------------
-peername(#sslsocket{pid = [Pid|_], fd = {Transport, Socket, _}}) when is_pid(Pid)->
+peername(#sslsocket{pid = [Pid|_], fd = {Transport, Socket,_}}) when is_pid(Pid)->
dtls_socket:peername(Transport, Socket);
-peername(#sslsocket{pid = [Pid|_], fd = {Transport, Socket, _, _}}) when is_pid(Pid)->
+peername(#sslsocket{pid = [Pid|_], fd = {Transport, Socket,_,_}}) when is_pid(Pid)->
tls_socket:peername(Transport, Socket);
-peername(#sslsocket{pid = {dtls, #config{dtls_handler = {_Pid, _}}}}) ->
+peername(#sslsocket{pid = {dtls, #config{dtls_handler = {_Pid,_}}}}) ->
dtls_socket:peername(dtls, undefined);
-peername(#sslsocket{pid = {ListenSocket, #config{transport_info = {Transport,_,_,_}}}}) ->
+peername(#sslsocket{pid = {ListenSocket, #config{transport_info = {Transport,_,_,_,_}}}}) ->
tls_socket:peername(Transport, ListenSocket); %% Will return {error, enotconn}
peername(#sslsocket{pid = {dtls,_}}) ->
{error,enotconn}.
@@ -886,7 +890,7 @@ getopts(#sslsocket{pid = {dtls, #config{transport_info = {Transport,_,_,_}}}} =
_:Error ->
{error, {options, {socket_options, OptionTags, Error}}}
end;
-getopts(#sslsocket{pid = {_, #config{transport_info = {Transport,_,_,_}}}} = ListenSocket,
+getopts(#sslsocket{pid = {_, #config{transport_info = {Transport,_,_,_,_}}}} = ListenSocket,
OptionTags) when is_list(OptionTags) ->
try tls_socket:getopts(Transport, ListenSocket, OptionTags) of
{ok, _} = Result ->
@@ -943,7 +947,7 @@ setopts(#sslsocket{pid = {dtls, #config{transport_info = {Transport,_,_,_}}}} =
_:Error ->
{error, {options, {socket_options, Options, Error}}}
end;
-setopts(#sslsocket{pid = {_, #config{transport_info = {Transport,_,_,_}}}} = ListenSocket, Options) when is_list(Options) ->
+setopts(#sslsocket{pid = {_, #config{transport_info = {Transport,_,_,_,_}}}} = ListenSocket, Options) when is_list(Options) ->
try tls_socket:setopts(Transport, ListenSocket, Options) of
ok ->
ok;
@@ -987,8 +991,9 @@ getstat(#sslsocket{pid = [Pid|_], fd = {Transport, Socket, _, _}}, Options) when
%%
%% Description: Same as gen_tcp:shutdown/2
%%--------------------------------------------------------------------
-shutdown(#sslsocket{pid = {Listen, #config{transport_info = {Transport,_, _, _}}}},
+shutdown(#sslsocket{pid = {Listen, #config{transport_info = Info}}},
How) when is_port(Listen) ->
+ Transport = element(1, Info),
Transport:shutdown(Listen, How);
shutdown(#sslsocket{pid = {dtls,_}},_) ->
{error, enotconn};
@@ -1000,13 +1005,13 @@ shutdown(#sslsocket{pid = [Pid|_]}, How) when is_pid(Pid) ->
%%
%% Description: Same as inet:sockname/1
%%--------------------------------------------------------------------
-sockname(#sslsocket{pid = {Listen, #config{transport_info = {Transport, _, _, _}}}}) when is_port(Listen) ->
+sockname(#sslsocket{pid = {Listen, #config{transport_info = {Transport,_,_,_,_}}}}) when is_port(Listen) ->
tls_socket:sockname(Transport, Listen);
sockname(#sslsocket{pid = {dtls, #config{dtls_handler = {Pid, _}}}}) ->
dtls_packet_demux:sockname(Pid);
-sockname(#sslsocket{pid = [Pid|_], fd = {Transport, Socket, _}}) when is_pid(Pid) ->
+sockname(#sslsocket{pid = [Pid|_], fd = {Transport, Socket,_}}) when is_pid(Pid) ->
dtls_socket:sockname(Transport, Socket);
-sockname(#sslsocket{pid = [Pid| _], fd = {Transport, Socket, _, _}}) when is_pid(Pid) ->
+sockname(#sslsocket{pid = [Pid| _], fd = {Transport, Socket,_,_}}) when is_pid(Pid) ->
tls_socket:sockname(Transport, Socket).
%%---------------------------------------------------------------
@@ -1140,7 +1145,7 @@ supported_suites(all, Version) ->
supported_suites(anonymous, Version) ->
ssl_cipher:anonymous_suites(Version).
-do_listen(Port, #config{transport_info = {Transport, _, _, _}} = Config, tls_connection) ->
+do_listen(Port, #config{transport_info = {Transport, _, _, _,_}} = Config, tls_connection) ->
tls_socket:listen(Transport, Port, Config);
do_listen(Port, Config, dtls_connection) ->
@@ -1288,7 +1293,7 @@ handle_options(Opts0, Role, Host) ->
customize_hostname_check = handle_option(customize_hostname_check, Opts, [])
},
- CbInfo = proplists:get_value(cb_info, Opts, default_cb_info(Protocol)),
+ CbInfo = handle_option(cb_info, Opts, default_cb_info(Protocol)),
SslOptions = [protocol, versions, verify, verify_fun, partial_chain,
fail_if_no_peer_cert, verify_client_once,
depth, cert, certfile, key, keyfile,
@@ -1330,6 +1335,10 @@ handle_option(sni_fun, Opts, Default) ->
_ ->
throw({error, {conflict_options, [sni_fun, sni_hosts]}})
end;
+handle_option(cb_info, Opts, Default) ->
+ CbInfo = proplists:get_value(cb_info, Opts, Default),
+ true = validate_option(cb_info, CbInfo),
+ handle_cb_info(CbInfo, Default);
handle_option(OptionName, Opts, Default) ->
validate_option(OptionName,
proplists:get_value(OptionName, Opts, Default)).
@@ -1551,9 +1560,29 @@ validate_option(handshake, full = Value) ->
Value;
validate_option(customize_hostname_check, Value) when is_list(Value) ->
Value;
+validate_option(cb_info, {V1, V2, V3, V4}) when is_atom(V1),
+ is_atom(V2),
+ is_atom(V3),
+ is_atom(V4)
+ ->
+ true;
+validate_option(cb_info, {V1, V2, V3, V4, V5}) when is_atom(V1),
+ is_atom(V2),
+ is_atom(V3),
+ is_atom(V4),
+ is_atom(V5)
+ ->
+ true;
+validate_option(cb_info, _) ->
+ false;
validate_option(Opt, Value) ->
throw({error, {options, {Opt, Value}}}).
+handle_cb_info({V1, V2, V3, V4}, {_,_,_,_,_}) ->
+ {V1,V2,V3,V4, list_to_atom(atom_to_list(V2) ++ "passive")};
+handle_cb_info(CbInfo, _) ->
+ CbInfo.
+
handle_hashsigns_option(Value, Version) when is_list(Value)
andalso Version >= {3, 3} ->
case tls_v1:signature_algs(Version, Value) of
@@ -1964,7 +1993,7 @@ default_option_role(_,_,_) ->
undefined.
default_cb_info(tls) ->
- {gen_tcp, tcp, tcp_closed, tcp_error};
+ {gen_tcp, tcp, tcp_closed, tcp_error, tcp_passive};
default_cb_info(dtls) ->
{gen_udp, udp, udp_closed, udp_error}.
diff --git a/lib/ssl/src/ssl_connection.hrl b/lib/ssl/src/ssl_connection.hrl
index 9efd65b2d2..c90fe926b7 100644
--- a/lib/ssl/src/ssl_connection.hrl
+++ b/lib/ssl/src/ssl_connection.hrl
@@ -40,6 +40,7 @@
data_tag :: atom(), % ex tcp.
close_tag :: atom(), % ex tcp_closed
error_tag :: atom(), % ex tcp_error
+ passive_tag :: atom(), % ex tcp_passive
host :: string() | inet:ip_address(),
port :: integer(),
socket :: port() | tuple(), %% TODO: dtls socket
diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl
index 3229004c9d..114710a92e 100644
--- a/lib/ssl/src/tls_connection.erl
+++ b/lib/ssl/src/tls_connection.erl
@@ -79,7 +79,7 @@
%% Setup
%%====================================================================
start_fsm(Role, Host, Port, Socket, {#ssl_options{erl_dist = false},_, Tracker} = Opts,
- User, {CbModule, _,_, _} = CbInfo,
+ User, {CbModule, _,_, _, _} = CbInfo,
Timeout) ->
try
{ok, Sender} = tls_sender:start(),
@@ -93,7 +93,7 @@ start_fsm(Role, Host, Port, Socket, {#ssl_options{erl_dist = false},_, Tracker}
end;
start_fsm(Role, Host, Port, Socket, {#ssl_options{erl_dist = true},_, Tracker} = Opts,
- User, {CbModule, _,_, _} = CbInfo,
+ User, {CbModule, _,_, _, _} = CbInfo,
Timeout) ->
try
{ok, Sender} = tls_sender:start([{spawn_opt, ?DIST_CNTRL_SPAWN_OPTS}]),
@@ -223,7 +223,22 @@ next_event(StateName, Record, State, Actions) ->
%%% TLS record protocol level application data messages
-
+handle_protocol_record(#ssl_tls{type = ?APPLICATION_DATA, fragment = Data}, StateName,
+ #state{start_or_recv_from = From,
+ socket_options = #socket_options{active = false}} = State0) when From =/= undefined ->
+ case ssl_connection:read_application_data(Data, State0) of
+ {stop, _, _} = Stop->
+ Stop;
+ {Record, #state{start_or_recv_from = Caller} = State1} ->
+ TimerAction = case Caller of
+ undefined -> %% Passive recv complete cancel timer
+ [{{timeout, recv}, infinity, timeout}];
+ _ ->
+ []
+ end,
+ {next_state, StateName, State, Actions} = next_event(StateName, Record, State1, TimerAction),
+ ssl_connection:hibernate_after(StateName, State, Actions)
+ end;
handle_protocol_record(#ssl_tls{type = ?APPLICATION_DATA, fragment = Data}, StateName, State0) ->
case ssl_connection:read_application_data(Data, State0) of
{stop, _, _} = Stop->
@@ -765,7 +780,7 @@ code_change(_OldVsn, StateName, State, _) ->
%%% Internal functions
%%--------------------------------------------------------------------
initial_state(Role, Sender, Host, Port, Socket, {SSLOptions, SocketOptions, Tracker}, User,
- {CbModule, DataTag, CloseTag, ErrorTag}) ->
+ {CbModule, DataTag, CloseTag, ErrorTag, PassiveTag}) ->
#ssl_options{beast_mitigation = BeastMitigation,
erl_dist = IsErlDist} = SSLOptions,
ConnectionStates = tls_record:init_connection_states(Role, BeastMitigation),
@@ -790,6 +805,7 @@ initial_state(Role, Sender, Host, Port, Socket, {SSLOptions, SocketOptions, Trac
data_tag = DataTag,
close_tag = CloseTag,
error_tag = ErrorTag,
+ passive_tag = PassiveTag,
host = Host,
port = Port,
socket = Socket,
@@ -879,8 +895,9 @@ handle_info({Protocol, _, Data}, StateName,
ssl_connection:handle_normal_shutdown(Alert, StateName, State0),
{stop, {shutdown, own_alert}, State0}
end;
-handle_info({tcp_passive, Socket}, StateName,
- #state{static_env = #static_env{socket = Socket},
+handle_info({PassiveTag, Socket}, StateName,
+ #state{static_env = #static_env{socket = Socket,
+ passive_tag = PassiveTag},
protocol_specific = PS
} = State) ->
next_event(StateName, no_record,
diff --git a/lib/ssl/src/tls_socket.erl b/lib/ssl/src/tls_socket.erl
index c3c41d3e12..6c32e6fa04 100644
--- a/lib/ssl/src/tls_socket.erl
+++ b/lib/ssl/src/tls_socket.erl
@@ -46,7 +46,7 @@
send(Transport, Socket, Data) ->
Transport:send(Socket, Data).
-listen(Transport, Port, #config{transport_info = {Transport, _, _, _},
+listen(Transport, Port, #config{transport_info = {Transport, _, _, _, _},
inet_user = Options,
ssl = SslOpts, emulated = EmOpts} = Config) ->
case Transport:listen(Port, Options ++ internal_inet_values()) of
@@ -59,7 +59,7 @@ listen(Transport, Port, #config{transport_info = {Transport, _, _, _},
Err
end.
-accept(ListenSocket, #config{transport_info = {Transport,_,_,_} = CbInfo,
+accept(ListenSocket, #config{transport_info = {Transport,_,_,_,_} = CbInfo,
connection_cb = ConnectionCb,
ssl = SslOpts,
emulated = Tracker}, Timeout) ->
@@ -80,7 +80,7 @@ accept(ListenSocket, #config{transport_info = {Transport,_,_,_} = CbInfo,
{error, Reason}
end.
-upgrade(Socket, #config{transport_info = {Transport,_,_,_}= CbInfo,
+upgrade(Socket, #config{transport_info = {Transport,_,_,_,_}= CbInfo,
ssl = SslOptions,
emulated = EmOpts, connection_cb = ConnectionCb}, Timeout) ->
ok = setopts(Transport, Socket, tls_socket:internal_inet_values()),
@@ -98,7 +98,7 @@ connect(Address, Port,
#config{transport_info = CbInfo, inet_user = UserOpts, ssl = SslOpts,
emulated = EmOpts, inet_ssl = SocketOpts, connection_cb = ConnetionCb},
Timeout) ->
- {Transport, _, _, _} = CbInfo,
+ {Transport, _, _, _, _} = CbInfo,
try Transport:connect(Address, Port, SocketOpts, Timeout) of
{ok, Socket} ->
ssl_connection:connect(ConnetionCb, Address, Port, Socket,
@@ -125,7 +125,7 @@ setopts(gen_tcp, Socket = #sslsocket{pid = {ListenSocket, #config{emulated = Tra
ok = set_emulated_opts(Tracker, EmulatedOpts),
check_active_n(EmulatedOpts, Socket),
inet:setopts(ListenSocket, SockOpts);
-setopts(_, Socket = #sslsocket{pid = {ListenSocket, #config{transport_info = {Transport,_,_,_},
+setopts(_, Socket = #sslsocket{pid = {ListenSocket, #config{transport_info = {Transport,_,_,_,_},
emulated = Tracker}}}, Options) ->
{SockOpts, EmulatedOpts} = split_options(Options),
ok = set_emulated_opts(Tracker, EmulatedOpts),
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index e86d2eaf9e..f55d1c8ea7 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -4063,7 +4063,7 @@ tls_tcp_error_propagation_in_active_mode(Config) when is_list(Config) ->
[_, _,_, _, Prop] = StatusInfo,
State = ssl_test_lib:state(Prop),
StaticEnv = element(2, State),
- Socket = element(10, StaticEnv),
+ Socket = element(11, StaticEnv),
%% Fake tcp error
Pid ! {tcp_error, Socket, etimedout},
diff --git a/lib/ssl/vsn.mk b/lib/ssl/vsn.mk
index 0d9f907d5c..c4bcc1560c 100644
--- a/lib/ssl/vsn.mk
+++ b/lib/ssl/vsn.mk
@@ -1 +1 @@
-SSL_VSN = 9.2
+SSL_VSN = 9.2.1
diff --git a/lib/stdlib/doc/src/notes.xml b/lib/stdlib/doc/src/notes.xml
index 278560af1d..f677438154 100644
--- a/lib/stdlib/doc/src/notes.xml
+++ b/lib/stdlib/doc/src/notes.xml
@@ -31,6 +31,21 @@
</header>
<p>This document describes the changes made to the STDLIB application.</p>
+<section><title>STDLIB 3.8.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fixed a performance regression when reading files
+ opened with the <c>compressed</c> flag.</p>
+ <p>
+ Own Id: OTP-15706 Aux Id: ERIERL-336 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>STDLIB 3.8</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/stdlib/src/erl_tar.erl b/lib/stdlib/src/erl_tar.erl
index d8b8f466b1..7064fcacfa 100644
--- a/lib/stdlib/src/erl_tar.erl
+++ b/lib/stdlib/src/erl_tar.erl
@@ -324,7 +324,7 @@ do_open(Name, Mode) when is_list(Mode) ->
open1({binary,Bin}, read, _Raw, Opts) when is_binary(Bin) ->
case file:open(Bin, [ram,binary,read]) of
{ok,File} ->
- _ = [ram_file:uncompress(File) || Opts =:= [compressed]],
+ _ = [ram_file:uncompress(File) || lists:member(compressed, Opts)],
{ok, #reader{handle=File,access=read,func=fun file_op/2}};
Error ->
Error
@@ -357,7 +357,7 @@ open_mode([read|Rest], false, Raw, Opts) ->
open_mode([write|Rest], false, Raw, Opts) ->
open_mode(Rest, write, Raw, Opts);
open_mode([compressed|Rest], Access, Raw, Opts) ->
- open_mode(Rest, Access, Raw, [compressed|Opts]);
+ open_mode(Rest, Access, Raw, [compressed,read_ahead|Opts]);
open_mode([cooked|Rest], Access, _Raw, Opts) ->
open_mode(Rest, Access, [], Opts);
open_mode([], Access, Raw, Opts) ->
diff --git a/lib/stdlib/src/stdlib.appup.src b/lib/stdlib/src/stdlib.appup.src
index 37ea97c353..08612ed17f 100644
--- a/lib/stdlib/src/stdlib.appup.src
+++ b/lib/stdlib/src/stdlib.appup.src
@@ -41,7 +41,9 @@
{<<"^3\\.6\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
{<<"^3\\.7$">>,[restart_new_emulator]},
{<<"^3\\.7\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
- {<<"^3\\.7\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}],
+ {<<"^3\\.7\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
+ {<<"^3\\.8$">>,[restart_new_emulator]},
+ {<<"^3\\.8\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}],
[{<<"^3\\.4$">>,[restart_new_emulator]},
{<<"^3\\.4\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
{<<"^3\\.4\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
@@ -56,4 +58,6 @@
{<<"^3\\.6\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
{<<"^3\\.7$">>,[restart_new_emulator]},
{<<"^3\\.7\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
- {<<"^3\\.7\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}]}.
+ {<<"^3\\.7\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
+ {<<"^3\\.8$">>,[restart_new_emulator]},
+ {<<"^3\\.8\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}]}.
diff --git a/lib/stdlib/vsn.mk b/lib/stdlib/vsn.mk
index cbefd6590a..6471dc70e0 100644
--- a/lib/stdlib/vsn.mk
+++ b/lib/stdlib/vsn.mk
@@ -1 +1 @@
-STDLIB_VSN = 3.8
+STDLIB_VSN = 3.8.1
diff --git a/lib/xmerl/doc/src/notes.xml b/lib/xmerl/doc/src/notes.xml
index 7f6874e36b..d6b6dfdfb5 100644
--- a/lib/xmerl/doc/src/notes.xml
+++ b/lib/xmerl/doc/src/notes.xml
@@ -32,6 +32,28 @@
<p>This document describes the changes made to the Xmerl application.</p>
+<section><title>Xmerl 1.3.20</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Handling of character references in attributes are fixed.</p>
+ <p>
+ Own Id: OTP-15684 Aux Id: ERL-837 </p>
+ </item>
+ <item>
+ <p>
+ Normalization of whitespace characters in attributes are
+ fixed so it works when character references are used.</p>
+ <p>
+ Own Id: OTP-15685 Aux Id: ERL-475 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Xmerl 1.3.19</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/xmerl/src/xmerl_scan.erl b/lib/xmerl/src/xmerl_scan.erl
index e543a5a11e..d76ed5c820 100644
--- a/lib/xmerl/src/xmerl_scan.erl
+++ b/lib/xmerl/src/xmerl_scan.erl
@@ -2410,15 +2410,22 @@ scan_att_chars("&" ++ T, S0, Delim, Acc, TmpAcc,AT,IsNorm) -> % Reference
true ->
scan_att_chars(T1,S1,Delim,[ExpRef|Acc],[ExpRef|TmpAcc],AT,IsNorm);
_ ->
- Ch = string_to_char_set(S#xmerl_scanner.encoding, ExpRef),
case T of
"#" ++ _ ->
%% normalization rules (sec 3.3.3) require that for
%% character references, the referenced character be
%% added directly to the normalized value
- scan_att_chars(T1, S1, Delim, Ch ++ Acc,TmpAcc, AT,IsNorm);
+ {T2,S2,IsNorm2} =
+ if
+ ?whitespace(hd(ExpRef)) ->
+ normalize(T1, S1, IsNorm);
+ true ->
+ {T1, S1, IsNorm}
+ end,
+ scan_att_chars(T2, S2, Delim, ExpRef ++ Acc, TmpAcc, AT, IsNorm2);
_ ->
- scan_att_chars(Ch ++ T1, S1, Delim, Acc,TmpAcc, AT,IsNorm)
+ Ch = string_to_char_set(S#xmerl_scanner.encoding, ExpRef),
+ scan_att_chars(Ch ++ T1, S1, Delim, Acc, TmpAcc, AT, IsNorm)
end
end;
scan_att_chars("<" ++ _T, S0, _Delim, _Acc,_, _,_) -> % Tags not allowed here
@@ -3964,7 +3971,7 @@ normalize(T,S,IsNorm) ->
{_,T,S} ->
{T,S,IsNorm};
{_,T1,S1} ->
- {T1,S1,true}
+ normalize(T1,S1,true)
end.
diff --git a/lib/xmerl/vsn.mk b/lib/xmerl/vsn.mk
index b6486681c2..31ffa6e749 100644
--- a/lib/xmerl/vsn.mk
+++ b/lib/xmerl/vsn.mk
@@ -1 +1 @@
-XMERL_VSN = 1.3.19
+XMERL_VSN = 1.3.20
diff --git a/make/otp_patch_solve_forward_merge_version b/make/otp_patch_solve_forward_merge_version
index 7f8f011eb7..45a4fb75db 100644
--- a/make/otp_patch_solve_forward_merge_version
+++ b/make/otp_patch_solve_forward_merge_version
@@ -1 +1 @@
-7
+8
diff --git a/make/otp_version_tickets b/make/otp_version_tickets
index 77633c2ce2..b8220e1a87 100644
--- a/make/otp_version_tickets
+++ b/make/otp_version_tickets
@@ -1,79 +1 @@
-OTP-14702
-OTP-15229
-OTP-15298
-OTP-15369
-OTP-15375
-OTP-15398
-OTP-15423
-OTP-15442
-OTP-15445
-OTP-15447
-OTP-15460
-OTP-15479
-OTP-15484
-OTP-15490
-OTP-15493
-OTP-15494
-OTP-15498
-OTP-15502
-OTP-15503
-OTP-15508
-OTP-15514
-OTP-15518
-OTP-15519
-OTP-15527
-OTP-15529
-OTP-15539
-OTP-15540
-OTP-15541
-OTP-15542
-OTP-15545
-OTP-15552
-OTP-15553
-OTP-15555
-OTP-15556
-OTP-15557
-OTP-15558
-OTP-15561
-OTP-15562
-OTP-15567
-OTP-15569
-OTP-15570
-OTP-15572
-OTP-15576
-OTP-15577
-OTP-15578
-OTP-15580
-OTP-15583
-OTP-15584
-OTP-15586
-OTP-15587
-OTP-15592
-OTP-15599
-OTP-15600
-OTP-15601
-OTP-15602
-OTP-15604
-OTP-15605
-OTP-15619
-OTP-15624
-OTP-15625
-OTP-15629
-OTP-15630
-OTP-15634
-OTP-15637
-OTP-15639
-OTP-15642
-OTP-15647
-OTP-15650
-OTP-15654
-OTP-15657
-OTP-15659
-OTP-15660
-OTP-15662
-OTP-15663
-OTP-15665
-OTP-15666
-OTP-15667
-OTP-15669
-OTP-15670
+DEVELOPMENT
diff --git a/make/otp_version_tickets_in_merge b/make/otp_version_tickets_in_merge
index ff967634a2..01d0313dc9 100644
--- a/make/otp_version_tickets_in_merge
+++ b/make/otp_version_tickets_in_merge
@@ -1,3 +1,6 @@
-OTP-15551
-OTP-15651
-OTP-15652
+OTP-15716
+OTP-15750
+OTP-15753
+OTP-15757
+OTP-15762
+OTP-15763
diff --git a/otp_versions.table b/otp_versions.table
index eef6a9c8fe..c570a1dbca 100644
--- a/otp_versions.table
+++ b/otp_versions.table
@@ -1,3 +1,7 @@
+OTP-21.3.4 : common_test-1.17.1 crypto-4.4.2 erl_interface-3.11.2 erts-10.3.3 ssh-4.7.5 # asn1-5.0.8 compiler-7.3.2 debugger-4.2.6 dialyzer-3.3.2 diameter-2.2 edoc-0.10 eldap-1.2.6 erl_docgen-0.9 et-1.6.4 eunit-2.3.7 ftp-1.0.2 hipe-3.18.3 inets-7.0.6 jinterface-1.9.1 kernel-6.3.1 megaco-3.18.4 mnesia-4.15.6 observer-2.9 odbc-2.12.3 os_mon-2.4.7 otp_mibs-1.2.1 parsetools-2.1.8 public_key-1.6.5 reltool-0.7.8 runtime_tools-1.13.2 sasl-3.3 snmp-5.2.12 ssl-9.2.1 stdlib-3.8.1 syntax_tools-2.1.7 tftp-1.0.1 tools-3.1 wx-1.8.7 xmerl-1.3.20 :
+OTP-21.3.3 : erts-10.3.2 kernel-6.3.1 stdlib-3.8.1 # asn1-5.0.8 common_test-1.17 compiler-7.3.2 crypto-4.4.1 debugger-4.2.6 dialyzer-3.3.2 diameter-2.2 edoc-0.10 eldap-1.2.6 erl_docgen-0.9 erl_interface-3.11.1 et-1.6.4 eunit-2.3.7 ftp-1.0.2 hipe-3.18.3 inets-7.0.6 jinterface-1.9.1 megaco-3.18.4 mnesia-4.15.6 observer-2.9 odbc-2.12.3 os_mon-2.4.7 otp_mibs-1.2.1 parsetools-2.1.8 public_key-1.6.5 reltool-0.7.8 runtime_tools-1.13.2 sasl-3.3 snmp-5.2.12 ssh-4.7.4 ssl-9.2.1 syntax_tools-2.1.7 tftp-1.0.1 tools-3.1 wx-1.8.7 xmerl-1.3.20 :
+OTP-21.3.2 : erts-10.3.1 xmerl-1.3.20 # asn1-5.0.8 common_test-1.17 compiler-7.3.2 crypto-4.4.1 debugger-4.2.6 dialyzer-3.3.2 diameter-2.2 edoc-0.10 eldap-1.2.6 erl_docgen-0.9 erl_interface-3.11.1 et-1.6.4 eunit-2.3.7 ftp-1.0.2 hipe-3.18.3 inets-7.0.6 jinterface-1.9.1 kernel-6.3 megaco-3.18.4 mnesia-4.15.6 observer-2.9 odbc-2.12.3 os_mon-2.4.7 otp_mibs-1.2.1 parsetools-2.1.8 public_key-1.6.5 reltool-0.7.8 runtime_tools-1.13.2 sasl-3.3 snmp-5.2.12 ssh-4.7.4 ssl-9.2.1 stdlib-3.8 syntax_tools-2.1.7 tftp-1.0.1 tools-3.1 wx-1.8.7 :
+OTP-21.3.1 : erl_interface-3.11.1 ssl-9.2.1 # asn1-5.0.8 common_test-1.17 compiler-7.3.2 crypto-4.4.1 debugger-4.2.6 dialyzer-3.3.2 diameter-2.2 edoc-0.10 eldap-1.2.6 erl_docgen-0.9 erts-10.3 et-1.6.4 eunit-2.3.7 ftp-1.0.2 hipe-3.18.3 inets-7.0.6 jinterface-1.9.1 kernel-6.3 megaco-3.18.4 mnesia-4.15.6 observer-2.9 odbc-2.12.3 os_mon-2.4.7 otp_mibs-1.2.1 parsetools-2.1.8 public_key-1.6.5 reltool-0.7.8 runtime_tools-1.13.2 sasl-3.3 snmp-5.2.12 ssh-4.7.4 stdlib-3.8 syntax_tools-2.1.7 tftp-1.0.1 tools-3.1 wx-1.8.7 xmerl-1.3.19 :
OTP-21.3 : common_test-1.17 compiler-7.3.2 crypto-4.4.1 dialyzer-3.3.2 diameter-2.2 edoc-0.10 erl_docgen-0.9 erl_interface-3.11 erts-10.3 ftp-1.0.2 hipe-3.18.3 inets-7.0.6 kernel-6.3 mnesia-4.15.6 observer-2.9 odbc-2.12.3 public_key-1.6.5 runtime_tools-1.13.2 ssh-4.7.4 ssl-9.2 stdlib-3.8 syntax_tools-2.1.7 tools-3.1 wx-1.8.7 # asn1-5.0.8 debugger-4.2.6 eldap-1.2.6 et-1.6.4 eunit-2.3.7 jinterface-1.9.1 megaco-3.18.4 os_mon-2.4.7 otp_mibs-1.2.1 parsetools-2.1.8 reltool-0.7.8 sasl-3.3 snmp-5.2.12 tftp-1.0.1 xmerl-1.3.19 :
OTP-21.2.7 : erts-10.2.5 kernel-6.2.1 # asn1-5.0.8 common_test-1.16.1 compiler-7.3.1 crypto-4.4 debugger-4.2.6 dialyzer-3.3.1 diameter-2.1.6 edoc-0.9.4 eldap-1.2.6 erl_docgen-0.8.1 erl_interface-3.10.4 et-1.6.4 eunit-2.3.7 ftp-1.0.1 hipe-3.18.2 inets-7.0.5 jinterface-1.9.1 megaco-3.18.4 mnesia-4.15.5 observer-2.8.2 odbc-2.12.2 os_mon-2.4.7 otp_mibs-1.2.1 parsetools-2.1.8 public_key-1.6.4 reltool-0.7.8 runtime_tools-1.13.1 sasl-3.3 snmp-5.2.12 ssh-4.7.3 ssl-9.1.2 stdlib-3.7.1 syntax_tools-2.1.6 tftp-1.0.1 tools-3.0.2 wx-1.8.6 xmerl-1.3.19 :
OTP-21.2.6 : erts-10.2.4 stdlib-3.7.1 # asn1-5.0.8 common_test-1.16.1 compiler-7.3.1 crypto-4.4 debugger-4.2.6 dialyzer-3.3.1 diameter-2.1.6 edoc-0.9.4 eldap-1.2.6 erl_docgen-0.8.1 erl_interface-3.10.4 et-1.6.4 eunit-2.3.7 ftp-1.0.1 hipe-3.18.2 inets-7.0.5 jinterface-1.9.1 kernel-6.2 megaco-3.18.4 mnesia-4.15.5 observer-2.8.2 odbc-2.12.2 os_mon-2.4.7 otp_mibs-1.2.1 parsetools-2.1.8 public_key-1.6.4 reltool-0.7.8 runtime_tools-1.13.1 sasl-3.3 snmp-5.2.12 ssh-4.7.3 ssl-9.1.2 syntax_tools-2.1.6 tftp-1.0.1 tools-3.0.2 wx-1.8.6 xmerl-1.3.19 :