From 64853dc28ce838583e35d5fefb0604933b6e98f9 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Fri, 6 Jul 2018 12:55:10 +0200 Subject: Implement socket option recvtos and friends Implement socket options recvtclass, recvtos, recvttl and pktoptions. Document the implemented socket options, new types and message formats. The options recvtclass, recvtos and recvttl are boolean options that when activated (true) for a socket will cause ancillary data to be received through recvmsg(). That is for packet oriented sockets (UDP and SCTP). The required options for this feature were recvtclass and recvtos, and recvttl was only added to test that the ancillary data parsing handled multiple data items in one message correctly. These options does not work on Windows since ancillary data is not handled by the Winsock2 API. For stream sockets (TCP) there is no clear connection between a received packet and what is returned when reading data from the socket, so recvmsg() is not useful. It is possible to get the same ancillary data through a getsockopt() call with the IPv6 socket option IPV6_PKTOPTIONS, on Linux named IPV6_2292PKTOPTIONS after the now obsoleted RFC where it originated. (unfortunately RFC 3542 that obsoletes it explicitly undefines this way to get packet ancillary data from a stream socket) Linux also has got a way to get packet ancillary data for IPv4 TCP sockets through a getsockopt() call with IP_PKTOPTIONS, which appears to be Linux specific. This implementation uses a flag field in the inet_drv.c socket internal data that records if any setsockopt() call with recvtclass, recvtos or recvttl (IPV6_RECVTCLASS, IP_RECVTOS or IP_RECVTTL) has been activated. If so recvmsg() is used instead of recvfrom(). Ancillary data is delivered to the application by a new return tuple format from gen_udp:recv/2,3 containing a list of ancillary data tuples [{tclass,TCLASS} | {tos,TOS} | {ttl,TTL}], as returned by recvmsg(). For a socket in active mode a new message format, containing the ancillary data list, delivers the data in the same way. For gen_sctp the ancillary data is delivered in the same way, except that the gen_sctp return tuple format already contained an ancillary data list so there are just more possible elements when using these socket options. Note that the active mode message format has got an extra tuple level for the ancillary data compared to what is now implemented gen_udp. The gen_sctp active mode format was considered to be the odd one - now all tuples containing ancillary data are flat, except for gen_sctp active mode. Note that testing has not shown that Linux SCTP sockets deliver any ancillary data for these socket options, so it is probably not implemented yet. Remains to be seen what FreeBSD does... For gen_tcp inet:getopts([pktoptions]) will deliver the latest received ancillary data for any activated socket option recvtclass, recvtos or recvttl, on platforms where IP_PKTOPTIONS is defined for an IPv4 socket, or where IPV6_PKTOPTIONS or IPV6_2292PKTOPTIONS is defined for an IPv6 socket. It will be delivered as a list of ancillary data items in the same way as for gen_udp (and gen_sctp). On some platforms, e.g the BSD:s, when you activate IP_RECVTOS you get ancillary data tagged IP_RECVTOS with the TOS value, but on Linux you get ancillary data tagged IP_TOS with the TOS value. Linux follows the style of RFC 2292, and the BSD:s use an older notion. For RFC 2292 that defines the IP_PKTOPTIONS socket option it is more logical to tag the items with the tag that is the item's, than with the tag that defines that you want the item. Therefore this implementation translates all BSD style ancillary data tags to the corresponding Linux style data tags, so the application will only see the tags 'tclass', 'tos' and 'ttl' on all platforms. --- lib/kernel/doc/src/gen_sctp.xml | 69 ++++++++++++++++-- lib/kernel/doc/src/gen_tcp.xml | 16 ++++- lib/kernel/doc/src/gen_udp.xml | 35 ++++++++-- lib/kernel/doc/src/inet.xml | 123 ++++++++++++++++++++++++++++++++- lib/kernel/src/gen_sctp.erl | 18 +++-- lib/kernel/src/gen_tcp.erl | 16 ++++- lib/kernel/src/gen_udp.erl | 19 ++++- lib/kernel/src/inet.erl | 19 +++-- lib/kernel/src/inet6_tcp.erl | 8 ++- lib/kernel/src/inet_int.hrl | 7 +- lib/kernel/src/inet_tcp.erl | 8 ++- lib/kernel/test/gen_tcp_misc_SUITE.erl | 2 +- 12 files changed, 307 insertions(+), 33 deletions(-) (limited to 'lib') 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 @@
- 20072016 + 20072018 Ericsson AB. All Rights Reserved. @@ -331,6 +331,37 @@ connect(Socket, Ip, Port>, with SockType seqpacket, and with reasonably large kernel and driver buffers.

+

+ If the socket is in + passive + mode data can be received through the + recv/1,2 + calls. +

+

+ If the socket is in + active + mode data received data is delivered to the controlling process + as messages: +

+ +{sctp, Socket, FromIP, FromPort, {AncData, Data}} + +

+ See + recv/1,2 + for a description of the message fields. +

+ +

+ This message format unfortunately differs slightly from the + gen_udp + message format with ancillary data, + and from the + recv/1,2 + return tuple format. +

+
@@ -380,6 +411,19 @@ connect(Socket, Ip, Port>, socket option sctp_get_peer_addr_info, but this does still not produce the stream number).

+

+ AncData may also contain + + ancillary data + + from the socket + options + recvtos, + recvtclass + or + recvttl, + if that is supported by the platform for the socket. +

The Data received can be a binary() or a list() of bytes (integers in the range 0 through 255) depending on the socket mode, or an SCTP event.

@@ -544,12 +588,25 @@ connect(Socket, Ip, Port>, recv call to retrieve the available data from the socket.

+ +

+ If true|once|N (active modes) + received data or events are sent to the owning process. + See open/0..2 + for the message format. +

+
-

If true (full active mode), the pending data or events are - sent to the owning process.

-

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).

+

+ If true (full active mode) there is no flow control. +

+ +

+ Note that this can cause the message queue to overflow + causing for example the virtual machine + to run out of memory and crash. +

+

If once, 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 @@

- 19972017 + 19972018 Ericsson AB. All Rights Reserved. @@ -69,6 +69,20 @@ do_recv(Sock, Bs) -> + + + +

+ If the platform implements the IPv4 option + IP_PKTOPTIONS (probably Linux specific), or the IPv6 option + IPV6_PKTOPTIONS or IPV6_2292PKTOPTIONS for the socket + this value is returned from + inet:getopts/2 + when called with the option name + pktoptions. +

+
+
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 @@
- 19972016 + 19972018 Ericsson AB. All Rights Reserved. @@ -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:

-{udp, Socket, IP, InPortNo, Packet} +{udp, Socket, IP, InPortNo, Packet} % Without ancillary data +{udp, Socket, IP, InPortNo, AncData, Packet} % With ancillary data + +

+ The message contains an AncData field + if any of the socket + options + recvtos, + recvtclass + or + recvttl + are active, otherwise it does not. +

+

+

If the socket is not in an active mode, data can be retrieved through the recv/2,3 calls. @@ -179,9 +193,22 @@ Receive a packet from a passive socket. -

Receives a packet from a socket in passive mode. Optional parameter +

+ Receives a packet from a socket in passive mode. Optional parameter Timeout specifies a time-out in milliseconds. - Defaults to infinity.

+ Defaults to infinity. +

+

+ If any of the socket + options + recvtos, + recvtclass + or + recvttl + are active, the RecvData tuple contains an + AncData field, + otherwise it does not. +

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 @@ -176,6 +176,27 @@ fe80::204:acff:fe17:bf38

+ + + +

+ Ancillary data received with the data packet + or read with the socket option + + pktoptions + + from a TCP socket. +

+

+ The value(s) correspond to the currently active socket + options + recvtos, + recvtclass + and + recvttl. +

+
+
@@ -344,7 +365,11 @@ fe80::204:acff:fe17:bf38

Gets one or more options for a socket. For a list of available options, see - setopts/2.

+ setopts/2. + See also the description for the type + + gen_tcp:pktoptions_value() + .

The number of elements in the returned OptionValues 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.

+ present on a particular platform.

RawOptReq consists of tag raw 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 the socket. You are encouraged to use getopts/2 to retrieve the size set by your operating system.

+ + + {recvtclass, Boolean} + +

+ If set to true activates returning the received + TCLASS value on platforms that implements + the protocol IPPROTO_IPV6 + option IPV6_RECVTCLASS or IPV6_2292RECVTCLASS + for the socket. + The value is returned as a {tclass,TCLASS} tuple + regardless of if the platform returns an IPV6_TCLASS + or an IPV6_RECVTCLASS CMSG value. +

+

+ For packet oriented sockets that supports receiving + ancillary data with the payload data + (gen_udp and gen_sctp), + the TCLASS value is returned + in an extended return tuple contained in an + + ancillary data + + list. + For stream oriented sockets (gen_tcp) + the only way to get the TCLASS + value is if the platform supports the + + pktoptions + + option. +

+ +
+ {recvtos, Boolean} + +

+ If set to true activates returning the received + TOS value on platforms that implements + the protocol IPPROTO_IP option IP_RECVTOS + for the socket. + The value is returned as a {tos,TOS} tuple + regardless of if the platform returns an IP_TOS + or an IP_RECVTOS CMSG value. +

+

+ For packet oriented sockets that supports receiving + ancillary data with the payload data + (gen_udp and gen_sctp), + the TOS value is returned + in an extended return tuple contained in an + + ancillary data + + list. + For stream oriented sockets (gen_tcp) + the only way to get the TOS + value is if the platform supports the + + pktoptions + + option. +

+ +
+ {recvttl, Boolean} + +

+ If set to true activates returning the received + TTL value on platforms that implements + the protocol IPPROTO_IP option IP_RECVTTL + for the socket. + The value is returned as a {ttl,TTL} tuple + regardless of if the platform returns an IP_TTL + or an IP_RECVTTL CMSG value. +

+

+ For packet oriented sockets that supports receiving + ancillary data with the payload data + (gen_udp and gen_sctp), + the TTL value is returned + in an extended return tuple contained in an + + ancillary data + + list. + For stream oriented sockets (gen_tcp) + the only way to get the TTL + value is if the platform supports the + + pktoptions + + option. +

{reuseaddr, Boolean} 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..75dc909e3d 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,11 @@ 'recv_cnt' | 'recv_max' | 'recv_avg' | 'recv_oct' | 'recv_dvi' | 'send_cnt' | 'send_max' | 'send_avg' | 'send_oct' | 'send_pend'. +-type ancillary_data() :: + [ {'tos', TOS :: byte()} | + {'tclass', TCLASS :: byte()} | + {'ttl', TTL :: byte()} ]. + %%% --------------------------------- -spec get_rc() -> [{Par :: atom(), Val :: any()} | @@ -302,7 +307,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 +727,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 +796,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 +877,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 +947,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..91c89e76dd 100644 --- a/lib/kernel/test/gen_tcp_misc_SUITE.erl +++ b/lib/kernel/test/gen_tcp_misc_SUITE.erl @@ -2205,7 +2205,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; -- cgit v1.2.3 From 6a556ffb979273e84ae00c997cb38086ba9ef2f5 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Wed, 5 Sep 2018 15:38:02 +0200 Subject: Fix documentation due to feedback --- lib/kernel/src/inet.erl | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl index 75dc909e3d..5dd68dc285 100644 --- a/lib/kernel/src/inet.erl +++ b/lib/kernel/src/inet.erl @@ -164,9 +164,7 @@ 'send_cnt' | 'send_max' | 'send_avg' | 'send_oct' | 'send_pend'. -type ancillary_data() :: - [ {'tos', TOS :: byte()} | - {'tclass', TCLASS :: byte()} | - {'ttl', TTL :: byte()} ]. + [ {'tos', byte()} | {'tclass', byte()} | {'ttl', byte()} ]. %%% --------------------------------- -- cgit v1.2.3 From 947c2a97ad51e1936bad7df0e3f768ab15fcbb36 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 5 Sep 2018 18:53:15 +0200 Subject: [snmp] Improved Audit Trail Log conversion failure If conversion of an Audit Trail Log (ATL) entry failed, this could result in an abort of the entire conversion, not just the one entry. This has now been improved so that the failure now results in a "error message" into the "stream". Furthermore, we now keep track of the number of entries we succeede and fail to convert. OTP-15287 (ERIERL-206) --- lib/snmp/src/misc/snmp_log.erl | 335 ++++++++++++++++++++++++----------------- 1 file changed, 197 insertions(+), 138 deletions(-) (limited to 'lib') diff --git a/lib/snmp/src/misc/snmp_log.erl b/lib/snmp/src/misc/snmp_log.erl index 767d801eee..d8a0141ec8 100644 --- a/lib/snmp/src/misc/snmp_log.erl +++ b/lib/snmp/src/misc/snmp_log.erl @@ -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; + X -> + X 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,66 @@ 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 + T:E -> + {error, {T, E}} 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 + T:E -> + {error, {T, E}} + 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) -> + try 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) + catch + T:E:S -> + {error, {T, E, S}} + end. format_msg(Entry, Mib, Start, Stop) -> @@ -733,88 +761,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 +927,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(" 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 +1032,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 +1048,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 -- cgit v1.2.3 From f21ba51b85e18feec2f4cd408b51c22d7847f635 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 5 Sep 2018 18:55:40 +0200 Subject: [snmp] Corrected (agent) ATL logging of outgoing messages For some outgoing messages (not response) the following error(s) has been corrected: * encrypted: logged incorrectly, should have written the v3-header and the scoped pdu, but was actually logged as-is (encrypted), making conversion impossible. * un-encrypted: messages was not logged at all. OTP-15287 (ERIERL-206) --- lib/snmp/src/agent/snmpa_net_if.erl | 109 ++++++++++++++++-------------------- 1 file changed, 47 insertions(+), 62 deletions(-) (limited to 'lib') diff --git a/lib/snmp/src/agent/snmpa_net_if.erl b/lib/snmp/src/agent/snmpa_net_if.erl index ecf9498ca9..807491bfcb 100644 --- a/lib/snmp/src/agent/snmpa_net_if.erl +++ b/lib/snmp/src/agent/snmpa_net_if.erl @@ -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); -- cgit v1.2.3 From 8f184f6d4bace131e95c3ac905fb8bd0b4895bee Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 6 Sep 2018 19:21:18 +0200 Subject: [snmp] Updated doc for atl conversion functions OTP-15287 (ERIERL-206) --- lib/snmp/doc/src/snmp.xml | 31 +++++++++++++++++++++++-------- lib/snmp/doc/src/snmpa.xml | 36 +++++++++++++++++++++--------------- lib/snmp/doc/src/snmpm.xml | 36 +++++++++++++++++++++--------------- 3 files changed, 65 insertions(+), 38 deletions(-) (limited to 'lib') diff --git a/lib/snmp/doc/src/snmp.xml b/lib/snmp/doc/src/snmp.xml index 801193675c..2d44e3ff83 100644 --- a/lib/snmp/doc/src/snmp.xml +++ b/lib/snmp/doc/src/snmp.xml @@ -341,10 +341,10 @@ - log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile) -> ok | {error, Reason} - log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block | Start) -> ok | {error, Reason} - log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Block | Stop) -> ok | {error, Reason} - log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop, Block) -> ok | {error, Reason} + log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile) -> ok | {ok, Cnt} | {error, Reason} + log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block | Start) -> ok | {ok, Cnt} | {error, Reason} + log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Block | Stop) -> ok | {ok, Cnt} | {error, Reason} + log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop, Block) -> ok | {ok, Cnt} | {error, Reason} Convert an Audit Trail Log to text format LogDir = string() @@ -355,6 +355,9 @@ LogFile = string() Start = Stop = null | datetime() | {local_time,datetime()} | {universal_time,datetime()} Block = boolean() + Cnt = {NumOK, NumERR} + NumOK = non_neg_integer() + NumERR = pos_integer() Reason = term() @@ -394,16 +397,25 @@ and Vsn is the SNMP version. PDU is a textual version of the protocol data unit. There is a new line between Vsn and PDU.

+ +

If the entire log is successfully converted, the function + will return ok. + If one of more entries fail to convert, the function will instead + return {ok, {NumOK, NumERR}}, where the counters indicate + how many valid and erroneous entries where found. + If instead {error, Reason} is returned, the conversion + encountered a fatal error and where either never done of aborted + midway.

- log_to_io(LogDir, Mibs, LogName, LogFile) -> ok | {error, Reason} - log_to_io(LogDir, Mibs, LogName, LogFile, Block | Start) -> ok | {error, Reason} - log_to_io(LogDir, Mibs, LogName, LogFile, Start, Block | Stop) -> ok | {error, Reason} - log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop, Block) -> ok | {error, Reason} + log_to_io(LogDir, Mibs, LogName, LogFile) -> ok | {ok, Cnt} | {error, Reason} + log_to_io(LogDir, Mibs, LogName, LogFile, Block | Start) -> ok | {ok, Cnt} | {error, Reason} + log_to_io(LogDir, Mibs, LogName, LogFile, Start, Block | Stop) -> ok | {ok, Cnt} | {error, Reason} + log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop, Block) -> ok | {ok, Cnt} | {error, Reason} Convert an Audit Trail Log to text format LogDir = string() @@ -412,6 +424,9 @@ LogName = string() LogFile = string() Start = Stop = null | datetime() | {local_time,datetime()} | {universal_time,datetime()} + Cnt = {NumOK, NumERR} + NumOK = non_neg_integer() + NumERR = pos_integer() Reason = term() diff --git a/lib/snmp/doc/src/snmpa.xml b/lib/snmp/doc/src/snmpa.xml index d756ff7a65..fd56c89a7e 100644 --- a/lib/snmp/doc/src/snmpa.xml +++ b/lib/snmp/doc/src/snmpa.xml @@ -559,13 +559,13 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} log_to_txt(LogDir) log_to_txt(LogDir, Block | Mibs) - log_to_txt(LogDir, Mibs, Block | OutFile) -> ok | {error, Reason} - log_to_txt(LogDir, Mibs, OutFile, Block | LogName) -> ok | {error, Reason} - log_to_txt(LogDir, Mibs, OutFile, LogName, Block | LogFile) -> ok | {error, Reason} - log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block | Start) -> ok | {error, Reason} - log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start) -> ok | {error, Reason} - log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop) -> ok | {error, Reason} - log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop) -> ok | {error, Reason} + log_to_txt(LogDir, Mibs, Block | OutFile) -> ok | {ok, Cnt} | {error, Reason} + log_to_txt(LogDir, Mibs, OutFile, Block | LogName) -> ok | {ok, Cnt} | {error, Reason} + log_to_txt(LogDir, Mibs, OutFile, LogName, Block | LogFile) -> ok | {ok, Cnt} | {error, Reason} + log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block | Start) -> ok | {ok, Cnt} | {error, Reason} + log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start) -> ok | {ok, Cnt} | {error, Reason} + log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop) -> ok | {ok, Cnt} | {error, Reason} + log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop) -> ok | {ok, Cnt} | {error, Reason} Convert an Audit Trail Log to text format LogDir = string() @@ -576,6 +576,9 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} LogName = string() LogFile = string() Start = Stop = null | calendar:datetime() | {local_time, calendar:datetime()} | {universal_time, calendar:datetime()} + Cnt = {NumOK, NumERR} + NumOK = non_neg_integer() + NumERR = pos_integer() Reason = disk_log_open_error() | file_open_error() | term() disk_log_open_error() = {LogName, term()} file_open_error() = {OutFile, term()} @@ -597,14 +600,14 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} - log_to_io(LogDir) -> ok | {error, Reason} - log_to_io(LogDir, Block | Mibs) -> ok | {error, Reason} - log_to_io(LogDir, Mibs, Block | LogName) -> ok | {error, Reason} - log_to_io(LogDir, Mibs, LogName, Block | LogFile) -> ok | {error, Reason} - log_to_io(LogDir, Mibs, LogName, LogFile, Block | Start) -> ok | {error, Reason} - log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start) -> ok | {error, Reason} - log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop) -> ok | {error, Reason} - log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop) -> ok | {error, Reason} + log_to_io(LogDir) -> ok | {ok, Cnt} | {error, Reason} + log_to_io(LogDir, Block | Mibs) -> ok | {ok, Cnt} | {error, Reason} + log_to_io(LogDir, Mibs, Block | LogName) -> ok | {ok, Cnt} | {error, Reason} + log_to_io(LogDir, Mibs, LogName, Block | LogFile) -> ok | {ok, Cnt} | {error, Reason} + log_to_io(LogDir, Mibs, LogName, LogFile, Block | Start) -> ok | {ok, Cnt} | {error, Reason} + log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start) -> ok | {ok, Cnt} | {error, Reason} + log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop) -> ok | {ok, Cnt} | {error, Reason} + log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop) -> ok | {ok, Cnt} | {error, Reason} Convert an Audit Trail Log to text format LogDir = string() @@ -614,6 +617,9 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} LogName = string() LogFile = string() Start = Stop = null | calendar:datetime() | {local_time, calendar:datetime()} | {universal_time, calendar:datetime()} + Cnt = {NumOK, NumERR} + NumOK = non_neg_integer() + NumERR = pos_integer() Reason = disk_log_open_error() | file_open_error() | term() disk_log_open_error() = {LogName, term()} file_open_error() = {OutFile, term()} diff --git a/lib/snmp/doc/src/snmpm.xml b/lib/snmp/doc/src/snmpm.xml index 4818aeb697..cdab7c51d7 100644 --- a/lib/snmp/doc/src/snmpm.xml +++ b/lib/snmp/doc/src/snmpm.xml @@ -1216,13 +1216,13 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 log_to_txt(LogDir) log_to_txt(LogDir, Block | Mibs) - log_to_txt(LogDir, Mibs, Block | OutFile) -> ok | {error, Reason} - log_to_txt(LogDir, Mibs, OutFile, Block | LogName) -> ok | {error, Reason} - log_to_txt(LogDir, Mibs, OutFile, LogName, Block | LogFile) -> ok | {error, Reason} - log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block | Start) -> ok | {error, Reason} - log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start) -> ok | {error, Reason} - log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop) -> ok | {error, Reason} - log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop) -> ok | {error, Reason} + log_to_txt(LogDir, Mibs, Block | OutFile) -> ok | {ok, Cnt} | {error, Reason} + log_to_txt(LogDir, Mibs, OutFile, Block | LogName) -> ok | {ok, Cnt} | {error, Reason} + log_to_txt(LogDir, Mibs, OutFile, LogName, Block | LogFile) -> ok | {ok, Cnt} | {error, Reason} + log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block | Start) -> ok | {ok, Cnt} | {error, Reason} + log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start) -> ok | {ok, Cnt} | {error, Reason} + log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop) -> ok | {ok, Cnt} | {error, Reason} + log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop) -> ok | {ok, Cnt} | {error, Reason} Convert an Audit Trail Log to text format LogDir = string() @@ -1233,6 +1233,9 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 LogName = string() LogFile = string() Start = Stop = null | calendar:datetime() | {local_time, calendar:datetime()} | {universal_time, calendar:datetime()} + Cnt = {NumOK, NumERR} + NumOK = non_neg_integer() + NumERR = pos_integer() Reason = disk_log_open_error() | file_open_error() | term() disk_log_open_error() = {LogName, term()} file_open_error() = {OutFile, term()} @@ -1254,15 +1257,15 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 - log_to_io(LogDir) -> ok | {error, Reason} - log_to_io(LogDir, Block | Mibs) -> ok | {error, Reason} + log_to_io(LogDir) -> ok | {ok, Cnt} | {error, Reason} + log_to_io(LogDir, Block | Mibs) -> ok | {ok, Cnt} | {error, Reason} log_to_io(LogDir, Mibs) -> ok | {error, Reason} - log_to_io(LogDir, Mibs, Block | LogName) -> ok | {error, Reason} - log_to_io(LogDir, Mibs, LogName, Block | LogFile) -> ok | {error, Reason} - log_to_io(LogDir, Mibs, LogName, LogFile, Block | Start) -> ok | {error, Reason} - log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start) -> ok | {error, Reason} - log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop) -> ok | {error, Reason} - log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop) -> ok | {error, Reason} + log_to_io(LogDir, Mibs, Block | LogName) -> ok | {ok, Cnt} | {error, Reason} + log_to_io(LogDir, Mibs, LogName, Block | LogFile) -> ok | {ok, Cnt} | {error, Reason} + log_to_io(LogDir, Mibs, LogName, LogFile, Block | Start) -> ok | {ok, Cnt} | {error, Reason} + log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start) -> ok | {ok, Cnt} | {error, Reason} + log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop) -> ok | {ok, Cnt} | {error, Reason} + log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop) -> ok | {ok, Cnt} | {error, Reason} Convert an Audit Trail Log to text format LogDir = string() @@ -1272,6 +1275,9 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 LogName = string() LogFile = string() Start = Stop = null | calendar:datetime() | {local_time, calendar:datetime()} | {universal_time, calendar:datetime()} + Cnt = {NumOK, NumERR} + NumOK = non_neg_integer() + NumERR = pos_integer() Reason = disk_log_open_error() | file_open_error() | term() disk_log_open_error() = {LogName, term()} file_open_error() = {OutFile, term()} -- cgit v1.2.3 From b665dd1fdab1c03b123911b5ccaca4dd0fc2809c Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Fri, 7 Sep 2018 12:55:41 +0200 Subject: [snmp] Update copyright end date OTP-15287 (ERIERL-206) --- lib/snmp/doc/src/snmp.xml | 2 +- lib/snmp/doc/src/snmpa.xml | 2 +- lib/snmp/doc/src/snmpm.xml | 2 +- lib/snmp/src/agent/snmpa_net_if.erl | 2 +- lib/snmp/src/misc/snmp_log.erl | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/snmp/doc/src/snmp.xml b/lib/snmp/doc/src/snmp.xml index 2d44e3ff83..480ed2e825 100644 --- a/lib/snmp/doc/src/snmp.xml +++ b/lib/snmp/doc/src/snmp.xml @@ -4,7 +4,7 @@
- 19962016 + 19962018 Ericsson AB. All Rights Reserved. diff --git a/lib/snmp/doc/src/snmpa.xml b/lib/snmp/doc/src/snmpa.xml index fd56c89a7e..b78f14da01 100644 --- a/lib/snmp/doc/src/snmpa.xml +++ b/lib/snmp/doc/src/snmpa.xml @@ -4,7 +4,7 @@
- 20042016 + 20042018 Ericsson AB. All Rights Reserved. diff --git a/lib/snmp/doc/src/snmpm.xml b/lib/snmp/doc/src/snmpm.xml index cdab7c51d7..be4cd58a1a 100644 --- a/lib/snmp/doc/src/snmpm.xml +++ b/lib/snmp/doc/src/snmpm.xml @@ -4,7 +4,7 @@
- 20042016 + 20042018 Ericsson AB. All Rights Reserved. diff --git a/lib/snmp/src/agent/snmpa_net_if.erl b/lib/snmp/src/agent/snmpa_net_if.erl index 807491bfcb..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. diff --git a/lib/snmp/src/misc/snmp_log.erl b/lib/snmp/src/misc/snmp_log.erl index d8a0141ec8..ce93b95c8e 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. -- cgit v1.2.3 From 229795aba1d4da773938715f2e5122d4885af826 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Fri, 7 Sep 2018 18:31:16 +0200 Subject: [snmp] Add proper version Also fixed case clause. OTP-15287 (ERIERL-206) --- lib/snmp/doc/src/notes.xml | 4 ++-- lib/snmp/src/misc/snmp_log.erl | 17 +++++++---------- lib/snmp/vsn.mk | 4 ++-- 3 files changed, 11 insertions(+), 14 deletions(-) (limited to 'lib') 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 @@
- 19962017 + 19962018 Ericsson AB. All Rights Reserved. @@ -48,7 +48,7 @@ - +
SNMP 5.2.10 diff --git a/lib/snmp/src/misc/snmp_log.erl b/lib/snmp/src/misc/snmp_log.erl index ce93b95c8e..5713c14912 100644 --- a/lib/snmp/src/misc/snmp_log.erl +++ b/lib/snmp/src/misc/snmp_log.erl @@ -652,8 +652,8 @@ do_log_to_file(Log, TextFile, Mibs, Start, Stop) -> {Tag, S} when (Tag =:= ok) orelse (Tag =:= error) -> io:format(Fd, "~s", [S]), Tag; - X -> - X + Ignore -> + Ignore end end, Res = (catch loop(Log, Write)), @@ -696,8 +696,8 @@ loop({Cont, Terms}, Log, Write, NumOK, NumERR) -> loop(disk_log:chunk(Log, Cont), Log, Write, NumOK+AddedOK, NumERR+AddedERR) catch - T:E -> - {error, {T, E}} + C:E:S -> + {error, {C, E, S}} end; loop({Cont, Terms, BadBytes}, Log, Write, NumOK, NumERR) -> error_logger:error_msg("Skipping ~w bytes while converting ~p~n~n", @@ -707,8 +707,8 @@ loop({Cont, Terms, BadBytes}, Log, Write, NumOK, NumERR) -> loop(disk_log:chunk(Log, Cont), Log, Write, NumOK+AddedOK, NumERR+AddedERR) catch - T:E -> - {error, {T, E}} + C:E:S -> + {error, {C, E, S}} end. @@ -718,16 +718,13 @@ loop_terms(Terms, Write) -> loop_terms([], _Write, NumOK, NumERR) -> {ok, {NumOK, NumERR}}; loop_terms([Term|Terms], Write, NumOK, NumERR) -> - try Write(Term) of + 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) - catch - T:E:S -> - {error, {T, E, S}} end. diff --git a/lib/snmp/vsn.mk b/lib/snmp/vsn.mk index 96123f02f5..4d5a0fbce8 100644 --- a/lib/snmp/vsn.mk +++ b/lib/snmp/vsn.mk @@ -2,7 +2,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. @@ -19,6 +19,6 @@ # %CopyrightEnd% APPLICATION = snmp -SNMP_VSN = 5.2.11 +SNMP_VSN = 5.2.12 PRE_VSN = APP_VSN = "$(APPLICATION)-$(SNMP_VSN)$(PRE_VSN)" -- cgit v1.2.3 From 6053725bb54f7302d3698d0df100eb01c4df4f12 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Wed, 5 Sep 2018 16:36:53 +0200 Subject: Write testcases for recvtos and friends Use os:type() and os:version() to predict if the individual options are supposed to be supported. We'll see if this holds. --- lib/kernel/test/gen_tcp_misc_SUITE.erl | 207 ++++++++++++++++++++++++++++++++- lib/kernel/test/gen_udp_SUITE.erl | 163 ++++++++++++++++++++++++++ 2 files changed, 369 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/kernel/test/gen_tcp_misc_SUITE.erl b/lib/kernel/test/gen_tcp_misc_SUITE.erl index 91c89e76dd..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() -> 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)}, -- cgit v1.2.3