diff options
author | Raimo Niskanen <[email protected]> | 2018-09-17 15:42:26 +0200 |
---|---|---|
committer | Raimo Niskanen <[email protected]> | 2018-09-17 15:42:26 +0200 |
commit | b13ef106fb134f8d8b929e03300a8b6524f367cf (patch) | |
tree | 24b6a029f413987b2f48e200dc96c5953df4025e /lib | |
parent | fd3d7e7ce693bb960b85b3ea09429adb30145e49 (diff) | |
parent | d6a08843e473da6eebbab0b0e7312efc978108ee (diff) | |
download | otp-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.xml | 69 | ||||
-rw-r--r-- | lib/kernel/doc/src/gen_tcp.xml | 16 | ||||
-rw-r--r-- | lib/kernel/doc/src/gen_udp.xml | 35 | ||||
-rw-r--r-- | lib/kernel/doc/src/inet.xml | 123 | ||||
-rw-r--r-- | lib/kernel/src/gen_sctp.erl | 18 | ||||
-rw-r--r-- | lib/kernel/src/gen_tcp.erl | 16 | ||||
-rw-r--r-- | lib/kernel/src/gen_udp.erl | 19 | ||||
-rw-r--r-- | lib/kernel/src/inet.erl | 17 | ||||
-rw-r--r-- | lib/kernel/src/inet6_tcp.erl | 8 | ||||
-rw-r--r-- | lib/kernel/src/inet_int.hrl | 7 | ||||
-rw-r--r-- | lib/kernel/src/inet_tcp.erl | 8 | ||||
-rw-r--r-- | lib/kernel/test/gen_tcp_misc_SUITE.erl | 209 | ||||
-rw-r--r-- | lib/kernel/test/gen_udp_SUITE.erl | 163 | ||||
-rw-r--r-- | lib/snmp/doc/src/notes.xml | 4 | ||||
-rw-r--r-- | lib/snmp/doc/src/snmp.xml | 33 | ||||
-rw-r--r-- | lib/snmp/doc/src/snmpa.xml | 38 | ||||
-rw-r--r-- | lib/snmp/doc/src/snmpm.xml | 38 | ||||
-rw-r--r-- | lib/snmp/src/agent/snmpa_net_if.erl | 111 | ||||
-rw-r--r-- | lib/snmp/src/misc/snmp_log.erl | 334 |
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 |