aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorRaimo Niskanen <[email protected]>2018-09-17 15:42:26 +0200
committerRaimo Niskanen <[email protected]>2018-09-17 15:42:26 +0200
commitb13ef106fb134f8d8b929e03300a8b6524f367cf (patch)
tree24b6a029f413987b2f48e200dc96c5953df4025e /lib
parentfd3d7e7ce693bb960b85b3ea09429adb30145e49 (diff)
parentd6a08843e473da6eebbab0b0e7312efc978108ee (diff)
downloadotp-b13ef106fb134f8d8b929e03300a8b6524f367cf.tar.gz
otp-b13ef106fb134f8d8b929e03300a8b6524f367cf.tar.bz2
otp-b13ef106fb134f8d8b929e03300a8b6524f367cf.zip
Merge branch 'maint'
Diffstat (limited to 'lib')
-rw-r--r--lib/kernel/doc/src/gen_sctp.xml69
-rw-r--r--lib/kernel/doc/src/gen_tcp.xml16
-rw-r--r--lib/kernel/doc/src/gen_udp.xml35
-rw-r--r--lib/kernel/doc/src/inet.xml123
-rw-r--r--lib/kernel/src/gen_sctp.erl18
-rw-r--r--lib/kernel/src/gen_tcp.erl16
-rw-r--r--lib/kernel/src/gen_udp.erl19
-rw-r--r--lib/kernel/src/inet.erl17
-rw-r--r--lib/kernel/src/inet6_tcp.erl8
-rw-r--r--lib/kernel/src/inet_int.hrl7
-rw-r--r--lib/kernel/src/inet_tcp.erl8
-rw-r--r--lib/kernel/test/gen_tcp_misc_SUITE.erl209
-rw-r--r--lib/kernel/test/gen_udp_SUITE.erl163
-rw-r--r--lib/snmp/doc/src/notes.xml4
-rw-r--r--lib/snmp/doc/src/snmp.xml33
-rw-r--r--lib/snmp/doc/src/snmpa.xml38
-rw-r--r--lib/snmp/doc/src/snmpm.xml38
-rw-r--r--lib/snmp/src/agent/snmpa_net_if.erl111
-rw-r--r--lib/snmp/src/misc/snmp_log.erl334
19 files changed, 987 insertions, 279 deletions
diff --git a/lib/kernel/doc/src/gen_sctp.xml b/lib/kernel/doc/src/gen_sctp.xml
index 737800c6b1..1e08b25f66 100644
--- a/lib/kernel/doc/src/gen_sctp.xml
+++ b/lib/kernel/doc/src/gen_sctp.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2007</year><year>2016</year>
+ <year>2007</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -331,6 +331,37 @@ connect(Socket, Ip, Port>,
with <anno>SockType</anno> <c>seqpacket</c>, and with reasonably large
<seealso marker="inet#option-sndbuf">kernel</seealso> and driver
<seealso marker="inet#option-buffer">buffers</seealso>.</p>
+ <p>
+ If the socket is in
+ <seealso marker="#option-active">passive</seealso>
+ mode data can be received through the
+ <seealso marker="#recv/1"><c>recv/1,2</c></seealso>
+ calls.
+ </p>
+ <p>
+ If the socket is in
+ <seealso marker="#option-active">active</seealso>
+ mode data received data is delivered to the controlling process
+ as messages:
+ </p>
+ <code type="none">
+{sctp, <anno>Socket</anno>, FromIP, FromPort, {AncData, Data}}
+ </code>
+ <p>
+ See
+ <seealso marker="#recv/1"><c>recv/1,2</c></seealso>
+ for a description of the message fields.
+ </p>
+ <note>
+ <p>
+ This message format unfortunately differs slightly from the
+ <seealso marker="gen_udp#open/1"><c>gen_udp</c></seealso>
+ message format with ancillary data,
+ and from the
+ <seealso marker="#recv/1"><c>recv/1,2</c></seealso>
+ return tuple format.
+ </p>
+ </note>
</desc>
</func>
@@ -380,6 +411,19 @@ connect(Socket, Ip, Port>,
socket option
<seealso marker="#option-sctp_get_peer_addr_info"><c>sctp_get_peer_addr_info</c></seealso>,
but this does still not produce the stream number).</p>
+ <p>
+ <c><anno>AncData</anno></c> may also contain
+ <seealso marker="inet#type-ancillary_data">
+ ancillary data
+ </seealso>
+ from the socket
+ <seealso marker="#type-option">options</seealso>
+ <seealso marker="inet#option-recvtos"><c>recvtos</c></seealso>,
+ <seealso marker="inet#option-recvtclass"><c>recvtclass</c></seealso>
+ or
+ <seealso marker="inet#option-recvttl"><c>recvttl</c></seealso>,
+ if that is supported by the platform for the socket.
+ </p>
<p>The <c><anno>Data</anno></c> received can be a <c>binary()</c>
or a <c>list()</c> of bytes (integers in the range 0 through 255)
depending on the socket mode, or an SCTP event.</p>
@@ -544,12 +588,25 @@ connect(Socket, Ip, Port>,
<seealso marker="#recv/1"><c>recv</c></seealso> call
to retrieve the available data from the socket.</p>
</item>
+ <item>
+ <p>
+ If <c>true|once|N</c> (active modes)
+ received data or events are sent to the owning process.
+ See <seealso marker="#open/0"><c>open/0..2</c></seealso>
+ for the message format.
+ </p>
+ </item>
<item>
- <p>If <c>true</c> (full active mode), the pending data or events are
- sent to the owning process.</p>
- <p>Notice that this can cause the message queue to overflow,
- as there is no way to throttle the sender in this case
- (no flow control).</p>
+ <p>
+ If <c>true</c> (full active mode) there is no flow control.
+ </p>
+ <note>
+ <p>
+ Note that this can cause the message queue to overflow
+ causing for example the virtual machine
+ to run out of memory and crash.
+ </p>
+ </note>
</item>
<item>
<p>If <c>once</c>, only one message is automatically placed
diff --git a/lib/kernel/doc/src/gen_tcp.xml b/lib/kernel/doc/src/gen_tcp.xml
index e6104b0c76..cf649991d0 100644
--- a/lib/kernel/doc/src/gen_tcp.xml
+++ b/lib/kernel/doc/src/gen_tcp.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1997</year><year>2017</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -70,6 +70,20 @@ do_recv(Sock, Bs) ->
<name name="option"/>
</datatype>
<datatype>
+ <name name="pktoptions_value"/>
+ <desc>
+ <p>
+ If the platform implements the IPv4 option
+ <c>IP_PKTOPTIONS</c> (probably Linux specific), or the IPv6 option
+ <c>IPV6_PKTOPTIONS</c> or <c>IPV6_2292PKTOPTIONS</c> for the socket
+ this value is returned from
+ <seealso marker="inet#getopts/2"><c>inet:getopts/2</c></seealso>
+ when called with the option name
+ <seealso marker="#type-option_name"><c>pktoptions</c></seealso>.
+ </p>
+ </desc>
+ </datatype>
+ <datatype>
<name name="option_name"/>
</datatype>
<datatype>
diff --git a/lib/kernel/doc/src/gen_udp.xml b/lib/kernel/doc/src/gen_udp.xml
index f79566ef71..840ca3c188 100644
--- a/lib/kernel/doc/src/gen_udp.xml
+++ b/lib/kernel/doc/src/gen_udp.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1997</year><year>2016</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -147,7 +147,21 @@
at the opened port, if the socket is in an active mode, the packets
are delivered as messages to the controlling process:</p>
<code type="none">
-{udp, Socket, IP, InPortNo, Packet}</code>
+{udp, Socket, IP, InPortNo, Packet} % Without ancillary data
+{udp, Socket, IP, InPortNo, AncData, Packet} % With ancillary data
+ </code>
+ <p>
+ The message contains an <c>AncData</c> field
+ if any of the socket
+ <seealso marker="#type-option">options</seealso>
+ <seealso marker="inet#option-recvtos"><c>recvtos</c></seealso>,
+ <seealso marker="inet#option-recvtclass"><c>recvtclass</c></seealso>
+ or
+ <seealso marker="inet#option-recvttl"><c>recvttl</c></seealso>
+ are active, otherwise it does not.
+ </p>
+ <p>
+ </p>
<p>If the socket is not in an active mode, data can be
retrieved through the
<seealso marker="#recv/2"><c>recv/2,3</c></seealso> calls.
@@ -179,9 +193,22 @@
<name name="recv" arity="3"/>
<fsummary>Receive a packet from a passive socket.</fsummary>
<desc>
- <p>Receives a packet from a socket in passive mode. Optional parameter
+ <p>
+ Receives a packet from a socket in passive mode. Optional parameter
<c><anno>Timeout</anno></c> specifies a time-out in milliseconds.
- Defaults to <c>infinity</c>.</p>
+ Defaults to <c>infinity</c>.
+ </p>
+ <p>
+ If any of the socket
+ <seealso marker="#type-option">options</seealso>
+ <seealso marker="inet#option-recvtos"><c>recvtos</c></seealso>,
+ <seealso marker="inet#option-recvtclass"><c>recvtclass</c></seealso>
+ or
+ <seealso marker="inet#option-recvttl"><c>recvttl</c></seealso>
+ are active, the <c><anno>RecvData</anno></c> tuple contains an
+ <c><anno>AncData</anno></c> field,
+ otherwise it does not.
+ </p>
</desc>
</func>
diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml
index f281d61459..ed775d67eb 100644
--- a/lib/kernel/doc/src/inet.xml
+++ b/lib/kernel/doc/src/inet.xml
@@ -177,6 +177,27 @@ fe80::204:acff:fe17:bf38
</desc>
</datatype>
<datatype>
+ <name name="ancillary_data"/>
+ <desc>
+ <p>
+ Ancillary data received with the data packet
+ or read with the socket option
+ <seealso marker="gen_tcp#type-pktoptions_value">
+ <c>pktoptions</c>
+ </seealso>
+ from a TCP socket.
+ </p>
+ <p>
+ The value(s) correspond to the currently active socket
+ <seealso marker="#type-socket_setopt">options</seealso>
+ <seealso marker="inet#option-recvtos"><c>recvtos</c></seealso>,
+ <seealso marker="inet#option-recvtclass"><c>recvtclass</c></seealso>
+ and
+ <seealso marker="inet#option-recvttl"><c>recvttl</c></seealso>.
+ </p>
+ </desc>
+ </datatype>
+ <datatype>
<name name="posix"/>
<desc>
<p>An atom that is named from the POSIX error codes used in Unix,
@@ -344,7 +365,11 @@ fe80::204:acff:fe17:bf38
<desc>
<p>Gets one or more options for a socket. For a list of available
options, see
- <seealso marker="#setopts/2"><c>setopts/2</c></seealso>.</p>
+ <seealso marker="#setopts/2"><c>setopts/2</c></seealso>.
+ See also the description for the type
+ <seealso marker="gen_tcp#type-pktoptions_value">
+ <c>gen_tcp:pktoptions_value()</c>
+ </seealso>.</p>
<p>The number of elements in the returned
<c><anno>OptionValues</anno></c>
list does not necessarily correspond to the number of options
@@ -360,7 +385,7 @@ fe80::204:acff:fe17:bf38
socket options not (explicitly) supported by the emulator. The
use of raw socket options makes the code non-portable, but
allows the Erlang programmer to take advantage of unusual features
- present on the current platform.</p>
+ present on a particular platform.</p>
<p><c>RawOptReq</c> consists of tag <c>raw</c> followed
by the protocol level, the option number, and either a binary
or the size, in bytes, of the
@@ -1115,6 +1140,100 @@ setcap cap_sys_admin,cap_sys_ptrace,cap_dac_read_search+epi beam.smp</code>
the socket. You are encouraged to use
<seealso marker="#getopts/2"><c>getopts/2</c></seealso>
to retrieve the size set by your operating system.</p>
+ <marker id="option-recvtclass"></marker>
+ </item>
+ <tag><c>{recvtclass, Boolean}</c></tag>
+ <item>
+ <p>
+ If set to <c>true</c> activates returning the received
+ <c>TCLASS</c> value on platforms that implements
+ the protocol <c>IPPROTO_IPV6</c>
+ option <c>IPV6_RECVTCLASS</c> or <c>IPV6_2292RECVTCLASS</c>
+ for the socket.
+ The value is returned as a <c>{tclass,TCLASS}</c> tuple
+ regardless of if the platform returns an <c>IPV6_TCLASS</c>
+ or an <c>IPV6_RECVTCLASS</c> CMSG value.
+ </p>
+ <p>
+ For packet oriented sockets that supports receiving
+ ancillary data with the payload data
+ (<c>gen_udp</c> and <c>gen_sctp</c>),
+ the <c>TCLASS</c> value is returned
+ in an extended return tuple contained in an
+ <seealso marker="inet#type-ancillary_data">
+ ancillary data
+ </seealso>
+ list.
+ For stream oriented sockets (<c>gen_tcp</c>)
+ the only way to get the <c>TCLASS</c>
+ value is if the platform supports the
+ <seealso marker="gen_tcp#type-pktoptions_value">
+ <c>pktoptions</c>
+ </seealso>
+ option.
+ </p>
+ <marker id="option-recvtos"></marker>
+ </item>
+ <tag><c>{recvtos, Boolean}</c></tag>
+ <item>
+ <p>
+ If set to <c>true</c> activates returning the received
+ <c>TOS</c> value on platforms that implements
+ the protocol <c>IPPROTO_IP</c> option <c>IP_RECVTOS</c>
+ for the socket.
+ The value is returned as a <c>{tos,TOS}</c> tuple
+ regardless of if the platform returns an <c>IP_TOS</c>
+ or an <c>IP_RECVTOS</c> CMSG value.
+ </p>
+ <p>
+ For packet oriented sockets that supports receiving
+ ancillary data with the payload data
+ (<c>gen_udp</c> and <c>gen_sctp</c>),
+ the <c>TOS</c> value is returned
+ in an extended return tuple contained in an
+ <seealso marker="inet#type-ancillary_data">
+ ancillary data
+ </seealso>
+ list.
+ For stream oriented sockets (<c>gen_tcp</c>)
+ the only way to get the <c>TOS</c>
+ value is if the platform supports the
+ <seealso marker="gen_tcp#type-pktoptions_value">
+ <c>pktoptions</c>
+ </seealso>
+ option.
+ </p>
+ <marker id="option-recvttl"></marker>
+ </item>
+ <tag><c>{recvttl, Boolean}</c></tag>
+ <item>
+ <p>
+ If set to <c>true</c> activates returning the received
+ <c>TTL</c> value on platforms that implements
+ the protocol <c>IPPROTO_IP</c> option <c>IP_RECVTTL</c>
+ for the socket.
+ The value is returned as a <c>{ttl,TTL}</c> tuple
+ regardless of if the platform returns an <c>IP_TTL</c>
+ or an <c>IP_RECVTTL</c> CMSG value.
+ </p>
+ <p>
+ For packet oriented sockets that supports receiving
+ ancillary data with the payload data
+ (<c>gen_udp</c> and <c>gen_sctp</c>),
+ the <c>TTL</c> value is returned
+ in an extended return tuple contained in an
+ <seealso marker="inet#type-ancillary_data">
+ ancillary data
+ </seealso>
+ list.
+ For stream oriented sockets (<c>gen_tcp</c>)
+ the only way to get the <c>TTL</c>
+ value is if the platform supports the
+ <seealso marker="gen_tcp#type-pktoptions_value">
+ <c>pktoptions</c>
+ </seealso>
+ option.
+ </p>
</item>
<tag><c>{reuseaddr, Boolean}</c></tag>
<item>
diff --git a/lib/kernel/src/gen_sctp.erl b/lib/kernel/src/gen_sctp.erl
index bf795ee9c6..d893d44079 100644
--- a/lib/kernel/src/gen_sctp.erl
+++ b/lib/kernel/src/gen_sctp.erl
@@ -66,7 +66,12 @@
{sctp_set_peer_primary_addr, #sctp_setpeerprim{}} |
{sctp_status, #sctp_status{}} |
{sndbuf, non_neg_integer()} |
- {tos, non_neg_integer()}.
+ {tos, non_neg_integer()} |
+ {tclass, non_neg_integer()} |
+ {ttl, non_neg_integer()} |
+ {recvtos, boolean()} |
+ {recvtclass, boolean()} |
+ {recvttl, boolean()}.
-type option_name() ::
active |
buffer |
@@ -97,7 +102,12 @@
sctp_set_peer_primary_addr |
sctp_status |
sndbuf |
- tos.
+ tos |
+ tclass |
+ ttl |
+ recvtos |
+ recvtclass |
+ recvttl.
-type sctp_socket() :: port().
-export_type([assoc_id/0, option/0, option_name/0, sctp_socket/0]).
@@ -365,7 +375,7 @@ send(S, AssocChange, Stream, Data) ->
Socket :: sctp_socket(),
FromIP :: inet:ip_address(),
FromPort :: inet:port_number(),
- AncData :: [#sctp_sndrcvinfo{}],
+ AncData :: [#sctp_sndrcvinfo{} | inet:ancillary_data()],
Data :: binary() | string() | #sctp_sndrcvinfo{}
| #sctp_assoc_change{} | #sctp_paddr_change{}
| #sctp_adaptation_event{},
@@ -382,7 +392,7 @@ recv(S) ->
Timeout :: timeout(),
FromIP :: inet:ip_address(),
FromPort :: inet:port_number(),
- AncData :: [#sctp_sndrcvinfo{}],
+ AncData :: [#sctp_sndrcvinfo{} | inet:ancillary_data()],
Data :: binary() | string() | #sctp_sndrcvinfo{}
| #sctp_assoc_change{} | #sctp_paddr_change{}
| #sctp_adaptation_event{},
diff --git a/lib/kernel/src/gen_tcp.erl b/lib/kernel/src/gen_tcp.erl
index c61411e814..7f7833ec23 100644
--- a/lib/kernel/src/gen_tcp.erl
+++ b/lib/kernel/src/gen_tcp.erl
@@ -62,7 +62,14 @@
{show_econnreset, boolean()} |
{sndbuf, non_neg_integer()} |
{tos, non_neg_integer()} |
+ {tclass, non_neg_integer()} |
+ {ttl, non_neg_integer()} |
+ {recvtos, boolean()} |
+ {recvtclass, boolean()} |
+ {recvttl, boolean()} |
{ipv6_v6only, boolean()}.
+-type pktoptions_value() ::
+ {pktoptions, inet:ancillary_data()}.
-type option_name() ::
active |
buffer |
@@ -81,6 +88,7 @@
nodelay |
packet |
packet_size |
+ pktoptions |
priority |
{raw,
Protocol :: non_neg_integer(),
@@ -94,6 +102,12 @@
show_econnreset |
sndbuf |
tos |
+ tclass |
+ ttl |
+ recvtos |
+ recvtclass |
+ recvttl |
+ pktoptions |
ipv6_v6only.
-type connect_option() ::
{ip, inet:socket_address()} |
@@ -119,7 +133,7 @@
-type socket() :: port().
-export_type([option/0, option_name/0, connect_option/0, listen_option/0,
- socket/0]).
+ socket/0, pktoptions_value/0]).
%%
%% Connect a socket
diff --git a/lib/kernel/src/gen_udp.erl b/lib/kernel/src/gen_udp.erl
index 44eef9f3c5..d6e8652e77 100644
--- a/lib/kernel/src/gen_udp.erl
+++ b/lib/kernel/src/gen_udp.erl
@@ -51,6 +51,11 @@
{reuseaddr, boolean()} |
{sndbuf, non_neg_integer()} |
{tos, non_neg_integer()} |
+ {tclass, non_neg_integer()} |
+ {ttl, non_neg_integer()} |
+ {recvtos, boolean()} |
+ {recvtclass, boolean()} |
+ {recvttl, boolean()} |
{ipv6_v6only, boolean()}.
-type option_name() ::
active |
@@ -76,6 +81,12 @@
reuseaddr |
sndbuf |
tos |
+ tclass |
+ ttl |
+ recvtos |
+ recvtclass |
+ recvttl |
+ pktoptions |
ipv6_v6only.
-type socket() :: port().
@@ -147,11 +158,13 @@ send(S, Packet) when is_port(S) ->
end.
-spec recv(Socket, Length) ->
- {ok, {Address, Port, Packet}} | {error, Reason} when
+ {ok, RecvData} | {error, Reason} when
Socket :: socket(),
Length :: non_neg_integer(),
+ RecvData :: {Address, Port, Packet} | {Address, Port, AncData, Packet},
Address :: inet:ip_address() | inet:returned_non_ip_address(),
Port :: inet:port_number(),
+ AncData :: inet:ancillary_data(),
Packet :: string() | binary(),
Reason :: not_owner | inet:posix().
@@ -164,12 +177,14 @@ recv(S,Len) when is_port(S), is_integer(Len) ->
end.
-spec recv(Socket, Length, Timeout) ->
- {ok, {Address, Port, Packet}} | {error, Reason} when
+ {ok, RecvData} | {error, Reason} when
Socket :: socket(),
Length :: non_neg_integer(),
Timeout :: timeout(),
+ RecvData :: {Address, Port, Packet} | {Address, Port, AncData, Packet},
Address :: inet:ip_address() | inet:returned_non_ip_address(),
Port :: inet:port_number(),
+ AncData :: inet:ancillary_data(),
Packet :: string() | binary(),
Reason :: not_owner | inet:posix().
diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl
index 73c53b9011..5dd68dc285 100644
--- a/lib/kernel/src/inet.erl
+++ b/lib/kernel/src/inet.erl
@@ -76,7 +76,7 @@
-export_type([address_family/0, socket_protocol/0, hostent/0, hostname/0, ip4_address/0,
ip6_address/0, ip_address/0, port_number/0,
local_address/0, socket_address/0, returned_non_ip_address/0,
- socket_setopt/0, socket_getopt/0,
+ socket_setopt/0, socket_getopt/0, ancillary_data/0,
posix/0, socket/0, stat_option/0]).
%% imports
-import(lists, [append/1, duplicate/2, filter/2, foldl/3]).
@@ -163,6 +163,9 @@
'recv_cnt' | 'recv_max' | 'recv_avg' | 'recv_oct' | 'recv_dvi' |
'send_cnt' | 'send_max' | 'send_avg' | 'send_oct' | 'send_pend'.
+-type ancillary_data() ::
+ [ {'tos', byte()} | {'tclass', byte()} | {'ttl', byte()} ].
+
%%% ---------------------------------
-spec get_rc() -> [{Par :: atom(), Val :: any()} |
@@ -302,7 +305,7 @@ setopts(Socket, Opts) ->
{'ok', OptionValues} | {'error', posix()} when
Socket :: socket(),
Options :: [socket_getopt()],
- OptionValues :: [socket_setopt()].
+ OptionValues :: [socket_setopt() | gen_tcp:pktoptions_value()].
getopts(Socket, Opts) ->
case prim_inet:getopts(Socket, Opts) of
@@ -722,6 +725,7 @@ stats() ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
connect_options() ->
[tos, tclass, priority, reuseaddr, keepalive, linger, sndbuf, recbuf, nodelay,
+ recvtos, recvtclass, ttl, recvttl,
header, active, packet, packet_size, buffer, mode, deliver, line_delimiter,
exit_on_close, high_watermark, low_watermark, high_msgq_watermark,
low_msgq_watermark, send_timeout, send_timeout_close, delay_send, raw,
@@ -790,6 +794,7 @@ con_add(Name, Val, #connect_opts{} = R, Opts, AllOpts) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
listen_options() ->
[tos, tclass, priority, reuseaddr, keepalive, linger, sndbuf, recbuf, nodelay,
+ recvtos, recvtclass, ttl, recvttl,
header, active, packet, buffer, mode, deliver, backlog, ipv6_v6only,
exit_on_close, high_watermark, low_watermark, high_msgq_watermark,
low_msgq_watermark, send_timeout, send_timeout_close, delay_send,
@@ -870,7 +875,7 @@ tcp_module_1(Opts, Address) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
udp_options() ->
[tos, tclass, priority, reuseaddr, sndbuf, recbuf, header, active, buffer, mode,
- deliver, ipv6_v6only,
+ recvtos, recvtclass, ttl, recvttl, deliver, ipv6_v6only,
broadcast, dontroute, multicast_if, multicast_ttl, multicast_loop,
add_membership, drop_membership, read_packets,raw,
high_msgq_watermark, low_msgq_watermark, bind_to_device].
@@ -940,8 +945,10 @@ udp_module(Opts) ->
% (*) passing of open FDs ("fdopen") is not supported.
sctp_options() ->
[ % The following are generic inet options supported for SCTP sockets:
- mode, active, buffer, tos, tclass, priority, dontroute, reuseaddr, linger, sndbuf,
- recbuf, ipv6_v6only, high_msgq_watermark, low_msgq_watermark,
+ mode, active, buffer, tos, tclass, ttl,
+ priority, dontroute, reuseaddr, linger,
+ recvtos, recvtclass, recvttl,
+ sndbuf, recbuf, ipv6_v6only, high_msgq_watermark, low_msgq_watermark,
bind_to_device,
% Other options are SCTP-specific (though they may be similar to their
diff --git a/lib/kernel/src/inet6_tcp.erl b/lib/kernel/src/inet6_tcp.erl
index a0d5d3df70..347b8b9a1b 100644
--- a/lib/kernel/src/inet6_tcp.erl
+++ b/lib/kernel/src/inet6_tcp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. 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.
@@ -167,7 +167,7 @@ listen(Port, Opts) ->
%% Accept
%%
accept(L) ->
- case prim_inet:accept(L) of
+ case prim_inet:accept(L, accept_family_opts()) of
{ok, S} ->
inet_db:register_socket(S, ?MODULE),
{ok,S};
@@ -175,13 +175,15 @@ accept(L) ->
end.
accept(L, Timeout) ->
- case prim_inet:accept(L, Timeout) of
+ case prim_inet:accept(L, Timeout, accept_family_opts()) of
{ok, S} ->
inet_db:register_socket(S, ?MODULE),
{ok,S};
Error -> Error
end.
+accept_family_opts() -> [tclass, recvtclass].
+
%%
%% Create a port/socket from a file descriptor
%%
diff --git a/lib/kernel/src/inet_int.hrl b/lib/kernel/src/inet_int.hrl
index 357e27826c..c8e09d18ad 100644
--- a/lib/kernel/src/inet_int.hrl
+++ b/lib/kernel/src/inet_int.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. 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.
@@ -157,6 +157,11 @@
-define(INET_LOPT_LINE_DELIM, 40).
-define(INET_OPT_TCLASS, 41).
-define(INET_OPT_BIND_TO_DEVICE, 42).
+-define(INET_OPT_RECVTOS, 43).
+-define(INET_OPT_RECVTCLASS, 44).
+-define(INET_OPT_PKTOPTIONS, 45).
+-define(INET_OPT_TTL, 46).
+-define(INET_OPT_RECVTTL, 47).
% Specific SCTP options: separate range:
-define(SCTP_OPT_RTOINFO, 100).
-define(SCTP_OPT_ASSOCINFO, 101).
diff --git a/lib/kernel/src/inet_tcp.erl b/lib/kernel/src/inet_tcp.erl
index dac6b3119d..f1e3116856 100644
--- a/lib/kernel/src/inet_tcp.erl
+++ b/lib/kernel/src/inet_tcp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. 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.
@@ -164,7 +164,7 @@ listen(Port, Opts) ->
%% Accept
%%
accept(L) ->
- case prim_inet:accept(L) of
+ case prim_inet:accept(L, accept_family_opts()) of
{ok, S} ->
inet_db:register_socket(S, ?MODULE),
{ok,S};
@@ -172,13 +172,15 @@ accept(L) ->
end.
accept(L, Timeout) ->
- case prim_inet:accept(L, Timeout) of
+ case prim_inet:accept(L, Timeout, accept_family_opts()) of
{ok, S} ->
inet_db:register_socket(S, ?MODULE),
{ok,S};
Error -> Error
end.
+accept_family_opts() -> [tos, ttl, recvtos, recvttl].
+
%%
%% Create a port/socket from a file descriptor
%%
diff --git a/lib/kernel/test/gen_tcp_misc_SUITE.erl b/lib/kernel/test/gen_tcp_misc_SUITE.erl
index 950f5bea6f..d532537eb9 100644
--- a/lib/kernel/test/gen_tcp_misc_SUITE.erl
+++ b/lib/kernel/test/gen_tcp_misc_SUITE.erl
@@ -41,6 +41,7 @@
busy_send/1, busy_disconnect_passive/1, busy_disconnect_active/1,
fill_sendq/1, partial_recv_and_close/1,
partial_recv_and_close_2/1,partial_recv_and_close_3/1,so_priority/1,
+ recvtos/1, recvttl/1, recvtosttl/1, recvtclass/1,
%% Accept tests
primitive_accept/1,multi_accept_close_listen/1,accept_timeout/1,
accept_timeouts_in_order/1,accept_timeouts_in_order2/1,
@@ -83,7 +84,8 @@ all() ->
busy_disconnect_passive, busy_disconnect_active,
fill_sendq, partial_recv_and_close,
partial_recv_and_close_2, partial_recv_and_close_3,
- so_priority, primitive_accept,
+ so_priority, recvtos, recvttl, recvtosttl,
+ recvtclass, primitive_accept,
multi_accept_close_listen, accept_timeout,
accept_timeouts_in_order, accept_timeouts_in_order2,
accept_timeouts_in_order3, accept_timeouts_in_order4,
@@ -1914,6 +1916,209 @@ so_priority(Config) when is_list(Config) ->
end
end.
+
+
+%% IP_RECVTOS and IP_RECVTCLASS for IP_PKTOPTIONS
+%% does not seem to be implemented in Linux until kernel 3.0
+
+recvtos(_Config) ->
+ test_pktoptions(
+ inet, [{recvtos,tos,96}],
+ fun recvtos_ok/2,
+ false).
+
+recvtosttl(_Config) ->
+ test_pktoptions(
+ inet, [{recvtos,tos,96},{recvttl,ttl,33}],
+ fun (OSType, OSVer) ->
+ recvtos_ok(OSType, OSVer) andalso recvttl_ok(OSType, OSVer)
+ end,
+ false).
+
+recvttl(_Config) ->
+ test_pktoptions(
+ inet, [{recvttl,ttl,33}],
+ fun recvttl_ok/2,
+ false).
+
+recvtclass(_Config) ->
+ {ok,IFs} = inet:getifaddrs(),
+ case
+ [Name ||
+ {Name,Opts} <- IFs,
+ lists:member({addr,{0,0,0,0,0,0,0,1}}, Opts)]
+ of
+ [_] ->
+ test_pktoptions(
+ inet6, [{recvtclass,tclass,224}],
+ fun recvtclass_ok/2,
+ true);
+ [] ->
+ {skip,{ipv6_not_supported,IFs}}
+ end.
+
+%% These version numbers are the highest noted in daily tests
+%% where the test fails for a plausible reason, so
+%% skip on that platform.
+%%
+%% On newer versions it might be fixed, but we'll see about that
+%% when machines with newer versions gets installed...
+%% If the test still fails for a plausible reason these
+%% version numbers simply should be increased.
+
+%% Using the option returns einval, so it is not implemented.
+recvtos_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {17,6,0});
+%% Does not return any value - not implemented for pktoptions
+recvtos_ok({unix,linux}, OSVer) -> not semver_lt(OSVer, {3,1,0});
+%%
+recvtos_ok({unix,_}, _) -> true;
+recvtos_ok(_, _) -> false.
+
+recvttl_ok({unix,linux}, _) -> true;
+recvttl_ok({unix,_}, _) -> true;
+recvttl_ok(_, _) -> false.
+
+%% Using the option returns einval, so it is not implemented.
+recvtclass_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,4,0});
+recvtclass_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {11,2,0});
+%% Using the option returns einval up to 0.9.0, so it is not implemented.
+%% Does not return any value - not implemented for pktoptions
+recvtclass_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {17,6,0});
+%% Does not return any value - not implemented for pktoptions
+recvtclass_ok({unix,linux}, OSVer) -> not semver_lt(OSVer, {3,1,0});
+%%
+recvtclass_ok({unix,_}, _) -> true;
+recvtclass_ok(_, _) -> false.
+
+semver_lt({X1,Y1,Z1}, {X2,Y2,Z2}) ->
+ if
+ X1 > X2 -> false;
+ X1 < X2 -> true;
+ Y1 > Y2 -> false;
+ Y1 < Y2 -> true;
+ Z1 > Z2 -> false;
+ Z1 < Z2 -> true;
+ true -> false
+ end;
+semver_lt(_, {_,_,_}) -> false.
+
+test_pktoptions(Family, Spec, OSFilter, CheckAccept) ->
+ OSType = os:type(),
+ OSVer = os:version(),
+ case OSFilter(OSType, OSVer) of
+ true ->
+ io:format("Os: ~p, ~p~n", [OSType,OSVer]),
+ test_pktoptions(Family, Spec, CheckAccept, OSType, OSVer);
+ false ->
+ {skip,{not_supported_for_os_version,{OSType,OSVer}}}
+ end.
+%%
+test_pktoptions(Family, Spec, CheckAccept, OSType, OSVer) ->
+ Timeout = 5000,
+ RecvOpts = [RecvOpt || {RecvOpt,_,_} <- Spec],
+ TrueRecvOpts = [{RecvOpt,true} || {RecvOpt,_,_} <- Spec],
+ FalseRecvOpts = [{RecvOpt,false} || {RecvOpt,_,_} <- Spec],
+ Opts = [Opt || {_,Opt,_} <- Spec],
+ OptsVals = [{Opt,Val} || {_,Opt,Val} <- Spec],
+ Address =
+ case Family of
+ inet ->
+ {127,0,0,1};
+ inet6 ->
+ {0,0,0,0,0,0,0,1}
+ end,
+ %%
+ %% Set RecvOpts on listen socket
+ {ok,L} =
+ gen_tcp:listen(
+ 0,
+ [Family,binary,{active,false},{send_timeout,Timeout}
+ |TrueRecvOpts]),
+ {ok,P} = inet:port(L),
+ {ok,TrueRecvOpts} = inet:getopts(L, RecvOpts),
+ {ok,OptsValsDefault} = inet:getopts(L, Opts),
+ %%
+ %% Set RecvOpts and Option values on connect socket
+ {ok,S2} =
+ gen_tcp:connect(
+ Address, P,
+ [Family,binary,{active,false},{send_timeout,Timeout}
+ |TrueRecvOpts ++ OptsVals],
+ Timeout),
+ {ok,TrueRecvOpts} = inet:getopts(S2, RecvOpts),
+ {ok,OptsVals} = inet:getopts(S2, Opts),
+ %%
+ %% Accept socket inherits the options from listen socket
+ {ok,S1} = gen_tcp:accept(L, Timeout),
+ {ok,TrueRecvOpts} = inet:getopts(S1, RecvOpts),
+ {ok,OptsValsDefault} = inet:getopts(S1, Opts),
+%%% %%
+%%% %% Handshake
+%%% ok = gen_tcp:send(S1, <<"hello">>),
+%%% {ok,<<"hello">>} = gen_tcp:recv(S2, 5, Timeout),
+%%% ok = gen_tcp:send(S2, <<"hi">>),
+%%% {ok,<<"hi">>} = gen_tcp:recv(S1, 2, Timeout),
+ %%
+ %% Verify returned remote options
+ {ok,[{pktoptions,OptsVals1}]} = inet:getopts(S1, [pktoptions]),
+ {ok,[{pktoptions,OptsVals2}]} = inet:getopts(S2, [pktoptions]),
+ (Result1 = sets_eq(OptsVals1, OptsVals))
+ orelse io:format(
+ "Accept differs: ~p neq ~p~n", [OptsVals1,OptsVals]),
+ (Result2 = sets_eq(OptsVals2, OptsValsDefault))
+ orelse io:format(
+ "Connect differs: ~p neq ~p~n",
+ [OptsVals2,OptsValsDefault]),
+ %%
+ ok = gen_tcp:close(S2),
+ ok = gen_tcp:close(S1),
+ %%
+ %%
+ %% Clear RecvOpts on listen socket and set Option values
+ ok = inet:setopts(L, FalseRecvOpts ++ OptsVals),
+ {ok,FalseRecvOpts} = inet:getopts(L, RecvOpts),
+ {ok,OptsVals} = inet:getopts(L, Opts),
+ %%
+ %% Set RecvOpts on connecting socket
+ %%
+ {ok,S4} =
+ gen_tcp:connect(
+ Address, P,
+ [Family,binary,{active,false},{send_timeout,Timeout}
+ |TrueRecvOpts],
+ Timeout),
+ {ok,TrueRecvOpts} = inet:getopts(S4, RecvOpts),
+ {ok,OptsValsDefault} = inet:getopts(S4, Opts),
+ %%
+ %% Accept socket inherits the options from listen socket
+ {ok,S3} = gen_tcp:accept(L, Timeout),
+ {ok,FalseRecvOpts} = inet:getopts(S3, RecvOpts),
+ {ok,OptsVals} = inet:getopts(S3, Opts),
+ %%
+ %% Verify returned remote options
+ {ok,[{pktoptions,[]}]} = inet:getopts(S3, [pktoptions]),
+ {ok,[{pktoptions,OptsVals4}]} = inet:getopts(S4, [pktoptions]),
+ (Result3 = sets_eq(OptsVals4, OptsVals))
+ orelse io:format(
+ "Accept2 differs: ~p neq ~p~n", [OptsVals4,OptsVals]),
+ %%
+ ok = gen_tcp:close(S4),
+ ok = gen_tcp:close(S3),
+ ok = gen_tcp:close(L),
+ (Result1 and ((not CheckAccept) or (Result2 and Result3)))
+ orelse
+ exit({failed,
+ [{OptsVals1,OptsVals4,OptsVals},
+ {OptsVals2,OptsValsDefault}],
+ {OSType,OSVer}}),
+%% exit({{OSType,OSVer},success}), % In search for the truth
+ ok.
+
+sets_eq(L1, L2) ->
+ lists:sort(L1) == lists:sort(L2).
+
+
+
%% Accept test utilities (suites are below)
millis() ->
@@ -2205,7 +2410,7 @@ wait_until_accepting(Proc,0) ->
exit({timeout_waiting_for_accepting,Proc});
wait_until_accepting(Proc,N) ->
case process_info(Proc,current_function) of
- {current_function,{prim_inet,accept0,2}} ->
+ {current_function,{prim_inet,accept0,3}} ->
case process_info(Proc,status) of
{status,waiting} ->
ok;
diff --git a/lib/kernel/test/gen_udp_SUITE.erl b/lib/kernel/test/gen_udp_SUITE.erl
index 3acfff929e..878e48786c 100644
--- a/lib/kernel/test/gen_udp_SUITE.erl
+++ b/lib/kernel/test/gen_udp_SUITE.erl
@@ -36,6 +36,7 @@
-export([send_to_closed/1, active_n/1,
buffer_size/1, binary_passive_recv/1, max_buffer_size/1, bad_address/1,
read_packets/1, open_fd/1, connect/1, implicit_inet6/1,
+ recvtos/1, recvtosttl/1, recvttl/1, recvtclass/1,
local_basic/1, local_unbound/1,
local_fdopen/1, local_fdopen_unbound/1, local_abstract/1]).
@@ -47,6 +48,7 @@ all() ->
[send_to_closed, buffer_size, binary_passive_recv, max_buffer_size,
bad_address, read_packets, open_fd, connect,
implicit_inet6, active_n,
+ recvtos, recvtosttl, recvttl, recvtclass,
{group, local}].
groups() ->
@@ -572,6 +574,167 @@ active_n(Config) when is_list(Config) ->
ok.
+
+recvtos(_Config) ->
+ test_recv_opts(
+ inet, [{recvtos,tos,96}],
+ fun recvtos_ok/2).
+
+recvtosttl(_Config) ->
+ test_recv_opts(
+ inet, [{recvtos,tos,96},{recvttl,ttl,33}],
+ fun (OSType, OSVer) ->
+ recvtos_ok(OSType, OSVer) andalso recvttl_ok(OSType, OSVer)
+ end).
+
+recvttl(_Config) ->
+ test_recv_opts(
+ inet, [{recvttl,ttl,33}],
+ fun recvttl_ok/2).
+
+recvtclass(_Config) ->
+ {ok,IFs} = inet:getifaddrs(),
+ case
+ [Name ||
+ {Name,Opts} <- IFs,
+ lists:member({addr,{0,0,0,0,0,0,0,1}}, Opts)]
+ of
+ [_] ->
+ test_recv_opts(
+ inet6, [{recvtclass,tclass,224}],
+ fun recvtclass_ok/2);
+ [] ->
+ {skip,ipv6_not_supported,IFs}
+ end.
+
+%% These version numbers are just above the highest noted in daily tests
+%% where the test fails for a plausible reason, that is the lowest
+%% where we can expect that the test mighe succeed, so
+%% skip on platforms lower than this.
+%%
+%% On newer versions it might be fixed, but we'll see about that
+%% when machines with newer versions gets installed...
+%% If the test still fails for a plausible reason these
+%% version numbers simply should be increased.
+
+%% Using the option returns einval, so it is not implemented.
+recvtos_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {17,6,0});
+%% Using the option returns einval, so it is not implemented.
+recvtos_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,4,0});
+%% Using the option returns einval, so it is not implemented.
+recvtos_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,11,0});
+%%
+recvtos_ok({unix,_}, _) -> true;
+recvtos_ok(_, _) -> false.
+
+recvttl_ok({unix,_}, _) -> true;
+recvttl_ok(_, _) -> false.
+
+%% Using the option returns einval, so it is not implemented.
+recvtclass_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {9,9,0});
+recvtclass_ok({unix,linux}, OSVer) -> not semver_lt(OSVer, {2,6,11});
+%%
+recvtclass_ok({unix,_}, _) -> true;
+recvtclass_ok(_, _) -> false.
+
+semver_lt({X1,Y1,Z1}, {X2,Y2,Z2}) ->
+ if
+ X1 > X2 -> false;
+ X1 < X2 -> true;
+ Y1 > Y2 -> false;
+ Y1 < Y2 -> true;
+ Z1 > Z2 -> false;
+ Z1 < Z2 -> true;
+ true -> false
+ end;
+semver_lt(_, {_,_,_}) -> false.
+
+test_recv_opts(Family, Spec, OSFilter) ->
+ OSType = os:type(),
+ OSVer = os:version(),
+ case OSFilter(OSType, OSVer) of
+ true ->
+ io:format("Os: ~p, ~p~n", [OSType,OSVer]),
+ test_recv_opts(Family, Spec, OSType, OSVer);
+ false ->
+ {skip,{not_supported_for_os_version,{OSType,OSVer}}}
+ end.
+%%
+test_recv_opts(Family, Spec, _OSType, _OSVer) ->
+ Timeout = 5000,
+ RecvOpts = [RecvOpt || {RecvOpt,_,_} <- Spec],
+ TrueRecvOpts = [{RecvOpt,true} || {RecvOpt,_,_} <- Spec],
+ FalseRecvOpts = [{RecvOpt,false} || {RecvOpt,_,_} <- Spec],
+ Opts = [Opt || {_,Opt,_} <- Spec],
+ OptsVals = [{Opt,Val} || {_,Opt,Val} <- Spec],
+ TrueRecvOpts_OptsVals = TrueRecvOpts ++ OptsVals,
+ Addr =
+ case Family of
+ inet ->
+ {127,0,0,1};
+ inet6 ->
+ {0,0,0,0,0,0,0,1}
+ end,
+ %%
+ {ok,S1} =
+ gen_udp:open(0, [Family,binary,{active,false}|TrueRecvOpts]),
+ {ok,P1} = inet:port(S1),
+ {ok,TrueRecvOpts} = inet:getopts(S1, RecvOpts),
+ ok = inet:setopts(S1, FalseRecvOpts),
+ {ok,FalseRecvOpts} = inet:getopts(S1, RecvOpts),
+ ok = inet:setopts(S1, TrueRecvOpts_OptsVals),
+ {ok,TrueRecvOpts_OptsVals} = inet:getopts(S1, RecvOpts ++ Opts),
+ %%
+ {ok,S2} =
+ gen_udp:open(0, [Family,binary,{active,true}|FalseRecvOpts]),
+ {ok,P2} = inet:port(S2),
+ {ok,FalseRecvOpts_OptsVals2} = inet:getopts(S2, RecvOpts ++ Opts),
+ OptsVals2 = FalseRecvOpts_OptsVals2 -- FalseRecvOpts,
+ %%
+ ok = gen_udp:send(S2, Addr, P1, <<"abcde">>),
+ ok = gen_udp:send(S1, Addr, P2, <<"fghij">>),
+ {ok,{_,P2,OptsVals3,<<"abcde">>}} = gen_udp:recv(S1, 0, Timeout),
+ verify_sets_eq(OptsVals3, OptsVals2),
+ receive
+ {udp,S2,_,P1,<<"fghij">>} ->
+ ok;
+ Other1 ->
+ exit({unexpected,Other1})
+ after Timeout ->
+ exit(timeout)
+ end,
+ %%
+ ok = inet:setopts(S1, FalseRecvOpts),
+ {ok,FalseRecvOpts} = inet:getopts(S1, RecvOpts),
+ ok = inet:setopts(S2, TrueRecvOpts),
+ {ok,TrueRecvOpts} = inet:getopts(S2, RecvOpts),
+ %%
+ ok = gen_udp:send(S2, Addr, P1, <<"klmno">>),
+ ok = gen_udp:send(S1, Addr, P2, <<"pqrst">>),
+ {ok,{_,P2,<<"klmno">>}} = gen_udp:recv(S1, 0, Timeout),
+ receive
+ {udp,S2,_,P1,OptsVals4,<<"pqrst">>} ->
+ verify_sets_eq(OptsVals4, OptsVals);
+ Other2 ->
+ exit({unexpected,Other2})
+ after Timeout ->
+ exit(timeout)
+ end,
+ ok = gen_udp:close(S1),
+ ok = gen_udp:close(S2),
+%% exit({{OSType,OSVer},success}), % In search for the truth
+ ok.
+
+verify_sets_eq(L1, L2) ->
+ L = lists:sort(L1),
+ case lists:sort(L2) of
+ L ->
+ ok;
+ _ ->
+ exit({sets_neq,L1,L2})
+ end.
+
+
local_basic(_Config) ->
SFile = local_filename(server),
SAddr = {local,bin_filename(SFile)},
diff --git a/lib/snmp/doc/src/notes.xml b/lib/snmp/doc/src/notes.xml
index f64e0cca97..1607363ad1 100644
--- a/lib/snmp/doc/src/notes.xml
+++ b/lib/snmp/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1996</year><year>2017</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -48,7 +48,7 @@
</list>
</section>
-</section>
+ </section>
<section><title>SNMP 5.2.10</title>
diff --git a/lib/snmp/doc/src/snmp.xml b/lib/snmp/doc/src/snmp.xml
index 801193675c..480ed2e825 100644
--- a/lib/snmp/doc/src/snmp.xml
+++ b/lib/snmp/doc/src/snmp.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2016</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -341,10 +341,10 @@
</func>
<func>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block | Start) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Block | Stop) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop, Block) -> ok | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block | Start) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Block | Stop) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop, Block) -> ok | {ok, Cnt} | {error, Reason}</name>
<fsummary>Convert an Audit Trail Log to text format</fsummary>
<type>
<v>LogDir = string()</v>
@@ -355,6 +355,9 @@
<v>LogFile = string()</v>
<v>Start = Stop = null | datetime() | {local_time,datetime()} | {universal_time,datetime()} </v>
<v>Block = boolean()</v>
+ <v>Cnt = {NumOK, NumERR}</v>
+ <v>NumOK = non_neg_integer()</v>
+ <v>NumERR = pos_integer()</v>
<v>Reason = term()</v>
</type>
<desc>
@@ -394,16 +397,25 @@
and <c>Vsn</c> is the SNMP version. <c>PDU</c> is a textual
version of the protocol data unit. There is a new line
between <c>Vsn</c> and <c>PDU</c>.</p>
+
+ <p>If the entire log is successfully converted, the function
+ will return <c>ok</c>.
+ If one of more entries fail to convert, the function will instead
+ return <c>{ok, {NumOK, NumERR}}</c>, where the counters indicate
+ how many valid and erroneous entries where found.
+ If instead <c>{error, Reason}</c> is returned, the conversion
+ encountered a fatal error and where either never done of aborted
+ midway. </p>
<marker id="log_to_io"></marker>
</desc>
</func>
<func>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block | Start) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile, Start, Block | Stop) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop, Block) -> ok | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, LogName, LogFile) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block | Start) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, LogName, LogFile, Start, Block | Stop) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop, Block) -> ok | {ok, Cnt} | {error, Reason}</name>
<fsummary>Convert an Audit Trail Log to text format</fsummary>
<type>
<v>LogDir = string()</v>
@@ -412,6 +424,9 @@
<v>LogName = string()</v>
<v>LogFile = string()</v>
<v>Start = Stop = null | datetime() | {local_time,datetime()} | {universal_time,datetime()} </v>
+ <v>Cnt = {NumOK, NumERR}</v>
+ <v>NumOK = non_neg_integer()</v>
+ <v>NumERR = pos_integer()</v>
<v>Reason = term()</v>
</type>
<desc>
diff --git a/lib/snmp/doc/src/snmpa.xml b/lib/snmp/doc/src/snmpa.xml
index d756ff7a65..b78f14da01 100644
--- a/lib/snmp/doc/src/snmpa.xml
+++ b/lib/snmp/doc/src/snmpa.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2004</year><year>2016</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -559,13 +559,13 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
<func>
<name>log_to_txt(LogDir)</name>
<name>log_to_txt(LogDir, Block | Mibs)</name>
- <name>log_to_txt(LogDir, Mibs, Block | OutFile) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, Block | LogName) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, Block | LogFile) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block | Start) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop) -> ok | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, Block | OutFile) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, Block | LogName) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, Block | LogFile) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block | Start) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name>
<fsummary>Convert an Audit Trail Log to text format</fsummary>
<type>
<v>LogDir = string()</v>
@@ -576,6 +576,9 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
<v>LogName = string()</v>
<v>LogFile = string()</v>
<v>Start = Stop = null | calendar:datetime() | {local_time, calendar:datetime()} | {universal_time, calendar:datetime()} </v>
+ <v>Cnt = {NumOK, NumERR}</v>
+ <v>NumOK = non_neg_integer()</v>
+ <v>NumERR = pos_integer()</v>
<v>Reason = disk_log_open_error() | file_open_error() | term()</v>
<v>disk_log_open_error() = {LogName, term()}</v>
<v>file_open_error() = {OutFile, term()}</v>
@@ -597,14 +600,14 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
</func>
<func>
- <name>log_to_io(LogDir) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Block | Mibs) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, Block | LogName) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, Block | LogFile) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block | Start) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop) -> ok | {error, Reason}</name>
+ <name>log_to_io(LogDir) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Block | Mibs) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, Block | LogName) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, LogName, Block | LogFile) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block | Start) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name>
<fsummary>Convert an Audit Trail Log to text format</fsummary>
<type>
<v>LogDir = string()</v>
@@ -614,6 +617,9 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
<v>LogName = string()</v>
<v>LogFile = string()</v>
<v>Start = Stop = null | calendar:datetime() | {local_time, calendar:datetime()} | {universal_time, calendar:datetime()} </v>
+ <v>Cnt = {NumOK, NumERR}</v>
+ <v>NumOK = non_neg_integer()</v>
+ <v>NumERR = pos_integer()</v>
<v>Reason = disk_log_open_error() | file_open_error() | term()</v>
<v>disk_log_open_error() = {LogName, term()}</v>
<v>file_open_error() = {OutFile, term()}</v>
diff --git a/lib/snmp/doc/src/snmpm.xml b/lib/snmp/doc/src/snmpm.xml
index 4818aeb697..be4cd58a1a 100644
--- a/lib/snmp/doc/src/snmpm.xml
+++ b/lib/snmp/doc/src/snmpm.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2004</year><year>2016</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -1216,13 +1216,13 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
<func>
<name>log_to_txt(LogDir)</name>
<name>log_to_txt(LogDir, Block | Mibs)</name>
- <name>log_to_txt(LogDir, Mibs, Block | OutFile) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, Block | LogName) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, Block | LogFile) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block | Start) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop) -> ok | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, Block | OutFile) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, Block | LogName) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, Block | LogFile) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block | Start) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name>
<fsummary>Convert an Audit Trail Log to text format</fsummary>
<type>
<v>LogDir = string()</v>
@@ -1233,6 +1233,9 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
<v>LogName = string()</v>
<v>LogFile = string()</v>
<v>Start = Stop = null | calendar:datetime() | {local_time, calendar:datetime()} | {universal_time, calendar:datetime()} </v>
+ <v>Cnt = {NumOK, NumERR}</v>
+ <v>NumOK = non_neg_integer()</v>
+ <v>NumERR = pos_integer()</v>
<v>Reason = disk_log_open_error() | file_open_error() | term()</v>
<v>disk_log_open_error() = {LogName, term()}</v>
<v>file_open_error() = {OutFile, term()}</v>
@@ -1254,15 +1257,15 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
</func>
<func>
- <name>log_to_io(LogDir) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Block | Mibs) -> ok | {error, Reason}</name>
+ <name>log_to_io(LogDir) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Block | Mibs) -> ok | {ok, Cnt} | {error, Reason}</name>
<name>log_to_io(LogDir, Mibs) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, Block | LogName) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, Block | LogFile) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block | Start) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop) -> ok | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, Block | LogName) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, LogName, Block | LogFile) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block | Start) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name>
<fsummary>Convert an Audit Trail Log to text format</fsummary>
<type>
<v>LogDir = string()</v>
@@ -1272,6 +1275,9 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
<v>LogName = string()</v>
<v>LogFile = string()</v>
<v>Start = Stop = null | calendar:datetime() | {local_time, calendar:datetime()} | {universal_time, calendar:datetime()} </v>
+ <v>Cnt = {NumOK, NumERR}</v>
+ <v>NumOK = non_neg_integer()</v>
+ <v>NumERR = pos_integer()</v>
<v>Reason = disk_log_open_error() | file_open_error() | term()</v>
<v>disk_log_open_error() = {LogName, term()}</v>
<v>file_open_error() = {OutFile, term()}</v>
diff --git a/lib/snmp/src/agent/snmpa_net_if.erl b/lib/snmp/src/agent/snmpa_net_if.erl
index ecf9498ca9..afed4482d2 100644
--- a/lib/snmp/src/agent/snmpa_net_if.erl
+++ b/lib/snmp/src/agent/snmpa_net_if.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. 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.
@@ -137,11 +137,10 @@ init(Prio, NoteStore, MasterAgent, Parent, Opts) ->
proc_lib:init_ack({ok, self()}),
try loop(State)
catch
- C:E when C =/= exit, E =/= shutdown ->
+ C:E:S when C =/= exit, E =/= shutdown ->
Fmt =
"loop/1 EXCEPTION ~w:~w~n"
" ~p",
- S = erlang:get_stacktrace(),
case C of
exit ->
%% Externally killed, root cause is elsewhere
@@ -647,10 +646,10 @@ maybe_handle_recv(
case
try FilterMod:accept_recv(From_1, From_2)
catch
- Class:Exception ->
+ Class:Exception:StackTrace ->
error_msg(
"FilterMod:accept_recv(~p, ~p) crashed: ~w:~w~n ~p",
- [From_1,From_2,Class,Exception,erlang:get_stacktrace()]),
+ [From_1, From_2, Class, Exception, StackTrace]),
true
end
of
@@ -753,12 +752,11 @@ maybe_handle_recv_pdu(
case
try FilterMod:accept_recv_pdu(From_1, From_2, Type)
catch
- Class:Exception ->
+ Class:Exception:StackTrace ->
error_msg(
"FilterMod:accept_recv_pdu(~p, ~p, ~p) crashed: ~w:~w~n"
" ~p",
- [From_1,From_2,Type,Class,Exception,
- erlang:get_stacktrace()]),
+ [From_1, From_2, Type, Class, Exception, StackTrace]),
true
end
of
@@ -834,11 +832,10 @@ maybe_handle_reply_pdu(
try
FilterMod:accept_send_pdu(Addresses, Type)
catch
- Class:Exception ->
+ Class:Exception:StackTrace ->
error_msg(
"FilterMod:accept_send_pdu(~p, ~p) crashed: ~w:~w~n ~p",
- [Addresses, Type, Class, Exception,
- erlang:get_stacktrace()]),
+ [Addresses, Type, Class, Exception, StackTrace]),
true
end
of
@@ -872,7 +869,7 @@ handle_reply_pdu(
ACMData, LogF)) of
{ok, Packet} ->
?vinfo("time in agent: ~w mysec", [time_in_agent()]),
- try maybe_udp_send(S, Transport, To, Packet)
+ try maybe_udp_send_wo_log(S, Transport, To, Packet)
catch
{Reason, Sz} ->
error_msg("Cannot send message "
@@ -917,11 +914,10 @@ maybe_handle_send_pdu(
case
try FilterMod:accept_send_pdu(AddressesToFilter, Type)
catch
- Class:Exception ->
+ Class:Exception:StackTrace ->
error_msg(
"FilterMod:accept_send_pdu(~p, ~p) crashed: ~w:~w~n ~p",
- [AddressesToFilter,Type,
- Class,Exception,erlang:get_stacktrace()]),
+ [AddressesToFilter, Type, Class, Exception, StackTrace]),
true
end
of
@@ -1049,46 +1045,36 @@ do_handle_send_pdu(S, Type, Pdu, Addresses) ->
[Sz, Reason, Pdu])
end.
-do_handle_send_pdu1(
- #state{transports = Transports} = S,
- Type, Addresses) ->
+do_handle_send_pdu1(S, Type, Addresses) ->
lists:foreach(
- fun ({Domain, Address, Packet}) when is_binary(Packet) ->
- ?vdebug(
- "[~w] sending packet:~n"
- " size: ~p~n"
- " to: ~p", [Domain, sz(Packet), Address]),
- To = {Domain, Address},
- case select_transport_from_domain(Domain, Transports) of
- false ->
- error_msg(
- "Can not find transport~n"
- " size: ~p~n"
- " to: ~s",
- [sz(Packet), format_address(To)]);
- Transport ->
- maybe_udp_send(S, Transport, To, Packet)
- end;
- ({Domain, Address, {Packet, LogData}}) when is_binary(Packet) ->
- ?vdebug(
- "[~w] sending encrypted packet:~n"
- " size: ~p~n"
- " to: ~p", [Domain, sz(Packet), Address]),
- To = {Domain, Address},
- case select_transport_from_domain(Domain, Transports) of
- false ->
- error_msg(
- "Can not find transport~n"
- " size: ~p~n"
- " to: ~s",
- [sz(Packet), format_address(To)]);
- Transport ->
- maybe_udp_send(S, Transport, To, Packet, Type, LogData)
- end
+ fun ({Domain, Address, Pkg}) when is_binary(Pkg) ->
+ do_handle_send_pdu2(S, Type, Domain, Address,
+ Pkg, Pkg, "");
+ ({Domain, Address, {Pkg, LogPkg}}) when is_binary(Pkg) ->
+ do_handle_send_pdu2(S, Type, Domain, Address,
+ Pkg, LogPkg, " encrypted")
end,
Addresses).
-maybe_udp_send(
+do_handle_send_pdu2(#state{transports = Transports} = S,
+ Type, Domain, Address, Pkg, LogPkg, EncrStr) ->
+ ?vdebug("[~w] sending~s packet:"
+ "~n size: ~p"
+ "~n to: ~p", [Domain, EncrStr, sz(Pkg), Address]),
+ To = {Domain, Address},
+ case select_transport_from_domain(Domain, Transports) of
+ false ->
+ error_msg("Can not find transport: "
+ "~n size: ~p"
+ "~n to: ~s",
+ [sz(Pkg), format_address(To)]);
+ Transport ->
+ maybe_udp_send_w_log(S, Transport, To, Pkg, LogPkg, Type)
+ end.
+
+
+%% This function is used when logging has already been done!
+maybe_udp_send_wo_log(
#state{filter = FilterMod, transports = Transports},
#transport{socket = Socket},
To, Packet) ->
@@ -1096,10 +1082,10 @@ maybe_udp_send(
case
try FilterMod:accept_send(To_1, To_2)
catch
- Class:Exception ->
+ Class:Exception:StackTrace ->
error_msg(
"FilterMod:accept_send(~p, ~p) crashed: ~w:~w~n ~p",
- [To_1,To_2,Class,Exception,erlang:get_stacktrace()]),
+ [To_1, To_2, Class, Exception, StackTrace]),
true
end
of
@@ -1118,18 +1104,18 @@ maybe_udp_send(
udp_send(Socket, To, Packet)
end.
-maybe_udp_send(
+maybe_udp_send_w_log(
#state{log = Log, filter = FilterMod, transports = Transports},
#transport{socket = Socket},
- To, Packet, Type, _LogData) ->
+ To, Pkg, LogPkg, Type) ->
{To_1, To_2} = fix_filter_address(Transports, To),
case
try FilterMod:accept_send(To_1, To_2)
catch
- Class:Exception ->
+ Class:Exception:StackTrace ->
error_msg(
"FilterMod:accept_send(~p, ~p) crashed for: ~w:~w~n ~p",
- [To_1, To_2, Class, Exception, erlang:get_stacktrace()]),
+ [To_1, To_2, Class, Exception, StackTrace]),
true
end
of
@@ -1143,10 +1129,10 @@ maybe_udp_send(
_ ->
error_msg(
"FilterMod:accept_send(~p, ~p) returned: ~p",
- [To_1,To_2,Other])
+ [To_1, To_2, Other])
end,
- log(Log, Type, Packet, To),
- udp_send(Socket, To, Packet)
+ log(Log, Type, LogPkg, To),
+ udp_send(Socket, To, Pkg)
end.
udp_send(Socket, To, B) ->
@@ -1168,11 +1154,10 @@ udp_send(Socket, To, B) ->
ok ->
ok
catch
- error:ExitReason ->
+ error:ExitReason:StackTrace ->
error_msg("[exit] cannot send message "
"(destination: ~p:~p, size: ~p, reason: ~p, at: ~p)",
- [IpAddr, IpPort, sz(B), ExitReason,
- erlang:get_stacktrace()])
+ [IpAddr, IpPort, sz(B), ExitReason, StackTrace])
end.
sz(L) when is_list(L) -> length(L);
diff --git a/lib/snmp/src/misc/snmp_log.erl b/lib/snmp/src/misc/snmp_log.erl
index 767d801eee..5713c14912 100644
--- a/lib/snmp/src/misc/snmp_log.erl
+++ b/lib/snmp/src/misc/snmp_log.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. 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.
@@ -649,13 +649,14 @@ do_log_to_file(Log, TextFile, Mibs, Start, Stop) ->
MiniMib = snmp_mini_mib:create(Mibs),
Write = fun(X) ->
case format_msg(X, MiniMib, Start, Stop) of
- {ok, S} ->
- io:format(Fd, "~s", [S]);
- _ ->
- ok
+ {Tag, S} when (Tag =:= ok) orelse (Tag =:= error) ->
+ io:format(Fd, "~s", [S]),
+ Tag;
+ Ignore ->
+ Ignore
end
end,
- Res = (catch loop(disk_log:chunk(Log, start), Log, Write)),
+ Res = (catch loop(Log, Write)),
snmp_mini_mib:delete(MiniMib),
file:close(Fd),
Res;
@@ -668,39 +669,63 @@ do_log_to_io(Log, Mibs, Start, Stop) ->
MiniMib = snmp_mini_mib:create(Mibs),
Write = fun(X) ->
case format_msg(X, MiniMib, Start, Stop) of
- {ok, S} ->
- io:format("~s", [S]);
- _ ->
- ok
+ {Tag, S} when (Tag =:= ok) orelse (Tag =:= error) ->
+ io:format("~s", [S]),
+ Tag;
+ X ->
+ X
end
end,
- (catch loop(disk_log:chunk(Log, start), Log, Write)),
+ Res = (catch loop(Log, Write)),
snmp_mini_mib:delete(MiniMib),
- ok.
+ Res.
+
+loop(Log, Write) ->
+ loop(disk_log:chunk(Log, start), Log, Write, 0, 0).
-loop(eof, _Log, _Write) ->
+loop(eof, _Log, _Write, _NumOK, 0 = _NumERR) ->
ok;
-loop({error, _} = Error, _Log, _Write) ->
+loop(eof, _Log, _Write, NumOK, NumERR) ->
+ {ok, {NumOK, NumERR}};
+loop({error, _} = Error, _Log, _Write, _NumOK, _NumERR) ->
Error;
-loop({Cont, Terms}, Log, Write) ->
- case (catch lists:foreach(Write, Terms)) of
- {'EXIT', Reason} ->
- {error, Reason};
- _ ->
- loop(disk_log:chunk(Log, Cont), Log, Write)
+loop({Cont, Terms}, Log, Write, NumOK, NumERR) ->
+ try loop_terms(Terms, Write) of
+ {ok, {AddedOK, AddedERR}} ->
+ loop(disk_log:chunk(Log, Cont), Log, Write,
+ NumOK+AddedOK, NumERR+AddedERR)
+ catch
+ C:E:S ->
+ {error, {C, E, S}}
end;
-loop({Cont, Terms, BadBytes}, Log, Write) ->
+loop({Cont, Terms, BadBytes}, Log, Write, NumOK, NumERR) ->
error_logger:error_msg("Skipping ~w bytes while converting ~p~n~n",
[BadBytes, Log]),
- case (catch lists:foreach(Write, Terms)) of
- {'EXIT', Reason} ->
- {error, Reason};
- _ ->
- loop(disk_log:chunk(Log, Cont), Log, Write)
- end;
-loop(Error, _Log, _Write) ->
- Error.
+ try loop_terms(Terms, Write) of
+ {ok, {AddedOK, AddedERR}} ->
+ loop(disk_log:chunk(Log, Cont), Log, Write,
+ NumOK+AddedOK, NumERR+AddedERR)
+ catch
+ C:E:S ->
+ {error, {C, E, S}}
+ end.
+
+
+loop_terms(Terms, Write) ->
+ loop_terms(Terms, Write, 0, 0).
+
+loop_terms([], _Write, NumOK, NumERR) ->
+ {ok, {NumOK, NumERR}};
+loop_terms([Term|Terms], Write, NumOK, NumERR) ->
+ case Write(Term) of
+ ok ->
+ loop_terms(Terms, Write, NumOK+1, NumERR);
+ error ->
+ loop_terms(Terms, Write, NumOK, NumERR+1);
+ _ ->
+ loop_terms(Terms, Write, NumOK, NumERR)
+ end.
format_msg(Entry, Mib, Start, Stop) ->
@@ -733,88 +758,149 @@ do_format_msg({Timestamp, SeqNo, Packet, Ip, Port}, Mib) ->
%% This is crap...
do_format_msg(_, _) ->
- format_tab("** unknown entry in log file\n\n", []).
+ {error, format_tab("** unknown entry in log file\n\n", [])}.
do_format_msg(TimeStamp, {V3Hdr, ScopedPdu}, AddrStr, Mib) ->
- case (catch snmp_pdus:dec_scoped_pdu(ScopedPdu)) of
+ try snmp_pdus:dec_scoped_pdu(ScopedPdu) of
ScopedPDU when is_record(ScopedPDU, scopedPdu) ->
Msg = #message{version = 'version-3',
vsn_hdr = V3Hdr,
data = ScopedPDU},
- f(ts2str(TimeStamp), "", Msg, AddrStr, Mib);
- {'EXIT', Reason} ->
- format_tab(
- "** error in log file at ~s from ~s ~p\n\n",
- [ts2str(TimeStamp), AddrStr, Reason])
+ try f(ts2str(TimeStamp), "", Msg, AddrStr, Mib) of
+ {ok, _} = OK ->
+ OK
+ catch
+ FormatT:FormatE ->
+ format_error("format scoped pdu",
+ TimeStamp, AddrStr, FormatT, FormatE)
+ end
+ catch
+ DecT:DecE ->
+ format_error("decode scoped pdu",
+ TimeStamp, AddrStr, DecT, DecE)
end;
do_format_msg(TimeStamp, Packet, AddrStr, Mib) ->
- case (catch snmp_pdus:dec_message(binary_to_list(Packet))) of
+ try snmp_pdus:dec_message(binary_to_list(Packet)) of
Msg when is_record(Msg, message) ->
- f(ts2str(TimeStamp), "", Msg, AddrStr, Mib);
- {'EXIT', Reason} ->
- format_tab("** error in log file ~p\n\n", [Reason])
+ try f(ts2str(TimeStamp), "", Msg, AddrStr, Mib) of
+ {ok, _} = OK ->
+ OK
+ catch
+ FormatT:FormatE ->
+ %% Provide info about the message
+ Extra =
+ case Msg#message.version of
+ 'version-3' ->
+ #v3_hdr{msgID = ID,
+ msgFlags = Flags,
+ msgSecurityModel = SecModel} =
+ Msg#message.vsn_hdr,
+ SecLevel = snmp_misc:get_sec_level(Flags),
+ f("msg-id: ~w, sec-level: ~w, sec-model: ~w",
+ [ID, SecLevel, sm2atom(SecModel)]);
+ _ -> %% Community
+ f("community: ~s", [Msg#message.vsn_hdr])
+ end,
+ format_error(f("format ~p message; ~s",
+ [Msg#message.version, Extra]),
+ TimeStamp, AddrStr, FormatT, FormatE)
+ end
+ catch
+ DecT:DecE ->
+ format_error("decode message",
+ TimeStamp, AddrStr, DecT, DecE)
+
end.
-
+
+sm2atom(?SEC_ANY) -> any;
+sm2atom(?SEC_V1) -> v1;
+sm2atom(?SEC_V2C) -> v2c;
+sm2atom(?SEC_USM) -> usm;
+sm2atom(_) -> unknown.
+
do_format_msg(TimeStamp, SeqNo, {V3Hdr, ScopedPdu}, AddrStr, Mib) ->
- case (catch snmp_pdus:dec_scoped_pdu(ScopedPdu)) of
+ try snmp_pdus:dec_scoped_pdu(ScopedPdu) of
ScopedPDU when is_record(ScopedPDU, scopedPdu) ->
Msg = #message{version = 'version-3',
vsn_hdr = V3Hdr,
data = ScopedPDU},
- f(ts2str(TimeStamp), sn2str(SeqNo), Msg, AddrStr, Mib);
- {'EXIT', Reason} ->
- format_tab(
- "** error in log file at ~s from ~s ~p\n\n",
- [ts2str(TimeStamp), sn2str(SeqNo), AddrStr, Reason])
+ try f(ts2str(TimeStamp), sn2str(SeqNo), Msg, AddrStr, Mib) of
+ {ok, _} = OK ->
+ OK
+ catch
+ FormatT:FormatE ->
+ format_error("format scoped pdu",
+ TimeStamp, SeqNo, AddrStr, FormatT, FormatE)
+ end
+ catch
+ DecT:DecE ->
+ format_error("decode scoped pdu",
+ TimeStamp, SeqNo, AddrStr, DecT, DecE)
end;
do_format_msg(TimeStamp, SeqNo, Packet, AddrStr, Mib) ->
- case (catch snmp_pdus:dec_message(binary_to_list(Packet))) of
+ try snmp_pdus:dec_message(binary_to_list(Packet)) of
Msg when is_record(Msg, message) ->
- f(ts2str(TimeStamp), sn2str(SeqNo), Msg, AddrStr, Mib);
- {'EXIT', Reason} ->
- format_tab(
- "** error in log file ~s from ~s ~p\n\n",
- [ts2str(TimeStamp), sn2str(SeqNo), AddrStr, Reason])
+ try f(ts2str(TimeStamp), sn2str(SeqNo), Msg, AddrStr, Mib) of
+ {ok, _} = OK ->
+ OK
+
+ catch
+ FormatT:FormatE ->
+ %% Provide info about the message
+ Extra =
+ case Msg#message.version of
+ 'version-3' ->
+ #v3_hdr{msgID = ID,
+ msgFlags = Flags,
+ msgSecurityModel = SecModel} =
+ Msg#message.vsn_hdr,
+ SecLevel = snmp_misc:get_sec_level(Flags),
+ f("msg-id: ~w, sec-level: ~w, sec-model: ~w",
+ [ID, SecLevel, sm2atom(SecModel)]);
+ _ -> %% Community
+ f("community: ~s", [Msg#message.vsn_hdr])
+ end,
+ format_error(f("format ~p message; ~s",
+ [Msg#message.version, Extra]),
+ TimeStamp, SeqNo, AddrStr, FormatT, FormatE)
+ end
+ catch
+ DecT:DecE ->
+ format_error("decode message",
+ TimeStamp, SeqNo, AddrStr, DecT, DecE)
end.
-
-
-%% format_msg({TimeStamp, {V3Hdr, ScopedPdu}, {Addr, Port}},
-%% Mib, Start, Stop) ->
-%% format_msg({TimeStamp, {V3Hdr, ScopedPdu}, Addr, Port},
-%% Mib, Start, Stop);
-%% format_msg({TimeStamp, {V3Hdr, ScopedPdu}, Addr, Port},
-%% Mib, Start, Stop) ->
-%% case timestamp_filter(TimeStamp, Start, Stop) of
-%% true ->
-%% case (catch snmp_pdus:dec_scoped_pdu(ScopedPdu)) of
-%% ScopedPDU when record(ScopedPDU, scopedPdu) ->
-%% Msg = #message{version = 'version-3',
-%% vsn_hdr = V3Hdr,
-%% data = ScopedPDU},
-%% f(ts2str(TimeStamp), Msg, Addr, Port, Mib);
-%% {'EXIT', Reason} ->
-%% format_tab("** error in log file at ~s from ~p:~w ~p\n\n",
-%% [ts2str(TimeStamp), ip(Addr), Port, Reason])
-%% end;
-%% false ->
-%% ignore
-%% end;
-%% format_msg({TimeStamp, Packet, {Addr, Port}}, Mib, Start, Stop) ->
-%% format_msg({TimeStamp, Packet, Addr, Port}, Mib, Start, Stop);
-%% format_msg({TimeStamp, Packet, Addr, Port}, Mib, Start, Stop) ->
-%% case timestamp_filter(TimeStamp, Start, Stop) of
-%% true ->
-%% case (catch snmp_pdus:dec_message(binary_to_list(Packet))) of
-%% Msg when record(Msg, message) ->
-%% f(ts2str(TimeStamp), Msg, Addr, Port, Mib);
-%% {'EXIT', Reason} ->
-%% format_tab("** error in log file ~p\n\n", [Reason])
-%% end;
-%% false ->
-%% ignore
-%% end;
-%% format_msg(_, _Mib, _Start, _Stop) ->
-%% format_tab("** unknown entry in log file\n\n", []).
+
+
+format_error(WhatStr, TimeStamp, AddrStr, throw, {error, Reason}) ->
+ {ok, Str} =
+ format_tab(
+ "** error (~s) in log file at ~s from ~s: "
+ "~n ~p\n\n",
+ [WhatStr, ts2str(TimeStamp), AddrStr, Reason]),
+ {error, Str};
+format_error(WhatStr, TimeStamp, AddrStr, T, E) ->
+ {ok, Str} =
+ format_tab(
+ "** error (~s) in log file at ~s from ~s: "
+ "~n ~w: ~p\n\n",
+ [WhatStr, ts2str(TimeStamp), AddrStr, T, E]),
+ {error, Str}.
+
+format_error(WhatStr, TimeStamp, SeqNo, AddrStr, throw, {error, Reason}) ->
+ {ok, Str} =
+ format_tab(
+ "** error (~s) in log file at ~s~s from ~s: "
+ "~n ~p\n\n",
+ [WhatStr, ts2str(TimeStamp), sn2str(SeqNo), AddrStr, Reason]),
+ {error, Str};
+format_error(WhatStr, TimeStamp, SeqNo, AddrStr, T, E) ->
+ {ok, Str} =
+ format_tab(
+ "** error (~s) in log file at ~s~s from ~s: "
+ "~n ~w, ~p\n\n",
+ [WhatStr, ts2str(TimeStamp), sn2str(SeqNo), AddrStr, T, E]),
+ {error, Str}.
+
f(TimeStamp, SeqNo,
#message{version = Vsn, vsn_hdr = VsnHdr, data = Data},
@@ -838,51 +924,21 @@ f(TimeStamp, SeqNo,
end,
format_tab(
"~w ~s - ~s [~s]~s ~w\n~s",
- [Class, AddrStr, HdrStr, TimeStamp, SeqNo, Vsn, Str]).
-
-%% f(TimeStamp, SeqNo,
-%% #message{version = Vsn, vsn_hdr = VsnHdr, data = Data},
-%% Addr, Port, Mib) ->
-%% Str = format_pdu(Data, Mib),
-%% HdrStr = format_header(Vsn, VsnHdr),
-%% case get_type(Data) of
-%% trappdu ->
-%% f_trap(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port);
-%% 'snmpv2-trap' ->
-%% f_trap(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port);
-%% 'inform-request' ->
-%% f_inform(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port);
-%% 'get-response' ->
-%% f_response(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port);
-%% report ->
-%% f_report(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port);
-%% _ ->
-%% f_request(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port)
-%% end.
-
-%% f_request(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port) ->
-%% format_tab("request ~s:~w - ~s [~s]~s ~w\n~s",
-%% [ip(Addr), Port, HdrStr, TimeStamp, SeqNo, Vsn, Str]).
-
-%% f_response(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port) ->
-%% format_tab("response ~s:~w - ~s [~s]~s ~w\n~s",
-%% [ip(Addr), Port, HdrStr, TimeStamp, SeqNo, Vsn, Str]).
-
-%% f_report(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port) ->
-%% format_tab("report ~s:~w - ~s [~s]~s ~w\n~s",
-%% [ip(Addr), Port, HdrStr, TimeStamp, SeqNo, Vsn, Str]).
+ [Class, AddrStr, HdrStr, TimeStamp, SeqNo, Vsn, Str]);
+f(TimeStamp, SeqNo, Msg, AddrStr, _Mib) ->
+ io:format("<ERROR> Unexpected data: "
+ "~n TimeStamp: ~s~s"
+ "~n Msg: ~p"
+ "~n AddrStr: ~p"
+ "~n", [TimeStamp, SeqNo, Msg, AddrStr]),
+ throw({error, 'invalid-message'}).
-%% f_trap(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port) ->
-%% format_tab("trap ~s:~w - ~s [~s]~s ~w\n~s",
-%% [ip(Addr), Port, HdrStr, TimeStamp, SeqNo, Vsn, Str]).
+f(F, A) ->
+ lists:flatten(io_lib:format(F, A)).
-%% f_inform(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port) ->
-%% format_tab("inform ~s:~w - ~s [~s]~s ~w\n~s",
-%% [ip(Addr), Port, HdrStr, TimeStamp, SeqNo, Vsn, Str]).
ipPort2Str(Ip, Port) ->
snmp_conf:mk_addr_string({Ip, Port}).
- %% io_lib:format("~s:~w", [ip(Ip), Port]).
%% Convert a timestamp 2-tupple to a printable string
%%
@@ -973,7 +1029,13 @@ format_pdu(#scopedPdu{contextName = Context, data = Pdu}, Mib) ->
io_lib:format("Context: \"~s\"\n~s",
[Context, snmp_misc:format_pdu(Pdu, Mib)]);
format_pdu(Pdu, Mib) ->
- snmp_misc:format_pdu(Pdu, Mib).
+ try snmp_misc:format_pdu(Pdu, Mib) of
+ Str ->
+ Str
+ catch
+ _:_ ->
+ throw({error, 'invalid-pdu'})
+ end.
get_type(#scopedPdu{data = Pdu}) ->
get_type(Pdu);
@@ -983,12 +1045,6 @@ get_type(#pdu{type = Type}) ->
Type.
-%% ip(Domain, Addr) ->
-%% snmp_conf:mk_addr_string(Domain, Addr).
-%% ip({A,B,C,D}) ->
-%% io_lib:format("~w.~w.~w.~w", [A,B,C,D]).
-
-
%% -------------------------------------------------------------------
%% Various utility functions