diff options
Diffstat (limited to 'lib')
151 files changed, 7458 insertions, 4424 deletions
diff --git a/lib/asn1/doc/src/asn1_ug.xml b/lib/asn1/doc/src/asn1_ug.xml index 020e58c615..8b33497dd3 100644 --- a/lib/asn1/doc/src/asn1_ug.xml +++ b/lib/asn1/doc/src/asn1_ug.xml @@ -1390,7 +1390,7 @@ GENERAL-PROCEDURES GENERAL-PROCEDURE ::= { instance, if a Type is used in a definition with certain purpose, one want the type-name to express the intention. This can be done with parameterization.</p> - <p>When many types (or an other ASN.1 entity) only differs in some + <p>When many types (or another ASN.1 entity) only differs in some minor cases, but the structure of the types are similar, only one general type can be defined and the differences may be supplied through parameters. </p> diff --git a/lib/common_test/test/ct_snmp_SUITE_data/snmp.cfg b/lib/common_test/test/ct_snmp_SUITE_data/snmp.cfg index 895e097de6..7ff356e49a 100644 --- a/lib/common_test/test/ct_snmp_SUITE_data/snmp.cfg +++ b/lib/common_test/test/ct_snmp_SUITE_data/snmp.cfg @@ -22,23 +22,23 @@ {agent_target_param_def,{data_dir_file,"target_params.conf"}}, {agent_vacm,{data_dir_file,"vacm.conf"}}]}. {snmp_app1,[{manager, [{config, [{verbosity, silence}]}, - {server,[{verbosity,silence}]}, - {net_if,[{verbosity,silence}]}, + {server,[{verbosity,log}]}, + {net_if,[{verbosity,log}]}, {versions,[v2]} ]}, {agent, [{config, [{verbosity, silence}]}, - {net_if,[{verbosity,silence}]}, + {net_if,[{verbosity,log}]}, {mib_server,[{verbosity,silence}]}, {local_db,[{verbosity,silence}]}, - {agent_verbosity,silence} + {agent_verbosity,log} ]}]}. {snmp_app2,[{manager, [{config, [{verbosity, silence}]}, - {server,[{verbosity,silence}]}, - {net_if,[{verbosity,silence}]} + {server,[{verbosity,log}]}, + {net_if,[{verbosity,log}]} ]}, {agent, [{config, [{verbosity, silence}]}, - {net_if,[{verbosity,silence}]}, + {net_if,[{verbosity,log}]}, {mib_server,[{verbosity,silence}]}, {local_db,[{verbosity,silence}]}, - {agent_verbosity,silence} + {agent_verbosity,log} ]}]}. diff --git a/lib/common_test/test/ct_snmp_SUITE_data/snmp_SUITE.erl b/lib/common_test/test/ct_snmp_SUITE_data/snmp_SUITE.erl index 16b2b5690c..e20832e1e7 100644 --- a/lib/common_test/test/ct_snmp_SUITE_data/snmp_SUITE.erl +++ b/lib/common_test/test/ct_snmp_SUITE_data/snmp_SUITE.erl @@ -1,7 +1,7 @@ %%-------------------------------------------------------------------- %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2012. All Rights Reserved. +%% Copyright Ericsson AB 2012-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -288,6 +288,9 @@ override_usm(Config) -> %% Check that usm.conf is overwritten {ok,MyUsm} = snmpa_conf:read_usm_config(DataDir), {ok,UsedUsm} = snmpa_conf:read_usm_config(ConfDir), + ct:pal( + "MyUsm = ~p~nUsedUsm = ~p", + [MyUsm, UsedUsm]), true = (MyUsm == UsedUsm), %% Check that the usm user is actually configured... @@ -304,6 +307,9 @@ override_standard(Config) -> %% Check that standard.conf is overwritten {ok,MyStandard} = snmpa_conf:read_standard_config(DataDir), {ok,UsedStandard} = snmpa_conf:read_standard_config(ConfDir), + ct:pal( + "MyStandard = ~p~nUsedStandard = ~p", + [MyStandard, UsedStandard]), true = (MyStandard == UsedStandard), %% Check that the values from standard.conf is actually configured... @@ -319,6 +325,9 @@ override_context(Config) -> %% Check that context.conf is overwritten {ok,MyContext} = snmpa_conf:read_context_config(DataDir), {ok,UsedContext} = snmpa_conf:read_context_config(ConfDir), + ct:pal( + "MyContext = ~p~nUsedContext = ~p", + [MyContext, UsedContext]), true = (MyContext == UsedContext), ok. @@ -330,6 +339,9 @@ override_community(Config) -> %% Check that community.conf is overwritten {ok,MyCommunity} = snmpa_conf:read_community_config(DataDir), {ok,UsedCommunity} = snmpa_conf:read_community_config(ConfDir), + ct:pal( + "MyCommunity = ~p~nUsedCommunity = ~p", + [MyCommunity, UsedCommunity]), true = (MyCommunity == UsedCommunity), ok. @@ -341,6 +353,9 @@ override_notify(Config) -> %% Check that notify.conf is overwritten {ok,MyNotify} = snmpa_conf:read_notify_config(DataDir), {ok,UsedNotify} = snmpa_conf:read_notify_config(ConfDir), + ct:pal( + "MyNotify = ~p~nUsedNotify = ~p", + [MyNotify, UsedNotify]), true = (MyNotify == UsedNotify), ok. @@ -352,6 +367,9 @@ override_target_addr(Config) -> %% Check that target_addr.conf is overwritten {ok,MyTargetAddr} = snmpa_conf:read_target_addr_config(DataDir), {ok,UsedTargetAddr} = snmpa_conf:read_target_addr_config(ConfDir), + ct:pal( + "MyTargetAddr = ~p~nUsedTargetAddr = ~p", + [MyTargetAddr, UsedTargetAddr]), true = (MyTargetAddr == UsedTargetAddr), ok. @@ -363,6 +381,9 @@ override_target_params(Config) -> %% Check that target_params.conf is overwritten {ok,MyTargetParams} = snmpa_conf:read_target_params_config(DataDir), {ok,UsedTargetParams} = snmpa_conf:read_target_params_config(ConfDir), + ct:pal( + "MyTargetParams = ~p~nUsedTargetParams = ~p", + [MyTargetParams, UsedTargetParams]), true = (MyTargetParams == UsedTargetParams), ok. @@ -374,6 +395,9 @@ override_vacm(Config) -> %% Check that vacm.conf is overwritten {ok,MyVacm} = snmpa_conf:read_vacm_config(DataDir), {ok,UsedVacm} = snmpa_conf:read_vacm_config(ConfDir), + ct:pal( + "MyVacm = ~p~nUsedVacm = ~p", + [MyVacm, UsedVacm]), true = (MyVacm == UsedVacm), ok. diff --git a/lib/common_test/test/ct_snmp_SUITE_data/snmp_SUITE_data/target_addr.conf b/lib/common_test/test/ct_snmp_SUITE_data/snmp_SUITE_data/target_addr.conf index d02672a074..d3ce2fa60e 100644 --- a/lib/common_test/test/ct_snmp_SUITE_data/snmp_SUITE_data/target_addr.conf +++ b/lib/common_test/test/ct_snmp_SUITE_data/snmp_SUITE_data/target_addr.conf @@ -1,2 +1,2 @@ -{"target1", snmpUDPDomain, [147,214,122,73], 5000, 1500, 3, "std_trap", "target_v3", "", [], 2048}. -{"target2", snmpUDPDomain, [147,214,122,73], 5000, 1500, 3, "std_inform", "target_v3", "", [], 2048}. +{"target1", snmpUDPDomain, {[147,214,122,73], 5000}, 1500, 3, "std_trap", "target_v3", "", [], 2048}. +{"target2", snmpUDPDomain, {[147,214,122,73], 5000}, 1500, 3, "std_inform", "target_v3", "", [], 2048}. diff --git a/lib/dialyzer/src/dialyzer_contracts.erl b/lib/dialyzer/src/dialyzer_contracts.erl index 1d2dfc7b2d..f27fc1a842 100644 --- a/lib/dialyzer/src/dialyzer_contracts.erl +++ b/lib/dialyzer/src/dialyzer_contracts.erl @@ -20,8 +20,6 @@ -module(dialyzer_contracts). --compile(export_all). - -export([check_contract/2, check_contracts/4, contracts_without_fun/3, @@ -686,7 +684,7 @@ picky_contract_check(CSig0, Sig0, MFA, FileLine, Contract, RecDict, Acc) -> true -> Acc; false -> case extra_contract_warning(MFA, FileLine, Contract, - CSig, Sig, RecDict) of + CSig0, Sig0, RecDict) of no_warning -> Acc; {warning, Warning} -> [Warning|Acc] end @@ -752,7 +750,8 @@ is_remote_types_related(Contract, CSig, Sig, RecDict) -> t_from_forms_without_remote([{FType, []}], RecDict) -> Type0 = erl_types:t_from_form(FType, RecDict), - {ok, erl_types:subst_all_remote(Type0, erl_types:t_none())}; + Type1 = erl_types:subst_all_remote(Type0, erl_types:t_none()), + {ok, erl_types:subst_all_vars_to_any(Type1)}; t_from_forms_without_remote([{_FType, _Constrs}], _RecDict) -> %% 'When' constraints unsupported; diff --git a/lib/dialyzer/src/dialyzer_dataflow.erl b/lib/dialyzer/src/dialyzer_dataflow.erl index 92aab68ad6..03005e689f 100644 --- a/lib/dialyzer/src/dialyzer_dataflow.erl +++ b/lib/dialyzer/src/dialyzer_dataflow.erl @@ -93,6 +93,8 @@ -define(TYPE_LIMIT, 3). +-define(BITS, 128). + -record(state, {callgraph :: dialyzer_callgraph:callgraph(), envs :: env_tab(), fun_tab :: fun_tab(), @@ -1610,10 +1612,18 @@ bind_bin_segs([Seg|Segs], BinType, Acc, Map, State) -> SizeVal = lists:max(List), Flags = cerl:concrete(cerl:bitstr_flags(Seg)), N = SizeVal * UnitVal, - case lists:member(signed, Flags) of - true -> t_from_range(-(1 bsl (N - 1)), 1 bsl (N - 1) - 1); - false -> t_from_range(0, 1 bsl N - 1) - end + case N >= ?BITS of + true -> + case lists:member(signed, Flags) of + true -> t_from_range(neg_inf, pos_inf); + false -> t_from_range(0, pos_inf) + end; + false -> + case lists:member(signed, Flags) of + true -> t_from_range(-(1 bsl (N - 1)), 1 bsl (N - 1) - 1); + false -> t_from_range(0, 1 bsl N - 1) + end + end end end, {Map2, [_]} = bind_pat_vars([Val], [ValConstr], [], Map1, State, false), diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/opaque/opaque_bug5.erl b/lib/dialyzer/test/opaque_SUITE_data/src/opaque/opaque_bug5.erl new file mode 100644 index 0000000000..28d739de8e --- /dev/null +++ b/lib/dialyzer/test/opaque_SUITE_data/src/opaque/opaque_bug5.erl @@ -0,0 +1,10 @@ +%% Second arg of is_record call wasn't checked properly + +-module(opaque_bug5). + +-export([b/0]). + +b() -> + is_record(id({a}), id(a)). + +id(I) -> I. diff --git a/lib/dialyzer/test/small_SUITE_data/src/limit.erl b/lib/dialyzer/test/small_SUITE_data/src/limit.erl new file mode 100644 index 0000000000..97ee585b77 --- /dev/null +++ b/lib/dialyzer/test/small_SUITE_data/src/limit.erl @@ -0,0 +1,20 @@ +%% Misc cases where Dialyzer would fail with system_limit or crash + +-module(limit). + +-export([tu/0, big/1, b2/0]). + +tu() -> + erlang:make_tuple(1 bsl 24, def, [{5,e},{1,a},{3,c}]). + +big(<<Int:1152921504606846976/unit:128,0,_/binary>>) -> {5,Int}. + +b2() -> + Maxbig = maxbig(), + _ = bnot Maxbig, + ok. + +maxbig() -> + %% We assume that the maximum arity is (1 bsl 19) - 1. + Ws = erlang:system_info(wordsize), + (((1 bsl ((16777184 * (Ws div 4))-1)) - 1) bsl 1) + 1. diff --git a/lib/dialyzer/test/underspecs_SUITE_data/results/arr b/lib/dialyzer/test/underspecs_SUITE_data/results/arr new file mode 100644 index 0000000000..9497d12eec --- /dev/null +++ b/lib/dialyzer/test/underspecs_SUITE_data/results/arr @@ -0,0 +1,4 @@ + +arr.erl:14: Type specification arr:test2(array:array(T),non_neg_integer(),T) -> array:array(T) is a supertype of the success typing: arr:test2(array:array(_),pos_integer(),_) -> array:array(_) +arr.erl:24: Type specification arr:test4(array:array(T),non_neg_integer(),_) -> array:array(T) is a supertype of the success typing: arr:test4(array:array(_),pos_integer(),_) -> array:array(_) +arr.erl:29: Type specification arr:test5(array:array(T),non_neg_integer(),T) -> array:array(T) is a supertype of the success typing: arr:test5(array:array(_),non_neg_integer(),integer()) -> array:array(_) diff --git a/lib/dialyzer/test/underspecs_SUITE_data/src/arr.erl b/lib/dialyzer/test/underspecs_SUITE_data/src/arr.erl new file mode 100644 index 0000000000..3b265ccec2 --- /dev/null +++ b/lib/dialyzer/test/underspecs_SUITE_data/src/arr.erl @@ -0,0 +1,41 @@ +-module(arr). + +%% http://erlang.org/pipermail/erlang-questions/2014-August/080445.html + +-define(A, array). + +-export([test/3, test2/3, test3/3, test4/3, test5/3, test6/3]). + +-spec test(?A:array(T), non_neg_integer(), T) -> ?A:array(T). + +test(Array, N, Value) -> + ?A:set(N, Value, Array). + +-spec test2(?A:array(T), non_neg_integer(), T) -> ?A:array(T). + +test2(Array, N, Value) when N > 0 -> + ?A:set(N, Value, Array). + +-spec test3(?A:array(T), non_neg_integer(), _) -> ?A:array(T). + +test3(Array, N, Value) -> + ?A:set(N, Value, Array). + +-spec test4(?A:array(T), non_neg_integer(), _) -> ?A:array(T). + +test4(Array, N, Value) when N > 0 -> + ?A:set(N, Value, Array). + +-spec test5(?A:array(T), non_neg_integer(), T) -> ?A:array(T). + +test5(Array, N, Value) when is_integer(Value) -> + ?A:set(N, Value, Array). + +%% One would ideally want a warning also for test6(), but the current +%% analysis of parametrized opaque types is not strong enough to +%% discover this. +-spec test6(?A:array(integer()), non_neg_integer(), integer()) -> + ?A:array(any()). + +test6(Array, N, Value) -> + ?A:set(N, Value, Array). diff --git a/lib/eldap/test/README b/lib/eldap/test/README index 8774db1504..ec774c1ae3 100644 --- a/lib/eldap/test/README +++ b/lib/eldap/test/README @@ -19,7 +19,7 @@ This will however not work, since slapd is guarded by apparmor that checks that To make a local extension of alowed operations: sudo emacs /etc/apparmor.d/local/usr.sbin.slapd -and, after the change (yes, at least on Ubuntu it is right to edit ../local/.. but run with an other file) : +and, after the change (yes, at least on Ubuntu it is right to edit ../local/.. but run with another file): sudo apparmor_parser -r /etc/apparmor.d/usr.sbin.slapd diff --git a/lib/erl_interface/configure.in b/lib/erl_interface/configure.in index d511f2e240..ef78f0f87b 100644 --- a/lib/erl_interface/configure.in +++ b/lib/erl_interface/configure.in @@ -311,6 +311,26 @@ else fi fi +dnl ---------------------------------------------------------------------- +dnl Enable -fsanitize= flags. +dnl ---------------------------------------------------------------------- + +m4_define(DEFAULT_SANITIZERS, [address,undefined]) +AC_ARG_ENABLE( + sanitizers, + AS_HELP_STRING( + [--enable-sanitizers@<:@=comma-separated list of sanitizers@:>@], + [Default=DEFAULT_SANITIZERS]), +[ +case "$enableval" in + no) sanitizers= ;; + yes) sanitizers="-fsanitize=DEFAULT_SANITIZERS" ;; + *) sanitizers="-fsanitize=$enableval" ;; +esac +CFLAGS="$CFLAGS $sanitizers" +LDFLAGS="$LDFLAGS $sanitizers" +]) + # --------------------------------------------------------------------------- # XXX # --------------------------------------------------------------------------- diff --git a/lib/erl_interface/src/connect/ei_connect.c b/lib/erl_interface/src/connect/ei_connect.c index 2e8418d61e..45c000ef76 100644 --- a/lib/erl_interface/src/connect/ei_connect.c +++ b/lib/erl_interface/src/connect/ei_connect.c @@ -761,7 +761,7 @@ int ei_close_connection(int fd) #endif /* - * Accept and initiate a connection from an other + * Accept and initiate a connection from another * Erlang node. Return a file descriptor at success, * otherwise -1; */ diff --git a/lib/erl_interface/src/legacy/erl_connect.c b/lib/erl_interface/src/legacy/erl_connect.c index ae0265a388..d70d914b79 100644 --- a/lib/erl_interface/src/legacy/erl_connect.c +++ b/lib/erl_interface/src/legacy/erl_connect.c @@ -190,7 +190,7 @@ int erl_close_connection(int fd) } /* - * Accept and initiate a connection from an other + * Accept and initiate a connection from another * Erlang node. Return a file descriptor at success, * otherwise -1; */ diff --git a/lib/hipe/cerl/erl_bif_types.erl b/lib/hipe/cerl/erl_bif_types.erl index a460f16272..74e93bf098 100644 --- a/lib/hipe/cerl/erl_bif_types.erl +++ b/lib/hipe/cerl/erl_bif_types.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2013. All Rights Reserved. +%% Copyright Ericsson AB 2003-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -1891,7 +1891,11 @@ infinity_add(neg_inf, _Number) -> neg_inf; infinity_add(_Number, pos_inf) -> pos_inf; infinity_add(_Number, neg_inf) -> neg_inf; infinity_add(Number1, Number2) when is_integer(Number1), is_integer(Number2) -> - Number1 + Number2. + try Number1 + Number2 + catch + error:system_limit when Number1 < 0 -> neg_inf; + error:system_limit -> pos_inf + end. infinity_mult(neg_inf, Number) -> Greater = infinity_geq(Number, 0), @@ -1902,7 +1906,13 @@ infinity_mult(pos_inf, Number) -> infinity_inv(infinity_mult(neg_inf, Number)); infinity_mult(Number, pos_inf) -> infinity_inv(infinity_mult(neg_inf, Number)); infinity_mult(Number, neg_inf) -> infinity_mult(neg_inf, Number); infinity_mult(Number1, Number2) when is_integer(Number1), is_integer(Number2)-> - Number1 * Number2. + try Number1 * Number2 + catch + error:system_limit -> + if (Number1 >= 0) =:= (Number2 >= 0) -> pos_inf; + true -> neg_inf + end + end. width({Min, Max}) -> infinity_max([width(Min), width(Max)]); width(pos_inf) -> pos_inf; @@ -2633,7 +2643,9 @@ opaque_args(M, F, A, Xs, Opaques) -> true -> case t_tuple_subtypes(X, Opaques) of unknown -> false; - List when length(List) >= 1 -> opaque_recargs(List, Y, Opaques) + List when length(List) >= 1 -> + (t_is_atom(Y, Opaques) andalso + opaque_recargs(List, Y, Opaques)) end; false -> t_has_opaque_subtype(X, Opaques) end]; diff --git a/lib/hipe/cerl/erl_types.erl b/lib/hipe/cerl/erl_types.erl index 0927c17b6b..4b2bec5fa8 100644 --- a/lib/hipe/cerl/erl_types.erl +++ b/lib/hipe/cerl/erl_types.erl @@ -262,6 +262,8 @@ -define(TAG_IMMED1_SIZE, 4). -define(BITS, (erlang:system_info(wordsize) * 8) - ?TAG_IMMED1_SIZE). +-define(MAX_TUPLE_SIZE, (1 bsl 10)). + %%----------------------------------------------------------------------------- %% Type tags and qualifiers %% @@ -1770,6 +1772,8 @@ t_tuple() -> -spec t_tuple(non_neg_integer() | [erl_type()]) -> erl_type(). +t_tuple(N) when is_integer(N), N > ?MAX_TUPLE_SIZE -> + t_tuple(); t_tuple(N) when is_integer(N) -> ?tuple(lists:duplicate(N, ?any), N, ?any); t_tuple(List) -> diff --git a/lib/inets/doc/src/httpc.xml b/lib/inets/doc/src/httpc.xml index 37eb7ba718..06cb035370 100644 --- a/lib/inets/doc/src/httpc.xml +++ b/lib/inets/doc/src/httpc.xml @@ -332,7 +332,7 @@ filename() = string() <p>Defaults to <c>true</c>. </p> </item> - <tag><c><![CDATA[header_as_is]]></c></tag> + <tag><c><![CDATA[headers_as_is]]></c></tag> <item> <p>Shall the headers provided by the user be made lower case or be regarded as case sensitive. </p> diff --git a/lib/inets/src/http_client/httpc_handler.erl b/lib/inets/src/http_client/httpc_handler.erl index 5ae6760f08..d152d9f0be 100644 --- a/lib/inets/src/http_client/httpc_handler.erl +++ b/lib/inets/src/http_client/httpc_handler.erl @@ -1793,7 +1793,7 @@ tls_tunnel_request(#request{headers = Headers, host_header(#http_request_h{host = Host}, _) -> Host; -%% Handles header_as_is +%% Handles headers_as_is host_header(_, URI) -> {ok, {_, _, Host, _, _, _}} = http_uri:parse(URI), Host. diff --git a/lib/inets/test/httpd_SUITE.erl b/lib/inets/test/httpd_SUITE.erl index de47760e6e..4010597657 100644 --- a/lib/inets/test/httpd_SUITE.erl +++ b/lib/inets/test/httpd_SUITE.erl @@ -148,8 +148,24 @@ init_per_suite(Config) -> inets_test_lib:del_dirs(ServerRoot), DocRoot = filename:join(ServerRoot, "htdocs"), setup_server_dirs(ServerRoot, DocRoot, DataDir), + {ok, Hostname0} = inet:gethostname(), + Inet = + case (catch ct:get_config(ipv6_hosts)) of + undefined -> + inet; + Hosts when is_list(Hosts) -> + case lists:member(list_to_atom(Hostname0), Hosts) of + true -> + inet6; + false -> + inet + end; + _ -> + inet + end, [{server_root, ServerRoot}, {doc_root, DocRoot}, + {ipfamily, Inet}, {node, node()}, {host, inets_test_lib:hostname()}, {address, getaddr()} | Config]. @@ -524,7 +540,7 @@ ipv6(Config) when is_list(Config) -> true -> Version = ?config(http_version, Config), Host = ?config(host, Config), - URI = http_request("GET /", Version, Host), + URI = http_request("GET / ", Version, Host), httpd_test_lib:verify_request(?config(type, Config), Host, ?config(port, Config), [inet6], ?config(code, Config), @@ -1397,7 +1413,7 @@ server_config(http, Config) -> {server_root, ServerRoot}, {document_root, ?config(doc_root, Config)}, {bind_address, any}, - {ipfamily, inet}, + {ipfamily, ?config(ipfamily, Config)}, {max_header_size, 256}, {max_header_action, close}, {directory_index, ["index.html", "welcome.html"]}, @@ -1666,9 +1682,10 @@ cleanup_mnesia() -> transport_opts(ssl, Config) -> PrivDir = ?config(priv_dir, Config), - [{cacertfile, filename:join(PrivDir, "public_key_cacert.pem")}]; -transport_opts(_, _) -> - []. + [?config(ipfamily, Config), + {cacertfile, filename:join(PrivDir, "public_key_cacert.pem")}]; +transport_opts(_, Config) -> + [?config(ipfamily, Config)]. %%% mod_range diff --git a/lib/inets/test/httpd_test_lib.erl b/lib/inets/test/httpd_test_lib.erl index 36a5bb9e71..647fa6f6c1 100644 --- a/lib/inets/test/httpd_test_lib.erl +++ b/lib/inets/test/httpd_test_lib.erl @@ -91,16 +91,7 @@ verify_request(SocketType, Host, Port, Node, RequestStr, Options, TimeOut) when (is_integer(TimeOut) orelse (TimeOut =:= infinity)) -> verify_request(SocketType, Host, Port, [], Node, RequestStr, Options, TimeOut). -verify_request(SocketType, Host, Port, TranspOpts0, Node, RequestStr, Options, TimeOut) -> - %% For now, until we modernize the httpd tests - TranspOpts = - case lists:member(inet6, TranspOpts0) of - true -> - TranspOpts0; - false -> - [inet | TranspOpts0] - end, - +verify_request(SocketType, Host, Port, TranspOpts, Node, RequestStr, Options, TimeOut) -> try inets_test_lib:connect_bin(SocketType, Host, Port, TranspOpts) of {ok, Socket} -> ok = inets_test_lib:send(SocketType, Socket, RequestStr), diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/AbstractConnection.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/AbstractConnection.java index 7aa30eef4a..85d303689f 100644 --- a/lib/jinterface/java_src/com/ericsson/otp/erlang/AbstractConnection.java +++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/AbstractConnection.java @@ -959,7 +959,9 @@ public abstract class AbstractConnection extends Thread { } catch (final Exception e) { final String nn = peer.node(); close(); - throw new IOException("Error accepting connection from " + nn); + IOException ioe = new IOException("Error accepting connection from " + nn); + ioe.initCause(e); + throw ioe; } if (traceLevel >= handshakeThreshold) { System.out.println("<- MD5 ACCEPTED " + peer.host()); @@ -990,7 +992,9 @@ public abstract class AbstractConnection extends Thread { throw ae; } catch (final Exception e) { close(); - throw new IOException("Cannot connect to peer node"); + IOException ioe = new IOException("Cannot connect to peer node"); + ioe.initCause(e); + throw ioe; } } diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangFun.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangFun.java index fc104e9564..c52909acc5 100644 --- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangFun.java +++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangFun.java @@ -94,7 +94,7 @@ public class OtpErlangFun extends OtpErlangObject implements Serializable { return false; } } else { - if (!md5.equals(f.md5)) { + if (!Arrays.equals(md5, f.md5)) { return false; } } @@ -104,7 +104,7 @@ public class OtpErlangFun extends OtpErlangObject implements Serializable { if (freeVars == null) { return f.freeVars == null; } - return freeVars.equals(f.freeVars); + return Arrays.equals(freeVars, f.freeVars); } @Override diff --git a/lib/jinterface/test/jinterface_SUITE.erl b/lib/jinterface/test/jinterface_SUITE.erl index cb725164cd..00abc97ff5 100644 --- a/lib/jinterface/test/jinterface_SUITE.erl +++ b/lib/jinterface/test/jinterface_SUITE.erl @@ -38,7 +38,8 @@ java_exit_with_reason_any_term/1, status_handler_localStatus/1, status_handler_remoteStatus/1, status_handler_connAttempt/1, - maps/1 + maps/1, + fun_equals/1 ]). -include_lib("common_test/include/ct.hrl"). @@ -106,7 +107,8 @@ fundamental() -> register_and_whereis, % RegisterAndWhereis.java get_names, % GetNames.java boolean_atom, % BooleanAtom.java - maps % Maps.java + maps, % Maps.java + fun_equals % FunEquals.java ]. ping() -> @@ -691,6 +693,18 @@ maps(Config) when is_list(Config) -> []). %%%----------------------------------------------------------------- +fun_equals(doc) -> + ["FunEquals.java: " + "Test OtpErlangFun.equals()"]; +fun_equals(suite) -> + []; +fun_equals(Config) when is_list(Config) -> + ok = jitu:java(?config(java, Config), + ?config(data_dir, Config), + "FunEquals", + []). + +%%%----------------------------------------------------------------- %%% INTERNAL FUNCTIONS %%%----------------------------------------------------------------- send_receive(TestCaseTag,Fun,Config) -> diff --git a/lib/jinterface/test/jinterface_SUITE_data/FunEquals.java b/lib/jinterface/test/jinterface_SUITE_data/FunEquals.java new file mode 100644 index 0000000000..14f884cee7 --- /dev/null +++ b/lib/jinterface/test/jinterface_SUITE_data/FunEquals.java @@ -0,0 +1,71 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2004-2010. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +import java.util.Arrays; + +import com.ericsson.otp.erlang.*; + +public class FunEquals { + + /* + Implements test case jinterface_SUITE:fun_equals/1 + + Test the function OtpErlangFun.equals() + */ + + public static void main(String argv[]) { + + OtpErlangPid pid = new OtpErlangPid("here", 4, 5, 0); + String module = "mod"; + int arity = 2; + byte[] md5 = new byte[]{3,5,7}; + int index = 2; + long old_index = 1; + long uniq= 2; + OtpErlangObject[] freeVars = new OtpErlangObject[]{ + new OtpErlangAtom("hej"), new OtpErlangLong(9) + }; + + OtpErlangFun f1 = new OtpErlangFun(pid, module, arity, md5, + index, old_index, uniq, freeVars); + OtpErlangFun f2 = new OtpErlangFun(pid, module, arity, copyArray(md5), + index, old_index, uniq, copyArray(freeVars)); + + if(!f1.equals(f2)) + fail(1); + + } + + private static void fail(int reason) { + System.exit(reason); + } + + private static byte[] copyArray(byte[] source) { + byte[] result = new byte[source.length]; + System.arraycopy(source, 0, result, 0, source.length); + return result; + } + + private static OtpErlangObject[] copyArray(OtpErlangObject[] source) { + OtpErlangObject[] result = new OtpErlangObject[source.length]; + System.arraycopy(source, 0, result, 0, source.length); + return result; + } + +} diff --git a/lib/jinterface/test/jinterface_SUITE_data/Makefile.src b/lib/jinterface/test/jinterface_SUITE_data/Makefile.src index a15ed1aa63..cd68f1ead5 100644 --- a/lib/jinterface/test/jinterface_SUITE_data/Makefile.src +++ b/lib/jinterface/test/jinterface_SUITE_data/Makefile.src @@ -47,7 +47,8 @@ JAVA_FILES = \ MboxSendReceive.java \ MboxLinkUnlink.java \ NodeStatusHandler.java \ - Maps.java + Maps.java \ + FunEquals.java CLASS_FILES = $(JAVA_FILES:.java=.class) diff --git a/lib/kernel/doc/src/gen_tcp.xml b/lib/kernel/doc/src/gen_tcp.xml index dbd0d3c815..820ecd1e30 100644 --- a/lib/kernel/doc/src/gen_tcp.xml +++ b/lib/kernel/doc/src/gen_tcp.xml @@ -112,7 +112,12 @@ do_recv(Sock, Bs) -> <item> <p>If a socket has somehow been connected without using <c>gen_tcp</c>, use this option to pass the file - descriptor for it.</p> + descriptor for it. If <c>{ip, ip_address()}</c> + and/or <c>{port, port_number()}</c> is combined with + this option the fd will be bound to the given interface + and port before connecting. If these options are not given + it is assumed that the fd is already bound appropriately. + </p> </item> <tag><c>inet</c></tag> diff --git a/lib/kernel/doc/src/gen_udp.xml b/lib/kernel/doc/src/gen_udp.xml index 503725fe18..291d1b0da7 100644 --- a/lib/kernel/doc/src/gen_udp.xml +++ b/lib/kernel/doc/src/gen_udp.xml @@ -84,7 +84,12 @@ <item> <p>If a socket has somehow been opened without using <c>gen_udp</c>, use this option to pass the file - descriptor for it.</p> + descriptor for it. If <c><anno>Port</anno></c> is not set to 0 + and/or <c>{ip, ip_address()}</c> is combined with this option + the fd will be bound to the given interface and port after being + opened. If these options are not given it is assumed that the fd + is already bound appropriately. + </p> </item> <tag><c>inet6</c></tag> <item> diff --git a/lib/kernel/doc/src/notes.xml b/lib/kernel/doc/src/notes.xml index 35889f9d11..f92770603a 100644 --- a/lib/kernel/doc/src/notes.xml +++ b/lib/kernel/doc/src/notes.xml @@ -151,7 +151,6 @@ </list> </section> - <section><title>Improvements and New Features</title> <list> <item> @@ -295,7 +294,26 @@ </item> </list> </section> +</section> +<section><title>Kernel 2.16.4.1</title> + + <section><title>Known Bugs and Problems</title> + <list> + <item> + <p> + When using gen_tcp:connect and the <c>fd</c> option with + <c>port</c> and/or <c>ip</c>, the <c>port</c> and + <c>ip</c> options were ignored. This has been fixed so + that if <c>port</c> and/or <c>ip</c> is specified + together with <c>fd</c> a bind is requested for that + <c>fd</c>. If <c>port</c> and/or <c>ip</c> is not + specified bind will not be called.</p> + <p> + Own Id: OTP-12061</p> + </item> + </list> + </section> </section> <section><title>Kernel 2.16.4</title> diff --git a/lib/kernel/src/erl_epmd.erl b/lib/kernel/src/erl_epmd.erl index b4fae24ef3..f6e2ca0954 100644 --- a/lib/kernel/src/erl_epmd.erl +++ b/lib/kernel/src/erl_epmd.erl @@ -85,24 +85,19 @@ port_please1(Node,HostName, Timeout) -> Else end. -names() -> +names() -> {ok, H} = inet:gethostname(), names(H). -names(HostName) when is_atom(HostName) -> - names1(atom_to_list(HostName)); -names(HostName) when is_list(HostName) -> - names1(HostName); -names(EpmdAddr) -> - get_names(EpmdAddr). - -names1(HostName) -> +names(HostName) when is_atom(HostName); is_list(HostName) -> case inet:gethostbyname(HostName) of {ok,{hostent, _Name, _ , _Af, _Size, [EpmdAddr | _]}} -> get_names(EpmdAddr); Else -> Else - end. + end; +names(EpmdAddr) -> + get_names(EpmdAddr). register_node(Name, PortNo) -> diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl index 41d422d7d4..d17da2d329 100644 --- a/lib/kernel/src/inet.erl +++ b/lib/kernel/src/inet.erl @@ -1257,9 +1257,9 @@ open(FdO, Addr, Port, Opts, Protocol, Family, Type, Module) Error -> Error end; -open(Fd, _Addr, _Port, Opts, Protocol, Family, Type, Module) +open(Fd, Addr, Port, Opts, Protocol, Family, Type, Module) when is_integer(Fd) -> - fdopen(Fd, Opts, Protocol, Family, Type, Module). + fdopen(Fd, Addr, Port, Opts, Protocol, Family, Type, Module). bindx(S, [Addr], Port0) -> {IP, Port} = set_bindx_port(Addr, Port0), @@ -1298,12 +1298,35 @@ change_bindx_0_port({_IP, _Port}=Addr, _AssignedPort) -> {'ok', socket()} | {'error', posix()}. fdopen(Fd, Opts, Protocol, Family, Type, Module) -> - case prim_inet:fdopen(Protocol, Family, Type, Fd) of + fdopen(Fd, any, 0, Opts, Protocol, Family, Type, Module). + +fdopen(Fd, Addr, Port, Opts, Protocol, Family, Type, Module) -> + IsAnyAddr = (Addr == {0,0,0,0} orelse Addr == {0,0,0,0,0,0,0,0} + orelse Addr == any), + Bound = Port == 0 andalso IsAnyAddr, + case prim_inet:fdopen(Protocol, Family, Type, Fd, Bound) of {ok, S} -> case prim_inet:setopts(S, Opts) of ok -> - inet_db:register_socket(S, Module), - {ok, S}; + case if + Bound -> + %% We do not do any binding if default + %% port+addr options where given in order + %% to keep backwards compatability with + %% pre Erlang/TOP 17 + {ok, ok}; + is_list(Addr) -> + bindx(S, Addr, Port); + true -> + prim_inet:bind(S, Addr, Port) + end of + {ok, _} -> + inet_db:register_socket(S, Module), + {ok, S}; + Error -> + prim_inet:close(S), + Error + end; Error -> prim_inet:close(S), Error end; diff --git a/lib/kernel/src/net_adm.erl b/lib/kernel/src/net_adm.erl index 3f5eac7822..2cdfb76417 100644 --- a/lib/kernel/src/net_adm.erl +++ b/lib/kernel/src/net_adm.erl @@ -89,18 +89,13 @@ names() -> -spec names(Host) -> {ok, [{Name, Port}]} | {error, Reason} when - Host :: atom() | string(), + Host :: atom() | string() | inet:ip_address(), Name :: string(), Port :: non_neg_integer(), Reason :: address | file:posix(). names(Hostname) -> - case inet:gethostbyname(Hostname) of - {ok, {hostent, _Name, _ , _Af, _Size, [Addr | _]}} -> - erl_epmd:names(Addr); - Else -> - Else - end. + erl_epmd:names(Hostname). -spec dns_hostname(Host) -> {ok, Name} | {error, Host} when Host :: atom() | string(), diff --git a/lib/kernel/test/gen_tcp_api_SUITE.erl b/lib/kernel/test/gen_tcp_api_SUITE.erl index a7af00c12a..c27d265550 100644 --- a/lib/kernel/test/gen_tcp_api_SUITE.erl +++ b/lib/kernel/test/gen_tcp_api_SUITE.erl @@ -32,14 +32,16 @@ t_connect_bad/1, t_recv_timeout/1, t_recv_eof/1, t_shutdown_write/1, t_shutdown_both/1, t_shutdown_error/1, - t_fdopen/1, t_implicit_inet6/1]). + t_fdopen/1, t_fdconnect/1, t_implicit_inet6/1]). + +-export([getsockfd/0,closesockfd/1]). suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [{group, t_accept}, {group, t_connect}, {group, t_recv}, t_shutdown_write, t_shutdown_both, t_shutdown_error, - t_fdopen, t_implicit_inet6]. + t_fdopen, t_fdconnect, t_implicit_inet6]. groups() -> [{t_accept, [], [t_accept_timeout]}, @@ -185,6 +187,37 @@ t_fdopen(Config) when is_list(Config) -> ?line ok = gen_tcp:close(L), ok. +t_fdconnect(Config) when is_list(Config) -> + Question = "Aaaa... Long time ago in a small town in Germany,", + Question1 = list_to_binary(Question), + Question2 = [<<"Aaaa">>, "... ", $L, <<>>, $o, "ng time ago ", + ["in ", [], <<"a small town">>, [" in Germany,", <<>>]]], + Question1 = iolist_to_binary(Question2), + Answer = "there was a shoemaker, Schumacher was his name.", + Path = ?config(data_dir, Config), + Lib = "gen_tcp_api_SUITE", + ok = erlang:load_nif(filename:join(Path,Lib), []), + {ok, L} = gen_tcp:listen(0, [{active, false}]), + {ok, Port} = inet:port(L), + FD = gen_tcp_api_SUITE:getsockfd(), + {ok, Client} = gen_tcp:connect(localhost, Port, [{fd,FD},{port,20002}, + {active,false}]), + {ok, Server} = gen_tcp:accept(L), + ok = gen_tcp:send(Client, Question), + {ok, Question} = gen_tcp:recv(Server, length(Question), 2000), + ok = gen_tcp:send(Client, Question1), + {ok, Question} = gen_tcp:recv(Server, length(Question), 2000), + ok = gen_tcp:send(Client, Question2), + {ok, Question} = gen_tcp:recv(Server, length(Question), 2000), + ok = gen_tcp:send(Server, Answer), + {ok, Answer} = gen_tcp:recv(Client, length(Answer), 2000), + ok = gen_tcp:close(Client), + FD = gen_tcp_api_SUITE:closesockfd(FD), + {error,closed} = gen_tcp:recv(Server, 1, 2000), + ok = gen_tcp:close(Server), + ok = gen_tcp:close(L), + ok. + %%% implicit inet6 option to api functions @@ -300,3 +333,7 @@ unused_ip(A, B, C, D) -> end. ok({ok,V}) -> V. + + +getsockfd() -> undefined. +closesockfd(_FD) -> undefined. diff --git a/lib/kernel/test/gen_tcp_api_SUITE_data/Makefile.src b/lib/kernel/test/gen_tcp_api_SUITE_data/Makefile.src new file mode 100644 index 0000000000..5477598160 --- /dev/null +++ b/lib/kernel/test/gen_tcp_api_SUITE_data/Makefile.src @@ -0,0 +1,9 @@ + +NIF_LIBS = gen_tcp_api_SUITE@dll@ +SHLIB_EXTRA_LDLIBS = @LIBS@ + +all: $(NIF_LIBS) + +@SHLIB_RULES@ + +$(NIF_LIBS): gen_tcp_api_SUITE.c diff --git a/lib/kernel/test/gen_tcp_api_SUITE_data/gen_tcp_api_SUITE.c b/lib/kernel/test/gen_tcp_api_SUITE_data/gen_tcp_api_SUITE.c new file mode 100644 index 0000000000..73a6568b30 --- /dev/null +++ b/lib/kernel/test/gen_tcp_api_SUITE_data/gen_tcp_api_SUITE.c @@ -0,0 +1,60 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2009-2013. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#include "erl_nif.h" + +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <limits.h> +#include <sys/types.h> + +#ifdef __WIN32__ +#include <winsock2.h> +#else +#include <sys/socket.h> +#endif + +#define sock_open(af, type, proto) socket((af), (type), (proto)) + +static ERL_NIF_TERM getsockfd(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + int fd; + + fd = sock_open(AF_INET, SOCK_STREAM, 0); + return enif_make_int(env, fd); +} + +static ERL_NIF_TERM closesockfd(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + int fd; + + enif_get_int(env, argv[0], &fd); + + close(fd); + + return enif_make_int(env, fd); +} + +static ErlNifFunc nif_funcs[] = +{ + {"getsockfd", 0, getsockfd}, + {"closesockfd", 1, closesockfd} +}; + +ERL_NIF_INIT(gen_tcp_api_SUITE,nif_funcs,NULL,NULL,NULL,NULL) diff --git a/lib/kernel/test/gen_tcp_misc_SUITE.erl b/lib/kernel/test/gen_tcp_misc_SUITE.erl index 2df4bf7c95..4e4aeb67e2 100644 --- a/lib/kernel/test/gen_tcp_misc_SUITE.erl +++ b/lib/kernel/test/gen_tcp_misc_SUITE.erl @@ -882,7 +882,7 @@ passive_sockets_server_send(Socket, X) -> accept_closed_by_other_process(doc) -> ["Tests the return value from gen_tcp:accept when ", - "the socket is closed from an other process. (OTP-3817)"]; + "the socket is closed from another process. (OTP-3817)"]; accept_closed_by_other_process(Config) when is_list(Config) -> ?line Parent = self(), ?line {ok, ListenSocket} = gen_tcp:listen(0, []), diff --git a/lib/kernel/test/gen_udp_SUITE.erl b/lib/kernel/test/gen_udp_SUITE.erl index 6bb41999c5..8177123332 100644 --- a/lib/kernel/test/gen_udp_SUITE.erl +++ b/lib/kernel/test/gen_udp_SUITE.erl @@ -447,8 +447,8 @@ open_fd(Config) when is_list(Config) -> {ok,S1} = gen_udp:open(0), {ok,P2} = inet:port(S1), {ok,FD} = prim_inet:getfd(S1), - {error,einval} = gen_udp:open(P2, [inet6, {fd,FD}]), - {ok,S2} = gen_udp:open(P2, [{fd,FD}]), + {error,einval} = gen_udp:open(0, [inet6, {fd,FD}]), + {ok,S2} = gen_udp:open(0, [{fd,FD}]), {ok,S3} = gen_udp:open(0), {ok,P3} = inet:port(S3), ok = gen_udp:send(S3, Addr, P2, Msg), diff --git a/lib/megaco/configure.in b/lib/megaco/configure.in index 64daa959b5..e3c24a58b8 100644 --- a/lib/megaco/configure.in +++ b/lib/megaco/configure.in @@ -167,6 +167,26 @@ if test "x$GCC" = xyes; then LM_TRY_ENABLE_CFLAG([-Werror=return-type], [CFLAGS]) fi +dnl ---------------------------------------------------------------------- +dnl Enable -fsanitize= flags. +dnl ---------------------------------------------------------------------- + +m4_define(DEFAULT_SANITIZERS, [address,undefined]) +AC_ARG_ENABLE( + sanitizers, + AS_HELP_STRING( + [--enable-sanitizers@<:@=comma-separated list of sanitizers@:>@], + [Default=DEFAULT_SANITIZERS]), +[ +case "$enableval" in + no) sanitizers= ;; + yes) sanitizers="-fsanitize=DEFAULT_SANITIZERS" ;; + *) sanitizers="-fsanitize=$enableval" ;; +esac +CFLAGS="$CFLAGS $sanitizers" +LDFLAGS="$LDFLAGS $sanitizers" +]) + dnl dnl If ${ERL_TOP}/make/otp_ded.mk.in exists and contains DED_MK_VSN > 0, dnl every thing releted to compiling Dynamic Erlang Drivers can be found diff --git a/lib/mnesia/src/mnesia_frag.erl b/lib/mnesia/src/mnesia_frag.erl index 4a1616e054..66fc20913c 100644 --- a/lib/mnesia/src/mnesia_frag.erl +++ b/lib/mnesia/src/mnesia_frag.erl @@ -939,7 +939,7 @@ do_split(_FH, _OldN, _FragNames, [], Ops) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Delete a fragment from a fragmented table -%% and merge its records with an other fragment +%% and merge its records with another fragment make_multi_del_frag(Tab) -> verify_multi(Tab), diff --git a/lib/mnesia/src/mnesia_loader.erl b/lib/mnesia/src/mnesia_loader.erl index 4afbea1cc2..530317bcdd 100644 --- a/lib/mnesia/src/mnesia_loader.erl +++ b/lib/mnesia/src/mnesia_loader.erl @@ -208,7 +208,8 @@ do_get_network_copy(Tab, Reason, Ns, Storage, Cs) -> set({Tab, load_node}, Node), set({Tab, load_reason}, Reason), mnesia_controller:i_have_tab(Tab), - dbg_out("Table ~p copied from ~p to ~p~n", [Tab, Node, node()]), + dbg_out("Table ~p copied from ~p to ~p (~b entries)~n", + [Tab, Node, node(), mnesia:table_info(Tab, size)]), {loaded, ok}; Err = {error, _} when element(1, Reason) == dumper -> {not_loaded,Err}; diff --git a/lib/observer/src/observer_wx.erl b/lib/observer/src/observer_wx.erl index 03ca1bf9c1..c86f5ea916 100644 --- a/lib/observer/src/observer_wx.erl +++ b/lib/observer/src/observer_wx.erl @@ -112,10 +112,6 @@ setup(#state{frame = Frame} = State) -> observer_lib:create_menus(DefMenus, MenuBar, default), wxFrame:setMenuBar(Frame, MenuBar), - StatusBar = wxStatusBar:new(Frame), - wxFrame:setStatusBar(Frame, StatusBar), - wxFrame:setTitle(Frame, atom_to_list(node())), - wxStatusBar:setStatusText(StatusBar, atom_to_list(node())), %% Setup panels Panel = wxPanel:new(Frame, []), @@ -131,6 +127,11 @@ setup(#state{frame = Frame} = State) -> wxSizer:add(MainSizer, Notebook, [{proportion, 1}, {flag, ?wxEXPAND}]), wxPanel:setSizer(Panel, MainSizer), + StatusBar = wxStatusBar:new(Frame), + wxFrame:setStatusBar(Frame, StatusBar), + wxFrame:setTitle(Frame, atom_to_list(node())), + wxStatusBar:setStatusText(StatusBar, atom_to_list(node())), + wxNotebook:connect(Notebook, command_notebook_page_changing), wxFrame:connect(Frame, close_window, [{skip, true}]), wxMenu:connect(Frame, command_menu_selected), diff --git a/lib/odbc/configure.in b/lib/odbc/configure.in index f86146759c..ea5c51965f 100644 --- a/lib/odbc/configure.in +++ b/lib/odbc/configure.in @@ -228,4 +228,24 @@ if test "x$GCC" = xyes; then LM_TRY_ENABLE_CFLAG([-Werror=return-type], [CFLAGS]) fi +dnl ---------------------------------------------------------------------- +dnl Enable -fsanitize= flags. +dnl ---------------------------------------------------------------------- + +m4_define(DEFAULT_SANITIZERS, [address,undefined]) +AC_ARG_ENABLE( + sanitizers, + AS_HELP_STRING( + [--enable-sanitizers@<:@=comma-separated list of sanitizers@:>@], + [Default=DEFAULT_SANITIZERS]), +[ +case "$enableval" in + no) sanitizers= ;; + yes) sanitizers="-fsanitize=DEFAULT_SANITIZERS" ;; + *) sanitizers="-fsanitize=$enableval" ;; +esac +CFLAGS="$CFLAGS $sanitizers" +LDFLAGS="$LDFLAGS $sanitizers" +]) + AC_OUTPUT(c_src/$host/Makefile:c_src/Makefile.in) diff --git a/lib/odbc/doc/src/error_handling.xml b/lib/odbc/doc/src/error_handling.xml index b255865263..0b6179409d 100644 --- a/lib/odbc/doc/src/error_handling.xml +++ b/lib/odbc/doc/src/error_handling.xml @@ -88,7 +88,7 @@ <section> <title>The whole picture </title> <p>As the Erlang ODBC application relies on third party products - and communicates with a database that probably runs on an other + and communicates with a database that probably runs on another computer in the network there are plenty of things that might go wrong. To fully understand the things that might happen it facilitate to know the design of the Erlang ODBC application, diff --git a/lib/odbc/test/odbc_connect_SUITE.erl b/lib/odbc/test/odbc_connect_SUITE.erl index 2a16388929..1907069726 100644 --- a/lib/odbc/test/odbc_connect_SUITE.erl +++ b/lib/odbc/test/odbc_connect_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2013. All Rights Reserved. +%% Copyright Ericsson AB 2002-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -47,7 +47,7 @@ all() -> case odbc_test_lib:odbc_check() of ok -> [not_exist_db, commit, rollback, not_explicit_commit, - no_c_node, port_dies, control_process_dies, + no_c_executable, port_dies, control_process_dies, {group, client_dies}, connect_timeout, timeout, many_timeouts, timeout_reset, disconnect_on_timeout, connection_closed, disable_scrollable_cursors, @@ -248,28 +248,31 @@ not_exist_db(_Config) -> test_server:sleep(100). %%------------------------------------------------------------------------- -no_c_node(doc) -> +no_c_executable(doc) -> "Test what happens if the port-program can not be found"; -no_c_node(suite) -> []; -no_c_node(_Config) -> +no_c_executable(suite) -> []; +no_c_executable(_Config) -> process_flag(trap_exit, true), Dir = filename:nativename(filename:join(code:priv_dir(odbc), "bin")), FileName1 = filename:nativename(os:find_executable("odbcserver", Dir)), FileName2 = filename:nativename(filename:join(Dir, "odbcsrv")), - ok = file:rename(FileName1, FileName2), - Result = - case catch odbc:connect(?RDBMS:connection_string(), - odbc_test_lib:platform_options()) of - {error, port_program_executable_not_found} -> - ok; - Else -> - Else - end, - - ok = file:rename(FileName2, FileName1), - ok = Result. + case file:rename(FileName1, FileName2) of + ok -> + Result = + case catch odbc:connect(?RDBMS:connection_string(), + odbc_test_lib:platform_options()) of + {error, port_program_executable_not_found} -> + ok; + Else -> + Else + end, + ok = file:rename(FileName2, FileName1), + ok = Result; + _ -> + {skip, "File permission issues"} + end. %%------------------------------------------------------------------------ port_dies(doc) -> diff --git a/lib/orber/COSS/CosNaming/orber_cosnaming_utils.erl b/lib/orber/COSS/CosNaming/orber_cosnaming_utils.erl index 5ec0c084e3..c665e1fbc8 100644 --- a/lib/orber/COSS/CosNaming/orber_cosnaming_utils.erl +++ b/lib/orber/COSS/CosNaming/orber_cosnaming_utils.erl @@ -176,7 +176,6 @@ addresses({false, Adr, Rest}, Addresses) -> {lists:reverse([Adr|Addresses]), Rest}; addresses({true, Adr, Rest}, Addresses) -> addresses(address(protocol, Rest, [], []), [Adr|Addresses]). - %% Which protocol. address(protocol, [$:|T], [], []) -> address(version, T, [], [iiop]); @@ -192,6 +191,7 @@ address(protocol, What, _, _) -> [?LINE, What], ?DEBUG_LEVEL), corba:raise(#'CosNaming_NamingContextExt_InvalidAddress'{}); + %% Parsed one address, no version found or port found. address(version, [$,|T], Acc, Previous) -> {true, lists:reverse([?DEF_PORT, lists:reverse(Acc), ?DEF_VERS|Previous]), T}; @@ -208,15 +208,26 @@ address(version, [$@|T], Acc, Previous) -> [?LINE, What], ?DEBUG_LEVEL), corba:raise(#'CosNaming_NamingContextExt_InvalidAddress'{}) end; + +%% Found no iiop version, switch to ipv6. +address(version, [$[|T], [], Previous) -> + address(ipv6, T, [], [?DEF_VERS|Previous]); + %% Found no iiop version, switch to port. In this case Acc contains the %% Host. address(version, [$:|T], Acc, Previous) -> - case check_ip_version(T, [$:|Acc]) of - false -> - address(port, T, [], [lists:reverse(Acc), ?DEF_VERS|Previous]); - {ok, NewAcc, NewT, Type} -> - address(Type, NewT, [], [lists:reverse(NewAcc), ?DEF_VERS|Previous]) - end; + address(port, T, [], [lists:reverse(Acc), ?DEF_VERS|Previous]); + +%% Found IPv6 +address(address, [$[|T], [], Previous) -> + address(ipv6, T, [], Previous); + +%% Found port +address(address, [$:|T], Acc, Previous) -> + address(port, T, [], [lists:reverse(Acc)|Previous]); + +address(ipv6, [$]|T], Acc, Previous) -> + address(address, T, Acc, Previous); %% Parsed one address, port not found. address(address, [$,|T], [], Previous) -> @@ -267,68 +278,9 @@ address(address, [], [], Previous) -> address(address, [], Acc, Previous) -> {false, lists:reverse([?DEF_PORT, lists:reverse(Acc)|Previous]), []}; -%% Found port -address(address, [$:|T], Acc, Previous) -> - case check_ip_version(T, [$:|Acc]) of - false -> - address(port, T, [], [lists:reverse(Acc)|Previous]); - {ok, NewAcc, NewT, Type} -> - address(Type, NewT, [], [lists:reverse(NewAcc)|Previous]) - end; - address(Type, [H|T], Acc, Previous) -> address(Type, T, [H|Acc], Previous). - -check_ip_version(T, Acc) -> - case orber_env:ip_version() of - inet -> - false; - inet6 -> - case search_for_delimiter(1, T, Acc, $:) of - {ok, NewAcc, NewT, Type} -> - {ok, NewAcc, NewT, Type}; - _ -> - false - end - end. - -%% An IPv6 address may look like (x == hex, d == dec): -%% * "0:0:0:0:0:0:10.1.1.1" - x:x:x:x:x:x:d.d.d.d -%% * "0:0:0:0:8:800:200C:417A" - x:x:x:x:x:x:x:x -%% We cannot allow compressed addresses (::10.1.1.1) since we it is not -%% possible to know if the last part is a port number or part of the address. -search_for_delimiter(7, [], Acc, $:) -> - {ok, Acc, [], address}; -search_for_delimiter(9, [], Acc, $.) -> - {ok, Acc, [], address}; -search_for_delimiter(_, [], _, _) -> - false; -search_for_delimiter(7, [$/|T], Acc, $:) -> - {ok, Acc, [$/|T], address}; -search_for_delimiter(9, [$/|T], Acc, $.) -> - {ok, Acc, [$/|T], address}; -search_for_delimiter(_, [$/|_T], _Acc, _) -> - false; -search_for_delimiter(7, [$,|T], Acc, $:) -> - {ok, Acc, [$,|T], address}; -search_for_delimiter(9, [$,|T], Acc, $.) -> - {ok, Acc, [$,|T], address}; -search_for_delimiter(_, [$,|_T], _Acc, _) -> - false; -search_for_delimiter(7, [$:|T], Acc, $:) -> - {ok, Acc, T, port}; -search_for_delimiter(9, [$:|T], Acc, $.) -> - {ok, Acc, T, port}; -search_for_delimiter(N, [$:|T], Acc, $:) -> - search_for_delimiter(N+1, T, [$:|Acc], $:); -search_for_delimiter(N, [$.|T], Acc, $.) when N > 6, N < 9 -> - search_for_delimiter(N+1, T, [$.|Acc], $.); -search_for_delimiter(6, [$.|T], Acc, $:) -> - search_for_delimiter(7, T, [$.|Acc], $.); -search_for_delimiter(N, [H|T], Acc, LookingFor) -> - search_for_delimiter(N, T, [H|Acc], LookingFor). - %%---------------------------------------------------------------------- %% Function : key %% Arguments : A string which contain a Key we want to use and, if defined, diff --git a/lib/orber/doc/src/ch_naming_service.xml b/lib/orber/doc/src/ch_naming_service.xml index b735629a14..e355db2edb 100644 --- a/lib/orber/doc/src/ch_naming_service.xml +++ b/lib/orber/doc/src/ch_naming_service.xml @@ -273,25 +273,28 @@ lists:foreach(fun({{Id, Kind},BindingType}) -> case BindingType of <p>The notation of this scheme is similar to the more well known URL <c>HTTP</c>, and the full <c>corbaloc</c> BNF is:</p> <code type="none"><![CDATA[ -<corbaloc> = "corbaloc:"<obj_addr_list>["/"<key_string>] -<obj_addr_list> = [<obj_addr>","]*<obj_addr> -<obj_addr> = <prot_addr> | <future_prot_addr> -<prot_addr> = <rir_prot_addr> | <iiop_prot_addr> -<rir_prot_addr> = <rir_prot_token>":" -<rir_prot_token> = rir -<future_prot_addr> = <future_prot_id><future_prot_addr> -<future_prot_id> = <future_prot_token>":" -<iiop_prot_addr> = <iiop_id><iiop_addr> -<iiop_id> = <iiop_default> | <iiop_prot_token>":" -<iiop_default> = ":" -<iiop_prot_token> = "iiop" -<iiop_addr> = <version><host>[":"<port>] -<host> = DNS-style Host Name | ip_address -<version> = <major>"."<minor>"@" | empty_string -<port> = number -<major> = number -<minor> = number -<key_string> = for example NameService +<corbaloc> = "corbaloc:"<obj_addr_list>["/"<key_string>] +<obj_addr_list> = [<obj_addr>","]*<obj_addr> +<obj_addr> = <prot_addr> | <future_prot_addr> +<prot_addr> = <rir_prot_addr> | <iiop_prot_addr> +<rir_prot_addr> = <rir_prot_token>":" +<rir_prot_token> = rir +<future_prot_addr> = <future_prot_id><future_prot_addr> +<future_prot_id> = <future_prot_token>":" +<iiop_prot_addr> = <iiop_id><iiop_addr> +<iiop_id> = <iiop_default> | <iiop_prot_token>":" +<iiop_default> = ":" +<iiop_prot_token> = "iiop" +<iiop_addr> = <version><host>[":"<port>] +<host> = <DNS-style Host Name> | <ip_v4_address> | "["<ip_v6_address>"]" +<version> = <major>"."<minor>"@" | empty_string +<port> = number +<major> = number +<minor> = number +<DNS-style Host Name> = string +<ip_v4_address> = string +<ip_v6_address> = string +<key_string> = for example NameService ]]></code> <p>The <c>corbaloc</c> scheme consists of 3 parts:</p> <list type="bulleted"> diff --git a/lib/orber/doc/src/corba.xml b/lib/orber/doc/src/corba.xml index 004c7fb9b0..4a11b271b4 100644 --- a/lib/orber/doc/src/corba.xml +++ b/lib/orber/doc/src/corba.xml @@ -294,7 +294,9 @@ Example: <p>This function returns the object reference for the object id asked for. The remote modifier string has the following format: - <c>"iiop://host:port"</c>.</p> + <c>"iiop://"<host>":"<port></c> where <c><host> = <DNS hostname> | + <IPv4 address> | "["<IPv6 address>"]"</c>. + </p> <p>The <em>configuration</em> context is used to override the global SSL client side <seealso marker="ch_install#config">configuration</seealso>.</p> @@ -322,8 +324,11 @@ Example: <v>ObjectId = string()</v> </type> <desc> - <p>This function returns a list of allowed object id's. The remote modifier - string has the following format: <c>"iiop://host:port"</c>.</p> + <p>This function returns a list of allowed object id's. + The remote modifier string has the following format: + <c>"iiop://"<host>":"<port></c> where <c><host> = <DNS hostname> | + <IPv4 address> | "["<IPv6 address>"]"</c>. + </p> <p>The <em>configuration</em> context is used to override the global SSL client side <seealso marker="ch_install#config">configuration</seealso>.</p> @@ -365,9 +370,11 @@ Example: <p>This function takes a <c>corbaname</c>, <c>corbaloc</c> or an IOR on the external string representation and returns the object reference.</p> <p>To lookup the NameService reference, simply use - <c>"corbaloc:iiop:[email protected]:4001/NameService"</c></p> + <c>"corbaloc:iiop:[email protected]:4001/NameService"</c></p> <p>We can also resolve an object from the NameService by using - <c>"corbaname:iiop:[email protected]:4001/NameService#org/Erlang/MyObj"</c></p> + <c>"corbaname:iiop:[email protected]:4001/NameService#org/Erlang/MyObj"</c></p> + <p>To lookup the NameService reference with an IPv6 address, simply use + <c>"corbaloc:iiop:1.2@[FEC1:0:3:0:0312:44AF:FAB1:3D01]:4001/NameService"</c></p> <p>For more information about <c>corbaname</c> and <c>corbaloc</c>, see the User's Guide (Interoperable Naming Service).</p> <p>The <em>configuration</em> context is used to override the global diff --git a/lib/orber/doc/src/notes.xml b/lib/orber/doc/src/notes.xml index 93dc403c47..141d306740 100644 --- a/lib/orber/doc/src/notes.xml +++ b/lib/orber/doc/src/notes.xml @@ -33,7 +33,46 @@ </header> - <section><title>Orber 3.6.27</title> + <section><title>Orber 3.7</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> The following functions have been corrected so they + work properly with IPv6 addresses. </p> <list> + <item><c>corba:resolve_initial_references_remote/2/3</c></item> + <item><c>corba:list_initial_references_remote/1/2</c></item> + <item><c>corba:string_to_object/1/2</c></item> </list> + <p> + Own Id: OTP-12016</p> + </item> + <item> + <p> A couple of macros were malformed, missing commas: + PROFILEBODY_1_1_TYPEDEF and PROFILEBODY_1_2_TYPEDEF. + Thanks to Vlad Dumitrescu. </p> + <p> + Own Id: OTP-12062</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> It is now possible to add listen interfaces for IPv6 + when orber is default configured for IPv4 and the other + way around. For more information, consult the User's + Guide and the orber module Reference Manual. </p> + <p> + Own Id: OTP-12007</p> + </item> + </list> + </section> + +</section> + +<section><title>Orber 3.6.27</title> <section><title>Fixed Bugs and Malfunctions</title> <list> diff --git a/lib/orber/doc/src/orber.xml b/lib/orber/doc/src/orber.xml index 16781059c7..a182a56972 100644 --- a/lib/orber/doc/src/orber.xml +++ b/lib/orber/doc/src/orber.xml @@ -356,8 +356,8 @@ <v>Type = normal | ssl</v> <v>Port = integer() > 0</v> <v>ConfigurationParameters = [{Key, Value}]</v> - <v>Key = flags | iiop_in_connection_timeout | iiop_max_fragments | iiop_max_in_requests | interceptors | iiop_port | iiop_ssl_port | ssl_server_options</v> - <v>Value = as described in the User's Guide</v> + <v>Key = flags | ip_family | iiop_in_connection_timeout | iiop_max_fragments | iiop_max_in_requests | interceptors | iiop_port | iiop_ssl_port | ssl_server_options</v> + <v>Value = as described in the User's Guide or below</v> <v>Result = {ok, Ref} | {error, Reason} | {'EXCEPTION', #'BAD_PARAM'{}}</v> <v>Ref = #Ref</v> <v>Reason = string()</v> @@ -383,6 +383,9 @@ <item><em>flags</em> - currently it is only possible to override the global setting for the <c>Use Current Interface in IOR</c> and <c>Exclude CodeSet Component</c> flags.</item> + <item><em>ip_family</em> - can be set to <c>inet</c> or <c>inet6</c> and is + used to get a listen interface that uses another IP version than the default + set with flags at startup.</item> <item><em>iiop_port</em> - requires that <c>Use Current Interface in IOR</c> is activated and the supplied <c>Type</c> is <c>normal</c>. If so, exported IOR:s will contain the IIOP port defined by this configuration @@ -390,7 +393,7 @@ <item><em>iiop_ssl_port</em> - almost equivalent to <c>iiop_port</c>. The difference is that <c>Type</c> shall be <c>ssl</c> and that exported IOR:s will contain the IIOP via SSL port defined by this configuration - parameter.</item> + parameter.</item> </list> <p>If it is not possible to add a listener based on the supplied interface and port, the error message is one of the ones described in <c>inet</c> diff --git a/lib/orber/src/Makefile b/lib/orber/src/Makefile index d96350f4d5..398e481138 100644 --- a/lib/orber/src/Makefile +++ b/lib/orber/src/Makefile @@ -194,8 +194,7 @@ ERL_IDL_FLAGS += -pa $(ERL_TOP)/lib/orber/ebin ERL_COMPILE_FLAGS += $(ERL_IDL_FLAGS) \ -I$(ERL_TOP)/lib/orber/include \ +'{parse_transform,sys_pre_attributes}' \ - +'{attribute,insert,app_vsn,"orber_$(ORBER_VSN)"}' \ - -D'ORBVSN="$(ORBER_VSN)"' + +'{attribute,insert,app_vsn,"orber_$(ORBER_VSN)"}' ASN_FLAGS = -bber +der +compact_bit_string +nowarn_unused_record diff --git a/lib/orber/src/corba.erl b/lib/orber/src/corba.erl index 989e84f581..586a02d540 100644 --- a/lib/orber/src/corba.erl +++ b/lib/orber/src/corba.erl @@ -311,19 +311,18 @@ resolve_initial_references_remote(_ObjectId, [], _Ctx) -> raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}); resolve_initial_references_remote(ObjectId, [RemoteModifier| Rest], Ctx) when is_list(RemoteModifier) -> - case lists:prefix("iiop://", RemoteModifier) of - true -> - [_, Host, Port] = string:tokens(RemoteModifier, ":/"), + case parse_remote_modifier(RemoteModifier) of + {error, _} -> + resolve_initial_references_remote(ObjectId, Rest, Ctx); + {ok, Host, Port} -> IOR = iop_ior:create_external(orber:giop_version(), "", - Host, list_to_integer(Port), "INIT"), + Host, list_to_integer(Port), "INIT"), %% We know it's an external referens. Hence, no need to check. {_, Key} = iop_ior:get_key(IOR), orber_iiop:request(Key, 'get', [ObjectId], {{'tk_objref', 12, "object"}, [{'tk_string', 0}], - []}, 'true', infinity, IOR, Ctx); - false -> - resolve_initial_references_remote(ObjectId, Rest, Ctx) + []}, 'true', infinity, IOR, Ctx) end. list_initial_services_remote(Address) -> @@ -332,24 +331,44 @@ list_initial_services_remote(Address) -> list_initial_services_remote([], _Ctx) -> raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}); list_initial_services_remote([RemoteModifier| Rest], Ctx) when is_list(RemoteModifier) -> - case lists:prefix("iiop://", RemoteModifier) of - true -> - [_, Host, Port] = string:tokens(RemoteModifier, ":/"), + case parse_remote_modifier(RemoteModifier) of + {error, _} -> + resolve_initial_references_remote(Rest, Ctx); + {ok, Host, Port} -> IOR = iop_ior:create_external(orber:giop_version(), "", Host, list_to_integer(Port), "INIT"), %% We know it's an external referens. Hence, no need to check. {_, Key} = iop_ior:get_key(IOR), orber_iiop:request(Key, 'list', [], {{'tk_sequence', {'tk_string',0},0}, - [], []}, 'true', infinity, IOR, Ctx); - false -> - list_initial_services_remote(Rest, Ctx) + [], []}, 'true', infinity, IOR, Ctx) end; list_initial_services_remote(_, _) -> raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). +parse_remote_modifier("iiop://" ++ Rest) -> + parse_host_version(Rest); +parse_remote_modifier(_RemoteModifier) -> + {error, not_supported}. + +parse_host_version("[" ++ Rest) -> + parse_ipv6(Rest, []); +parse_host_version(Rest) -> + parse_ipv4_or_dnsname(Rest, []). + + +parse_ipv4_or_dnsname([$: |Rest], Acc) -> + {ok, lists:reverse(Acc), Rest}; +parse_ipv4_or_dnsname([C |Rest], Acc) -> + parse_ipv4_or_dnsname(Rest, [C |Acc]). + +parse_ipv6("]:" ++ Rest, Acc) -> + {ok, lists:reverse(Acc), Rest}; +parse_ipv6([C |Rest], Acc) -> + parse_ipv6(Rest, [C |Acc]). + %%----------------------------------------------------------------- %% Objectreference convertions %%----------------------------------------------------------------- diff --git a/lib/orber/src/corba_request.erl b/lib/orber/src/corba_request.erl deleted file mode 100644 index c4226739a9..0000000000 --- a/lib/orber/src/corba_request.erl +++ /dev/null @@ -1,384 +0,0 @@ -%%-------------------------------------------------------------------- -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1998-2009. All Rights Reserved. -%% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% %CopyrightEnd% -%% -%% -%%----------------------------------------------------------------- -%% File: corba_request.erl -%% Description: -%% This file contains an corba request server for Orber -%% -%%----------------------------------------------------------------- --module(corba_request). - --behaviour(gen_server). - --include_lib("orber/include/corba.hrl"). - -%%----------------------------------------------------------------- -%% External exports -%%----------------------------------------------------------------- --export([start/1, stop/0, stop_all/0, create/1, - create_schema/1]). - -%%----------------------------------------------------------------- -%% Internal exports -%%----------------------------------------------------------------- --export([init/1, terminate/2, install/2, handle_call/3, handle_info/2]). --export([handle_cast/2, dump/0, get_key_from_pid/1]). - -%%----------------------------------------------------------------- -%% Standard interface CORBA::Request -%%----------------------------------------------------------------- --export([add_arg/6, - invoke/2, - delete/1, - send/2, - get_response/2]). - -%%----------------------------------------------------------------- -%% Mnesia table definition -%%----------------------------------------------------------------- --record('corba_request', {reqid, ctx, operation, arg_list, result, req_flags, pid}). - - -%%----------------------------------------------------------------- -%% Macros -%%----------------------------------------------------------------- --define(dirty_query_context, true). - -%% This macro returns a read fun suitable for evaluation in a transaction --define(read_function(ReqId), - fun() -> - mnesia:dirty_read(ReqId) - end). - -%% This macro returns a write fun suitable for evaluation in a transaction --define(write_function(R), - fun() -> - mnesia:dirty_write(R) - end). - -%% This macro returns a write fun suitable for evaluation in a transaction --define(update(R), - fun() -> - mnesia:dirty_write(R) - end). - -%% This macro returns a delete fun suitable for evaluation in a transaction --define(delete_function(R), - fun() -> - mnesia:delete(R) - end). - --ifdef(dirty_query_context). --define(query_check(Q_res), Q_res). --else. --define(query_check(Q_res), {atomic, Q_res}). --endif. - - --define(CHECK_EXCEPTION(Res), case Res of - {'EXCEPTION', E} -> - corba:raise(E); - R -> - R - end). - -%%----------------------------------------------------------------- -%% Debugging function -%%----------------------------------------------------------------- -dump() -> - case catch mnesia:dirty_first('orber_request') of - {'EXIT', R} -> - io:format("Exited with ~p\n",[R]); - Key -> - dump_print(Key), - dump_loop(Key) - end. - -dump_loop(PreviousKey) -> - case catch mnesia:dirty_next('orber_request', PreviousKey) of - {'EXIT', R} -> - io:format("Exited with ~p\n",[R]); - '$end_of_table' -> - ok; - Key -> - dump_print(Key), - dump_loop(Key) - end. - -dump_print(Key) -> - case catch mnesia:dirty_read({'orber_request', Key}) of - {'EXIT', R} -> - io:format("Exited with ~p\n",[R]); - [X] -> - io:format("Req Id: ~p, op: ~p\n",[binary_to_term(X#orber_request.object_key), - X#orber_request.pid]); - _ -> - ok - end. - - -%%----------------------------------------------------------------- -%% External interface functions -%%----------------------------------------------------------------- -start(Opts) -> - gen_server:start_link({local, orber_requestserver}, orber_request, Opts, []). - -stop() -> - gen_server:call(orber_requestserver, stop, infinity). - - -stop_all() -> - Fun = fun() -> - mnesia:match_object({orber_request, '_', '_', '_', '_', '_', '_', '_'}) - end, - case catch mnesia:transaction(Fun) of - {atomic, Objects} -> - lists:foreach(fun({orber_request, _, _, _, _, _, _, _ }) -> - ok %gen_server:call(Pid, stop, infinity) - end, - Objects); - R -> - R - end. - -create() -> - ?CHECK_EXCEPTION(gen_server:call(orber_requestserver, - create, infinity)). - -create(Ctx, OP, Args, Flags) -> - ?CHECK_EXCEPTION(gen_server:call(orber_requestserver, - {create, Ctx, OP, Args, Flags}, infinity)). - -delete(ReqId) -> - ?CHECK_EXCEPTION(gen_server:call(orber_requestserver, - {delete, ReqId}, infinity)). - -%%------------------------------------------------------------ -%% Implementation of standard interface -%%------------------------------------------------------------ -add_arg(ReqId, ArgumentName, TC, Value, Len, ArgFlags) -> - Request = ets:lookup_element(orber_request, ReqId), - case Request of - [] -> - ok; - R -> - Args = Request#orber_request.arg_list, - NewArgs = lists:append(Args, []), - ets:insert(orber_request, NewArgs), - ok - end. - -invoke(ReqId, InvokeFlags) -> - ok. - - - -send(ReqId, InvokeFlags) -> - ok. - -get_response(ReqId, ResponseFlags) -> - [{_, Val}] = ets:lookup_element(orber_request, ReqId), - Val#'orber_request'.result. - -%%----------------------------------------------------------------- -%% Server functions -%%----------------------------------------------------------------- -init(Env) -> - case mnesia:wait_for_tables(['orber_request'], infinity) of - ok -> - process_flag(trap_exit, true), - {ok, []}; - StopReason -> - {stop, StopReason} - end. - -terminate(From, Reason) -> - ok. - - - -install(Timeout, Options) -> - %% check if there already exists a database. If not, create one. - %% DB_initialized = perhaps_create_schema(Nodelist), - %% check if mnesia is running. If not, start mnesia. - DB_started = perhaps_start_mnesia(), - - %% Do we have a complete set of IFR tables? If not, create them. - AllTabs = mnesia:system_info(tables), - - DB_Result = case lists:member(orber_request, AllTabs) of - true -> - case lists:member({local_content, true}, - Options) of - true-> - mnesia:add_table_copy(orber_request, - node(), - ram_copies); - _ -> - mnesia:create_table(orber_request, - [{attributes, - record_info(fields, - orber_objkeys)} - |Options]) - end; - _ -> - mnesia:create_table(orber_request, - [{attributes, - record_info(fields, - orber_objkeys)} - |Options]) - end, - - Wait = mnesia:wait_for_tables([orber_request], Timeout), - %% Check if any error has occured yet. If there are errors, return them. - if - DB_Result == {atomic, ok}, - Wait == ok -> - ok; - true -> - {error, {DB_Result, Wait}} - end. - -%%----------------------------------------------------------------- -%% Func: handle_call/3 -%% -%% Comment: -%% In objectkey gen_server all exceptions are tupples and corba:raise -%% may not be used. It is too time consuming to add catches in every -%% function before returning. On the client side there is a case which -%% maps every tupple on the format {'exception', E} to corba:raise(E). -%%----------------------------------------------------------------- -handle_call(stop, From, State) -> - {stop, normal, [], State}; -handle_call(create, From, State) -> - ReqId = term_to_binary({node(), now()}), - _F = ?write_function(#'corba_request'{reqid=ReqId}), - R = write_result(mnesia:transaction(_F)), - - ReqId - - ?query_check(Qres) = mnesia:dirty_read({orber_request, Objkey}), - case Qres of - [] -> - _F = ?write_function(#orber_requests{object_key=Objkey, pid=Pid}), - R = write_result(mnesia:transaction(_F)), - if - R == ok, pid(Pid) -> - link(Pid); - true -> - true - end, - {reply, R, State}; - X -> - {reply, {'EXCEPTION', #'INTERNAL'{completion_status=?COMPLETED_NO}}, - State} - end; -handle_call({delete, ReqId}, From, State) -> - ?query_check(Qres) = mnesia:dirty_read({orber_request, ReqId}), - case Qres of - [] -> - true; - [X] when pid(X#orber_request.pid) -> - unlink(X#orber_request.pid); - _ -> - true - end, - _F = ?delete_function({orber_request, ReqId}), - R = write_result(mnesia:transaction(_F)), - {reply, R, State}. - -handle_info({'EXIT', Pid, Reason}, State) when pid(Pid) -> - _MF = fun() -> - mnesia:match_object({orber_request, '_', '_', '_', '_', '_', '_', Pid}) - end, - ?query_check(Qres) = mnesia:ets(_MF), - case Qres of - [] -> - true; - X -> - remove_requests(X), - unlink(Pid); - _ -> - true - end, - {noreply, State}. - -%%----------------------------------------------------------------- -%% Internal Functions -%%----------------------------------------------------------------- -get_reqids_from_pid(Pid) -> - case mnesia:dirty_match_object({orber_request, '_', '_', '_', '_', '_', '_', Pid}) of - Keys -> - [Keys] - _ -> - corba:raise(#'OBJECT_NOT_EXIST'{completion_status=?COMPLETED_NO}) - end. - -remove_requests([]) -> - ok; -remove_requests([H|T]) -> - _F = ?delete_function({orber_request, H#orber_request.reqid}), - write_result(mnesia:transaction(_F)), - remove_requests(T). - -%%----------------------------------------------------------------- -%% Check a read transaction -query_result(?query_check(Qres)) -> - case Qres of - [Hres] -> - Hres#orber_request.pid; - [] -> - {'excpetion', #'OBJECT_NOT_EXIST'{completion_status=?COMPLETED_NO}}; - Other -> - {'excpetion', #'INTERNAL'{completion_status=?COMPLETED_NO}} - end. - -%%----------------------------------------------------------------- -%% Check a write transaction -write_result({atomic,ok}) -> ok; -write_result(Foo) -> - {'excpetion', #'INTERNAL'{completion_status=?COMPLETED_NO}}. - - -create_schema(Nodes) -> - case mnesia:system_info(use_dir) of - false -> - mnesia:create_schema(Nodes); - _ -> - ok - end. - -perhaps_start_mnesia() -> - case mnesia:system_info(is_running) of - no -> - mnesia:start(); - _ -> - ok - end. - - -%%------------------------------------------------------------ -%% Standard gen_server cast handle -%% -handle_cast(_, State) -> - {noreply, State}. - - diff --git a/lib/orber/src/orber_env.erl b/lib/orber/src/orber_env.erl index 1c8a90bc81..16dbb74253 100644 --- a/lib/orber/src/orber_env.erl +++ b/lib/orber/src/orber_env.erl @@ -204,9 +204,9 @@ info(IoDevice) -> _ -> lists:flatten( io_lib:format("======= Orber Execution Environment ======~n" - " *** Orber-~s is not running ***~n" + " *** Orber is not running ***~n" "==========================================~n", - [?ORBVSN])) + [])) end, case IoDevice of info_msg -> @@ -223,6 +223,7 @@ info(IoDevice) -> create_main_info() -> {Major, Minor} = giop_version(), + {orber, _, OrberVsn} = lists:keyfind(orber, 1, application:loaded_applications()), [io_lib:format("======= Orber Execution Environment ======~n" "Orber version.................: ~s~n" "Orber domain..................: ~s~n" @@ -257,7 +258,7 @@ create_main_info() -> "Debug Level...................: ~p~n" "orbInitRef....................: ~p~n" "orbDefaultInitRef.............: ~p~n", - [?ORBVSN, domain(), iiop_port(), nat_iiop_port(), host(), + [OrberVsn, domain(), iiop_port(), nat_iiop_port(), host(), nat_host(), ip_address_local(), orber:orber_nodes(), Major, Minor, iiop_timeout(), iiop_connection_timeout(), diff --git a/lib/orber/src/orber_iiop_net.erl b/lib/orber/src/orber_iiop_net.erl index 33e02e3c04..1bfc6b7d58 100644 --- a/lib/orber/src/orber_iiop_net.erl +++ b/lib/orber/src/orber_iiop_net.erl @@ -157,7 +157,7 @@ terminate(_Reason, _State) -> ok. %%----------------------------------------------------------------- -%% Func: parse_options/2 +%% Func: get_options/2 %%----------------------------------------------------------------- get_options(normal, _Options) -> []; @@ -212,14 +212,21 @@ get_options(ssl, Options) -> %%----------------------------------------------------------------- parse_options([{port, Type, Port} | Rest], State) -> Options = get_options(Type, []), - Options2 = case orber_env:ip_address_variable_defined() of - false -> - Options; - Host -> - IPVersion = orber:ip_version(), - {ok, IP} = inet:getaddr(Host, IPVersion), - [{ip, IP} | Options] - end, + Family = orber_env:ip_version(), + IPFamilyOptions = + case Family of + inet -> [inet]; + inet6 -> [inet6, {ipv6_v6only, true}] + end, + Options2 = + case orber_env:ip_address_variable_defined() of + false -> + IPFamilyOptions ++ Options; + Host -> + {ok, IP} = inet:getaddr(Host, Family), + IPFamilyOptions ++ [{ip, IP} |Options] + end, + {ok, Listen, NewPort} = orber_socket:listen(Type, Port, Options2, true), {ok, Pid} = orber_iiop_socketsup:start_accept(Type, Listen, 0), link(Pid), @@ -283,28 +290,33 @@ handle_call({remove, Ref}, _From, State) -> {reply, ok, State} end; handle_call({add, IP, Type, Port, AllOptions}, _From, State) -> - Family = orber_env:ip_version(), + Family = orber_tb:keysearch(ip_family, AllOptions, orber_env:ip_version()), + IPFamilyOptions = + case Family of + inet -> [inet]; + inet6 -> [inet6, {ipv6_v6only, true}] + end, case inet:getaddr(IP, Family) of {ok, IPTuple} -> - try [{ip, IPTuple} |get_options(Type, AllOptions)] of - Options -> - Ref = make_ref(), - ProxyOptions = filter_options(AllOptions, []), - case orber_socket:listen(Type, Port, Options, false) of - {ok, Listen, NewPort} -> - {ok, Pid} = orber_iiop_socketsup:start_accept(Type, Listen, Ref, - ProxyOptions), - link(Pid), - ets:insert(?CONNECTION_DB, #listen{pid = Pid, - socket = Listen, - port = NewPort, - type = Type, ref = Ref, - options = Options, - proxy_options = ProxyOptions}), - {reply, {ok, Ref}, State}; - Error -> - {reply, Error, State} - end + try + Options = IPFamilyOptions ++ [{ip, IPTuple} |get_options(Type, AllOptions)], + Ref = make_ref(), + ProxyOptions = filter_options(AllOptions, []), + case orber_socket:listen(Type, Port, Options, false) of + {ok, Listen, NewPort} -> + {ok, Pid} = orber_iiop_socketsup:start_accept(Type, Listen, Ref, + ProxyOptions), + link(Pid), + ets:insert(?CONNECTION_DB, #listen{pid = Pid, + socket = Listen, + port = NewPort, + type = Type, ref = Ref, + options = Options, + proxy_options = ProxyOptions}), + {reply, {ok, Ref}, State}; + Error -> + {reply, Error, State} + end catch error:Reason -> {reply, {error, Reason}, State} diff --git a/lib/orber/src/orber_iiop_outproxy.erl b/lib/orber/src/orber_iiop_outproxy.erl index 8319d89088..4ba5b05995 100644 --- a/lib/orber/src/orber_iiop_outproxy.erl +++ b/lib/orber/src/orber_iiop_outproxy.erl @@ -112,7 +112,8 @@ stop(Pid) -> %%----------------------------------------------------------------- init({connect, Host, Port, SocketType, SocketOptions, Parent, Key, NewKey}) -> process_flag(trap_exit, true), - case catch orber_socket:connect(SocketType, Host, Port, SocketOptions) of + case catch orber_socket:connect(SocketType, Host, Port, + get_ip_family_opts(Host) ++ SocketOptions) of {'EXCEPTION', _E} -> ignore; %% We used to reply the below but since this would generate a CRASH REPORT @@ -507,3 +508,38 @@ clear_queue(Proxy, RequestId, MRef) -> end end. +get_ip_family_opts(Host) -> + case inet:parse_address(Host) of + {ok, {_,_,_,_}} -> + [inet]; + {ok, {_,_,_,_,_,_,_,_}} -> + [inet6]; + {error, einval} -> + check_family_for_name(Host, orber_env:ip_version()) + end. + +check_family_for_name(Host, inet) -> + case inet:getaddr(Host, inet) of + {ok, _Address} -> + [inet]; + {error, _} -> + case inet:getaddrs(Host, inet6) of + {ok, _Address} -> + [inet6]; + {error, _} -> + [inet] + end + end; +check_family_for_name(Host, inet6) -> + case inet:getaddr(Host, inet6) of + {ok, _Address} -> + [inet6]; + {error, _} -> + case inet:getaddr(Host, inet) of + {ok, _Address} -> + [inet]; + {error, _} -> + [inet6] + end + end. + diff --git a/lib/orber/src/orber_socket.erl b/lib/orber/src/orber_socket.erl index 07a0e09ccc..c8d2f0636b 100644 --- a/lib/orber/src/orber_socket.erl +++ b/lib/orber/src/orber_socket.erl @@ -205,29 +205,27 @@ listen(normal, Port, Options, Exception) -> MaxSize -> [{packet_size, MaxSize}|Options2] end, - case catch gen_tcp:listen(Port, [binary, {packet,cdr}, {keepalive, Keepalive}, + Options4 = [binary, {packet,cdr}, {keepalive, Keepalive}, {reuseaddr,true}, {backlog, Backlog} | - Options3]) of + Options3], + + case catch gen_tcp:listen(Port, Options4) of {ok, ListenSocket} -> {ok, ListenSocket, check_port(Port, normal, ListenSocket)}; {error, Reason} when Exception == false -> {error, Reason}; {error, eaddrinuse} -> - AllOpts = [binary, {packet,cdr}, - {reuseaddr,true} | Options3], orber:dbg("[~p] orber_socket:listen(normal, ~p, ~p);~n" "Looks like the listen port is already in use.~n" "Check if another Orber is started~n" "on the same node and uses the same listen port (iiop_port). But it may also~n" "be used by any other application; confirm with 'netstat'.", - [?LINE, Port, AllOpts], ?DEBUG_LEVEL), + [?LINE, Port, Options4], ?DEBUG_LEVEL), corba:raise(#'COMM_FAILURE'{completion_status=?COMPLETED_NO}); Error -> - AllOpts = [binary, {packet,cdr}, - {reuseaddr,true} | Options3], orber:dbg("[~p] orber_socket:listen(normal, ~p, ~p);~n" "Failed with reason: ~p", - [?LINE, Port, AllOpts, Error], ?DEBUG_LEVEL), + [?LINE, Port, Options4, Error], ?DEBUG_LEVEL), corba:raise(#'COMM_FAILURE'{completion_status=?COMPLETED_NO}) end; listen(ssl, Port, Options, Exception) -> @@ -252,26 +250,24 @@ listen(ssl, Port, Options, Exception) -> true -> Options3 end, - case catch ssl:listen(Port, [binary, {packet,cdr}, - {backlog, Backlog} | Options4]) of + Options5 = [binary, {packet,cdr}, {backlog, Backlog} | Options4], + case catch ssl:listen(Port, Options5) of {ok, ListenSocket} -> {ok, ListenSocket, check_port(Port, ssl, ListenSocket)}; {error, Reason} when Exception == false -> {error, Reason}; {error, eaddrinuse} -> - AllOpts = [binary, {packet,cdr} | Options4], orber:dbg("[~p] orber_socket:listen(ssl, ~p, ~p);~n" "Looks like the listen port is already in use. Check if~n" "another Orber is started on the same node and uses the~n" "same listen port (iiop_port). But it may also~n" "be used by any other application; confirm with 'netstat'.", - [?LINE, Port, AllOpts], ?DEBUG_LEVEL), + [?LINE, Port, Options5], ?DEBUG_LEVEL), corba:raise(#'COMM_FAILURE'{completion_status=?COMPLETED_NO}); Error -> - AllOpts = [binary, {packet,cdr} | Options4], orber:dbg("[~p] orber_socket:listen(ssl, ~p, ~p);~n" "Failed with reason: ~p", - [?LINE, Port, AllOpts, Error], ?DEBUG_LEVEL), + [?LINE, Port, Options5, Error], ?DEBUG_LEVEL), corba:raise(#'COMM_FAILURE'{completion_status=?COMPLETED_NO}) end. @@ -485,16 +481,14 @@ check_port(Port, _, _) -> %%----------------------------------------------------------------- %% Check Options. check_options(normal, Options, _Generation) -> - [orber:ip_version()|Options]; + Options; check_options(ssl, Options, Generation) -> - case orber:ip_version() of - inet when Generation > 2 -> + if + Generation > 2 -> [{ssl_imp, new}|Options]; - inet -> - [{ssl_imp, old}|Options]; - inet6 when Generation > 2 -> - [{ssl_imp, new}, inet6|Options]; - inet6 -> - [{ssl_imp, old}, inet6|Options] + true -> + [{ssl_imp, old}|Options] end. + + diff --git a/lib/orber/test/Makefile b/lib/orber/test/Makefile index 2f8777c773..50be14c24a 100644 --- a/lib/orber/test/Makefile +++ b/lib/orber/test/Makefile @@ -73,7 +73,8 @@ MODULES = \ orber_firewall_ipv6_in_SUITE \ orber_firewall_ipv4_out_SUITE \ orber_firewall_ipv6_out_SUITE \ - orber_nat_SUITE + orber_nat_SUITE \ + ip_v4v6_interop_SUITE GEN_MOD_ORBER = \ oe_orber_test \ diff --git a/lib/orber/test/ip_v4v6_interop_SUITE.erl b/lib/orber/test/ip_v4v6_interop_SUITE.erl new file mode 100644 index 0000000000..5eee5a29c2 --- /dev/null +++ b/lib/orber/test/ip_v4v6_interop_SUITE.erl @@ -0,0 +1,199 @@ +%%---------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%%---------------------------------------------------------------------- +%% File : ip_v4v6_interop_SUITE.erl +%% Description : +%% +%%---------------------------------------------------------------------- +-module(ip_v4v6_interop_SUITE). + +-compile(export_all). +%%---------------------------------------------------------------------- +%% External exports +%%---------------------------------------------------------------------- +-export([ + all/0, + init_per_suite/1, + end_per_suite/1, + init_per_testcase/2, + end_per_testcase/2, + groups/0, + init_per_group/2, + end_per_group/2 + ]). +%%----------------------------------------------------------------- +%% Internal exports +%%----------------------------------------------------------------- +-export([]). + +%%---------------------------------------------------------------------- +%% Include files +%%---------------------------------------------------------------------- +-include_lib("test_server/include/test_server.hrl"). +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/COSS/CosNaming/CosNaming.hrl"). +-include_lib("orber/src/orber_iiop.hrl"). +-include_lib("orber/src/ifr_objects.hrl"). +-include("idl_output/orber_test_server.hrl"). +-include_lib("orber/COSS/CosNaming/CosNaming_NamingContextExt.hrl"). +-include_lib("orber/COSS/CosNaming/CosNaming_NamingContext.hrl"). + +%%---------------------------------------------------------------------- +%% Macros +%%---------------------------------------------------------------------- +-define(default_timeout, ?t:minutes(15)). + +-define(match(ExpectedRes,Expr), + fun() -> + AcTuAlReS = (catch (Expr)), + case AcTuAlReS of + ExpectedRes -> + io:format("------ CORRECT RESULT ------~n~p~n", + [AcTuAlReS]), + AcTuAlReS; + _ -> + io:format("###### ERROR ERROR ######~nRESULT: ~p~n", + [AcTuAlReS]), + ?line exit(AcTuAlReS) + end + end()). +%%---------------------------------------------------------------------- +%% Records +%%---------------------------------------------------------------------- + +%%====================================================================== +%% Initialization functions. +%%====================================================================== + +init_per_testcase(_Case, Config) -> + %% Starting dual configured ORB + orber:jump_start([{iiop_port, 10001}, {flags, 16#1000}]), + orber:info(), + Dog=test_server:timetrap(?default_timeout), + [{watchdog, Dog}|Config]. + + +end_per_testcase(_Case, Config) -> + orber:jump_stop(), + Dog = ?config(watchdog, Config), + test_server:timetrap_cancel(Dog), + ok. + +init_per_suite(Config) -> + Config. + +end_per_suite(Config) -> + Config. + +%%==================================================================== +%% SUITE specification +%%==================================================================== +all() -> + [ + dual_ipv4v6 + ]. + +suite() -> [{ct_hooks,[ts_install_cth]}]. + + +groups() -> + []. + +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. + +%%==================================================================== +%% Test Cases +%%==================================================================== +dual_ipv4v6(doc) -> + ["ORB configured for supporting both IPv4 and IPv6"]; +dual_ipv4v6(_Config) -> + + %% Starting slave node with ipv4 configured ORB + {ok, Ipv4Node, _Ipv4Host} = + ?match({ok,_,_}, orber_test_lib:js_node([{iiop_port, 4001}])), + Ipv4NS = orber_test_lib:remote_apply(Ipv4Node, corba, resolve_initial_references, ["NameService"]), + + %% Starting slave node with ipv6 configured ORB + {ok, Ipv6Node, _Ipv6Host} = + ?match({ok,_,_}, orber_test_lib:js_node([{iiop_port, 6001}, {flags, 16#0100}])), + Ipv6NS = orber_test_lib:remote_apply(Ipv6Node, corba, resolve_initial_references, ["NameService"]), + + %% Add the ipv6 interface in the dual configured ORB + ?match({ok, _}, orber:add_listen_interface("::1", normal, + [{ip_family, inet6}, {iiop_port, 10002}])), + DualNS = corba:resolve_initial_references("NameService"), + + %% Bind IPv4 NameServer to a name in the dual stack orbs NameServer + NSDual4 = orber_test_lib:remote_apply(Ipv4Node, corba, resolve_initial_references_remote, + ["NameService", ["iiop://127.0.0.1:10001"]]), + ?match(ok, orber_test_lib:remote_apply(Ipv4Node, 'CosNaming_NamingContext', bind, + [NSDual4, lname:new(["ns4"]), Ipv4NS])), + 'CosNaming_NamingContext':resolve(DualNS, lname:new(["ns4"])), + + %% Bind IPv6 NameServer to a name in the dual stack orbs NameServer + NSDual6 = orber_test_lib:remote_apply(Ipv6Node, corba, resolve_initial_references_remote, + ["NameService", ["iiop://[::1]:10002"]]), + ?match(ok, orber_test_lib:remote_apply(Ipv6Node, 'CosNaming_NamingContext', bind, + [NSDual6, lname:new(["ns6"]), Ipv6NS])), + 'CosNaming_NamingContext':resolve(DualNS, lname:new(["ns6"])), + + %% IPv4: Fetch IPv6 NS reference from dual stack orber and register own NameServer in that + Ipv4NSO = orber_test_lib:remote_apply(Ipv4Node, 'CosNaming_NamingContext', resolve, + [NSDual4, lname:new(["ns6"])]), + ?match(ok, orber_test_lib:remote_apply(Ipv4Node, 'CosNaming_NamingContext', bind, + [Ipv4NSO, lname:new(["nso"]), Ipv4NS])), + + %% IPv6: Fetch IPv4 NS reference from dual stack orber and register own NameServer in that + Ipv6NSO = orber_test_lib:remote_apply(Ipv6Node, 'CosNaming_NamingContext', resolve, + [NSDual6, lname:new(["ns4"])]), + ?match(ok, orber_test_lib:remote_apply(Ipv6Node, 'CosNaming_NamingContext', bind, + [Ipv6NSO, lname:new(["nso"]), Ipv6NS])), + + + %% IPv4: Fetch own NS reference from IPv6 NameServer and add a context then check that everything went well + Ipv4NSFromIpv6 = orber_test_lib:remote_apply(Ipv6Node, 'CosNaming_NamingContext', resolve, + [Ipv6NS, lname:new(["nso"])]), + _Ipv4NC = orber_test_lib:remote_apply(Ipv4Node, 'CosNaming_NamingContext', bind_new_context, + [Ipv4NSFromIpv6, lname:new(["test_context4"])]), + + %% IPv6: Fetch own NS reference from IPv4 NameServer and add a context then check that everything went well + Ipv6NSFromIpv4 = orber_test_lib:remote_apply(Ipv4Node, 'CosNaming_NamingContext', resolve, + [Ipv4NS, lname:new(["nso"])]), + _Ipv6NC = orber_test_lib:remote_apply(Ipv6Node, 'CosNaming_NamingContext', bind_new_context, + [Ipv6NSFromIpv4, lname:new(["test_context6"])]), + + %% Check that all the names are register correctly + {ok,DualNames,_} = 'CosNaming_NamingContext':list(DualNS, 100), + {ok,Ipv4Names,_} = orber_test_lib:remote_apply(Ipv4Node, 'CosNaming_NamingContext', list, [Ipv4NS, 100]), + {ok,Ipv6Names,_} = orber_test_lib:remote_apply(Ipv6Node, 'CosNaming_NamingContext', list, [Ipv6NS, 100]), + + io:format("\nNames in Dual NS: ~p\n", [DualNames]), + ?match(2, length(DualNames)), + io:format("\nNames in IPv4 NS: ~p\n", [Ipv4Names]), + ?match(2, length(Ipv4Names)), + io:format("\nNames in IPv6 NS: ~p\n", [Ipv6Names]), + ?match(2, length(Ipv6Names)), + + ok. + diff --git a/lib/orber/test/multi_ORB_SUITE.erl b/lib/orber/test/multi_ORB_SUITE.erl index 41a309ff16..40d8846e0f 100644 --- a/lib/orber/test/multi_ORB_SUITE.erl +++ b/lib/orber/test/multi_ORB_SUITE.erl @@ -582,12 +582,12 @@ proxy_interface_ipv6_api2() -> IOR1 = ?match(#'IOP_IOR'{}, orber_test_lib:remote_apply(ClientNode, corba, string_to_object, - ["corbaloc::1.2@"++IP++":"++integer_to_list(ServerPort)++"/NameService"])), + ["corbaloc::1.2@["++IP++"]:"++integer_to_list(ServerPort)++"/NameService"])), ?match({'external', {IP, ServerPort, _ObjectKey, _Counter, _TP, _NewHD}}, orber_test_lib:remote_apply(ClientNode, iop_ior, get_key, [IOR1])), IOR2 = ?match(#'IOP_IOR'{}, orber_test_lib:remote_apply(ClientNode, corba, string_to_object, - ["corbaloc::1.2@"++Loopback++":"++integer_to_list(ServerPort)++"/NameService"])), + ["corbaloc::1.2@["++Loopback++"]:"++integer_to_list(ServerPort)++"/NameService"])), ?match({'external', {Loopback, ServerPort, _ObjectKey, _Counter, _TP, _NewHD}}, orber_test_lib:remote_apply(ClientNode, iop_ior, get_key, [IOR2])), ok. diff --git a/lib/orber/test/orber_firewall_ipv6_in_SUITE.erl b/lib/orber/test/orber_firewall_ipv6_in_SUITE.erl index 10827b6ef5..2853949a49 100644 --- a/lib/orber/test/orber_firewall_ipv6_in_SUITE.erl +++ b/lib/orber/test/orber_firewall_ipv6_in_SUITE.erl @@ -188,6 +188,7 @@ allow_port_range_api(_Config) -> ?ORB_ENV_USE_ACL_INCOMING)}, {iiop_acl, [{tcp_in, IP++"/128#5980/6000"}]}])), ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []), + io:format("ServerNode: ~p\nServerHost: ~p\n", [ServerNode, ServerHost]), IOR = ?match({'IOP_IOR',_,_}, corba:string_to_object("corbaloc::1.2@"++ServerHost++":"++integer_to_list(ServerPort)++"/NameService")), @@ -243,34 +244,34 @@ check_address_api(doc) -> ["Test corbaloc strings"]; check_address_api(suite) -> []; check_address_api(_Config) -> ?match({[[iiop,{1,0},"0:0:0:0:0:FFFF:C02A:2A2A",2809]],"NameService"}, - orber_cosnaming_utils:addresses(":0:0:0:0:0:FFFF:C02A:2A2A/NameService")), + orber_cosnaming_utils:addresses(":[0:0:0:0:0:FFFF:C02A:2A2A]/NameService")), ?match({[[iiop,{1,0},"0:0:0:0:0:FFFF:C02A:2A2A",2809]],[]}, - orber_cosnaming_utils:addresses(":0:0:0:0:0:FFFF:C02A:2A2A")), + orber_cosnaming_utils:addresses(":[0:0:0:0:0:FFFF:C02A:2A2A]")), ?match({[[iiop,{1,2},"0:0:0:0:0:FFFF:C02A:2A2A",2809]],"NameService"}, - orber_cosnaming_utils:addresses(":1.2@0:0:0:0:0:FFFF:C02A:2A2A/NameService")), + orber_cosnaming_utils:addresses(":1.2@[0:0:0:0:0:FFFF:C02A:2A2A]/NameService")), ?match({[[iiop,{1,0},"0:0:0:0:0:FFFF:C02A:2A2A",4001]],"NameService"}, - orber_cosnaming_utils:addresses(":0:0:0:0:0:FFFF:C02A:2A2A:4001/NameService")), + orber_cosnaming_utils:addresses(":[0:0:0:0:0:FFFF:C02A:2A2A]:4001/NameService")), ?match({[[iiop,{1,1},"0:0:0:0:0:FFFF:C02A:2A2A",4001]],"NameService"}, - orber_cosnaming_utils:addresses(":1.1@0:0:0:0:0:FFFF:C02A:2A2A:4001/NameService")), + orber_cosnaming_utils:addresses(":1.1@[0:0:0:0:0:FFFF:C02A:2A2A]:4001/NameService")), ?match({[[iiop,{1,1},"0:0:0:0:0:FFFF:C02A:2A2A",4001]],[]}, - orber_cosnaming_utils:addresses(":1.1@0:0:0:0:0:FFFF:C02A:2A2A:4001")), + orber_cosnaming_utils:addresses(":1.1@[0:0:0:0:0:FFFF:C02A:2A2A]:4001")), ?match({[[iiop,{1,1},"0:0:0:0:0:FFFF:C02A:2A2A",4001]],[]}, - orber_cosnaming_utils:addresses("iiop:1.1@0:0:0:0:0:FFFF:C02A:2A2A:4001")), + orber_cosnaming_utils:addresses("iiop:1.1@[0:0:0:0:0:FFFF:C02A:2A2A]:4001")), ?match({[[iiop,{1,0},"0:0:0:0:0:FFFF:10.11.11.11",2809]],"NameService"}, - orber_cosnaming_utils:addresses(":0:0:0:0:0:FFFF:10.11.11.11/NameService")), + orber_cosnaming_utils:addresses(":[0:0:0:0:0:FFFF:10.11.11.11]/NameService")), ?match({[[iiop,{1,0},"0:0:0:0:0:FFFF:10.11.11.11",2809]],[]}, - orber_cosnaming_utils:addresses(":0:0:0:0:0:FFFF:10.11.11.11")), + orber_cosnaming_utils:addresses(":[0:0:0:0:0:FFFF:10.11.11.11]")), ?match({[[iiop,{1,2},"0:0:0:0:0:FFFF:10.11.11.11",2809]],"NameService"}, - orber_cosnaming_utils:addresses(":1.2@0:0:0:0:0:FFFF:10.11.11.11/NameService")), + orber_cosnaming_utils:addresses(":1.2@[0:0:0:0:0:FFFF:10.11.11.11]/NameService")), ?match({[[iiop,{1,0},"0:0:0:0:0:FFFF:10.11.11.11",4001]],"NameService"}, - orber_cosnaming_utils:addresses(":0:0:0:0:0:FFFF:10.11.11.11:4001/NameService")), + orber_cosnaming_utils:addresses(":[0:0:0:0:0:FFFF:10.11.11.11]:4001/NameService")), ?match({[[iiop,{1,1},"0:0:0:0:0:FFFF:10.11.11.11",4001]],"NameService"}, - orber_cosnaming_utils:addresses(":1.1@0:0:0:0:0:FFFF:10.11.11.11:4001/NameService")), + orber_cosnaming_utils:addresses(":1.1@[0:0:0:0:0:FFFF:10.11.11.11]:4001/NameService")), ?match({[[iiop,{1,1},"0:0:0:0:0:FFFF:10.11.11.11",4001]],[]}, - orber_cosnaming_utils:addresses(":1.1@0:0:0:0:0:FFFF:10.11.11.11:4001/")), + orber_cosnaming_utils:addresses(":1.1@[0:0:0:0:0:FFFF:10.11.11.11]:4001/")), ?match({[[iiop,{1,1},"0:0:0:0:0:FFFF:10.11.11.11",4001]],[]}, - orber_cosnaming_utils:addresses("iiop:1.1@0:0:0:0:0:FFFF:10.11.11.11:4001/")), + orber_cosnaming_utils:addresses("iiop:1.1@[0:0:0:0:0:FFFF:10.11.11.11]:4001/")), ?match({[[iiop,{1,1},"myhost",4001]],[]}, orber_cosnaming_utils:addresses("iiop:1.1@myhost:4001")), @@ -282,31 +283,31 @@ check_address_api(_Config) -> ?match({[[iiop,{1,1},"0:0:0:0:0:FFFF:10.11.11.11",4001], [iiop,{1,1},"0:0:0:0:0:FFFF:C02A:2A2A",4001]], "NameService"}, - orber_cosnaming_utils:addresses(":1.1@0:0:0:0:0:FFFF:10.11.11.11:4001,:1.1@0:0:0:0:0:FFFF:C02A:2A2A:4001/NameService")), + orber_cosnaming_utils:addresses(":1.1@[0:0:0:0:0:FFFF:10.11.11.11]:4001,:1.1@[0:0:0:0:0:FFFF:C02A:2A2A]:4001/NameService")), ?match({[[iiop,{1,1},"0:0:0:0:0:FFFF:10.11.11.11",4001], [iiop,{1,1},"0:0:0:0:0:FFFF:C02A:2A2A",4001]], []}, - orber_cosnaming_utils:addresses(":1.1@0:0:0:0:0:FFFF:10.11.11.11:4001,:1.1@0:0:0:0:0:FFFF:C02A:2A2A:4001")), + orber_cosnaming_utils:addresses(":1.1@[0:0:0:0:0:FFFF:10.11.11.11]:4001,:1.1@[0:0:0:0:0:FFFF:C02A:2A2A]:4001")), ?match({[[iiop,{1,0},"0:0:0:0:0:FFFF:10.11.11.11",4001], [iiop,{1,1},"0:0:0:0:0:FFFF:C02A:2A2A",4001]], "NameService"}, - orber_cosnaming_utils:addresses(":0:0:0:0:0:FFFF:10.11.11.11:4001,:1.1@0:0:0:0:0:FFFF:C02A:2A2A:4001/NameService")), + orber_cosnaming_utils:addresses(":[0:0:0:0:0:FFFF:10.11.11.11]:4001,:1.1@[0:0:0:0:0:FFFF:C02A:2A2A]:4001/NameService")), ?match({[[iiop,{1,1},"0:0:0:0:0:FFFF:10.11.11.11",4001], [iiop,{1,0},"0:0:0:0:0:FFFF:C02A:2A2A",4001]], "NameService"}, - orber_cosnaming_utils:addresses(":1.1@0:0:0:0:0:FFFF:10.11.11.11:4001,:0:0:0:0:0:FFFF:C02A:2A2A:4001/NameService")), + orber_cosnaming_utils:addresses(":1.1@[0:0:0:0:0:FFFF:10.11.11.11]:4001,:[0:0:0:0:0:FFFF:C02A:2A2A]:4001/NameService")), ?match({[[iiop,{1,1},"0:0:0:0:0:FFFF:10.11.11.11",2809], [iiop,{1,1},"0:0:0:0:0:FFFF:C02A:2A2A",4001]], "NameService"}, - orber_cosnaming_utils:addresses(":1.1@0:0:0:0:0:FFFF:10.11.11.11,:1.1@0:0:0:0:0:FFFF:C02A:2A2A:4001/NameService")), + orber_cosnaming_utils:addresses(":1.1@[0:0:0:0:0:FFFF:10.11.11.11],:1.1@[0:0:0:0:0:FFFF:C02A:2A2A]:4001/NameService")), ?match({[[iiop,{1,1},"0:0:0:0:0:FFFF:10.11.11.11",4001], [iiop,{1,1},"0:0:0:0:0:FFFF:C02A:2A2A",2809]], "NameService"}, - orber_cosnaming_utils:addresses(":1.1@0:0:0:0:0:FFFF:10.11.11.11:4001,:1.1@0:0:0:0:0:FFFF:C02A:2A2A/NameService")), + orber_cosnaming_utils:addresses(":1.1@[0:0:0:0:0:FFFF:10.11.11.11]:4001,:1.1@[0:0:0:0:0:FFFF:C02A:2A2A]/NameService")), ?match({[[iiop,{1,0},"0:0:0:0:0:FFFF:10.11.11.11",2809], [iiop,{1,0},"0:0:0:0:0:FFFF:C02A:2A2A",2809]], "NameService"}, - orber_cosnaming_utils:addresses(":0:0:0:0:0:FFFF:10.11.11.11,:0:0:0:0:0:FFFF:C02A:2A2A/NameService")), + orber_cosnaming_utils:addresses(":[0:0:0:0:0:FFFF:10.11.11.11],:[0:0:0:0:0:FFFF:C02A:2A2A]/NameService")), ?match({[[iiop,{1,0},"0:0:0:0:0:FFFF:10.11.11.11",2809], [iiop,{1,0},"0:0:0:0:0:FFFF:C02A:2A2A",2809]], []}, - orber_cosnaming_utils:addresses(":0:0:0:0:0:FFFF:10.11.11.11,:0:0:0:0:0:FFFF:C02A:2A2A/")), + orber_cosnaming_utils:addresses(":[0:0:0:0:0:FFFF:10.11.11.11],:[0:0:0:0:0:FFFF:C02A:2A2A]/")), ?match({[[iiop,{1,0},"0:0:0:0:0:FFFF:10.11.11.11",2809], [iiop,{1,0},"0:0:0:0:0:FFFF:C02A:2A2A",2809]], []}, - orber_cosnaming_utils:addresses("iiop:0:0:0:0:0:FFFF:10.11.11.11,:0:0:0:0:0:FFFF:C02A:2A2A/")), + orber_cosnaming_utils:addresses("iiop:[0:0:0:0:0:FFFF:10.11.11.11],:[0:0:0:0:0:FFFF:C02A:2A2A]/")), [IP] = ?match([_], orber:host()), {ok, ServerNode, _ServerHost} = @@ -315,7 +316,7 @@ check_address_api(_Config) -> {iiop_acl, [{tcp_in, IP++"/128"}]}])), ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []), ?match({'IOP_IOR',_,_}, - corba:string_to_object("corbaloc::1.2@"++IP++":"++integer_to_list(ServerPort)++"/NameService")), + corba:string_to_object("corbaloc::1.2@["++IP++"]:"++integer_to_list(ServerPort)++"/NameService")), % ?line catch orber_test_lib:destroy_node(ServerNode, timeout), ok. diff --git a/lib/orber/test/orber_test_lib.erl b/lib/orber/test/orber_test_lib.erl index 6824d25aef..46ed26f210 100644 --- a/lib/orber/test/orber_test_lib.erl +++ b/lib/orber/test/orber_test_lib.erl @@ -166,7 +166,7 @@ get_host(Family) -> {6, _, _} when Family == inet -> "127.0.0.1"; {6, _, _} -> - "0:0:0:0:0:FFFF:7F00:0001"; + "0:0:0:0:0:0:0:0001"; _ -> [IP] = ?match([_], orber:host()), IP @@ -192,16 +192,16 @@ get_loopback_interface(Family) -> {6, _, _} when Family == inet -> "127.0.0.2"; {6, _, _} -> - "0:0:0:0:0:FFFF:7F00:0002"; + "0:0:0:0:0:0:0:0002"; _ when Family == inet -> "127.0.0.1"; _ -> - "0:0:0:0:0:FFFF:7F00:0001" + "0:0:0:0:0:0:0:0001" end; _ when Family == inet -> "127.0.0.1"; _ -> - "0:0:0:0:0:FFFF:7F00:0001" + "0:0:0:0:0:0:0:0001" end. %%------------------------------------------------------------ diff --git a/lib/orber/vsn.mk b/lib/orber/vsn.mk index 3ea64b1ff6..13bdf55c07 100644 --- a/lib/orber/vsn.mk +++ b/lib/orber/vsn.mk @@ -1,2 +1,2 @@ -ORBER_VSN = 3.6.27 +ORBER_VSN = 3.7 diff --git a/lib/os_mon/doc/src/disksup.xml b/lib/os_mon/doc/src/disksup.xml index c8566d0126..0e76178edb 100644 --- a/lib/os_mon/doc/src/disksup.xml +++ b/lib/os_mon/doc/src/disksup.xml @@ -81,7 +81,8 @@ necessary on embedded systems with stripped-down versions of Unix tools like <c>df</c>. The returned disk data and alarms can be different when using this option.</p> - <p>The parameter is ignored on Windows.</p> + <p>The parameter is ignored on platforms that are known to not be + posix compatible (Windows and SunOS).</p> </item> </taglist> <p>See <seealso marker="kernel:config">config(4)</seealso> for diff --git a/lib/os_mon/src/disksup.erl b/lib/os_mon/src/disksup.erl index 3fd80f2365..af5bcc6fe8 100644 --- a/lib/os_mon/src/disksup.erl +++ b/lib/os_mon/src/disksup.erl @@ -211,14 +211,14 @@ format_status(_Opt, [_PDict, #state{os = OS, threshold = Threshold, get_os(PosixOnly) -> case os:type() of - {unix, _} when PosixOnly -> - {unix, posix}; {unix, sunos} -> - case os:version() of + case os:version() of {5,_,_} -> {unix, solaris}; {4,_,_} -> {unix, sunos4}; V -> exit({unknown_os_version, V}) - end; + end; + {unix, _} when PosixOnly -> + {unix, posix}; {unix, irix64} -> {unix, irix}; OS -> OS diff --git a/lib/os_mon/test/disksup_SUITE.erl b/lib/os_mon/test/disksup_SUITE.erl index 2f62564959..f9addd96cf 100644 --- a/lib/os_mon/test/disksup_SUITE.erl +++ b/lib/os_mon/test/disksup_SUITE.erl @@ -49,7 +49,8 @@ init_per_testcase(_Case, Config) -> Dog = ?t:timetrap(?default_timeout), [{watchdog,Dog} | Config]. -end_per_testcase(unavailable, Config) -> +end_per_testcase(TC, Config) when TC =:= unavailable; + TC =:= posix_only -> restart(Config), end_per_testcase(dummy, Config); end_per_testcase(_Case, Config) -> @@ -61,11 +62,10 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> Bugs = [otp_5910], + Always = [api, config, alarm, port, posix_only, unavailable] ++ Bugs, case test_server:os_type() of - {unix, sunos} -> - [api, config, alarm, port, unavailable, posix_only] ++ Bugs; - {unix, _OSname} -> [api, alarm, posix_only] ++ Bugs; - {win32, _OSname} -> [api, alarm, posix_only] ++ Bugs; + {unix, _OSname} -> Always; + {win32, _OSname} -> Always; _OS -> [unavailable] end. @@ -336,6 +336,7 @@ restart(suite) -> []; restart(Config) when is_list(Config) -> ok = application:set_env(os_mon, start_disksup, true), + ok = application:set_env(os_mon, disksup_posix_only, false), {ok, _Pid} = supervisor:restart_child(os_mon_sup, disksup), ok. @@ -409,13 +410,7 @@ posix_only(Config) when is_list(Config) -> ok = supervisor:terminate_child(os_mon_sup, disksup), {ok, _Child1} = supervisor:restart_child(os_mon_sup, disksup), - ok = check_get_disk_data(), - - %% Reset option and restart disksup - ok = application:set_env(os_mon, disksup_posix_only, false), - ok = supervisor:terminate_child(os_mon_sup, disksup), - {ok, _Child2} = supervisor:restart_child(os_mon_sup, disksup), - ok. + ok = check_get_disk_data(). dump_info() -> io:format("Status: ~p~n", [sys:get_status(disksup)]). diff --git a/lib/public_key/asn1/OTP-PKIX.asn1 b/lib/public_key/asn1/OTP-PKIX.asn1 index 8d3c76adf5..37196bb9bf 100644 --- a/lib/public_key/asn1/OTP-PKIX.asn1 +++ b/lib/public_key/asn1/OTP-PKIX.asn1 @@ -452,23 +452,23 @@ SupportedPublicKeyAlgorithms PUBLIC-KEY-ALGORITHM-CLASS ::= { ecdsa-with-sha1 SIGNATURE-ALGORITHM-CLASS ::= { ID ecdsa-with-SHA1 - TYPE NULL } -- XXX Must be empty and not NULL + TYPE EcpkParameters } -- XXX Must be empty and not NULL ecdsa-with-sha224 SIGNATURE-ALGORITHM-CLASS ::= { ID ecdsa-with-SHA224 - TYPE NULL } -- XXX Must be empty and not NULL + TYPE EcpkParameters } -- XXX Must be empty and not NULL ecdsa-with-sha256 SIGNATURE-ALGORITHM-CLASS ::= { ID ecdsa-with-SHA256 - TYPE NULL } -- XXX Must be empty and not NULL + TYPE EcpkParameters } -- XXX Must be empty and not NULL ecdsa-with-sha384 SIGNATURE-ALGORITHM-CLASS ::= { ID ecdsa-with-SHA384 - TYPE NULL } -- XXX Must be empty and not NULL + TYPE EcpkParameters } -- XXX Must be empty and not NULL ecdsa-with-sha512 SIGNATURE-ALGORITHM-CLASS ::= { ID ecdsa-with-SHA512 - TYPE NULL } -- XXX Must be empty and not NULL + TYPE EcpkParameters } -- XXX Must be empty and not NULL FIELD-ID-CLASS ::= CLASS { &id OBJECT IDENTIFIER UNIQUE, diff --git a/lib/public_key/doc/src/cert_records.xml b/lib/public_key/doc/src/cert_records.xml index 397c13b463..d1293d12b8 100644 --- a/lib/public_key/doc/src/cert_records.xml +++ b/lib/public_key/doc/src/cert_records.xml @@ -36,8 +36,9 @@ <p>This chapter briefly describes erlang records derived from ASN1 specifications used to handle <c> X509 certificates</c> and <c>CertificationRequest</c>. - The intent is to describe the data types and not to specify the meaning of each - component for this we refer you to <url + The intent is to describe the data types +and not to specify the semantics of each component. For information on the +semantics, please see <url href="http://www.ietf.org/rfc/rfc5280.txt">RFC 5280</url> and <url href="http://www.ietf.org/rfc/rfc5967.txt">PKCS-10</url>. </p> diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml index 8e93f562d4..f8011cd5c0 100644 --- a/lib/public_key/doc/src/public_key.xml +++ b/lib/public_key/doc/src/public_key.xml @@ -75,7 +75,7 @@ <p><em>Data Types </em></p> - <p><code>oid() - a tuple of integers as generated by the ASN1 compiler.</code></p> + <p><code>oid() - Object Identifier, a tuple of integers as generated by the ASN1 compiler.</code></p> <p><code>boolean() = true | false</code></p> diff --git a/lib/public_key/doc/src/public_key_records.xml b/lib/public_key/doc/src/public_key_records.xml index 13bb996f7f..d3534846fa 100644 --- a/lib/public_key/doc/src/public_key_records.xml +++ b/lib/public_key/doc/src/public_key_records.xml @@ -5,7 +5,7 @@ <header> <copyright> <year>2008</year> - <year>2013</year> + <year>2014</year> <holder>Ericsson AB, All Rights Reserved</holder> </copyright> <legalnotice> @@ -35,17 +35,27 @@ </header> <p>This chapter briefly describes Erlang records derived from ASN1 - specifications used to handle public and private keys. The intent - is to describe the data types and not to specify the meaning of - each component for this we refer you to the relevant standards and RFCs.</p> + specifications used to handle public and private keys. + The intent is to describe the data types + and not to specify the semantics of each component. For information on the + semantics, please see the relevant standards and RFCs.</p> <p>Use the following include directive to get access to the - records and constant macros used in the following sections.</p> + records and constant macros described in the following sections.</p> <code> -include_lib("public_key/include/public_key.hrl"). </code> + <section> + <title>Common Data Types</title> + + <p>Common non-standard Erlang + data types used to described the record fields in the + below sections are defined in <seealso + marker="public_key">public key reference manual </seealso></p> + </section> + <section> - <title>RSA as defined by the PKCS-1 standard and RFC 3447.</title> + <title>RSA as defined by the PKCS-1 standard and <url href="http://www.ietf.org/rfc/rfc3447.txt"> RFC 3447 </url></title> <code> #'RSAPublicKey'{ @@ -76,7 +86,8 @@ </section> <section> - <title>DSA as defined by Digital Signature Standard (NIST FIPS PUB 186-2) + <title>DSA as defined by + <url href="http://csrc.nist.gov/publications/fips/fips186-3/fips_186-3.pdf"> Digital Signature Standard (NIST FIPS PUB 186-2) </url> </title> <code> @@ -96,4 +107,47 @@ }. </code> </section> + + <section> + <title>ECC (Elliptic Curve) <url href="http://www.ietf.org/rfc/rfc3447.txt"> RFC 5480 </url> + </title> + + <code> +#'ECPrivateKey'{ + version, % integer() + privateKey, % octet_string() + parameters, % der_encoded() - {'EcpkParameters', #'ECParameters'{}} | + {'EcpkParameters', {namedCurve, oid()}} | + {'EcpkParameters', 'NULL'} % Inherited by CA + publicKey % bitstring() + }. + +#'ECParameters'{ + version, % integer() + fieldID, % #'FieldID'{} + curve, % #'Curve'{} + base, % octet_string() + order, % integer() + cofactor % integer() + }. + +#'Curve'{ + a, % octet_string() + b, % octet_string() + seed % bitstring() - optional + + }. + +#'FieldID'{ + fieldType, % oid() + parameters % Depending on fieldType + }. + +#'ECPoint'{ + point % octet_string() - the public key + }. + + </code> + </section> + </chapter> diff --git a/lib/public_key/src/pubkey_pbe.erl b/lib/public_key/src/pubkey_pbe.erl index 460624163b..521a32189d 100644 --- a/lib/public_key/src/pubkey_pbe.erl +++ b/lib/public_key/src/pubkey_pbe.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011-2013. All Rights Reserved. +%% Copyright Ericsson AB 2011-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -22,7 +22,7 @@ -include("public_key.hrl"). --export([encode/4, decode/4, decrypt_parameters/1]). +-export([encode/4, decode/4, decrypt_parameters/1, encrypt_parameters/1]). -export([pbdkdf1/4, pbdkdf2/7]). -define(DEFAULT_SHA_MAC_KEYLEN, 20). @@ -40,16 +40,16 @@ %%-------------------------------------------------------------------- encode(Data, Password, "DES-CBC" = Cipher, KeyDevParams) -> {Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams), - crypto:block_encrypt(des_cbc, Key, IV, Data); + crypto:block_encrypt(des_cbc, Key, IV, pbe_pad(Data, KeyDevParams)); encode(Data, Password, "DES-EDE3-CBC" = Cipher, KeyDevParams) -> {Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams), <<Key1:8/binary, Key2:8/binary, Key3:8/binary>> = Key, - crypto:block_encrypt(des3_cbc, [Key1, Key2, Key3], IV, Data); + crypto:block_encrypt(des3_cbc, [Key1, Key2, Key3], IV, pbe_pad(Data)); encode(Data, Password, "RC2-CBC" = Cipher, KeyDevParams) -> {Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams), - crypto:block_encrypt(rc2_cbc, Key, IV, Data). + crypto:block_encrypt(rc2_cbc, Key, IV, pbe_pad(Data, KeyDevParams)). %%-------------------------------------------------------------------- -spec decode(binary(), string(), string(), term()) -> binary(). %% @@ -108,6 +108,15 @@ decrypt_parameters(#'EncryptedPrivateKeyInfo_encryptionAlgorithm'{ algorithm = Oid, parameters = Param}) -> decrypt_parameters(Oid, Param). + +%%-------------------------------------------------------------------- +-spec encrypt_parameters({Cipher::string(), Params::term()}) -> + #'EncryptedPrivateKeyInfo_encryptionAlgorithm'{}. +%% +%% Description: Performs ANS1-decoding of encryption parameters. +%%-------------------------------------------------------------------- +encrypt_parameters({Cipher, Params}) -> + encrypt_parameters(Cipher, Params). %%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- @@ -117,14 +126,18 @@ password_to_key_and_iv(Password, _, #'PBES2-params'{} = Params) -> <<Key:KeyLen/binary, _/binary>> = pbdkdf2(Password, Salt, ItrCount, KeyLen, PseudoRandomFunction, PseudoHash, PseudoOtputLen), {Key, IV}; +password_to_key_and_iv(Password, _Cipher, {#'PBEParameter'{salt = Salt, + iterationCount = Count}, Hash}) -> + <<Key:8/binary, IV:8/binary, _/binary>> + = pbdkdf1(Password, erlang:iolist_to_binary(Salt), Count, Hash), + {Key, IV}; password_to_key_and_iv(Password, Cipher, Salt) -> - KeyLen = derived_key_length(Cipher, undefined), + KeyLen = derived_key_length(Cipher, undefined), <<Key:KeyLen/binary, _/binary>> = pem_encrypt(<<>>, Password, Salt, ceiling(KeyLen div 16), <<>>, md5), %% Old PEM encryption does not use standard encryption method - %% pbdkdf1 and uses then salt as IV + %% pbdkdf1 and uses then salt as IV {Key, Salt}. - pem_encrypt(_, _, _, 0, Acc, _) -> Acc; pem_encrypt(Prev, Password, Salt, Count, Acc, Hash) -> @@ -169,7 +182,52 @@ do_xor_sum(Prf, PrfHash, PrfLen, Prev, Password, Count, Acc)-> decrypt_parameters(?'id-PBES2', DekParams) -> {ok, Params} = 'PKCS-FRAME':decode('PBES2-params', DekParams), - {cipher(Params#'PBES2-params'.encryptionScheme), Params}. + {cipher(Params#'PBES2-params'.encryptionScheme), Params}; +decrypt_parameters(?'pbeWithSHA1AndRC2-CBC', DekParams) -> + {ok, Params} = 'PKCS-FRAME':decode('PBEParameter', DekParams), + {"RC2-CBC", {Params, sha}}; +decrypt_parameters(?'pbeWithSHA1AndDES-CBC', DekParams) -> + {ok, Params} = 'PKCS-FRAME':decode('PBEParameter', DekParams), + {"DES-CBC", {Params, sha}}; +decrypt_parameters(?'pbeWithMD5AndRC2-CBC', DekParams) -> + {ok, Params} = 'PKCS-FRAME':decode('PBEParameter', DekParams), + {"RC2-CBC", {Params, md5}}; +decrypt_parameters(?'pbeWithMD5AndDES-CBC', DekParams) -> + {ok, Params} = 'PKCS-FRAME':decode('PBEParameter', DekParams), + {"DES-CBC", {Params, md5}}. + +encrypt_parameters(_Cipher, #'PBES2-params'{} = Params) -> + {ok, Der} ='PKCS-FRAME':encode('PBES2-params', Params), + #'EncryptedPrivateKeyInfo_encryptionAlgorithm'{ + algorithm = ?'id-PBES2', + parameters = Der}; + +encrypt_parameters(Cipher, {#'PBEParameter'{} = Params, Hash}) -> + {ok, Der} ='PKCS-FRAME':encode('PBEParameter', Params), + #'EncryptedPrivateKeyInfo_encryptionAlgorithm'{ + algorithm = pbe1_oid(Cipher, Hash), + parameters = Der}. + +pbe1_oid("RC2-CBC", sha) -> + ?'pbeWithSHA1AndRC2-CBC'; +pbe1_oid("DES-CBC", sha) -> + ?'pbeWithSHA1AndDES-CBC'; +pbe1_oid("RC2-CBC", md5) -> + ?'pbeWithMD5AndRC2-CBC'; +pbe1_oid("DES-CBC", md5) -> + ?'pbeWithMD5AndDES-CBC'. + +pbe_pad(Data, {#'PBEParameter'{}, _}) -> + pbe_pad(Data); +pbe_pad(Data, #'PBES2-params'{}) -> + pbe_pad(Data); +pbe_pad(Data, _) -> + Data. + +pbe_pad(Data) -> + N = 8 - (erlang:byte_size(Data) rem 8), + Pad = list_to_binary(lists:duplicate(N, N)), + <<Data/binary, Pad/binary>>. key_derivation_params(#'PBES2-params'{keyDerivationFunc = KeyDerivationFunc, encryptionScheme = EncScheme}) -> diff --git a/lib/public_key/src/pubkey_pem.erl b/lib/public_key/src/pubkey_pem.erl index 3a1653d989..8d2e97ad77 100644 --- a/lib/public_key/src/pubkey_pem.erl +++ b/lib/public_key/src/pubkey_pem.erl @@ -94,6 +94,10 @@ encode_pem_entries(Entries) -> encode_pem_entry({Type, Der, not_encrypted}) -> StartStr = pem_start(Type), [StartStr, "\n", b64encode_and_split(Der), "\n", pem_end(StartStr) ,"\n\n"]; +encode_pem_entry({'PrivateKeyInfo', Der, EncParams}) -> + EncDer = encode_encrypted_private_keyinfo(Der, EncParams), + StartStr = pem_start('EncryptedPrivateKeyInfo'), + [StartStr, "\n", b64encode_and_split(EncDer), "\n", pem_end(StartStr) ,"\n\n"]; encode_pem_entry({Type, Der, {Cipher, Salt}}) -> StartStr = pem_start(Type), [StartStr,"\n", pem_decrypt(),"\n", pem_decrypt_info(Cipher, Salt),"\n", @@ -139,6 +143,12 @@ decode_encrypted_private_keyinfo(Der) -> DecryptParams = pubkey_pbe:decrypt_parameters(AlgorithmInfo), {'PrivateKeyInfo', iolist_to_binary(Data), DecryptParams}. + +encode_encrypted_private_keyinfo(EncData, EncryptParmams) -> + AlgorithmInfo = pubkey_pbe:encrypt_parameters(EncryptParmams), + public_key:der_encode('EncryptedPrivateKeyInfo', + #'EncryptedPrivateKeyInfo'{encryptionAlgorithm = AlgorithmInfo, + encryptedData = EncData}). split_bin(Bin) -> split_bin(0, Bin). @@ -197,13 +207,15 @@ pem_start('DSAPrivateKey') -> <<"-----BEGIN DSA PRIVATE KEY-----">>; pem_start('DHParameter') -> <<"-----BEGIN DH PARAMETERS-----">>; +pem_start('EncryptedPrivateKeyInfo') -> + <<"-----BEGIN ENCRYPTED PRIVATE KEY-----">>; pem_start('CertificationRequest') -> <<"-----BEGIN CERTIFICATE REQUEST-----">>; pem_start('ContentInfo') -> <<"-----BEGIN PKCS7-----">>; pem_start('CertificateList') -> <<"-----BEGIN X509 CRL-----">>; -pem_start('OTPEcpkParameters') -> +pem_start('EcpkParameters') -> <<"-----BEGIN EC PARAMETERS-----">>; pem_start('ECPrivateKey') -> <<"-----BEGIN EC PRIVATE KEY-----">>. @@ -260,7 +272,7 @@ asn1_type(<<"-----BEGIN PKCS7-----">>) -> asn1_type(<<"-----BEGIN X509 CRL-----">>) -> 'CertificateList'; asn1_type(<<"-----BEGIN EC PARAMETERS-----">>) -> - 'OTPEcpkParameters'; + 'EcpkParameters'; asn1_type(<<"-----BEGIN EC PRIVATE KEY-----">>) -> 'ECPrivateKey'. diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl index a732455aa7..bbe54ad4e1 100644 --- a/lib/public_key/src/public_key.erl +++ b/lib/public_key/src/public_key.erl @@ -133,20 +133,19 @@ pem_entry_decode({Asn1Type, CryptDer, {Cipher, #'PBES2-params'{}}} = PemEntry, is_binary(CryptDer) andalso is_list(Cipher) -> do_pem_entry_decode(PemEntry, Password); -pem_entry_decode({Asn1Type, CryptDer, {Cipher, Salt}} = PemEntry, +pem_entry_decode({Asn1Type, CryptDer, {Cipher, {#'PBEParameter'{},_}}} = PemEntry, Password) when is_atom(Asn1Type) andalso is_binary(CryptDer) andalso - is_list(Cipher) andalso - is_binary(Salt) andalso - erlang:byte_size(Salt) == 8 -> + is_list(Cipher) -> do_pem_entry_decode(PemEntry, Password); -pem_entry_decode({Asn1Type, CryptDer, {"AES-128-CBC"=Cipher, IV}} = PemEntry, +pem_entry_decode({Asn1Type, CryptDer, {Cipher, Salt}} = PemEntry, Password) when is_atom(Asn1Type) andalso is_binary(CryptDer) andalso is_list(Cipher) andalso - is_binary(IV) andalso - erlang:byte_size(IV) == 16 -> - do_pem_entry_decode(PemEntry, Password). + is_binary(Salt) andalso + ((erlang:byte_size(Salt) == 8) or (erlang:byte_size(Salt) == 16)) -> + do_pem_entry_decode(PemEntry, Password). + %%-------------------------------------------------------------------- -spec pem_entry_encode(pki_asn1_type(), term()) -> pem_entry(). @@ -174,13 +173,19 @@ pem_entry_encode(Asn1Type, Entity, {{Cipher, #'PBES2-params'{}} = CipherInfo, is_list(Password) andalso is_list(Cipher) -> do_pem_entry_encode(Asn1Type, Entity, CipherInfo, Password); - +pem_entry_encode(Asn1Type, Entity, {{Cipher, + {#'PBEParameter'{}, _}} = CipherInfo, + Password}) when is_atom(Asn1Type) andalso + is_list(Password) andalso + is_list(Cipher) -> + do_pem_entry_encode(Asn1Type, Entity, CipherInfo, Password); pem_entry_encode(Asn1Type, Entity, {{Cipher, Salt} = CipherInfo, Password}) when is_atom(Asn1Type) andalso is_list(Password) andalso is_list(Cipher) andalso is_binary(Salt) andalso - erlang:byte_size(Salt) == 8 -> + ((erlang:byte_size(Salt) == 8) or + (erlang:byte_size(Salt) == 16)) -> do_pem_entry_encode(Asn1Type, Entity, CipherInfo, Password). %%-------------------------------------------------------------------- diff --git a/lib/public_key/test/pbe_SUITE.erl b/lib/public_key/test/pbe_SUITE.erl index b68ffbd5fd..aa2bbdd24b 100644 --- a/lib/public_key/test/pbe_SUITE.erl +++ b/lib/public_key/test/pbe_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011-2013. All Rights Reserved. +%% Copyright Ericsson AB 2011-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -35,7 +35,9 @@ all() -> [ pbdkdf1, pbdkdf2, - encrypted_private_key_info]. + old_enc, + pbes1, + pbes2]. groups() -> []. @@ -192,44 +194,48 @@ pbdkdf2(Config) when is_list(Config) -> 16#cc, 16#37, 16#d7, 16#f0, 16#34, 16#25, 16#e0, 16#c3>> = pubkey_pbe:pbdkdf2("pass\0word", "sa\0lt", 4096, 16, fun crypto:hmac/4, sha, 20). - -encrypted_private_key_info() -> - [{doc,"Tests reading a EncryptedPrivateKeyInfo file encrypted with different ciphers"}]. -encrypted_private_key_info(Config) when is_list(Config) -> + +old_enc() -> + [{doc,"Tests encode/decode RSA key encrypted with different ciphers using old PEM encryption scheme"}]. +old_enc(Config) when is_list(Config) -> Datadir = ?config(data_dir, Config), - {ok, PemDes} = file:read_file(filename:join(Datadir, "des_cbc_enc_key.pem")), + %% key generated with ssh-keygen -N hello_aes -f old_aes_128_cbc_enc_key.pem + {ok, PemAesCbc} = file:read_file(filename:join(Datadir, "old_aes_128_cbc_enc_key.pem")), - PemDesEntry = public_key:pem_decode(PemDes), - ct:print("Pem entry: ~p" , [PemDesEntry]), - [{'PrivateKeyInfo', _, {"DES-CBC",_}} = PubEntry0] = PemDesEntry, - KeyInfo = public_key:pem_entry_decode(PubEntry0, "password"), - - {ok, Pem3Des} = file:read_file(filename:join(Datadir, "des_ede3_cbc_enc_key.pem")), - - Pem3DesEntry = public_key:pem_decode(Pem3Des), - ct:print("Pem entry: ~p" , [Pem3DesEntry]), - [{'PrivateKeyInfo', _, {"DES-EDE3-CBC",_}} = PubEntry1] = Pem3DesEntry, - KeyInfo = public_key:pem_entry_decode(PubEntry1, "password"), - - {ok, PemRc2} = file:read_file(filename:join(Datadir, "rc2_cbc_enc_key.pem")), - - PemRc2Entry = public_key:pem_decode(PemRc2), - ct:print("Pem entry: ~p" , [PemRc2Entry]), - [{'PrivateKeyInfo', _, {"RC2-CBC",_}} = PubEntry2] = PemRc2Entry, - KeyInfo = public_key:pem_entry_decode(PubEntry2, "password"), - - %% key generated with ssh-keygen -N hello_aes -f aes_128_cbc_enc_key - {ok, PemAesCbc} = file:read_file(filename:join(Datadir, "aes_128_cbc_enc_key")), - PemAesCbcEntry = public_key:pem_decode(PemAesCbc), ct:print("Pem entry: ~p" , [PemAesCbcEntry]), [{'RSAPrivateKey', _, {"AES-128-CBC",_}} = PubAesCbcEntry] = PemAesCbcEntry, - #'RSAPrivateKey'{} = public_key:pem_entry_decode(PubAesCbcEntry, "hello_aes"), - - check_key_info(KeyInfo). + #'RSAPrivateKey'{} = public_key:pem_entry_decode(PubAesCbcEntry, "hello_aes"). +pbes1() -> + [{doc,"Tests encode/decode EncryptedPrivateKeyInfo encrypted with different ciphers using PBES1"}]. +pbes1(Config) when is_list(Config) -> + decode_encode_key_file("pbes1_des_cbc_md5_enc_key.pem", "password", "DES-CBC", Config). + +pbes2() -> + [{doc,"Tests encode/decode EncryptedPrivateKeyInfo encrypted with different ciphers using PBES2"}]. +pbes2(Config) when is_list(Config) -> + decode_encode_key_file("pbes2_des_cbc_enc_key.pem", "password", "DES-CBC", Config), + decode_encode_key_file("pbes2_des_ede3_cbc_enc_key.pem", "password", "DES-EDE3-CBC", Config), + decode_encode_key_file("pbes2_rc2_cbc_enc_key.pem", "password", "RC2-CBC", Config). check_key_info(#'PrivateKeyInfo'{privateKeyAlgorithm = #'PrivateKeyInfo_privateKeyAlgorithm'{algorithm = ?rsaEncryption}, privateKey = Key}) -> #'RSAPrivateKey'{} = public_key:der_decode('RSAPrivateKey', iolist_to_binary(Key)). + +decode_encode_key_file(File, Password, Cipher, Config) -> + Datadir = ?config(data_dir, Config), + {ok, PemKey} = file:read_file(filename:join(Datadir, File)), + + PemEntry = public_key:pem_decode(PemKey), + ct:print("Pem entry: ~p" , [PemEntry]), + [{Asn1Type, _, {Cipher,_} = CipherInfo} = PubEntry] = PemEntry, + KeyInfo = public_key:pem_entry_decode(PubEntry, Password), + PemKey1 = public_key:pem_encode([public_key:pem_entry_encode(Asn1Type, KeyInfo, {CipherInfo, Password})]), + Pem = strip_ending_newlines(PemKey), + Pem = strip_ending_newlines(PemKey1), + check_key_info(KeyInfo). + +strip_ending_newlines(Bin) -> + string:strip(binary_to_list(Bin), right, 10). diff --git a/lib/public_key/test/pbe_SUITE_data/aes_128_cbc_enc_key b/lib/public_key/test/pbe_SUITE_data/old_aes_128_cbc_enc_key.pem index 34c7543f30..34c7543f30 100644 --- a/lib/public_key/test/pbe_SUITE_data/aes_128_cbc_enc_key +++ b/lib/public_key/test/pbe_SUITE_data/old_aes_128_cbc_enc_key.pem diff --git a/lib/public_key/test/pbe_SUITE_data/pbes1_des_cbc_md5_enc_key.pem b/lib/public_key/test/pbe_SUITE_data/pbes1_des_cbc_md5_enc_key.pem new file mode 100644 index 0000000000..12e860c7a7 --- /dev/null +++ b/lib/public_key/test/pbe_SUITE_data/pbes1_des_cbc_md5_enc_key.pem @@ -0,0 +1,17 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIICoTAbBgkqhkiG9w0BBQMwDgQIZmB6EGEnIOcCAggABIICgDaaKoCEUowjKt5M +uwMAIf7uugy09OcqR8PcB9ioiuk5NQGXkIBxOOlOuFb6xrP+O2dSppr5k/ZU+NEX +Lf18AdMld1nlE6lwjPytOIqt6Q3YMeny8un1/jopnkQZKthJ5moER5ohp/2osTDV +4Ih8MtHTwE879SHAmj7Y3G7itKHQi17212DVmL+D+P7iRzTCKIyPj5KMXvXN+eor +j0urZXVOeyRTABHQnf6xJn8K+dGowC/AJTQWOgFunlBKzecepqF22OQzIW2R60aM +VgykSd8A5G8o1F+tO2Qrp6KM9Ak709dUX8qRb/C02w5rjg2g0frgFyEGX0pUJbno +dJLKMOT1WvDnsXaS720beyzrOynWiAuaFZwb1/nPSQnzJ4t0mUvQQis5ph3eHSR/ +a9/PER81IDjPtjlTJjaOGuwhIRmGFsLUrQhOnVcI7Z5TCSj7EHdqK3xzjSVzu5DY +BqE2rsigiIOszPdbK4tKCDheIwBhYdptDvG9c+j3Mj0YNOXJxsX0gVoMqtpwryNG +OZy5fLujS4l+cPq64dOh/LE87mrM9St6M6gw2VRW7d0U18Muubp/MK8q9O2i80Nw +ZFrHHE1N09x3aTnty4mwdCHl6w5aJMZg6WbUXJnf0zKa8ADv5wZmAvW3fO4G8434 +3FHj1hdyKPcoVjoFVawyRUflF/jYd1pLpV+iZwDDR4lacb4ay1Lut452ifZ8DqOq +lWYL0uskCn1WI856vtlLV3gnV02xDjAilSY2hASOyoD1wypZefPn5S+U3vkLuzFZ +ycbyIwGYTLWj71u8Vu3JceRI3OIPDuM7zcNHr71eQyiwLEA0iszQQA9xgqmeFtJO +IkpUTAY= +-----END ENCRYPTED PRIVATE KEY----- diff --git a/lib/public_key/test/pbe_SUITE_data/des_cbc_enc_key.pem b/lib/public_key/test/pbe_SUITE_data/pbes2_des_cbc_enc_key.pem index eaa06145aa..eaa06145aa 100644 --- a/lib/public_key/test/pbe_SUITE_data/des_cbc_enc_key.pem +++ b/lib/public_key/test/pbe_SUITE_data/pbes2_des_cbc_enc_key.pem diff --git a/lib/public_key/test/pbe_SUITE_data/des_ede3_cbc_enc_key.pem b/lib/public_key/test/pbe_SUITE_data/pbes2_des_ede3_cbc_enc_key.pem index 22ea46d56f..22ea46d56f 100644 --- a/lib/public_key/test/pbe_SUITE_data/des_ede3_cbc_enc_key.pem +++ b/lib/public_key/test/pbe_SUITE_data/pbes2_des_ede3_cbc_enc_key.pem diff --git a/lib/public_key/test/pbe_SUITE_data/rc2_cbc_enc_key.pem b/lib/public_key/test/pbe_SUITE_data/pbes2_rc2_cbc_enc_key.pem index 618cddcfd7..618cddcfd7 100644 --- a/lib/public_key/test/pbe_SUITE_data/rc2_cbc_enc_key.pem +++ b/lib/public_key/test/pbe_SUITE_data/pbes2_rc2_cbc_enc_key.pem diff --git a/lib/snmp/doc/src/notes.xml b/lib/snmp/doc/src/notes.xml index 06674095f2..15efd47a1c 100644 --- a/lib/snmp/doc/src/notes.xml +++ b/lib/snmp/doc/src/notes.xml @@ -33,7 +33,29 @@ </header> - <section><title>SNMP 4.25.1</title> + <section><title>SNMP 5.0</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + SNMP has been improved to handle IPv6. The agent can + handle dual stack IPv4 + IPv6, but not yet the manager. + The documentation also still lags behind... If you do + such advanced stuff like writing a custom net_if module, + the interface for it has changed, but other than that + SNMP is backwards compatible.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-12020 Aux Id: OTP-11518 </p> + </item> + </list> + </section> + +</section> + +<section><title>SNMP 4.25.1</title> <section><title>Fixed Bugs and Malfunctions</title> <list> diff --git a/lib/snmp/src/agent/snmp_community_mib.erl b/lib/snmp/src/agent/snmp_community_mib.erl index 7bdd500727..4546c343b7 100644 --- a/lib/snmp/src/agent/snmp_community_mib.erl +++ b/lib/snmp/src/agent/snmp_community_mib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2012. All Rights Reserved. +%% Copyright Ericsson AB 1999-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -31,6 +31,7 @@ -include("snmpa_internal.hrl"). -include("SNMP-COMMUNITY-MIB.hrl"). -include("SNMP-TARGET-MIB.hrl"). +-include("SNMPv2-TM.hrl"). -include("SNMPv2-TC.hrl"). -include("snmp_types.hrl"). @@ -129,10 +130,11 @@ read_community_config_files(Dir) -> [FileName, D, Reason]), ok end, - Filter = fun(Comms) -> Comms end, - Check = fun(Entry) -> check_community(Entry) end, + Order = fun snmp_conf:no_order/2, + Filter = fun snmp_conf:no_filter/1, + Check = fun(Entry, State) -> {check_community(Entry), State} end, [Comms] = - snmp_conf:read_files(Dir, [{Gen, Filter, Check, "community.conf"}]), + snmp_conf:read_files(Dir, [{FileName, Gen, Order, Check, Filter}]), Comms. check_community({Index, CommunityName, SecName, CtxName, TransportTag}) -> @@ -192,7 +194,7 @@ add_community(Idx, CommName, SecName, EngineId, CtxName, TransportTag) -> do_add_community(Community). do_add_community(Community) -> - case (catch check_community(Community)) of + try check_community(Community) of {ok, Row} -> Key = element(1, Row), case table_cre_row(snmpCommunityTable, Key, Row) of @@ -201,11 +203,12 @@ do_add_community(Community) -> {ok, Key}; false -> {error, create_failed} - end; + end + catch {error, Reason} -> {error, Reason}; - Error -> - {error, Error} + Class:Reason -> + {error, {Class, Reason, erlang:get_stacktrace()}} end. %% FIXME: does not work with mnesia @@ -243,6 +246,10 @@ gc_tabs() -> %%----------------------------------------------------------------- community2vacm(Community, Addr) -> Idxs = ets:lookup(snmp_community_cache, Community), + ?vtrace("community2vacm ->~n" + " Community: ~p~n" + " Addr: ~p~n" + " Idxs: ~p", [Community, Addr, Idxs]), loop_c2v_rows(lists:keysort(2, Idxs), Addr). loop_c2v_rows([{_, CommunityIndex} | T], Addr) -> @@ -250,6 +257,9 @@ loop_c2v_rows([{_, CommunityIndex} | T], Addr) -> "~n CommunityIndex: ~p", [CommunityIndex]), case get_row(CommunityIndex) of {_Community, VacmParams, Tag} -> + ?vtrace("loop_c2v_rows ->~n" + " VacmParams: ~p~n" + " Tag: ~p", [VacmParams, Tag]), {TDomain, TAddr} = Addr, case snmp_target_mib:is_valid_tag(Tag, TDomain, TAddr) of true -> @@ -506,7 +516,12 @@ snmpTargetAddrExtTable(get_next, RowIndex, Cols) -> NCols = conv1(Cols), conv2(next(snmpTargetAddrExtTable, RowIndex, NCols)); snmpTargetAddrExtTable(set, RowIndex, Cols0) -> - case (catch verify_snmpTargetAddrExtTable_cols(Cols0, [])) of + case + (catch verify_snmpTargetAddrExtTable_cols( + Cols0, + get_snmpTargetAddrTDomain(RowIndex, Cols0), + [])) + of {ok, Cols} -> NCols = conv3(Cols), snmp_generic:table_func(set, RowIndex, NCols, @@ -515,7 +530,11 @@ snmpTargetAddrExtTable(set, RowIndex, Cols0) -> Error end; snmpTargetAddrExtTable(is_set_ok, RowIndex, Cols0) -> - case (catch verify_snmpTargetAddrExtTable_cols(Cols0, [])) of + case (catch verify_snmpTargetAddrExtTable_cols( + Cols0, + get_snmpTargetAddrTDomain(RowIndex, Cols0), + [])) + of {ok, Cols} -> NCols = conv3(Cols), snmp_generic:table_func(is_set_ok, RowIndex, NCols, @@ -525,29 +544,49 @@ snmpTargetAddrExtTable(is_set_ok, RowIndex, Cols0) -> end. -verify_snmpTargetAddrExtTable_cols([], Cols) -> + +get_snmpTargetAddrTDomain(RowIndex, Col) -> + case + get( + snmpTargetAddrTable, RowIndex, + [?snmpTargetAddrRowStatus,?snmpTargetAddrTDomain]) + of + [{value,?snmpTargetAddrRowStatus_active},ValueTDomain] -> + case ValueTDomain of + {value,TDomain} -> + TDomain; + _ -> + ?snmpUDPDomain + end; + _ -> + wrongValue(Col) + end. + + + +verify_snmpTargetAddrExtTable_cols([], _TDomain, Cols) -> {ok, lists:reverse(Cols)}; -verify_snmpTargetAddrExtTable_cols([{Col, Val0}|Cols], Acc) -> - Val = verify_snmpTargetAddrExtTable_col(Col, Val0), - verify_snmpTargetAddrExtTable_cols(Cols, [{Col, Val}|Acc]). +verify_snmpTargetAddrExtTable_cols([{Col, Val0}|Cols], TDomain, Acc) -> + Val = verify_snmpTargetAddrExtTable_col(Col, TDomain, Val0), + verify_snmpTargetAddrExtTable_cols(Cols, TDomain, [{Col, Val}|Acc]). -verify_snmpTargetAddrExtTable_col(?snmpTargetAddrTMask, []) -> +verify_snmpTargetAddrExtTable_col(?snmpTargetAddrTMask, _TDomain, []) -> []; -verify_snmpTargetAddrExtTable_col(?snmpTargetAddrTMask, TMask) -> - case (catch snmp_conf:check_taddress(TMask)) of +verify_snmpTargetAddrExtTable_col(?snmpTargetAddrTMask, TDomain, TMask) -> + case (catch snmp_conf:check_taddress(TDomain, TMask)) of ok -> TMask; _ -> wrongValue(?snmpTargetAddrTMask) end; -verify_snmpTargetAddrExtTable_col(?snmpTargetAddrMMS, MMS) -> +verify_snmpTargetAddrExtTable_col(?snmpTargetAddrMMS, _TDomain, MMS) -> case (catch snmp_conf:check_packet_size(MMS)) of ok -> MMS; _ -> wrongValue(?snmpTargetAddrMMS) end; -verify_snmpTargetAddrExtTable_col(_, Val) -> +verify_snmpTargetAddrExtTable_col(_, _TDomain, Val) -> Val. db(snmpTargetAddrExtTable) -> db(snmpTargetAddrTable); @@ -583,6 +622,7 @@ conv3([{Idx, Val}|T]) -> [{Idx+10, Val} | conv3(T)]; conv3([]) -> []. + get(Name, RowIndex, Cols) -> snmp_generic:handle_table_get(db(Name), RowIndex, Cols, foi(Name)). diff --git a/lib/snmp/src/agent/snmp_framework_mib.erl b/lib/snmp/src/agent/snmp_framework_mib.erl index cc191bd956..9d3f7ef5e7 100644 --- a/lib/snmp/src/agent/snmp_framework_mib.erl +++ b/lib/snmp/src/agent/snmp_framework_mib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2012. All Rights Reserved. +%% Copyright Ericsson AB 1999-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -41,6 +41,7 @@ -compile({no_auto_import,[error/1]}). -export([init/0, configure/1]). -export([intContextTable/1, intContextTable/3, + intAgentTransportDomain/1, intAgentTransports/1, intAgentUDPPort/1, intAgentIpAddress/1, snmpEngineID/1, snmpEngineBoots/1, @@ -51,7 +52,7 @@ set_engine_boots/1, set_engine_time/1, table_next/2, check_status/3]). -export([add_context/1, delete_context/1]). --export([check_agent/1, check_context/1]). +-export([check_agent/2, check_context/1, order_agent/2]). %%----------------------------------------------------------------- @@ -115,54 +116,46 @@ do_configure(Dir) -> read_internal_config_files(Dir) -> ?vdebug("read context config file",[]), - Gen = fun(D, Reason) -> - convert_context(D, Reason) - end, - Filter = fun(Contexts) -> Contexts end, - Check = fun(Entry) -> check_context(Entry) end, - [Ctxs] = snmp_conf:read_files(Dir, [{Gen, Filter, Check, "context.conf"}]), + Gen = fun gen_context/2, + Order = fun snmp_conf:no_order/2, + Filter = fun snmp_conf:no_filter/1, + Check = fun(Entry, State) -> {check_context(Entry), State} end, + [Ctxs] = + snmp_conf:read_files + (Dir, [{"context.conf", Gen, Order, Check, Filter}]), Ctxs. - read_agent(Dir) -> ?vdebug("read agent config file", []), - FileName = "agent.conf", - Check = fun(Entry) -> check_agent(Entry) end, + FileName = "agent.conf", File = filename:join(Dir, FileName), - Agent = + Conf0 = try - snmp_conf:read(File, Check) + snmp_conf:read(File, fun order_agent/2, fun check_agent/2) catch throw:{error, Reason} -> error({failed_reading_config_file, Dir, FileName, Reason}) end, - sort_agent(Agent). - - -%%----------------------------------------------------------------- -%% Make sure that each mandatory agent attribute is present, and -%% provide default values for the other non-present attributes. -%%----------------------------------------------------------------- -sort_agent(L) -> - Mand = [{intAgentIpAddress, mandatory}, - {intAgentUDPPort, mandatory}, - {snmpEngineMaxMessageSize, mandatory}, - {snmpEngineID, mandatory}], - {ok, L2} = snmp_conf:check_mandatory(L, Mand), - lists:keysort(1, L2). + Mand = + [{intAgentTransports, mandatory}, + {snmpEngineMaxMessageSize, mandatory}, + {snmpEngineID, mandatory}], + {ok, Conf} = snmp_conf:check_mandatory(Conf0, Mand), + Conf. %%----------------------------------------------------------------- %% Generate a context.conf file. %%----------------------------------------------------------------- -convert_context(Dir, _Reason) -> +gen_context(Dir, _Reason) -> config_err("missing context.conf file => generating a default file", []), File = filename:join(Dir, "context.conf"), case file:open(File, [write]) of {ok, Fid} -> ok = io:format(Fid, "~s\n", [context_header()]), ok = io:format(Fid, "%% The default context\n\"\".\n", []), - file:close(Fid); + file:close(Fid), + []; {error, Reason} -> file:delete(File), error({failed_creating_file, File, Reason}) @@ -196,10 +189,44 @@ check_context(Context) -> %% Agent %% {Name, Value}. %%----------------------------------------------------------------- -check_agent({intAgentIpAddress, Value}) -> - snmp_conf:check_ip(Value); -check_agent({intAgentUDPPort, Value}) -> - snmp_conf:check_integer(Value); +check_agent(Entry, undefined) -> + check_agent(Entry, {snmp_target_mib:default_domain(), undefined}); +check_agent({intAgentTransportDomain, Domain}, {_, Port}) -> + {snmp_conf:check_domain(Domain), {Domain, Port}}; +check_agent({intAgentUDPPort, Port}, {Domain, _}) -> + ok = snmp_conf:check_port(Port), + {ok, {Domain, Port}}; +check_agent({intAgentIpAddress, _}, {_, undefined}) -> + error({missing_mandatory, intAgentUDPPort}); +check_agent({intAgentIpAddress = Tag, Ip} = Entry, {Domain, Port} = State) -> + {case snmp_conf:check_ip(Domain, Ip) of + ok -> + [Entry, + {intAgentTransports, [{Domain, {Ip, Port}}]}]; + {ok, FixedIp} -> + [{Tag, FixedIp}, + {intAgentTransports, [{Domain, {FixedIp, Port}}]}] + end, State}; +check_agent({intAgentTransports = Tag, Transports}, {_, Port} = State) -> + CheckedTransports = + [case + case Port of + undefined -> + snmp_conf:check_address(Domain, Address); + _ -> + snmp_conf:check_address(Domain, Address, Port) + end + of + ok -> + Transport; + {ok, FixedAddress} -> + {Domain, FixedAddress} + end + || {Domain, Address} = Transport <- Transports], + {{ok, {Tag, CheckedTransports}}, State}; +check_agent(Entry, State) -> + {check_agent(Entry), State}. + %% This one is kept for backwards compatibility check_agent({intAgentMaxPacketSize, Value}) -> snmp_conf:check_packet_size(Value); @@ -210,6 +237,14 @@ check_agent({snmpEngineID, Value}) -> check_agent(X) -> error({invalid_agent_attribute, X}). +%% Ordering function to sort intAgentTransportDomain first +%% hence before intAgentIpAddress. Sort other entries on the key. +order_agent(EntryA, EntryB) -> + snmp_conf:keyorder( + 1, EntryA, EntryB, + [intAgentTransportDomain, intAgentUDPPort | sort]). + + maybe_create_table(Name) -> case snmpa_local_db:table_exists(db(Name)) of @@ -382,6 +417,14 @@ intAgentUDPPort(Op) -> intAgentIpAddress(Op) -> snmp_generic:variable_func(Op, db(intAgentIpAddress)). +intAgentTransportDomain(Op) -> + snmp_generic:variable_func(Op, db(intAgentTransportDomain)). + +intAgentTransports(Op) -> + snmp_generic:variable_func(Op, db(intAgentTransports)). + + + snmpEngineID(print) -> VarAndValue = [{snmpEngineID, snmpEngineID(get)}], snmpa_mib_lib:print_variables(VarAndValue); diff --git a/lib/snmp/src/agent/snmp_generic.erl b/lib/snmp/src/agent/snmp_generic.erl index 06afa68d96..3195ca2500 100644 --- a/lib/snmp/src/agent/snmp_generic.erl +++ b/lib/snmp/src/agent/snmp_generic.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% Copyright Ericsson AB 1996-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -414,7 +414,12 @@ table_check_status(NameDb, Col, ?'RowStatus_createAndGo', RowIndex, Cols) -> % side effect free and we only use the result temporary. case catch snmpa_local_db:table_construct_row( NameDb, RowIndex, ?'RowStatus_createAndGo', Cols) of - {'EXIT', _} -> + {'EXIT', _Reason} -> + ?vtrace( + "failed construct row (createAndGo): " + " n Reason: ~p" + " n Stack: ~p", + [_Reason, erlang:get_stacktrace()]), {noCreation, Col}; % Bad RowIndex Row -> case lists:member(noinit, tuple_to_list(Row)) of @@ -431,7 +436,12 @@ table_check_status(NameDb, Col, ?'RowStatus_createAndWait', RowIndex, Cols) -> false -> case catch snmpa_local_db:table_construct_row( NameDb, RowIndex, ?'RowStatus_createAndGo', Cols) of - {'EXIT', _} -> + {'EXIT', _Reason} -> + ?vtrace( + "failed construct row (createAndWait): " + " n Reason: ~p" + " n Stack: ~p", + [_Reason, erlang:get_stacktrace()]), {noCreation, Col}; % Bad RowIndex _Row -> {noError, 0} @@ -711,7 +721,19 @@ find_col(Col, [_H | T]) -> find_col(Col, T). try_apply(nofunc, _) -> {noError, 0}; -try_apply(F, Args) -> apply(F, Args). +try_apply(F, Args) -> maybe_verbose_apply(F, Args). + +maybe_verbose_apply(M, Args) -> + case get(verbosity) of + false -> + apply(M, Args); + _ -> + ?vlog("~n apply: ~w,~p~n", [M,Args]), + Res = apply(M,Args), + ?vlog("~n returned: ~p", [Res]), + Res + end. + table_info({Name, _Db}) -> case snmpa_symbolic_store:table_info(Name) of diff --git a/lib/snmp/src/agent/snmp_notification_mib.erl b/lib/snmp/src/agent/snmp_notification_mib.erl index 37e09f5d3e..31c7735226 100644 --- a/lib/snmp/src/agent/snmp_notification_mib.erl +++ b/lib/snmp/src/agent/snmp_notification_mib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2012. All Rights Reserved. +%% Copyright Ericsson AB 1998-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -106,17 +106,19 @@ do_reconfigure(Dir) -> read_notify_config_files(Dir) -> ?vdebug("read notify config file",[]), FileName = "notify.conf", - Gen = fun(D, Reason) -> - info_msg("failed reading config file ~s" - "~n Config Dir: ~s" - "~n Reason: ~p", - [FileName, D, Reason]), - ok - end, - Filter = fun(Notifs) -> Notifs end, - Check = fun(Entry) -> check_notify(Entry) end, + Gen = + fun (D, Reason) -> + info_msg("failed reading config file ~s" + "~n Config Dir: ~s" + "~n Reason: ~p", + [FileName, D, Reason]), + ok + end, + Order = fun snmp_conf:no_order/2, + Filter = fun snmp_conf:no_filter/1, + Check = fun (Entry, State) -> {check_notify(Entry), State} end, [Notifs] = - snmp_conf:read_files(Dir, [{Gen, Filter, Check, "notify.conf"}]), + snmp_conf:read_files(Dir, [{FileName, Gen, Order, Check, Filter}]), Notifs. check_notify({Name, Tag, Type}) -> diff --git a/lib/snmp/src/agent/snmp_standard_mib.erl b/lib/snmp/src/agent/snmp_standard_mib.erl index 766b75022b..aace3fd413 100644 --- a/lib/snmp/src/agent/snmp_standard_mib.erl +++ b/lib/snmp/src/agent/snmp_standard_mib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2012. All Rights Reserved. +%% Copyright Ericsson AB 1996-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -152,16 +152,19 @@ do_reconfigure(Dir) -> %%----------------------------------------------------------------- read_standard(Dir) -> ?vdebug("check standard config file",[]), - FileName = "standard.conf", - Gen = fun(D, Reason) -> - throw({error, {failed_reading_config_file, - D, FileName, - list_dir(Dir), Reason}}) - end, - Filter = fun(Standard) -> sort_standard(Standard) end, - Check = fun(Entry) -> check_standard(Entry) end, + FileName = "standard.conf", + Gen = + fun (D, Reason) -> + throw( + {error, + {failed_reading_config_file, + D, FileName, list_dir(Dir), Reason}}) + end, + Order = fun snmp_conf:no_order/2, + Check = fun (Entry, State) -> {check_standard(Entry), State} end, + Filter = fun sort_standard/1, [Standard] = - snmp_conf:read_files(Dir, [{Gen, Filter, Check, FileName}]), + snmp_conf:read_files(Dir, [{FileName, Gen, Order, Check, Filter}]), Standard. list_dir(Dir) -> diff --git a/lib/snmp/src/agent/snmp_target_mib.erl b/lib/snmp/src/agent/snmp_target_mib.erl index b01d536caa..e916f17d6a 100644 --- a/lib/snmp/src/agent/snmp_target_mib.erl +++ b/lib/snmp/src/agent/snmp_target_mib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2012. All Rights Reserved. +%% Copyright Ericsson AB 1998-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -133,18 +133,22 @@ do_reconfigure(Dir) -> read_target_config_files(Dir) -> ?vdebug("check target address and parameter config file(s)",[]), - TAGen = fun(_D, _Reason) -> ok end, - TAFilter = fun(Addr) -> Addr end, - TACheck = fun(Entry) -> check_target_addr(Entry) end, - TPGen = fun(_D, _Reason) -> ok end, - TPFilter = fun(Params) -> Params end, - TPCheck = fun(Entry) -> check_target_params(Entry) end, + TAName = "target_addr.conf", + TACheck = fun (Entry, State) -> {check_target_addr(Entry), State} end, + + TPName = "target_params.conf", + TPCheck = fun (Entry, State) -> {check_target_params(Entry), State} end, + + NoGen = fun snmp_conf:no_gen/2, + NoOrder = fun snmp_conf:no_order/2, + NoFilter = fun snmp_conf:no_filter/1, [Addrs, Params] = - snmp_conf:read_files(Dir, - [{TAGen, TAFilter, TACheck, "target_addr.conf"}, - {TPGen, TPFilter, TPCheck, "target_params.conf"}]), + snmp_conf:read_files( + Dir, + [{TAName, NoGen, NoOrder, TACheck, NoFilter}, + {TPName, NoGen, NoOrder, TPCheck, NoFilter}]), {Addrs, Params}. @@ -154,79 +158,154 @@ read_target_config_files(Dir) -> %% TMask, MMS} %%----------------------------------------------------------------- -check_target_addr({Name, Domain, Ip, Udp, Timeout, RetryCount, TagList, - Params, EngineId, TMask, MMS}) -> +check_target_addr( + {Name, Domain, Ip, Udp, Timeout, RetryCount, TagList, Params, + EngineId, TMask, MMS}) -> % Arity 11 + Address = {Ip, Udp}, + check_target_addr( + Name, Domain, Address, Timeout, RetryCount, TagList, Params, + EngineId, TMask, MMS); +check_target_addr( + {Name, Domain, Address, Timeout, RetryCount, TagList, Params, + EngineId, TMask, MMS}) % Arity 10 + when is_atom(Domain) -> + check_target_addr( + Name, Domain, Address, Timeout, RetryCount, TagList, Params, + EngineId, TMask, MMS); +check_target_addr( + {Name, Ip, Udp, Timeout, RetryCount, TagList, Params, + EngineId, TMask, MMS}) + when is_integer(Udp) -> % Arity 10 + Domain = default_domain(), + Address = {Ip, Udp}, + check_target_addr( + Name, Domain, Address, Timeout, RetryCount, TagList, Params, + EngineId, TMask, MMS); +check_target_addr( + {Name, Domain, Address, Timeout, RetryCount, TagList, Params, + EngineId}) % Arity 8 + when is_atom(Domain) -> + check_target_addr( + Name, Domain, Address, Timeout, RetryCount, TagList, Params, + EngineId); +check_target_addr( + {Name, Ip, Udp, Timeout, RetryCount, TagList, Params, + EngineId}) % Arity 8 + when is_integer(Udp) -> + Domain = default_domain(), + Address = {Ip, Udp}, + check_target_addr( + Name, Domain, Address, Timeout, RetryCount, TagList, Params, + EngineId); +%% Use dummy engine id if the old style is found +check_target_addr( + {Name, Domain, Address, Timeout, RetryCount, TagList, Params}) % Arity 7 + when is_atom(Domain) -> + check_target_addr( + Name, Domain, Address, Timeout, RetryCount, TagList, Params); +check_target_addr( + {Name, Ip, Udp, Timeout, RetryCount, TagList, Params}) % Arity 7 + when is_integer(Udp) -> + Domain = default_domain(), + Address = {Ip, Udp}, + check_target_addr( + Name, Domain, Address, Timeout, RetryCount, TagList, Params); +%% Use dummy engine id if the old style is found +check_target_addr( + {Name, Domain, Address, Timeout, RetryCount, TagList, Params, + TMask, MMS}) % Arity 9 + when is_atom(Domain) -> + check_target_addr( + Name, Domain, Address, Timeout, RetryCount, TagList, Params, TMask, MMS); +check_target_addr( + {Name, Ip, Udp, Timeout, RetryCount, TagList, Params, + TMask, MMS}) % Arity 9 + when is_integer(Udp) -> + Domain = default_domain(), + Address = {Ip, Udp}, + check_target_addr( + Name, Domain, Address, Timeout, RetryCount, TagList, Params, TMask, MMS); +check_target_addr(X) -> + error({invalid_target_addr, X}). + +check_target_addr( + Name, Domain, Address, Timeout, RetryCount, TagList, Params) -> % Arity 7 + check_target_addr( + Name, Domain, Address, Timeout, RetryCount, TagList, Params, + "dummy"). +%% +check_target_addr( + Name, Domain, Address, Timeout, RetryCount, TagList, Params, + EngineId) -> % Arity 8 + check_target_addr( + Name, Domain, Address, Timeout, RetryCount, TagList, Params, + EngineId, [], 2048). +%% +check_target_addr( + Name, Domain, Address, Timeout, RetryCount, TagList, Params, + TMask, MMS) -> % Arity 9 + check_target_addr( + Name, Domain, Address, Timeout, RetryCount, TagList, Params, + "dummy", TMask, MMS). +%% +check_target_addr( + Name, Domain, Address, Timeout, RetryCount, TagList, Params, + EngineId, Mask, MMS) -> % Arity 10 ?vtrace("check target address with:" "~n Name: ~s" "~n Domain: ~p" - "~n Ip: ~p" - "~n Udp: ~p" + "~n Address: ~p" "~n Timeout: ~p" "~n RetryCount: ~p" "~n TagList: ~p" "~n Params: ~p" "~n EngineId: ~p" - "~n TMask: ~p" + "~n Mask: ~p" "~n MMS: ~p", - [Name, - Domain, Ip, Udp, + [Name, Domain, Address, Timeout, RetryCount, - TagList, Params, EngineId, TMask, MMS]), + TagList, Params, EngineId, Mask, MMS]), snmp_conf:check_string(Name,{gt,0}), snmp_conf:check_domain(Domain), - snmp_conf:check_ip(Domain, Ip), - snmp_conf:check_integer(Udp, {gt, 0}), + NAddress = check_address(Domain, Address), snmp_conf:check_integer(Timeout, {gte, 0}), snmp_conf:check_integer(RetryCount, {gte,0}), snmp_conf:check_string(TagList), snmp_conf:check_string(Params), check_engine_id(EngineId), - TAddress = snmp_conf:mk_taddress(Domain, Ip, Udp), + NMask = check_mask(Domain, Mask), TDomain = snmp_conf:mk_tdomain(Domain), - check_tmask(TDomain, TMask, TAddress), + TAddress = snmp_conf:mk_taddress(Domain, NAddress), + TMask = snmp_conf:mk_taddress(Domain, NMask), snmp_conf:check_packet_size(MMS), ?vtrace("check target address done",[]), Addr = {Name, TDomain, TAddress, Timeout, RetryCount, TagList, Params, ?'StorageType_nonVolatile', ?'RowStatus_active', EngineId, TMask, MMS}, % Values for Augmenting table in SNMP-COMMUNITY-MIB - {ok, Addr}; -check_target_addr({Name, Ip, Udp, Timeout, RetryCount, TagList, - Params, EngineId, TMask, MMS}) -> - Domain = default_domain(), - check_target_addr({Name, - Domain, Ip, Udp, - Timeout, RetryCount, TagList, - Params, EngineId, TMask, MMS}); -check_target_addr({Name, Ip, Udp, Timeout, RetryCount, TagList, Params, - EngineId}) -> - check_target_addr({Name, Ip, Udp, Timeout, RetryCount, TagList, - Params, EngineId, [], 2048}); -%% Use dummy engine id if the old style is found -check_target_addr({Name, Ip, Udp, Timeout, RetryCount, TagList, Params}) -> - check_target_addr({Name, Ip, Udp, Timeout, RetryCount, TagList, - Params, "dummy", [], 2048}); -%% Use dummy engine id if the old style is found -check_target_addr({Name, Ip, Udp, Timeout, RetryCount, TagList, Params, - TMask, MMS}) -> - check_target_addr({Name, Ip, Udp, Timeout, RetryCount, TagList, - Params, "dummy", TMask, MMS}); -check_target_addr(X) -> - error({invalid_target_addr, X}). - + {ok, Addr}. check_engine_id(discovery) -> ok; check_engine_id(EngineId) -> snmp_conf:check_string(EngineId). +check_address(Domain, Address) -> + case snmp_conf:check_address(Domain, Address) of + ok -> + Address; + {ok, NAddress} -> + NAddress + end. -check_tmask(_TDomain, [], _TAddress) -> - ok; -check_tmask(TDomain, TMask, TAddress) when length(TMask) =:= length(TAddress) -> - snmp_conf:check_taddress(TDomain, TMask); -check_tmask(_TDomain, TMask, _TAddr) -> - throw({error, {invalid_tmask, TMask}}). +check_mask(_Domain, [] = Mask) -> + Mask; +check_mask(Domain, Mask) -> + try check_address(Domain, Mask) + catch + {error, {bad_address, Info}} -> + error({bad_mask, Info}) + end. %%----------------------------------------------------------------- @@ -604,6 +683,20 @@ snmpTargetAddrTable(print) -> FOI = foi(Table), PrintRow = fun(Prefix, Row) -> + TDomain = element(?snmpTargetAddrTDomain, Row), + Domain = + try snmp_conf:tdomain_to_domain(TDomain) + catch + {error, {bad_tdomain, _}} -> + undefined + end, + TAddress = element(?snmpTargetAddrTAddress, Row), + AddrString = + try snmp_conf:mk_addr_string({Domain, TAddress}) + catch + {error, {bad_address, _}} -> + "-" + end, lists:flatten( io_lib:format("~sName: ~p" "~n~sTDomain: ~p (~w)" @@ -618,21 +711,8 @@ snmpTargetAddrTable(print) -> "~n~s[Ext] TMask: ~p" "~n~s[Ext] MMS: ~p", [Prefix, element(?snmpTargetAddrName, Row), - Prefix, element(?snmpTargetAddrTDomain, Row), - case element(?snmpTargetAddrTDomain, Row) of - ?snmpUDPDomain -> snmpUDPDomain; - ?transportDomainUdpIpv4 -> transportDomainUdpIpv4; - ?transportDomainUdpIpv6 -> transportDomainUdpIpv6; - _ -> undefined - end, - Prefix, element(?snmpTargetAddrTAddress, Row), - case element(?snmpTargetAddrTAddress, Row) of - [A,B,C,D,U1,U2] -> - lists:flatten( - io_lib:format("~w.~w.~w.~w:~w", - [A, B, C, D, U1 bsl 8 + U2])); - _ -> "-" - end, + Prefix, TDomain, Domain, + Prefix, TAddress, AddrString, Prefix, element(?snmpTargetAddrTimeout, Row), Prefix, element(?snmpTargetAddrRetryCount, Row), Prefix, element(?snmpTargetAddrTagList, Row), diff --git a/lib/snmp/src/agent/snmp_user_based_sm_mib.erl b/lib/snmp/src/agent/snmp_user_based_sm_mib.erl index 223d3f7218..69dce337ba 100644 --- a/lib/snmp/src/agent/snmp_user_based_sm_mib.erl +++ b/lib/snmp/src/agent/snmp_user_based_sm_mib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2013. All Rights Reserved. +%% Copyright Ericsson AB 1999-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -137,18 +137,20 @@ do_reconfigure(Dir) -> read_usm_config_files(Dir) -> ?vdebug("read usm config file",[]), - Gen = fun(D, Reason) -> generate_usm(D, Reason) end, - Filter = fun(Usms) -> Usms end, - Check = fun(Entry) -> check_usm(Entry) end, + Gen = fun (D, Reason) -> generate_usm(D, Reason) end, + Order = fun snmp_conf:no_order/2, + Check = fun (Entry, State) -> {check_usm(Entry), State} end, + Filter = fun snmp_conf:no_filter/1, [Usms] = - snmp_conf:read_files(Dir, [{Gen, Filter, Check, "usm.conf"}]), + snmp_conf:read_files(Dir, [{"usm.conf", Gen, Order, Check, Filter}]), Usms. generate_usm(Dir, _Reason) -> info_msg("Incomplete configuration. Generating empty usm.conf.", []), USMFile = filename:join(Dir, "usm.conf"), - ok = file:write_file(USMFile, list_to_binary([])). + ok = file:write_file(USMFile, list_to_binary([])), + []. check_usm({EngineID, Name, SecName, Clone, AuthP, AuthKeyC, OwnAuthKeyC, diff --git a/lib/snmp/src/agent/snmp_view_based_acm_mib.erl b/lib/snmp/src/agent/snmp_view_based_acm_mib.erl index c0177b1cea..722bd7ac5b 100644 --- a/lib/snmp/src/agent/snmp_view_based_acm_mib.erl +++ b/lib/snmp/src/agent/snmp_view_based_acm_mib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2013. All Rights Reserved. +%% Copyright Ericsson AB 1999-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -123,15 +123,18 @@ do_reconfigure(Dir) -> read_vacm_config_files(Dir) -> ?vdebug("read vacm config file",[]), - Gen = fun(_D, _Reason) -> ok end, - Filter = fun(Vacms) -> - Sec2Group = [X || {vacmSecurityToGroup, X} <- Vacms], - Access = [X || {vacmAccess, X} <- Vacms], - View = [X || {vacmViewTreeFamily, X} <- Vacms], - {Sec2Group, Access, View} - end, - Check = fun(Entry) -> check_vacm(Entry) end, - [Vacms] = snmp_conf:read_files(Dir, [{Gen, Filter, Check, "vacm.conf"}]), + Gen = fun snmp_conf:no_gen/2, + Order = fun snmp_conf:no_order/2, + Check = fun (Entry, State) -> {check_vacm(Entry), State} end, + Filter = + fun (Vacms) -> + Sec2Group = [X || {vacmSecurityToGroup, X} <- Vacms], + Access = [X || {vacmAccess, X} <- Vacms], + View = [X || {vacmViewTreeFamily, X} <- Vacms], + {Sec2Group, Access, View} + end, + [Vacms] = + snmp_conf:read_files(Dir, [{"vacm.conf", Gen, Order, Check, Filter}]), Vacms. %%----------------------------------------------------------------- diff --git a/lib/snmp/src/agent/snmpa_agent.erl b/lib/snmp/src/agent/snmpa_agent.erl index 9bed6e554e..6d3f1cca4a 100644 --- a/lib/snmp/src/agent/snmpa_agent.erl +++ b/lib/snmp/src/agent/snmpa_agent.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2013. All Rights Reserved. +%% Copyright Ericsson AB 1996-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -2512,10 +2512,19 @@ handle_mib_of(MibServer, Oid) -> %% Func: process_msg/7 %% Returns: RePdu %%----------------------------------------------------------------- -process_msg(MibView, Vsn, Pdu, PduMS, Community, {Ip, Udp}, ContextName, - GbMaxVBs) -> +process_msg( + MibView, Vsn, Pdu, PduMS, Community, + SourceAddress, ContextName, GbMaxVBs) -> #pdu{request_id = ReqId} = Pdu, - put(snmp_address, {tuple_to_list(Ip), Udp}), + put( + snmp_address, + case SourceAddress of + {Domain, _} when is_atom(Domain) -> + SourceAddress; + {Ip, Port} when is_integer(Port) -> + %% Legacy transport domain + {tuple_to_list(Ip), Port} + end), put(snmp_request_id, ReqId), put(snmp_community, Community), put(snmp_context, ContextName), diff --git a/lib/snmp/src/agent/snmpa_conf.erl b/lib/snmp/src/agent/snmpa_conf.erl index c17a6abbd7..b4d32dc928 100644 --- a/lib/snmp/src/agent/snmpa_conf.erl +++ b/lib/snmp/src/agent/snmpa_conf.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2011. All Rights Reserved. +%% Copyright Ericsson AB 2006-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -108,36 +108,25 @@ write_agent_config(Dir, Conf) -> Hdr = header() ++ Comment, write_agent_config(Dir, Hdr, Conf). -write_agent_config(Dir, Hdr, Conf) +write_agent_config(Dir, Hdr, Conf) when is_list(Dir) and is_list(Hdr) and is_list(Conf) -> - Verify = fun() -> verify_agent_conf(Conf) end, - Write = fun(Fd) -> write_agent_conf(Fd, Hdr, Conf) end, - write_config_file(Dir, "agent.conf", Verify, Write). - + Order = fun snmp_framework_mib:order_agent/2, + Check = fun snmp_framework_mib:check_agent/2, + Write = fun (Fd, Entries) -> write_agent_conf(Fd, Hdr, Entries) end, + write_config_file(Dir, "agent.conf", Order, Check, Write, Conf). -append_agent_config(Dir, Conf) +append_agent_config(Dir, Conf) when is_list(Dir) and is_list(Conf) -> - Verify = fun() -> verify_agent_conf(Conf) end, - Write = fun(Fd) -> write_agent_conf(Fd, Conf) end, - append_config_file(Dir, "agent.conf", Verify, Write). - + Order = fun snmp_framework_mib:order_agent/2, + Check = fun snmp_framework_mib:check_agent/2, + Write = fun write_agent_conf/2, + append_config_file(Dir, "agent.conf", Order, Check, Write, Conf). read_agent_config(Dir) -> - Verify = fun(Entry) -> verify_agent_conf_entry(Entry) end, - read_config_file(Dir, "agent.conf", Verify). + Order = fun snmp_framework_mib:order_agent/2, + Check = fun snmp_framework_mib:check_agent/2, + read_config_file(Dir, "agent.conf", Order, Check). - -verify_agent_conf([]) -> - ok; -verify_agent_conf([H|T]) -> - verify_agent_conf_entry(H), - verify_agent_conf(T); -verify_agent_conf(X) -> - error({bad_agent_config, X}). - -verify_agent_conf_entry(Entry) -> - ok = snmp_framework_mib:check_agent(Entry), - ok. write_agent_conf(Fd, "", Conf) -> write_agent_conf(Fd, Conf); @@ -151,6 +140,10 @@ write_agent_conf(Fd, [H|T]) -> do_write_agent_conf(Fd, H), write_agent_conf(Fd, T). +do_write_agent_conf(Fd, {intAgentTransports = Tag, Val}) -> + io:format(Fd, "{~w, ~w}.~n", [Tag, Val]); +do_write_agent_conf(Fd, {intAgentTransportDomain = Tag, Val}) -> + io:format(Fd, "{~w, ~w}.~n", [Tag, Val]); do_write_agent_conf(Fd, {intAgentIpAddress = Tag, Val}) -> io:format(Fd, "{~w, ~w}.~n", [Tag, Val]); do_write_agent_conf(Fd, {intAgentUDPPort = Tag, Val} ) -> @@ -191,34 +184,27 @@ write_context_config(Dir, Conf) -> write_context_config(Dir, Hdr, Conf) when is_list(Dir) and is_list(Hdr) and is_list(Conf) -> - Verify = fun() -> verify_context_conf(Conf) end, - Write = fun(Fd) -> write_context_conf(Fd, Hdr, Conf) end, - write_config_file(Dir, "context.conf", Verify, Write). - + Order = fun snmp_conf:no_order/2, + Check = fun check_context/2, + Write = fun (Fd, Entries) -> write_context_conf(Fd, Hdr, Entries) end, + write_config_file(Dir, "context.conf", Order, Check, Write, Conf). -append_context_config(Dir, Conf) +append_context_config(Dir, Conf) when is_list(Dir) and is_list(Conf) -> - Verify = fun() -> verify_context_conf(Conf) end, - Write = fun(Fd) -> write_context_conf(Fd, Conf) end, - append_config_file(Dir, "context.conf", Verify, Write). - + Order = fun snmp_conf:no_order/2, + Check = fun check_context/2, + Write = fun write_context_conf/2, + append_config_file(Dir, "context.conf", Order, Check, Write, Conf). read_context_config(Dir) -> - Verify = fun(Entry) -> verify_context_conf_entry(Entry) end, - read_config_file(Dir, "context.conf", Verify). + Order = fun snmp_conf:no_order/2, + Check = fun check_context/2, + read_config_file(Dir, "context.conf", Order, Check). - -verify_context_conf([]) -> - ok; -verify_context_conf([H|T]) -> - verify_context_conf_entry(H), - verify_context_conf(T); -verify_context_conf(X) -> - error({error_context_config, X}). - -verify_context_conf_entry(Context) -> - {ok, _} = snmp_framework_mib:check_context(Context), - ok. + +check_context(Entry, State) -> + {check_ok(snmp_framework_mib:check_context(Entry)), + State}. write_context_conf(Fd, "", Conf) -> write_context_conf(Fd, Conf); @@ -271,36 +257,29 @@ write_community_config(Dir, Conf) -> Hdr = header() ++ Comment, write_community_config(Dir, Hdr, Conf). -write_community_config(Dir, Hdr, Conf) +write_community_config(Dir, Hdr, Conf) when is_list(Dir) and is_list(Hdr) and is_list(Conf) -> - Verify = fun() -> verify_community_conf(Conf) end, - Write = fun(Fd) -> write_community_conf(Fd, Hdr, Conf) end, - write_config_file(Dir, "community.conf", Verify, Write). + Order = fun snmp_conf:no_order/2, + Check = fun check_community/2, + Write = fun (Fd, Entries) -> write_community_conf(Fd, Hdr, Entries) end, + write_config_file(Dir, "community.conf", Order, Check, Write, Conf). - -append_community_config(Dir, Conf) +append_community_config(Dir, Conf) when is_list(Dir) and is_list(Conf) -> - Verify = fun() -> verify_community_conf(Conf) end, - Write = fun(Fd) -> write_community_conf(Fd, Conf) end, - append_config_file(Dir, "community.conf", Verify, Write). - + Order = fun snmp_conf:no_order/2, + Check = fun check_community/2, + Write = fun write_community_conf/2, + append_config_file(Dir, "community.conf", Order, Check, Write, Conf). read_community_config(Dir) -> - Verify = fun(Entry) -> verify_community_conf_entry(Entry) end, - read_config_file(Dir, "community.conf", Verify). + Order = fun snmp_conf:no_order/2, + Check = fun check_community/2, + read_config_file(Dir, "community.conf", Order, Check). - -verify_community_conf([]) -> - ok; -verify_community_conf([H|T]) -> - verify_community_conf_entry(H), - verify_community_conf(T); -verify_community_conf(X) -> - error({invalid_community_config, X}). - -verify_community_conf_entry(Context) -> - {ok, _} = snmp_community_mib:check_community(Context), - ok. + +check_community(Entry, State) -> + {check_ok(snmp_community_mib:check_community(Entry)), + State}. write_community_conf(Fd, "", Conf) -> write_community_conf(Fd, Conf); @@ -309,14 +288,17 @@ write_community_conf(Fd, Hdr, Conf) -> write_community_conf(Fd, Conf). write_community_conf(Fd, Conf) -> - Fun = fun({Idx, Name, SecName, CtxName, TranspTag}) -> - io:format(Fd, "{\"~s\", \"~s\", \"~s\", \"~s\", \"~s\"}.~n", - [Idx, Name, SecName, CtxName, TranspTag]); + Fun = + fun({Idx, Name, SecName, CtxName, TranspTag}) -> + io:format( + Fd, + "{\"~s\", \"~s\", \"~s\", \"~s\", \"~s\"}.~n", + [Idx, Name, SecName, CtxName, TranspTag]); (Crap) -> - error({bad_community_config, Crap}) + error({bad_community_config, Crap}) end, lists:foreach(Fun, Conf). - + %% %% ------ standard.conf ------ @@ -343,40 +325,29 @@ write_standard_config(Dir, Conf) -> Hdr = header() ++ Comment, write_standard_config(Dir, Hdr, Conf). -write_standard_config(Dir, Hdr, Conf) +write_standard_config(Dir, Hdr, Conf) when is_list(Dir) and is_list(Hdr) and is_list(Conf) -> - Verify = fun() -> verify_standard_conf(Conf) end, - Write = fun(Fd) -> write_standard_conf(Fd, Hdr, Conf) end, - write_config_file(Dir, "standard.conf", Verify, Write). - + Order = fun snmp_conf:no_order/2, + Check = fun check_standard/2, + Write = fun (Fd, Entries) -> write_standard_conf(Fd, Hdr, Entries) end, + write_config_file(Dir, "standard.conf", Order, Check, Write, Conf). -append_standard_config(Dir, Conf) +append_standard_config(Dir, Conf) when is_list(Dir) and is_list(Conf) -> - Verify = fun() -> verify_standard_conf(Conf) end, - Write = fun(Fd) -> write_standard_conf(Fd, Conf) end, - append_config_file(Dir, "standard.conf", Verify, Write). - + Order = fun snmp_conf:no_order/2, + Check = fun check_standard/2, + Write = fun write_standard_conf/2, + append_config_file(Dir, "standard.conf", Order, Check, Write, Conf). read_standard_config(Dir) -> - Verify = fun(Entry) -> verify_standard_conf_entry(Entry) end, - read_config_file(Dir, "standard.conf", Verify). + Order = fun snmp_conf:no_order/2, + Check = fun check_standard/2, + read_config_file(Dir, "standard.conf", Order, Check). - -verify_standard_conf([]) -> - ok; -verify_standard_conf([H|T]) -> - verify_standard_conf_entry(H), - verify_standard_conf(T); -verify_standard_conf(X) -> - error({bad_standard_config, X}). - -verify_standard_conf_entry(Std) -> - case snmp_standard_mib:check_standard(Std) of - ok -> - ok; - {ok, _} -> - ok - end. + +check_standard(Entry, State) -> + {check_ok(snmp_standard_mib:check_standard(Entry)), + State}. write_standard_conf(Fd, "", Conf) -> write_standard_conf(Fd, Conf); @@ -410,72 +381,35 @@ do_write_standard_conf(_Fd, Tag, Val) -> %% ------ target_addr.conf ------ %% -target_addr_entry(Name, - Ip, - TagList, - ParamsName, - EngineId) -> +target_addr_entry( + Name, Ip, TagList, ParamsName, EngineId) -> target_addr_entry(Name, Ip, TagList, ParamsName, EngineId, []). -target_addr_entry(Name, - Ip, - TagList, - ParamsName, - EngineId, - TMask) -> - target_addr_entry(Name, Ip, 162, TagList, - ParamsName, EngineId, - TMask, 2048). - -target_addr_entry(Name, - Ip, - Udp, - TagList, - ParamsName, - EngineId, - TMask, - MaxMessageSize) -> - target_addr_entry(Name, Ip, Udp, 1500, 3, TagList, - ParamsName, EngineId, - TMask, MaxMessageSize). - -target_addr_entry(Name, - Ip, - Udp, - Timeout, - RetryCount, - TagList, - ParamsName, - EngineId, - TMask, - MaxMessageSize) -> - target_addr_entry(Name, snmp_target_mib:default_domain(), Ip, Udp, - Timeout, RetryCount, TagList, - ParamsName, EngineId, - TMask, MaxMessageSize). - -target_addr_entry(Name, - Domain, - Ip, - Udp, - Timeout, - RetryCount, - TagList, - ParamsName, - EngineId, - TMask, - MaxMessageSize) -> - {Name, - Domain, - Ip, - Udp, - Timeout, - RetryCount, - TagList, - ParamsName, - EngineId, - TMask, - MaxMessageSize}. +target_addr_entry( + Name, Ip, TagList, ParamsName, + EngineId, TMask) -> + target_addr_entry( + Name, Ip, 162, TagList, ParamsName, + EngineId, TMask, 2048). + +target_addr_entry( + Name, Domain_or_Ip, Addr_or_Port, TagList, + ParamsName, EngineId, TMask, MaxMessageSize) -> + target_addr_entry( + Name, Domain_or_Ip, Addr_or_Port, 1500, 3, TagList, + ParamsName, EngineId, TMask, MaxMessageSize). + +target_addr_entry( + Name, Domain_or_Ip, Addr_or_Port, Timeout, RetryCount, TagList, + ParamsName, EngineId, TMask, MaxMessageSize) -> + {Name, Domain_or_Ip, Addr_or_Port, Timeout, RetryCount, TagList, + ParamsName, EngineId, TMask, MaxMessageSize}. + +target_addr_entry( + Name, Domain, Ip, Udp, Timeout, RetryCount, TagList, + ParamsName, EngineId,TMask, MaxMessageSize) -> + {Name, Domain, Ip, Udp, Timeout, RetryCount, TagList, + ParamsName, EngineId, TMask, MaxMessageSize}. write_target_addr_config(Dir, Conf) -> @@ -504,37 +438,29 @@ write_target_addr_config(Dir, Conf) -> Hdr = header() ++ Comment, write_target_addr_config(Dir, Hdr, Conf). -write_target_addr_config(Dir, Hdr, Conf) +write_target_addr_config(Dir, Hdr, Conf) when is_list(Dir) and is_list(Hdr) and is_list(Conf) -> - Verify = fun() -> verify_target_addr_conf(Conf) end, - Write = fun(Fd) -> write_target_addr_conf(Fd, Hdr, Conf) end, - write_config_file(Dir, "target_addr.conf", Verify, Write). + Order = fun snmp_conf:no_order/2, + Check = fun check_target_addr/2, + Write = fun (Fd, Entries) -> write_target_addr_conf(Fd, Hdr, Entries) end, + write_config_file(Dir, "target_addr.conf", Order, Check, Write, Conf). - - -append_target_addr_config(Dir, Conf) +append_target_addr_config(Dir, Conf) when is_list(Dir) and is_list(Conf) -> - Verify = fun() -> verify_target_addr_conf(Conf) end, - Write = fun(Fd) -> write_target_addr_conf(Fd, Conf) end, - append_config_file(Dir, "target_addr.conf", Verify, Write). - + Order = fun snmp_conf:no_order/2, + Check = fun check_target_addr/2, + Write = fun write_target_addr_conf/2, + append_config_file(Dir, "target_addr.conf", Order, Check, Write, Conf). read_target_addr_config(Dir) -> - Verify = fun(Entry) -> verify_target_addr_conf_entry(Entry) end, - read_config_file(Dir, "target_addr.conf", Verify). + Order = fun snmp_conf:no_order/2, + Check = fun check_target_addr/2, + read_config_file(Dir, "target_addr.conf", Order, Check). - -verify_target_addr_conf([]) -> - ok; -verify_target_addr_conf([H|T]) -> - verify_target_addr_conf_entry(H), - verify_target_addr_conf(T); -verify_target_addr_conf(X) -> - error({bad_target_addr_config, X}). - -verify_target_addr_conf_entry(Entry) -> - {ok, _} = snmp_target_mib:check_target_addr(Entry), - ok. + +check_target_addr(Entry, State) -> + {check_ok(snmp_target_mib:check_target_addr(Entry)), + State}. write_target_addr_conf(Fd, "", Conf) -> write_target_addr_conf(Fd, Conf); @@ -547,29 +473,36 @@ write_target_addr_conf(Fd, Conf) -> lists:foreach(Fun, Conf), ok. -do_write_target_addr_conf(Fd, - {Name, - Ip, Udp, - Timeout, RetryCount, TagList, - ParamsName, EngineId, - TMask, MaxMessageSize}) -> - Domain = snmp_target_mib:default_domain(), - do_write_target_addr_conf(Fd, - {Name, - Domain, Ip, Udp, - Timeout, RetryCount, TagList, - ParamsName, EngineId, - TMask, MaxMessageSize}); -do_write_target_addr_conf(Fd, - {Name, - Domain, Ip, Udp, - Timeout, RetryCount, TagList, - ParamsName, EngineId, - TMask, MaxMessageSize}) -> - io:format(Fd, - "{\"~s\", ~w, ~w, ~w, ~w, ~w, \"~s\", \"~s\", \"~s\", ~w, ~w}.~n", - [Name, Domain, Ip, Udp, Timeout, RetryCount, TagList, - ParamsName, EngineId, TMask, MaxMessageSize]); +do_write_target_addr_conf( + Fd, + {Name, Ip, Udp, Timeout, RetryCount, TagList, + ParamsName, EngineId, TMask, MaxMessageSize}) + when is_integer(Udp) -> + Domain = snmp_target_mib:default_domain(), + Address = {Ip, Udp}, + do_write_target_addr_conf( + Fd, + {Name, Domain, Address, Timeout, RetryCount, TagList, + ParamsName, EngineId, TMask, MaxMessageSize}); +do_write_target_addr_conf( + Fd, + {Name, Domain, Address, Timeout, RetryCount, TagList, + ParamsName, EngineId, TMask, MaxMessageSize}) + when is_atom(Domain) -> + io:format( + Fd, + "{\"~s\", ~w, ~w, ~w, ~w, \"~s\", \"~s\", \"~s\", ~w, ~w}.~n", + [Name, Domain, Address, Timeout, RetryCount, TagList, + ParamsName, EngineId, TMask, MaxMessageSize]); +do_write_target_addr_conf( + Fd, + {Name, Domain, Ip, Udp, Timeout, RetryCount, TagList, + ParamsName, EngineId, TMask, MaxMessageSize}) -> + Address = {Ip, Udp}, + do_write_target_addr_conf( + Fd, + {Name, Domain, Address, Timeout, RetryCount, TagList, + ParamsName, EngineId, TMask, MaxMessageSize}); do_write_target_addr_conf(_Fd, Crap) -> error({bad_target_addr_config, Crap}). @@ -613,34 +546,27 @@ write_target_params_config(Dir, Conf) -> write_target_params_config(Dir, Hdr, Conf) when is_list(Dir) and is_list(Hdr) and is_list(Conf) -> - Verify = fun() -> verify_target_params_conf(Conf) end, - Write = fun(Fd) -> write_target_params_conf(Fd, Hdr, Conf) end, - write_config_file(Dir, "target_params.conf", Verify, Write). - + Order = fun snmp_conf:no_order/2, + Check = fun check_target_params/2, + Write = fun (Fd, Entries) -> write_target_params_conf(Fd, Hdr, Entries) end, + write_config_file(Dir, "target_params.conf", Order, Check, Write, Conf). append_target_params_config(Dir, Conf) when is_list(Dir) and is_list(Conf) -> - Verify = fun() -> verify_target_params_conf(Conf) end, - Write = fun(Fd) -> write_target_params_conf(Fd, Conf) end, - append_config_file(Dir, "target_params.conf", Verify, Write). - + Order = fun snmp_conf:no_order/2, + Check = fun check_target_params/2, + Write = fun write_target_params_conf/2, + append_config_file(Dir, "target_params.conf", Order, Check, Write, Conf). read_target_params_config(Dir) -> - Verify = fun(Entry) -> verify_target_params_conf_entry(Entry) end, - read_config_file(Dir, "target_params.conf", Verify). + Order = fun snmp_conf:no_order/2, + Check = fun check_target_params/2, + read_config_file(Dir, "target_params.conf", Order, Check). -verify_target_params_conf([]) -> - ok; -verify_target_params_conf([H|T]) -> - verify_target_params_conf_entry(H), - verify_target_params_conf(T); -verify_target_params_conf(X) -> - error({bad_target_params_config, X}). - -verify_target_params_conf_entry(Entry) -> - {ok, _} = snmp_target_mib:check_target_params(Entry), - ok. +check_target_params(Entry, State) -> + {check_ok(snmp_target_mib:check_target_params(Entry)), + State}. write_target_params_conf(Fd, "", Conf) -> write_target_params_conf(Fd, Conf); @@ -685,34 +611,27 @@ write_notify_config(Dir, Conf) -> write_notify_config(Dir, Hdr, Conf) when is_list(Dir) and is_list(Hdr) and is_list(Conf) -> - Verify = fun() -> verify_notify_conf(Conf) end, - Write = fun(Fd) -> write_notify_conf(Fd, Hdr, Conf) end, - write_config_file(Dir, "notify.conf", Verify, Write). - + Order = fun snmp_conf:no_order/2, + Check = fun check_notify/2, + Write = fun (Fd, Entries) -> write_notify_conf(Fd, Hdr, Entries) end, + write_config_file(Dir, "notify.conf", Order, Check, Write, Conf). append_notify_config(Dir, Conf) when is_list(Dir) and is_list(Conf) -> - Verify = fun() -> verify_notify_conf(Conf) end, - Write = fun(Fd) -> write_notify_conf(Fd, Conf) end, - append_config_file(Dir, "notify.conf", Verify, Write). - + Order = fun snmp_conf:no_order/2, + Check = fun check_notify/2, + Write = fun write_notify_conf/2, + append_config_file(Dir, "notify.conf", Order, Check, Write, Conf). read_notify_config(Dir) -> - Verify = fun(Entry) -> verify_notify_conf_entry(Entry) end, - read_config_file(Dir, "notify.conf", Verify). + Order = fun snmp_conf:no_order/2, + Check = fun check_notify/2, + read_config_file(Dir, "notify.conf", Order, Check). -verify_notify_conf([]) -> - ok; -verify_notify_conf([H|T]) -> - verify_notify_conf_entry(H), - verify_notify_conf(T); -verify_notify_conf(X) -> - error({bad_notify_config, X}). - -verify_notify_conf_entry(Entry) -> - {ok, _} = snmp_notification_mib:check_notify(Entry), - ok. +check_notify(Entry, State) -> + {check_ok(snmp_notification_mib:check_notify(Entry)), + State}. write_notify_conf(Fd, "", Conf) -> write_notify_conf(Fd, Conf); @@ -781,34 +700,27 @@ write_usm_config(Dir, Conf) -> write_usm_config(Dir, Hdr, Conf) when is_list(Dir) and is_list(Hdr) and is_list(Conf) -> - Verify = fun() -> verify_usm_conf(Conf) end, - Write = fun(Fd) -> write_usm_conf(Fd, Hdr, Conf) end, - write_config_file(Dir, "usm.conf", Verify, Write). - + Order = fun snmp_conf:no_order/2, + Check = fun check_usm/2, + Write = fun (Fd, Entries) -> write_usm_conf(Fd, Hdr, Entries) end, + write_config_file(Dir, "usm.conf", Order, Check, Write, Conf). append_usm_config(Dir, Conf) when is_list(Dir) and is_list(Conf) -> - Verify = fun() -> verify_usm_conf(Conf) end, - Write = fun(Fd) -> write_usm_conf(Fd, Conf) end, - append_config_file(Dir, "usm.conf", Verify, Write). - + Order = fun snmp_conf:no_order/2, + Check = fun check_usm/2, + Write = fun write_usm_conf/2, + append_config_file(Dir, "usm.conf", Order, Check, Write, Conf). read_usm_config(Dir) -> - Verify = fun(Entry) -> verify_usm_conf_entry(Entry) end, - read_config_file(Dir, "usm.conf", Verify). + Order = fun snmp_conf:no_order/2, + Check = fun check_usm/2, + read_config_file(Dir, "usm.conf", Order, Check). -verify_usm_conf([]) -> - ok; -verify_usm_conf([H|T]) -> - verify_usm_conf_entry(H), - verify_usm_conf(T); -verify_usm_conf(X) -> - error({bad_usm_conf, X}). - -verify_usm_conf_entry(Entry) -> - {ok, _} = snmp_user_based_sm_mib:check_usm(Entry), - ok. +check_usm(Entry, State) -> + {check_ok(snmp_user_based_sm_mib:check_usm(Entry)), + State}. write_usm_conf(Fd, "", Conf) -> write_usm_conf(Fd, Conf); @@ -820,11 +732,12 @@ write_usm_conf(Fd, Conf) -> Fun = fun(Entry) -> do_write_usm_conf(Fd, Entry) end, lists:foreach(Fun, Conf). -do_write_usm_conf(Fd, - {EngineID, UserName, SecName, Clone, - AuthP, AuthKeyC, OwnAuthKeyC, - PrivP, PrivKeyC, OwnPrivKeyC, - Public, AuthKey, PrivKey}) -> +do_write_usm_conf( + Fd, + {EngineID, UserName, SecName, Clone, + AuthP, AuthKeyC, OwnAuthKeyC, + PrivP, PrivKeyC, OwnPrivKeyC, + Public, AuthKey, PrivKey}) -> io:format(Fd, "{", []), io:format(Fd, "\"~s\", ", [EngineID]), io:format(Fd, "\"~s\", ", [UserName]), @@ -890,34 +803,27 @@ write_vacm_config(Dir, Conf) -> write_vacm_config(Dir, Hdr, Conf) when is_list(Dir) and is_list(Hdr) and is_list(Conf) -> - Verify = fun() -> verify_vacm_conf(Conf) end, - Write = fun(Fd) -> write_vacm_conf(Fd, Hdr, Conf) end, - write_config_file(Dir, "vacm.conf", Verify, Write). - + Order = fun snmp_conf:no_order/2, + Check = fun check_vacm/2, + Write = fun (Fd, Entries) -> write_vacm_conf(Fd, Hdr, Entries) end, + write_config_file(Dir, "vacm.conf", Order, Check, Write, Conf). append_vacm_config(Dir, Conf) when is_list(Dir) and is_list(Conf) -> - Verify = fun() -> verify_vacm_conf(Conf) end, - Write = fun(Fd) -> write_vacm_conf(Fd, Conf) end, - append_config_file(Dir, "vacm.conf", Verify, Write). - + Order = fun snmp_conf:no_order/2, + Check = fun check_vacm/2, + Write = fun write_vacm_conf/2, + append_config_file(Dir, "vacm.conf", Order, Check, Write, Conf). read_vacm_config(Dir) -> - Verify = fun(Entry) -> verify_vacm_conf_entry(Entry) end, - read_config_file(Dir, "vacm.conf", Verify). + Order = fun snmp_conf:no_order/2, + Check = fun check_vacm/2, + read_config_file(Dir, "vacm.conf", Order, Check). -verify_vacm_conf([]) -> - ok; -verify_vacm_conf([H|T]) -> - verify_vacm_conf_entry(H), - verify_vacm_conf(T); -verify_vacm_conf(X) -> - error({bad_vacm_conf, X}). - -verify_vacm_conf_entry(Entry) -> - {ok, _} = snmp_view_based_acm_mib:check_vacm(Entry), - ok. +check_vacm(Entry, State) -> + {check_ok(snmp_view_based_acm_mib:check_vacm(Entry)), + State}. write_vacm_conf(Fd, "", Conf) -> write_vacm_conf(Fd, Conf); @@ -929,49 +835,60 @@ write_vacm_conf(Fd, Conf) -> Fun = fun(Entry) -> do_write_vacm_conf(Fd, Entry) end, lists:foreach(Fun, Conf). -do_write_vacm_conf(Fd, - {vacmSecurityToGroup, - SecModel, SecName, GroupName}) -> - io:format(Fd, "{vacmSecurityToGroup, ~w, \"~s\", \"~s\"}.~n", - [SecModel, SecName, GroupName]); -do_write_vacm_conf(Fd, - {vacmAccess, - GroupName, Prefix, SecModel, SecLevel, Match, RV, WV, NV}) -> - io:format(Fd, "{vacmAccess, \"~s\", \"~s\", ~w, ~w, ~w, " - "\"~s\", \"~s\", \"~s\"}.~n", - [GroupName, Prefix, SecModel, SecLevel, - Match, RV, WV, NV]); -do_write_vacm_conf(Fd, - {vacmViewTreeFamily, - ViewIndex, ViewSubtree, ViewStatus, ViewMask}) -> - io:format(Fd, "{vacmViewTreeFamily, \"~s\", ~w, ~w, ~w}.~n", - [ViewIndex, ViewSubtree, ViewStatus, ViewMask]); +do_write_vacm_conf( + Fd, + {vacmSecurityToGroup, + SecModel, SecName, GroupName}) -> + io:format( + Fd, "{vacmSecurityToGroup, ~w, \"~s\", \"~s\"}.~n", + [SecModel, SecName, GroupName]); +do_write_vacm_conf( + Fd, + {vacmAccess, + GroupName, Prefix, SecModel, SecLevel, Match, RV, WV, NV}) -> + io:format( + Fd, "{vacmAccess, \"~s\", \"~s\", ~w, ~w, ~w, " + "\"~s\", \"~s\", \"~s\"}.~n", + [GroupName, Prefix, SecModel, SecLevel, + Match, RV, WV, NV]); +do_write_vacm_conf( + Fd, + {vacmViewTreeFamily, + ViewIndex, ViewSubtree, ViewStatus, ViewMask}) -> + io:format( + Fd, "{vacmViewTreeFamily, \"~s\", ~w, ~w, ~w}.~n", + [ViewIndex, ViewSubtree, ViewStatus, ViewMask]); do_write_vacm_conf(_Fd, Crap) -> error({bad_vacm_config, Crap}). %% ---- config file wrapper functions ---- -write_config_file(Dir, File, Verify, Write) -> - snmp_config:write_config_file(Dir, File, Verify, Write). +write_config_file(Dir, File, Order, Check, Write, Conf) -> + snmp_config:write_config_file(Dir, File, Order, Check, Write, Conf). -append_config_file(Dir, File, Verify, Write) -> - snmp_config:append_config_file(Dir, File, Verify, Write). +append_config_file(Dir, File, Order, Check, Write, Conf) -> + snmp_config:append_config_file(Dir, File, Order, Check, Write, Conf). -read_config_file(Dir, File, Verify) -> - snmp_config:read_config_file(Dir, File, Verify). +read_config_file(Dir, File, Order, Check) -> + snmp_config:read_config_file(Dir, File, Order, Check). %% ---- config file utility functions ---- +check_ok(ok) -> + ok; +check_ok({ok, _}) -> + ok. + header() -> {Y,Mo,D} = date(), {H,Mi,S} = time(), - io_lib:format("%% This file was generated by " - "~w (version-~s) ~w-~2.2.0w-~2.2.0w " - "~2.2.0w:~2.2.0w:~2.2.0w\n", - [?MODULE, ?version, Y, Mo, D, H, Mi, S]). - + io_lib:format( + "%% This file was generated by " + "~w (version-~s) ~w-~2.2.0w-~2.2.0w " + "~2.2.0w:~2.2.0w:~2.2.0w\n", + [?MODULE, ?version, Y, Mo, D, H, Mi, S]). error(R) -> throw({error, R}). diff --git a/lib/snmp/src/agent/snmpa_local_db.erl b/lib/snmp/src/agent/snmpa_local_db.erl index f991244287..292c370d51 100644 --- a/lib/snmp/src/agent/snmpa_local_db.erl +++ b/lib/snmp/src/agent/snmpa_local_db.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2013. All Rights Reserved. +%% Copyright Ericsson AB 1996-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -1011,6 +1011,10 @@ table_construct_row(Name, RowIndex, Status, Cols) -> defvals = Defs, status_col = StatusCol, first_own_index = FirstOwnIndex, not_accessible = NoAccs} = snmp_generic:table_info(Name), + ?vtrace( + "table_construct_row Indexes: ~p~n" + " RowIndex: ~p", + [Indexes, RowIndex]), Keys = snmp_generic:split_index_to_keys(Indexes, RowIndex), OwnKeys = snmp_generic:get_own_indexes(FirstOwnIndex, Keys), Row = OwnKeys ++ snmp_generic:table_create_rest(length(OwnKeys) + 1, diff --git a/lib/snmp/src/agent/snmpa_mpd.erl b/lib/snmp/src/agent/snmpa_mpd.erl index 11ae806866..642b1f7fc5 100644 --- a/lib/snmp/src/agent/snmpa_mpd.erl +++ b/lib/snmp/src/agent/snmpa_mpd.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2013. All Rights Reserved. +%% Copyright Ericsson AB 1997-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -20,7 +20,7 @@ -export([init/1, reset/0, inc/1, counters/0, discarded_pdu/1, - process_packet/6, process_packet/7, + process_packet/5, process_packet/6, process_packet/7, generate_response_msg/5, generate_response_msg/6, generate_msg/5, generate_msg/6, generate_discovery_msg/4, @@ -113,22 +113,30 @@ reset() -> % length(snmp_pdus:enc_message(M)) + 4. %%----------------------------------------------------------------- -%% Func: process_packet(Packet, TDomain, TAddress, State, Log) -> +%% Func: process_packet(Packet, Domain, Address, State, Log) -> %% {ok, SnmpVsn, Pdu, PduMS, ACMData} | {discarded, Reason} %% Types: Packet = binary() -%% TDomain = snmpUDPDomain | transportDomain() -%% TAddress = {Ip, Udp} (*but* depends on TDomain) +%% Domain = snmpUDPDomain | transportDomain() +%% Address = {Ip, Udp} (*but* depends on Domain) %% State = #state %% Purpose: This is the main Message Dispatching function. (see %% section 4.2.1 in rfc2272) %%----------------------------------------------------------------- -process_packet(Packet, TDomain, TAddress, State, NoteStore, Log) -> +process_packet(Packet, From, State, NoteStore, Log) -> LocalEngineID = ?DEFAULT_LOCAL_ENGINE_ID, - process_packet(Packet, TDomain, TAddress, LocalEngineID, - State, NoteStore, Log). - -process_packet(Packet, TDomain, TAddress, LocalEngineID, - State, NoteStore, Log) -> + process_packet(Packet, From, LocalEngineID, State, NoteStore, Log). + +process_packet( + Packet, Domain, Address, LocalEngineID, State, NoteStore, Log) -> + From = {Domain, Address}, + process_packet(Packet, From, LocalEngineID, State, NoteStore, Log). + +process_packet(Packet, Domain, Address, State, NoteStore, Log) + when is_atom(Domain) -> + LocalEngineID = ?DEFAULT_LOCAL_ENGINE_ID, + From = {Domain, Address}, + process_packet(Packet, From, LocalEngineID, State, NoteStore, Log); +process_packet(Packet, From, LocalEngineID, State, NoteStore, Log) -> inc(snmpInPkts), case catch snmp_pdus:dec_message_only(binary_to_list(Packet)) of @@ -136,17 +144,17 @@ process_packet(Packet, TDomain, TAddress, LocalEngineID, when State#state.v1 =:= true -> ?vlog("v1, community: ~s", [Community]), HS = ?empty_msg_size + length(Community), - v1_v2c_proc('version-1', NoteStore, Community, - TDomain, TAddress, - LocalEngineID, Data, HS, Log, Packet); + v1_v2c_proc( + 'version-1', NoteStore, Community, From, + LocalEngineID, Data, HS, Log, Packet); #message{version = 'version-2', vsn_hdr = Community, data = Data} when State#state.v2c =:= true -> ?vlog("v2c, community: ~s", [Community]), HS = ?empty_msg_size + length(Community), - v1_v2c_proc('version-2', NoteStore, Community, - TDomain, TAddress, - LocalEngineID, Data, HS, Log, Packet); + v1_v2c_proc( + 'version-2', NoteStore, Community, From, + LocalEngineID, Data, HS, Log, Packet); #message{version = 'version-3', vsn_hdr = V3Hdr, data = Data} when State#state.v3 =:= true -> @@ -154,9 +162,9 @@ process_packet(Packet, TDomain, TAddress, LocalEngineID, [V3Hdr#v3_hdr.msgID, V3Hdr#v3_hdr.msgFlags, V3Hdr#v3_hdr.msgSecurityModel]), - v3_proc(NoteStore, Packet, - TDomain, TAddress, - LocalEngineID, V3Hdr, Data, Log); + v3_proc( + NoteStore, Packet, From, + LocalEngineID, V3Hdr, Data, Log); {'EXIT', {bad_version, Vsn}} -> ?vtrace("exit: bad version: ~p",[Vsn]), @@ -183,11 +191,32 @@ discarded_pdu(Variable) -> inc(Variable). %%----------------------------------------------------------------- %% Handles a Community based message (v1 or v2c). %%----------------------------------------------------------------- -v1_v2c_proc(Vsn, NoteStore, Community, Domain, - {Ip, Udp}, LocalEngineID, - Data, HS, Log, Packet) -> - TDomain = snmp_conf:mk_tdomain(Domain), - TAddress = snmp_conf:mk_taddress(Domain, Ip, Udp), +v1_v2c_proc( + Vsn, NoteStore, Community, From, + LocalEngineID, Data, HS, Log, Packet) -> + try + case From of + {D, A} when is_atom(D) -> + {snmp_conf:mk_tdomain(D), + snmp_conf:mk_taddress(D, A)}; + {_, P} = A when is_integer(P) -> + {snmp_conf:mk_tdomain(), + snmp_conf:mk_taddress(A)} + end + of + {TDomain, TAddress} -> + v1_v2c_proc_dec( + Vsn, NoteStore, Community, TDomain, TAddress, + LocalEngineID, Data, HS, Log, Packet) + catch + _ -> + {discarded, {badarg, From}} + end. + + +v1_v2c_proc_dec( + Vsn, NoteStore, Community, TDomain, TAddress, + LocalEngineID, Data, HS, Log, Packet) -> AgentMS = get_engine_max_message_size(LocalEngineID), MgrMS = snmp_community_mib:get_target_addr_ext_mms(TDomain, TAddress), PduMS = case MgrMS of @@ -214,7 +243,7 @@ v1_v2c_proc(Vsn, NoteStore, Community, Domain, case Pdu#pdu.type of 'set-request' -> %% Check if this message has already been processed - Key = {agent, Ip, ReqId}, + Key = {agent, {TDomain, TAddress}, ReqId}, case snmp_note_store:get_note(NoteStore, Key) of undefined -> %% Set the processed note _after_ pdu processing. @@ -236,13 +265,7 @@ v1_v2c_proc(Vsn, NoteStore, Community, Domain, {discarded, Reason}; _TrapPdu -> {discarded, trap_pdu} - end; -v1_v2c_proc(_Vsn, _NoteStore, _Community, snmpUDPDomain, TAddress, - _LocalEngineID, _Data, _HS, _Log, _Packet) -> - {discarded, {badarg, TAddress}}; -v1_v2c_proc(_Vsn, _NoteStore, _Community, TDomain, _TAddress, - _LocalEngineID, _Data, _HS, _Log, _Packet) -> - {discarded, {badarg, TDomain}}. + end. sec_model('version-1') -> ?SEC_V1; sec_model('version-2') -> ?SEC_V2C. @@ -252,8 +275,7 @@ sec_model('version-2') -> ?SEC_V2C. %% Handles a SNMPv3 Message, following the procedures in rfc2272, %% section 4.2 and 7.2 %%----------------------------------------------------------------- -v3_proc(NoteStore, Packet, _TDomain, _TAddress, LocalEngineID, - V3Hdr, Data, Log) -> +v3_proc(NoteStore, Packet, _From, LocalEngineID, V3Hdr, Data, Log) -> case (catch v3_proc(NoteStore, Packet, LocalEngineID, V3Hdr, Data, Log)) of {'EXIT', Reason} -> exit(Reason); @@ -999,7 +1021,7 @@ generate_discovery_msg(NoteStore, {TDomain, TAddress}, InitialUserName, ContextName, Timeout) -> - {ok, {_Domain, Address}} = transform_taddr(TDomain, TAddress), + {ok, {Domain, Address}} = transform_taddr(TDomain, TAddress), %% 7.1.7 ?vdebug("generate_discovery_msg -> 7.1.7 (~w)", [ManagerEngineID]), @@ -1041,7 +1063,7 @@ generate_discovery_msg(NoteStore, {TDomain, TAddress}, %% Log(Packet), inc_snmp_out_vars(Pdu), ?vdebug("generate_discovery_msg -> done", []), - {Packet, Address}; + {Domain, Address, Packet}; Error -> throw(Error) @@ -1081,8 +1103,22 @@ transform_taddr(?transportDomainUdpIpv4, [A, B, C, D, P1, P2]) -> {ok, {Domain, Address}}; transform_taddr(?transportDomainUdpIpv4, BadAddr) -> {error, {bad_transportDomainUdpIpv4_address, BadAddr}}; -transform_taddr(?transportDomainUdpIpv6, - [A1, A2, A3, A4, A5, A6, A7, A8, P1, P2]) -> +transform_taddr( + ?transportDomainUdpIpv6, + [A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, + P1, P2]) -> + Domain = transportDomainUdpIpv6, + Addr = + {(A1 bsl 8) bor A2, (A3 bsl 8) bor A4, + (A5 bsl 8) bor A6, (A7 bsl 8) bor A8, + (A9 bsl 8) bor A10, (A11 bsl 8) bor A12, + (A13 bsl 8) bor A14, (A15 bsl 8) bor A16}, + Port = P1 bsl 8 + P2, + Address = {Addr, Port}, + {ok, {Domain, Address}}; +transform_taddr( + ?transportDomainUdpIpv6, + [A1, A2, A3, A4, A5, A6, A7, A8, P1, P2]) -> Domain = transportDomainUdpIpv6, Addr = {A1, A2, A3, A4, A5, A6, A7, A8}, Port = P1 bsl 8 + P2, @@ -1171,6 +1207,9 @@ mk_v1_v2_packet_list([{Domain, Addr} | T], %% Sending from default UDP port inc_snmp_out_vars(Pdu), Entry = {Domain, Addr, Packet}, + %% It would be cleaner to return {To, Packet} to not + %% break the abstraction for an address on the + %% {Domain, Address} format. mk_v1_v2_packet_list(T, Packet, Len, Pdu, [Entry | Acc]). @@ -1277,6 +1316,9 @@ mk_v3_packet_entry(NoteStore, Domain, Addr, req_id = Pdu#pdu.request_id}, snmp_note_store:set_note(NoteStore, 1500, CacheKey, CacheVal), inc_snmp_out_vars(Pdu), + %% It would be cleaner to return {To, Packet} to not + %% break the abstraction for an address on the + %% {Domain, Address} format. {ok, {Domain, Addr, Data}} end. diff --git a/lib/snmp/src/agent/snmpa_net_if.erl b/lib/snmp/src/agent/snmpa_net_if.erl index 79c85a6e4e..840d56d563 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-2011. All Rights Reserved. +%% Copyright Ericsson AB 2004-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -35,18 +35,27 @@ -include("snmp_debug.hrl"). -include("snmp_verbosity.hrl"). --record(state, {parent, - note_store, - master_agent, - usock, - usock_opts, - mpd_state, - log, - reqs = [], - debug = false, - limit = infinity, - rcnt = [], - filter}). +-record(state, + {parent, + note_store, + master_agent, + transports = [], +%% usock, +%% usock_opts, + mpd_state, + log, + reqs = [], + debug = false, + limit = infinity, +%% rcnt = [], + filter}). +%% domain = snmpUDPDomain}). + +-record(transport, + {socket, + domain = snmpUDPDomain, + opts = [], + req_refs = []}). -ifndef(default_verbosity). -define(default_verbosity,silence). @@ -104,13 +113,9 @@ get_request_limit(Pid) -> set_request_limit(Pid, NewLimit) -> call(Pid, {set_request_limit, NewLimit}). -get_port() -> - {value, UDPPort} = snmp_framework_mib:intAgentUDPPort(get), - UDPPort. - -get_address() -> - {value, IPAddress} = snmp_framework_mib:intAgentIpAddress(get), - IPAddress. +get_transports() -> + {value, Transports} = snmp_framework_mib:intAgentTransports(get), + Transports. filter_reset(Pid) -> Pid ! filter_reset. @@ -129,7 +134,22 @@ init(Prio, NoteStore, MasterAgent, Parent, Opts) -> case (catch do_init(Prio, NoteStore, MasterAgent, Parent, Opts)) of {ok, State} -> proc_lib:init_ack({ok, self()}), - loop(State); + try loop(State) + catch + C:E 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 + info_msg(Fmt, [C, E, S]); + _ -> + error_msg(Fmt, [C, E, S]) + end, + erlang:raise(C, E, S) + end; {error, Reason} -> config_err("failed starting net-if: ~n~p", [Reason]), proc_lib:init_ack({error, Reason}); @@ -147,12 +167,6 @@ do_init(Prio, NoteStore, MasterAgent, Parent, Opts) -> put(verbosity,get_verbosity(Opts)), ?vlog("starting",[]), - %% -- Port and address -- - UDPPort = get_port(), - ?vdebug("port: ~w",[UDPPort]), - IPAddress = get_address(), - ?vdebug("addr: ~w",[IPAddress]), - %% -- Versions -- Vsns = get_vsns(Opts), ?vdebug("vsns: ~w",[Vsns]), @@ -162,39 +176,45 @@ do_init(Prio, NoteStore, MasterAgent, Parent, Opts) -> ?vdebug("Limit: ~w", [Limit]), FilterOpts = get_filter_opts(Opts), FilterMod = create_filter(FilterOpts), - ?vdebug("FilterMod: ~w", [FilterMod]), + ?vdebug("FilterMod: ~w FilterOpts: ~p", [FilterMod,FilterOpts]), %% -- Audit trail log Log = create_log(), ?vdebug("Log: ~w",[Log]), - - %% -- Socket -- - IPOpts1 = ip_opt_bind_to_ip_address(Opts, IPAddress), - IPOpts2 = ip_opt_no_reuse_address(Opts), - IPOpts3 = ip_opt_recbuf(Opts), - IPOpts4 = ip_opt_sndbuf(Opts), - IPOpts = [binary | IPOpts1 ++ IPOpts2 ++ IPOpts3 ++ IPOpts4], - ?vdebug("open socket with options: ~w",[IPOpts]), - case gen_udp_open(UDPPort, IPOpts) of - {ok, Sock} -> + DomainAddresses = get_transports(), + ?vdebug("DomainAddresses: ~w",[DomainAddresses]), + try + [begin + SocketOpts = socket_opts(Domain, Address, Opts), + Socket = socket_open(Domain, SocketOpts), + active_once(Socket), + #transport{ + socket = Socket, + domain = Domain, + opts = SocketOpts} + end || {Domain, Address} <- DomainAddresses] + of + [] -> + ?vinfo("No transports configured: ~p", [DomainAddresses]), + {error, {no_transports,DomainAddresses}}; + Transports -> MpdState = snmpa_mpd:init(Vsns), - init_counters(), - active_once(Sock), + init_counters(), S = #state{parent = Parent, note_store = NoteStore, master_agent = MasterAgent, mpd_state = MpdState, - usock = Sock, - usock_opts = IPOpts, + transports = Transports, log = Log, limit = Limit, filter = FilterMod}, ?vdebug("started with MpdState: ~p", [MpdState]), - {ok, S}; - {error, Reason} -> - ?vinfo("Failed to open UDP socket: ~p", [Reason]), - {error, {udp_open, UDPPort, Reason}} + {ok, S} + catch + Error -> + ?vinfo("Failed to initialize socket(s): ~p", [Error]), + {error, Error} end. @@ -250,48 +270,84 @@ create_filter(BadOpts) -> throw({error, {bad_filter_opts, BadOpts}}). -log({_, []}, _, _, _, _) -> +log({_, []}, _, _, _) -> ok; -log({Log, Types}, 'set-request', Packet, Addr, Port) -> +log({Log, Types}, 'set-request', Packet, Address) -> case lists:member(write, Types) of true -> - snmp_log:log(Log, Packet, Addr, Port); + snmp_log:log(Log, Packet, format_address(Address)); false -> ok end; -log({Log, Types}, _, Packet, Addr, Port) -> +log({Log, Types}, _, Packet, Address) -> case lists:member(read, Types) of true -> - snmp_log:log(Log, Packet, Addr, Port); + snmp_log:log(Log, Packet, format_address(Address)); false -> ok - end; -log(_, _, _, _, _) -> - ok. - - -gen_udp_open(Port, Opts) -> + end. + +format_address(Address) -> + iolist_to_binary(snmp_conf:mk_addr_string(Address)). + + +socket_open(snmpUDPDomain = Domain, [IpPort | Opts]) -> case init:get_argument(snmp_fd) of {ok, [[FdStr]]} -> Fd = list_to_integer(FdStr), - gen_udp:open(0, [{fd, Fd}|Opts]); + ?vdebug("socket_open(~p, [~p | ~p]) Fd: ~p", + [Domain, IpPort, Opts, Fd]), + gen_udp_open(IpPort, [{fd, Fd} | Opts]); error -> case init:get_argument(snmpa_fd) of {ok, [[FdStr]]} -> Fd = list_to_integer(FdStr), - gen_udp:open(0, [{fd, Fd}|Opts]); + ?vdebug("socket_open(~p, [~p | ~p]) Fd: ~p", + [Domain, IpPort, Opts, Fd]), + gen_udp_open(IpPort, [{fd, Fd} | Opts]); error -> - gen_udp:open(Port, Opts) + ?vdebug("socket_open(~p, [~p | ~p])", + [Domain, IpPort, Opts]), + gen_udp_open(IpPort, Opts) end + end; +socket_open(Domain, [IpPort | Opts]) + when Domain =:= transportDomainUdpIpv4; + Domain =:= transportDomainUdpIpv6 -> + ?vdebug("socket_open(~p, [~p | ~p])", [Domain, IpPort, Opts]), + gen_udp_open(IpPort, Opts); +socket_open(Domain, Opts) -> + throw({socket_open, Domain, Opts}). + +gen_udp_open(IpPort, Opts) -> + case gen_udp:open(IpPort, Opts) of + {ok, Socket} -> + Socket; + {error, Reason} -> + throw({udp_open, IpPort, Reason}) end. -loop(S) -> + +loop(#state{transports = Transports, limit = Limit, parent = Parent} = S) -> + ?vdebug("loop(~p)", [S]), receive - {udp, _UdpId, Ip, Port, Packet} -> - ?vlog("got paket from ~w:~w",[Ip,Port]), - NewS = maybe_handle_recv(S, Ip, Port, Packet), - loop(NewS); + {udp, Socket, IpAddr, IpPort, Packet} = Msg when is_port(Socket) -> + ?vlog("got paket from ~w:~w on ~w", [IpAddr, IpPort, Socket]), + case lists:keyfind(Socket, #transport.socket, Transports) of + #transport{socket = Socket, domain = Domain} = Transport -> + From = + case Domain of + snmpUDPDomain -> + {IpAddr, IpPort}; + _ -> + {Domain, {IpAddr, IpPort}} + end, + loop(maybe_handle_recv(S, Transport, From, Packet)); + false -> + error_msg("Packet on unknown port: ~p", [Msg]), + loop(S) + end; {info, ReplyRef, Pid} -> Info = get_info(S), @@ -299,47 +355,78 @@ loop(S) -> loop(S); %% response (to get/get_next/get_bulk/set requests) - {snmp_response, Vsn, RePdu, Type, ACMData, Dest, []} -> + {snmp_response, Vsn, RePdu, Type, ACMData, To, Extra} -> ?vlog("reply pdu: " "~n ~s", [?vapply(snmp_misc, format, [256, "~w", [RePdu]])]), - NewS = maybe_handle_reply_pdu(S, Vsn, RePdu, Type, ACMData, Dest), - loop(NewS); + {_, ReqRef} = lists:keyfind(request_ref, 1, Extra), + case + case + (Limit =/= infinity) andalso + select_transport_from_req_ref(ReqRef, Transports) + of + false -> + select_transport_from_domain( + address_to_domain(To), + Transports); + T -> + T + end + of + false -> + error_msg( + "Can not find transport for response PDU to: ~s", + [format_address(To)]), + loop(S); + Transport -> + NewS = update_req_counter_outgoing(S, Transport, ReqRef), + maybe_handle_reply_pdu( + NewS, Transport, Vsn, RePdu, Type, ACMData, To), + loop(NewS) + end; %% Traps/notification - {send_pdu, Vsn, Pdu, MsgData, To} -> - ?vdebug("send pdu: " - "~n Pdu: ~p" - "~n To: ~p", [Pdu, To]), - NewS = maybe_handle_send_pdu(S, Vsn, Pdu, MsgData, To, undefined), + {send_pdu, Vsn, Pdu, MsgData, TDomAddrs} -> + ?vdebug("send pdu:~n" + " Pdu: ~p~n" + " TDomAddrs: ~p", [Pdu, TDomAddrs]), + NewS = + maybe_handle_send_pdu( + S, Vsn, Pdu, MsgData, TDomAddrs, undefined), loop(NewS); %% We dont use the extra-info at this time, ... - {send_pdu, Vsn, Pdu, MsgData, To, _ExtraInfo} -> - ?vdebug("send pdu: " - "~n Pdu: ~p" - "~n To: ~p", [Pdu, To]), - NewS = maybe_handle_send_pdu(S, Vsn, Pdu, MsgData, To, undefined), + {send_pdu, Vsn, Pdu, MsgData, TDomAddrs, _ExtraInfo} -> + ?vdebug("send pdu:~n" + " Pdu: ~p~n" + " TDomAddrs: ~p", [Pdu, TDomAddrs]), + NewS = + maybe_handle_send_pdu( + S, Vsn, Pdu, MsgData, TDomAddrs, undefined), loop(NewS); %% Informs - {send_pdu_req, Vsn, Pdu, MsgData, To, From} -> - ?vdebug("send pdu request: " - "~n Pdu: ~p" - "~n To: ~p" - "~n From: ~p", - [Pdu, To, toname(From)]), - NewS = maybe_handle_send_pdu(S, Vsn, Pdu, MsgData, To, From), + {send_pdu_req, Vsn, Pdu, MsgData, TDomAddrs, From} -> + ?vdebug("send pdu request:~n" + " Pdu: ~p~n" + " TDomAddrs: ~p~n" + " From: ~p", + [Pdu, TDomAddrs, toname(From)]), + NewS = + maybe_handle_send_pdu( + S, Vsn, Pdu, MsgData, TDomAddrs, From), loop(NewS); %% We dont use the extra-info at this time, ... - {send_pdu_req, Vsn, Pdu, MsgData, To, From, _ExtraInfo} -> - ?vdebug("send pdu request: " - "~n Pdu: ~p" - "~n To: ~p" - "~n From: ~p", - [Pdu, To, toname(From)]), - NewS = maybe_handle_send_pdu(S, Vsn, Pdu, MsgData, To, From), + {send_pdu_req, Vsn, Pdu, MsgData, TDomAddrs, From, _ExtraInfo} -> + ?vdebug("send pdu request:~n" + " Pdu: ~p~n" + " TDomAddrs: ~p~n" + " From: ~p", + [Pdu, TDomAddrs, toname(From)]), + NewS = + maybe_handle_send_pdu( + S, Vsn, Pdu, MsgData, TDomAddrs, From), loop(NewS); %% Discovery Inform @@ -365,15 +452,34 @@ loop(S) -> NewS = handle_send_discovery(S, Pdu, MsgData, To, From), loop(NewS); - {discarded_pdu, _Vsn, ReqId, _ACMData, Variable, _Extra} -> - ?vdebug("discard PDU: ~p", [Variable]), + {discarded_pdu, _Vsn, ReqId, _ACMData, Variable, Extra} -> + ?vdebug("discard PDU: ~p - ~p - ~p", + [Variable, Extra, Transports]), snmpa_mpd:discarded_pdu(Variable), - NewS = update_req_counter_outgoing(S, ReqId), - loop(NewS); + {_, ReqRef} = lists:keyfind(request_ref, 1, Extra), + if + Limit =:= infinity -> + %% The incoming PDU was not registered + loop(update_req_counter_outgoing(S, false, ReqRef)); + true -> + case + select_transport_from_req_ref(ReqRef, Transports) + of + false -> + error_msg( + "Can not find transport for discarded PDU: ~p", + [ReqId]), + loop(S); + Transport -> + loop( + update_req_counter_outgoing( + S, Transport, ReqRef)) + end + end; {get_log_type, ReplyRef, Pid} -> ?vdebug("get log type: ~p", []), - #state{log = {_, LogType}} = S, + {_, LogType} = S#state.log, Pid ! {ReplyRef, {ok, LogType}, self()}, loop(S); @@ -385,7 +491,6 @@ loop(S) -> {get_request_limit, ReplyRef, Pid} -> ?vdebug("get request limit: ~p", []), - #state{limit = Limit} = S, Pid ! {ReplyRef, {ok, Limit}, self()}, loop(S); @@ -409,36 +514,50 @@ loop(S) -> reset_counters(), loop(S); - {'EXIT', Parent, Reason} when Parent == S#state.parent -> + {'EXIT', Parent, Reason} -> ?vlog("parent (~p) exited: " "~n ~p", [Parent, Reason]), exit(Reason); - {'EXIT', Port, Reason} when Port == S#state.usock -> - UDPPort = get_port(), - NewS = - case gen_udp_open(UDPPort, S#state.usock_opts) of - {ok, Id} -> - error_msg("Port ~p exited for reason" - "~n ~p" - "~n Re-opened (~p)", [Port, Reason, Id]), - S#state{usock = Id}; - {error, ReopenReason} -> - error_msg("Port ~p exited for reason" - "~n ~p" - "~n Re-open failed with reason" - "~n ~p", - [Port, Reason, ReopenReason]), - ok - end, - loop(NewS); - - {'EXIT', Port, Reason} when is_port(Port) -> - error_msg("Exit message from port ~p for reason ~p~n", - [Port, Reason]), - loop(S); - - {'EXIT', Pid, Reason} -> + {'EXIT', Socket, Reason} when is_port(Socket) -> + case lists:keyfind(Socket, #transport.socket, Transports) of + #transport{ + socket = Socket, + domain = Domain, + opts = SocketOpts, + req_refs = ReqRefs} = Transport -> + try socket_open(Domain, SocketOpts) of + NewSocket -> + error_msg( + "Socket ~p exited for reason" + "~n ~p" + "~n Re-opened (~p)", + [Socket, Reason, NewSocket]), + (length(ReqRefs) < Limit) andalso + active_once(NewSocket), + S#state{ + transports = + lists:keyreplace( + Socket, #transport.socket, Transports, + Transport#transport{socket = NewSocket})} + catch + ReopenReason -> + error_msg( + "Socket ~p exited for reason" + "~n ~p" + "~n Re-open failed with reason" + "~n ~p", + [Socket, Reason, ReopenReason]), + exit(ReopenReason) + end; + false -> + error_msg( + "Exit message from port ~p for reason ~p~n", + [Socket, Reason]), + loop(S) + end; + + {'EXIT', Pid, Reason} when is_pid(Pid) -> ?vlog("~p exited: " "~n ~p", [Pid, Reason]), NewS = clear_reqs(Pid, S), @@ -446,205 +565,321 @@ loop(S) -> {system, From, Msg} -> ?vdebug("system event ~p from ~p", [Msg, From]), - sys:handle_system_msg(Msg, From, S#state.parent, ?MODULE, [], S); + sys:handle_system_msg(Msg, From, Parent, ?MODULE, [], S); _ -> loop(S) end. -update_req_counter_incomming(#state{limit = infinity, usock = Sock} = S, _) -> - active_once(Sock), %% No limit so activate directly +update_req_counter_incoming( + #state{limit = infinity} = S, + #transport{socket = Socket}, + _ReqRef) -> + active_once(Socket), %% No limit so activate directly S; -update_req_counter_incomming(#state{limit = Limit, - rcnt = RCnt, - usock = Sock} = S, Rid) - when length(RCnt) + 1 == Limit -> +update_req_counter_incoming( + #state{limit = Limit} = S, + #transport{socket = Socket, req_refs = ReqRefs} = T, + ReqRef) when length(ReqRefs) + 1 >= Limit -> %% Ok, one more and we are at the limit. %% Just make sure we are not already processing this one... - case lists:member(Rid, RCnt) of + case lists:member(ReqRef, ReqRefs) of false -> %% We are at the limit, do _not_ activate socket - S#state{rcnt = [Rid|RCnt]}; + update_transport_req_refs(S, T, [ReqRef | ReqRefs]); true -> - active_once(Sock), + active_once(Socket), S end; -update_req_counter_incomming(#state{rcnt = RCnt, - usock = Sock} = S, Rid) -> - active_once(Sock), - case lists:member(Rid, RCnt) of +update_req_counter_incoming( + #state{} = S, + #transport{socket = Socket, req_refs = ReqRefs} = T, + ReqRef) -> + active_once(Socket), + case lists:member(ReqRef, ReqRefs) of false -> - S#state{rcnt = [Rid|RCnt]}; + update_transport_req_refs(S, T, [ReqRef | ReqRefs]); true -> S end. - -update_req_counter_outgoing(#state{limit = infinity} = S, _Rid) -> +update_req_counter_outgoing( + #state{limit = infinity} = S, + _Transport, _ReqRef) -> %% Already activated (in the incoming function) S; -update_req_counter_outgoing(#state{limit = Limit, - rcnt = RCnt, - usock = Sock} = S, Rid) - when length(RCnt) == Limit -> - ?vtrace("handle_req_counter_outgoing(~w) -> entry with" - "~n Rid: ~w" - "~n length(RCnt): ~w", [Limit, Rid, length(RCnt)]), - case lists:delete(Rid, RCnt) of - NewRCnt when length(NewRCnt) < Limit -> +update_req_counter_outgoing( + #state{limit = Limit} = S, + #transport{socket = Socket, req_refs = ReqRefs} = Transport, + ReqRef) -> + LengthReqRefs = length(ReqRefs), + ?vtrace("update_req_counter_outgoing() -> entry with~n" + " Limit: ~w~n" + " ReqRef: ~w~n" + " length(ReqRefs): ~w", [Limit, ReqRef, LengthReqRefs]), + NewReqRefs = lists:delete(ReqRef, ReqRefs), + (LengthReqRefs >= Limit) andalso (length(NewReqRefs) < Limit) andalso + begin ?vtrace("update_req_counter_outgoing -> " - "passed below limit: activate", []), - active_once(Sock), - S#state{rcnt = NewRCnt}; - _ -> - S - end; -update_req_counter_outgoing(#state{limit = Limit, rcnt = RCnt} = S, - Rid) -> - ?vtrace("handle_req_counter_outgoing(~w) -> entry with" - "~n Rid: ~w" - "~n length(RCnt): ~w", [Limit, Rid, length(RCnt)]), - NewRCnt = lists:delete(Rid, RCnt), - S#state{rcnt = NewRCnt}. - - -maybe_handle_recv(#state{usock = Sock, filter = FilterMod} = S, - Ip, Port, Packet) -> - case (catch FilterMod:accept_recv(Ip, Port)) of + "passed below limit: activate", []), + active_once(Socket) + end, + update_transport_req_refs(S, Transport, NewReqRefs). + +update_transport_req_refs( + #state{transports = Transports} = S, + #transport{socket = Socket} = T, + ReqRefs) -> + S#state{ + transports = + lists:keyreplace( + Socket, #transport.socket, Transports, + T#transport{req_refs = ReqRefs})}. + + +maybe_handle_recv( + #state{filter = FilterMod} = S, + #transport{socket = Socket} = Transport, + From, Packet) -> + {From_1, From_2} = From, + case + try FilterMod:accept_recv(From_1, From_2) + catch + Class:Exception -> + error_msg( + "FilterMod:accept_recv(~p, ~p) crashed: ~w:~w~n ~p", + [From_1,From_2,Class,Exception,erlang:get_stacktrace()]), + true + end + of false -> %% Drop the received packet inc(netIfMsgInDrops), - active_once(Sock), + active_once(Socket), S; - _ -> - handle_recv(S, Ip, Port, Packet) + Other -> + case Other of + true -> + ok; + _ -> + error_msg( + "FilterMod:accept_recv(~p, ~p) returned: ~p", + [From_1,From_2,Other]) + end, + handle_recv(S, Transport, From, Packet) end. -handle_discovery_response(_Ip, _Port, #pdu{request_id = ReqId} = Pdu, - ManagerEngineId, - #state{usock = Sock, reqs = Reqs} = S) -> - case lists:keysearch(ReqId, 1, S#state.reqs) of - {value, {_, Pid}} -> - active_once(Sock), - Pid ! {snmp_discovery_response_received, Pdu, ManagerEngineId}, - NReqs = lists:keydelete(ReqId, 1, Reqs), - S#state{reqs = NReqs}; - _ -> - %% Ouch, timeout? resend? - S - end. - -handle_recv(#state{usock = Sock, - mpd_state = MpdState, - note_store = NS, - log = Log} = S, Ip, Port, Packet) -> +handle_recv( + #state{mpd_state = MpdState, note_store = NS, log = Log} = S, + #transport{socket = Socket} = Transport, + From, Packet) -> put(n1, erlang:now()), - LogF = fun(Type, Data) -> - log(Log, Type, Data, Ip, Port) - end, - Domain = snmp_conf:which_domain(Ip), % What the ****... - case (catch snmpa_mpd:process_packet(Packet, - Domain, {Ip, Port}, - MpdState, NS, LogF)) of + LogF = + fun(Type, Data) -> + log(Log, Type, Data, From) + end, + case (catch snmpa_mpd:process_packet( + Packet, From, MpdState, NS, LogF)) of {ok, _Vsn, Pdu, _PduMS, {discovery, ManagerEngineId}} -> - handle_discovery_response(Ip, Port, Pdu, ManagerEngineId, S); + handle_discovery_response( + S, Transport, From, Pdu, ManagerEngineId); {ok, _Vsn, Pdu, _PduMS, discovery} -> - handle_discovery_response(Ip, Port, Pdu, undefined, S); + handle_discovery_response( + S, Transport, From, Pdu, undefined); {ok, Vsn, Pdu, PduMS, ACMData} -> ?vlog("got pdu ~s", [?vapply(snmp_misc, format, [256, "~w", [Pdu]])]), - %% handle_recv_pdu(Ip, Port, Vsn, Pdu, PduMS, ACMData, S); - maybe_handle_recv_pdu(Ip, Port, Vsn, Pdu, PduMS, ACMData, S); + %% handle_recv_pdu(S, Transport, From, Vsn, Pdu, PduMS, ACMData); + maybe_handle_recv_pdu( + S, Transport, From, Vsn, Pdu, PduMS, ACMData); {discarded, Reason} -> ?vlog("packet discarded for reason: ~s", [?vapply(snmp_misc, format, [256, "~w", [Reason]])]), - active_once(Sock), + active_once(Socket), S; {discarded, Reason, ReportPacket} -> ?vlog("sending report for reason: " "~n ~s", [?vapply(snmp_misc, format, [256, "~w", [Reason]])]), - (catch udp_send(S#state.usock, Ip, Port, ReportPacket)), - active_once(Sock), + (catch udp_send(Socket, From, ReportPacket)), + active_once(Socket), S; {discovery, ReportPacket} -> ?vlog("sending discovery report", []), - (catch udp_send(S#state.usock, Ip, Port, ReportPacket)), - active_once(Sock), + (catch udp_send(Socket, From, ReportPacket)), + active_once(Socket), S; Error -> error_msg("processing of received message failed: " "~n ~p", [Error]), - active_once(Sock), + active_once(Socket), S end. - -maybe_handle_recv_pdu(Ip, Port, Vsn, #pdu{type = Type} = Pdu, PduMS, ACMData, - #state{usock = Sock, filter = FilterMod} = S) -> - case (catch FilterMod:accept_recv_pdu(Ip, Port, Type)) of + +handle_discovery_response( + #state{reqs = Reqs} = S, + #transport{socket = Socket}, + _From, + #pdu{request_id = ReqId} = Pdu, + ManagerEngineId) -> + case lists:keyfind(ReqId, 1, S#state.reqs) of + {ReqId, Pid} -> + active_once(Socket), + Pid ! {snmp_discovery_response_received, Pdu, ManagerEngineId}, + %% XXX Strange... Reqs from this Pid should be reaped + %% at process exit by clear_reqs/2 so the following + %% should be redundant. + NReqs = lists:keydelete(ReqId, 1, Reqs), + S#state{reqs = NReqs}; + false -> + %% Ouch, timeout? resend? + S + end. + +maybe_handle_recv_pdu( + #state{filter = FilterMod} = S, + #transport{socket = Socket} = Transport, + From, Vsn, + #pdu{type = Type} = Pdu, PduMS, ACMData) -> + {From_1, From_2} = From, + case + try FilterMod:accept_recv_pdu(From_1, From_2, Type) + catch + Class:Exception -> + error_msg( + "FilterMod:accept_recv_pdu(~p, ~p, ~p) crashed: ~w:~w~n" + " ~p", + [From_1,From_2,Type,Class,Exception, + erlang:get_stacktrace()]), + true + end + of false -> inc(netIfPduInDrops), - active_once(Sock), - ok; - _ -> - handle_recv_pdu(Ip, Port, Vsn, Pdu, PduMS, ACMData, S) - end; -maybe_handle_recv_pdu(Ip, Port, Vsn, Pdu, PduMS, ACMData, S) -> - handle_recv_pdu(Ip, Port, Vsn, Pdu, PduMS, ACMData, S). + active_once(Socket), + S; + Other -> + case Other of + true -> + ok; + _ -> + error_msg( + "FilterMod:accept_recv_pdu(~p, ~p, ~p) returned: ~p", + [From_1,From_2,Type,Other]) + end, + handle_recv_pdu(S, Transport, From, Vsn, Pdu, PduMS, ACMData) + end. -handle_recv_pdu(Ip, Port, Vsn, #pdu{type = 'get-response'} = Pdu, - _PduMS, _ACMData, #state{usock = Sock} = S) -> - active_once(Sock), - handle_response(Vsn, Pdu, {Ip, Port}, S), +handle_recv_pdu( + #state{reqs = Reqs} = S, + #transport{socket = Socket}, + From, Vsn, + #pdu{type = 'get-response', request_id = ReqId} = Pdu, + _PduMS, _ACMData) -> + active_once(Socket), + case lists:keyfind(ReqId, 1, Reqs) of + {ReqId, Pid} -> + ?vdebug("handle_recv_pdu -> " + "~n send response to receiver ~p", [Pid]), + Pid ! {snmp_response_received, Vsn, Pdu, From}; + false -> + ?vdebug("handle_recv_pdu -> " + "~n No receiver available for response pdu", []) + end, S; -handle_recv_pdu(Ip, Port, Vsn, #pdu{request_id = Rid, type = Type} = Pdu, - PduMS, ACMData, #state{master_agent = Pid} = S) - when ((Type =:= 'get-request') orelse - (Type =:= 'get-next-request') orelse - (Type =:= 'get-bulk-request')) -> - ?vtrace("handle_recv_pdu -> received get (~w)", [Type]), - Pid ! {snmp_pdu, Vsn, Pdu, PduMS, ACMData, {Ip, Port}, []}, - update_req_counter_incomming(S, Rid); -handle_recv_pdu(Ip, Port, Vsn, Pdu, PduMS, ACMData, - #state{usock = Sock, master_agent = Pid} = S) -> +handle_recv_pdu( + #state{master_agent = Pid} = S, + #transport{} = Transport, + From, Vsn, + #pdu{type = Type} = Pdu, + PduMS, ACMData) + when Type =:= 'set-request'; + Type =:= 'get-request'; + Type =:= 'get-next-request'; + Type =:= 'get-bulk-request' -> + ?vtrace("handle_recv_pdu -> received request (~w)", [Type]), + ReqRef = make_ref(), + Extra = [{request_ref, ReqRef}], + Pid ! {snmp_pdu, Vsn, Pdu, PduMS, ACMData, From, Extra}, + NewS = update_req_counter_incoming(S, Transport, ReqRef), + ?vdebug("handle_recv_pdu -> ~p", [NewS]), + NewS; +handle_recv_pdu( + #state{master_agent = Pid} = S, + #transport{socket = Socket}, + From, Vsn, Pdu, PduMS, ACMData) -> ?vtrace("handle_recv_pdu -> received other request", []), - active_once(Sock), - Pid ! {snmp_pdu, Vsn, Pdu, PduMS, ACMData, {Ip, Port}, []}, + active_once(Socket), + Pid ! {snmp_pdu, Vsn, Pdu, PduMS, ACMData, From, []}, S. -maybe_handle_reply_pdu(#state{filter = FilterMod} = S, Vsn, - #pdu{request_id = Rid} = Pdu, - Type, ACMData, {Ip, Port} = Dest) -> - S1 = update_req_counter_outgoing(S, Rid), - case (catch FilterMod:accept_send_pdu([{Ip, Port}], Type)) of +maybe_handle_reply_pdu( + #state{filter = FilterMod, transports = Transports} = S, + #transport{} = Transport, + Vsn, + #pdu{} = Pdu, + Type, ACMData, To) -> + %% + Addresses = [fix_filter_address(Transports, To)], + case + try + FilterMod:accept_send_pdu(Addresses, Type) + catch + Class:Exception -> + error_msg( + "FilterMod:accept_send_pdu(~p, ~p) crashed: ~w:~w~n ~p", + [Addresses, Type, Class, Exception, + erlang:get_stacktrace()]), + true + end + of false -> inc(netIfPduOutDrops), ok; - _ -> - handle_reply_pdu(S1, Vsn, Pdu, Type, ACMData, Dest) - end, - S1. - -handle_reply_pdu(#state{log = Log, - usock = Sock, - filter = FilterMod}, - Vsn, Pdu, Type, ACMData, {Ip, Port}) -> - LogF = fun(Type2, Data) -> - log(Log, Type2, Data, Ip, Port) - end, + Other -> + case Other of + true -> + ok; + _ -> + error_msg( + "FilterMod:accept_send_pdu(~p, ~p) returned: ~p", + [Addresses,Type,Other]) + end, + handle_reply_pdu(S, Transport, Vsn, Pdu, Type, ACMData, To) + end. + +handle_reply_pdu( + #state{log = Log} = S, + #transport{} = Transport, + Vsn, + #pdu{} = Pdu, + Type, ACMData, To) -> + %% + LogF = + fun(Type2, Data) -> + log(Log, Type2, Data, To) + end, case (catch snmpa_mpd:generate_response_msg(Vsn, Pdu, Type, ACMData, LogF)) of {ok, Packet} -> ?vinfo("time in agent: ~w mysec", [time_in_agent()]), - maybe_udp_send(FilterMod, Sock, Ip, Port, Packet); + try maybe_udp_send(S, Transport, To, Packet) + catch + {Reason, Sz} -> + error_msg("Cannot send message " + "~n size: ~p" + "~n reason: ~p" + "~n pdu: ~p", + [Sz, Reason, Pdu]) + end; {discarded, Reason} -> ?vlog("handle_reply_pdu -> " "~n reply discarded for reason: ~s", @@ -652,105 +887,116 @@ handle_reply_pdu(#state{log = Log, ok; {'EXIT', Reason} -> user_err("failed generating response message: " - "~nPDU: ~w~n~w", [Pdu, Reason]) + "~nPDU: ~p~n~p", [Pdu, Reason]) end. - -process_taddrs(To) -> - process_taddrs(To, []). -process_taddrs([], Acc) -> - lists:reverse(Acc); -%% v3 -process_taddrs([{{_Domain, AddrAndPort}, _SecData}|T], Acc) -> - process_taddrs(T, [AddrAndPort|Acc]); -%% v1 & v2 -process_taddrs([{_Domain, AddrAndPort}|T], Acc) -> - process_taddrs(T, [AddrAndPort|Acc]). -merge_taddrs(To1, To2) -> - merge_taddrs(To1, To2, []). +maybe_handle_send_pdu( + #state{filter = FilterMod, transports = Transports} = S, + Vsn, Pdu, MsgData, TDomAddrSecs, From) -> -merge_taddrs([], _To2, Acc) -> - lists:reverse(Acc); -%% v3 -merge_taddrs([{{_, AddrAndPort}, _} = H|To1], To2, Acc) -> - case lists:member(AddrAndPort, To2) of - true -> - merge_taddrs(To1, To2, [H|Acc]); - false -> - merge_taddrs(To1, To2, Acc) - end; -%% v1 & v2 -merge_taddrs([{_, AddrAndPort} = H|To1], To2, Acc) -> - case lists:member(AddrAndPort, To2) of - true -> - merge_taddrs(To1, To2, [H|Acc]); - false -> - merge_taddrs(To1, To2, Acc) - end; -merge_taddrs([_Crap|To1], To2, Acc) -> - merge_taddrs(To1, To2, Acc). - - -maybe_handle_send_pdu(#state{filter = FilterMod} = S, - Vsn, Pdu, MsgData, To0, From) -> + ?vtrace("maybe_handle_send_pdu -> entry with~n" + " FilterMod: ~p~n" + " TDomAddrSecs: ~p", [FilterMod, TDomAddrSecs]), - ?vtrace("maybe_handle_send_pdu -> entry with" - "~n FilterMod: ~p" - "~n To0: ~p", [FilterMod, To0]), - - To1 = snmpa_mpd:process_taddrs(To0), - To2 = process_taddrs(To1), + DomAddrSecs = snmpa_mpd:process_taddrs(TDomAddrSecs), + AddressesToFilter = + case is_legacy_transports(Transports) of + true -> + [fix_filter_legacy_mpd_address(DAS) + || DAS <- DomAddrSecs]; + false -> + [fix_filter_mpd_address(DAS) + || DAS <- DomAddrSecs] + end, - case (catch FilterMod:accept_send_pdu(To2, pdu_type_of(Pdu))) of + Type = pdu_type_of(Pdu), + + case + try FilterMod:accept_send_pdu(AddressesToFilter, Type) + catch + Class:Exception -> + error_msg( + "FilterMod:accept_send_pdu(~p, ~p) crashed: ~w:~w~n ~p", + [AddressesToFilter,Type, + Class,Exception,erlang:get_stacktrace()]), + true + end + of false -> inc(netIfPduOutDrops), ok; true -> - handle_send_pdu(S, Vsn, Pdu, MsgData, To1, From); - To3 when is_list(To3) -> - To4 = merge_taddrs(To1, To3), - ?vtrace("maybe_handle_send_pdu -> To4: " - "~n ~p", [To4]), - handle_send_pdu(S, Vsn, Pdu, MsgData, To4, From); - _ -> - handle_send_pdu(S, Vsn, Pdu, MsgData, To1, From) + handle_send_pdu(S, Vsn, Pdu, MsgData, DomAddrSecs, From); + FilteredAddresses when is_list(FilteredAddresses) -> + FilteredDomAddrSecs = + case is_legacy_transports(Transports) of + true -> + [DAS || + DAS <- DomAddrSecs, + lists:member( + fix_filter_legacy_mpd_address(DAS), + FilteredAddresses)]; + false -> + [DAS || + DAS <- DomAddrSecs, + lists:member( + fix_filter_mpd_address(DAS), + FilteredAddresses)] + end, + ?vtrace("maybe_handle_send_pdu -> FilteredDomAddrSecs:~n" + " ~p", [FilteredDomAddrSecs]), + handle_send_pdu(S, Vsn, Pdu, MsgData, FilteredDomAddrSecs, From); + Other -> + error_msg( + "FilterMod:accept_send_pdu(~p, ~p) returned: ~p", + [AddressesToFilter,Type,Other]), + handle_send_pdu(S, Vsn, Pdu, MsgData, DomAddrSecs, From) end. -handle_send_pdu(#state{note_store = NS} = S, Vsn, Pdu, MsgData, To, From) -> - - ?vtrace("handle_send_pdu -> entry with" - "~n Pdu: ~p" - "~n To: ~p", [Pdu, To]), +handle_send_pdu( + #state{note_store = NS} = S, + Vsn, Pdu, MsgData, DomAddrSecs, From) -> + %% + ?vtrace("handle_send_pdu -> entry with~n" + " Pdu: ~p~n" + " DomAddrSecs: ~p", [Pdu, DomAddrSecs]), - case (catch snmpa_mpd:generate_msg(Vsn, NS, Pdu, MsgData, To)) of + case (catch snmpa_mpd:generate_msg( + Vsn, NS, Pdu, MsgData, DomAddrSecs)) of {ok, Addresses} -> - handle_send_pdu(S, Pdu, Addresses); + do_handle_send_pdu(S, Pdu, Addresses); {discarded, Reason} -> ?vlog("handle_send_pdu -> " "~n PDU ~p not sent due to ~p", [Pdu, Reason]), ok; {'EXIT', Reason} -> user_err("failed generating message: " - "~nPDU: ~w~n~w", [Pdu, Reason]), + "~nPDU: ~p~n~p", [Pdu, Reason]), ok end, case From of undefined -> S; - Pid -> + Pid when is_pid(Pid) -> ?vtrace("link to ~p and add to request list", [Pid]), link(Pid), - NReqs = snmp_misc:keyreplaceadd(Pid, 2, S#state.reqs, - {Pdu#pdu.request_id, From}), + NReqs = + snmp_misc:keyreplaceadd( + Pid, 2, S#state.reqs, {Pdu#pdu.request_id, From}), S#state{reqs = NReqs} end. -handle_send_discovery(#state{note_store = NS} = S, - Pdu, MsgData, - To, From) -> +handle_send_discovery( + #state{ + note_store = NS, + log = Log, + reqs = Reqs, + transports = Transports} = S, + #pdu{type = Type, request_id = ReqId} = Pdu, + MsgData, To, From) when is_pid(From) -> ?vtrace("handle_send_discovery -> entry with" "~n Pdu: ~p" @@ -759,155 +1005,173 @@ handle_send_discovery(#state{note_store = NS} = S, "~n From: ~p", [Pdu, MsgData, To, From]), case (catch snmpa_mpd:generate_discovery_msg(NS, Pdu, MsgData, To)) of - {ok, {Packet, {Ip, Port}}} -> - handle_send_discovery(S, Pdu, Packet, Ip, Port, From); + {ok, {Domain, Address, Packet}} -> + case select_transport_from_domain(Domain, Transports) of + false -> + error_msg( + "Can not find transport to: ~s", + [format_address(To)]), + S; + #transport{socket = Socket} -> + log(Log, Type, Packet, {Domain, Address}), + udp_send(Socket, {Domain, Address}, Packet), + ?vtrace("handle_send_discovery -> sent (~w)", [ReqId]), + NReqs = snmp_misc:keyreplaceadd(From, 2, Reqs, {ReqId, From}), + S#state{reqs = NReqs} + end; {discarded, Reason} -> ?vlog("handle_send_discovery -> " "~n Discovery PDU ~p not sent due to ~p", [Pdu, Reason]), - ok; + S; {'EXIT', Reason} -> user_err("failed generating discovery message: " - "~n PDU: ~w" - "~n Reason: ~w", [Pdu, Reason]), - ok + "~n PDU: ~p" + "~n Reason: ~p", [Pdu, Reason]), + S end. -handle_send_discovery(#state{log = Log, - usock = Sock, - reqs = Reqs} = S, - #pdu{type = Type, - request_id = ReqId}, - Packet, Ip, Port, From) - when is_binary(Packet) -> - log(Log, Type, Packet, Ip, Port), - udp_send(Sock, Ip, Port, Packet), - ?vtrace("handle_send_discovery -> sent (~w)", [ReqId]), - NReqs = snmp_misc:keyreplaceadd(From, 2, Reqs, {ReqId, From}), - S#state{reqs = NReqs}. +do_handle_send_pdu(S, #pdu{type = Type} = Pdu, Addresses) -> + do_handle_send_pdu(S, Type, Pdu, Addresses); +do_handle_send_pdu(S, Trap, Addresses) -> + do_handle_send_pdu(S, trappdu, Trap, Addresses). -handle_send_pdu(S, #pdu{type = Type} = Pdu, Addresses) -> - handle_send_pdu(S, Type, Pdu, Addresses); -handle_send_pdu(S, Trap, Addresses) -> - handle_send_pdu(S, trappdu, Trap, Addresses). - -handle_send_pdu(S, Type, Pdu, Addresses) -> - case (catch handle_send_pdu1(S, Type, Addresses)) of +do_handle_send_pdu(S, Type, Pdu, Addresses) -> + try do_handle_send_pdu1(S, Type, Addresses) + catch {Reason, Sz} -> - error_msg("Cannot send message " - "~n size: ~p" - "~n reason: ~p" - "~n pdu: ~p", - [Sz, Reason, Pdu]); - _ -> - ok - end. - -handle_send_pdu1(#state{log = Log, - usock = Sock, - filter = FilterMod}, Type, Addresses) -> - SendFun = - fun({snmpUDPDomain, {Ip, Port}, Packet}) - when is_binary(Packet) -> - ?vdebug("[snmpUDPDomain] sending packet:" - "~n size: ~p" - "~n to: ~p:~p", - [sz(Packet), Ip, Port]), - maybe_udp_send(FilterMod, Log, Type, Sock, Ip, Port, Packet); - - ({snmpUDPDomain, {Ip, Port}, {Packet, _LogData}}) - when is_binary(Packet) -> - ?vdebug("[snmpUDPDomain] sending encrypted packet:" - "~n size: ~p" - "~n to: ~p:~p", - [sz(Packet), Ip, Port]), - maybe_udp_send(FilterMod, Log, Type, Sock, Ip, Port, Packet); - - ({transportDomainUdpIpv4, {Ip, Port}, Packet}) - when is_binary(Packet) -> - ?vdebug("[transportDomainUdpIpv4] sending packet:" - "~n size: ~p" - "~n to: ~p:~p", - [sz(Packet), Ip, Port]), - maybe_udp_send(FilterMod, Log, Type, Sock, Ip, Port, Packet); - - ({transportDomainUdpIpv4, {Ip, Port}, {Packet, _LogData}}) - when is_binary(Packet) -> - ?vdebug("[transportDomainUdpIpv4] sending encrypted packet:" - "~n size: ~p" - "~n to: ~p:~p", - [sz(Packet), Ip, Port]), - maybe_udp_send(FilterMod, Log, Type, Sock, Ip, Port, Packet); - - ({transportDomainUdpIpv6, {Ip, Port}, Packet}) - when is_binary(Packet) -> - ?vdebug("[transportDomainUdpIpv6] sending packet:" - "~n size: ~p" - "~n to: ~p:~p", - [sz(Packet), Ip, Port]), - maybe_udp_send(FilterMod, Log, Type, Sock, Ip, Port, Packet); - - ({transportDomainUdpIpv6, {Ip, Port}, {Packet, _LogData}}) - when is_binary(Packet) -> - ?vdebug("[transportDomainUdpIpv6] sending encrypted packet:" - "~n size: ~p" - "~n to: ~p:~p", - [sz(Packet), Ip, Port]), - maybe_udp_send(FilterMod, Log, Type, Sock, Ip, Port, Packet); - - (_X) -> - ?vlog("** bad res: ~p", [_X]), - ok - end, - lists:foreach(SendFun, Addresses). - - -handle_response(Vsn, Pdu, From, S) -> - case lists:keysearch(Pdu#pdu.request_id, 1, S#state.reqs) of - {value, {_, Pid}} -> - ?vdebug("handle_response -> " - "~n send response to receiver ~p", [Pid]), - Pid ! {snmp_response_received, Vsn, Pdu, From}; - _ -> - ?vdebug("handle_response -> " - "~n No receiver available for response pdu", []) + error_msg( + "Can not send message~n" + " size: ~p~n" + " reason: ~p~n" + " pdu: ~p", + [Sz, Reason, Pdu]) end. -maybe_udp_send(FilterMod, Sock, Ip, Port, Packet) -> - case (catch FilterMod:accept_send(Ip, Port)) of +do_handle_send_pdu1( + #state{transports = Transports} = 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 + end, + Addresses). + +maybe_udp_send( + #state{filter = FilterMod, transports = Transports}, + #transport{socket = Socket}, + To, Packet) -> + {To_1, To_2} = fix_filter_address(Transports, To), + case + try FilterMod:accept_send(To_1, To_2) + catch + Class:Exception -> + error_msg( + "FilterMod:accept_send(~p, ~p) crashed: ~w:~w~n ~p", + [To_1,To_2,Class,Exception,erlang:get_stacktrace()]), + true + end + of false -> inc(netIfMsgOutDrops), ok; - _ -> - (catch udp_send(Sock, Ip, Port, Packet)) + Other -> + case Other of + true -> + ok; + _ -> + error_msg( + "FilterMod:accept_send(~p, ~p) returned: ~p", + [To_1,To_2,Other]) + end, + udp_send(Socket, To, Packet) end. -maybe_udp_send(FilterMod, AtLog, Type, Sock, Ip, Port, Packet) -> - case (catch FilterMod:accept_send(Ip, Port)) of +maybe_udp_send( + #state{log = Log, filter = FilterMod, transports = Transports}, + #transport{socket = Socket}, + To, Packet, Type, _LogData) -> + {To_1, To_2} = fix_filter_address(Transports, To), + case + try FilterMod:accept_send(To_1, To_2) + catch + Class:Exception -> + error_msg( + "FilterMod:accept_send(~p, ~p) crashed for: ~w:~w~n ~p", + [To_1, To_2, Class, Exception, erlang:get_stacktrace()]), + true + end + of false -> inc(netIfMsgOutDrops), ok; - _ -> - log(AtLog, Type, Packet, Ip, Port), - (catch udp_send(Sock, Ip, Port, Packet)) + Other -> + case Other of + true -> + ok; + _ -> + error_msg( + "FilterMod:accept_send(~p, ~p) returned: ~p", + [To_1,To_2,Other]) + end, + log(Log, Type, Packet, To), + udp_send(Socket, To, Packet) end. - -udp_send(UdpId, AgentIp, UdpPort, B) -> - case (catch gen_udp:send(UdpId, AgentIp, UdpPort, B)) of +udp_send(Socket, To, B) -> + {IpAddr, IpPort} = + case To of + {Domain, Addr} when is_atom(Domain) -> + Addr; + {_, P} = Addr when is_integer(P) -> + Addr + end, + try gen_udp:send(Socket, IpAddr, IpPort, B) of {error, emsgsize} -> %% From this message we cannot recover, so exit sending loop throw({emsgsize, sz(B)}); {error, ErrorReason} -> error_msg("[error] cannot send message " "(destination: ~p:~p, size: ~p, reason: ~p)", - [AgentIp, UdpPort, sz(B), ErrorReason]); - {'EXIT', ExitReason} -> - error_msg("[exit] cannot send message " - "(destination: ~p:~p, size: ~p, reason: ~p)", - [AgentIp, UdpPort, sz(B), ExitReason]); - _ -> + [IpAddr, IpPort, sz(B), ErrorReason]); + ok -> ok + catch + error:ExitReason -> + error_msg("[exit] cannot send message " + "(destination: ~p:~p, size: ~p, reason: ~p, at: ~p)", + [IpAddr, IpPort, sz(B), ExitReason, + erlang:get_stacktrace()]) end. sz(L) when is_list(L) -> length(L); @@ -957,6 +1221,75 @@ active_once(Sock) -> inet:setopts(Sock, [{active, once}]). +select_transport_from_req_ref(_, []) -> + false; +select_transport_from_req_ref( + ReqRef, + [#transport{req_refs = ReqRefs} = Transport | Transports]) -> + case lists:member(ReqRef, ReqRefs) of + true -> + Transport; + false -> + select_transport_from_req_ref(ReqRef, Transports) + end. + +select_transport_from_domain(Domain, Transports) when is_atom(Domain) -> + Pos = #transport.domain, + case lists:keyfind(Domain, Pos, Transports) of + #transport{domain = Domain} = Transport -> + Transport; + false when Domain == snmpUDPDomain -> + lists:keyfind(transportDomainUdpIpv4, Pos, Transports); + false when Domain == transportDomainUdpIpv4 -> + lists:keyfind(snmpUDPDomain, Pos, Transports); + false -> + false + end. + +address_to_domain({Domain, _Addr}) when is_atom(Domain) -> + Domain; +address_to_domain({_Ip, Port}) when is_integer(Port) -> + snmpUDPDomain. + +%% If the agent uses legacy snmpUDPDomain e.g has not set +%% intAgentTransportDomain, then make sure +%% snmpa_network_interface_filter gets legacy arguments +%% to not break backwards compatibility. +%% +fix_filter_address(Transports, Address) -> + case is_legacy_transports(Transports) of + true -> + case Address of + {Domain, Addr} when is_atom(Domain) -> + Addr; + {_, IpPort} = Addr when is_integer(IpPort) -> + Addr + end; + false -> + Address + end. + +is_legacy_transports([#transport{domain = snmpUDPDomain}]) -> + true; +is_legacy_transports([#transport{} | _]) -> + false. + +fix_filter_legacy_mpd_address(Domain_Address_SecData) -> + case Domain_Address_SecData of + {{Domain, Addr}, _SecData} when is_atom(Domain) -> % v3 + Addr; + {Domain, Addr} when is_atom(Domain) -> % v1 & v2 + Addr + end. + +fix_filter_mpd_address(Domain_Address_SecData) -> + case Domain_Address_SecData of + {{Domain, _Addr} = Address, _SecData} when is_atom(Domain) -> % v3 + Address; + {Domain, _Addr} = Address when is_atom(Domain) -> % v1 & v2 + Address + end. + %%%----------------------------------------------------------------- handle_set_log_type(#state{log = {Log, OldValue}} = State, NewType) @@ -1113,37 +1446,39 @@ get_counters([Counter|Counters], Acc) -> %% ---------------------------------------------------------------- -ip_opt_bind_to_ip_address(Opts, Ip) -> - case get_bind_to_ip_address(Opts) of - true -> - [{ip, list_to_tuple(Ip)}]; - _ -> - [] - end. - -ip_opt_no_reuse_address(Opts) -> - case get_no_reuse_address(Opts) of - false -> - [{reuseaddr, true}]; - _ -> - [] - end. - -ip_opt_recbuf(Opts) -> - case get_recbuf(Opts) of - use_default -> - []; - Sz -> - [{recbuf, Sz}] - end. - -ip_opt_sndbuf(Opts) -> - case get_sndbuf(Opts) of - use_default -> - []; - Sz -> - [{sndbuf, Sz}] - end. +socket_opts(Domain, {IpAddr, IpPort}, Opts) -> + [IpPort, % Picked off at socket open, separate argument + binary + | case snmp_conf:tdomain_to_family(Domain) of + inet6 = Family -> + [Family, {ipv6_v6only, true}]; + Family -> + [Family] + end ++ + case get_bind_to_ip_address(Opts) of + true -> + [{ip, IpAddr}]; + _ -> + [] + end ++ + case get_no_reuse_address(Opts) of + false -> + [{reuseaddr, true}]; + _ -> + [] + end ++ + case get_recbuf(Opts) of + use_default -> + []; + Sz -> + [{recbuf, Sz}] + end ++ + case get_sndbuf(Opts) of + use_default -> + []; + Sz -> + [{sndbuf, Sz}] + end]. %% ---------------------------------------------------------------- @@ -1203,6 +1538,9 @@ get_bind_to_ip_address(Opts) -> error_msg(F,A) -> ?snmpa_error("NET-IF server: " ++ F, A). +info_msg(F,A) -> + ?snmpa_info("NET-IF server: " ++ F, A). + %% --- user_err(F, A) -> @@ -1227,14 +1565,14 @@ call(Pid, Req) -> %% ---------------------------------------------------------------- -get_info(#state{usock = Id, reqs = Reqs}) -> +get_info(#state{transports = Transports, reqs = Reqs}) -> ProcSize = proc_mem(self()), - PortInfo = get_port_info(Id), Counters = get_counters(), - [{reqs, Reqs}, - {counters, Counters}, - {process_memory, ProcSize}, - {port_info, PortInfo}]. + [{reqs, Reqs}, + {counters, Counters}, + {process_memory, ProcSize} + | [{port_info, get_port_info(Socket)} + || #transport{socket = Socket} <- Transports]]. proc_mem(P) when is_pid(P) -> case (catch erlang:process_info(P, memory)) of diff --git a/lib/snmp/src/agent/snmpa_net_if_filter.erl b/lib/snmp/src/agent/snmpa_net_if_filter.erl index 989f7c95b3..dd77b143d0 100644 --- a/lib/snmp/src/agent/snmpa_net_if_filter.erl +++ b/lib/snmp/src/agent/snmpa_net_if_filter.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2009. All Rights Reserved. +%% Copyright Ericsson AB 2007-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -18,35 +18,49 @@ %% -module(snmpa_net_if_filter). --export([accept_recv/2, - accept_send/2, - accept_recv_pdu/3, - accept_send_pdu/2]). +%% Behaviour +-export([accept_recv/2, accept_send/2, accept_recv_pdu/3, accept_send_pdu/2]). -include("snmp_debug.hrl"). -accept_recv(_Addr, _Port) -> - ?d("accept_recv -> entry with" - "~n Addr: ~p" - "~n Port: ~p", [_Addr, _Port]), +accept_recv(Domain, _Address) when is_atom(Domain) -> + ?d("accept_recv -> entry with~n" + " Domain: ~p~n" + " Address: ~p", [Domain, _Address]), + true; +accept_recv(_Addr, Port) when is_integer(Port) -> + ?d("accept_recv -> entry with~n" + " Addr: ~p~n" + " Port: ~p", [_Addr, Port]), true. -accept_send(_Addr, _Port) -> - ?d("accept_send -> entry with" - "~n Addr: ~p" - "~n Port: ~p", [_Addr, _Port]), +accept_send(Domain, _Address) when is_atom(Domain) -> + ?d("accept_send -> entry with~n" + " Domain: ~p~n" + " Address: ~p", [Domain, _Address]), + true; +accept_send(_Addr, Port) when is_integer(Port) -> + ?d("accept_send -> entry with~n" + " Addr: ~p~n" + " Port: ~p", [_Addr, Port]), true. -accept_recv_pdu(_Addr, _Port, _PduType) -> - ?d("accept_recv_pdu -> entry with" - "~n Addr: ~p" - "~n Port: ~p" - "~n PduType: ~p", [_Addr, _Port, _PduType]), +accept_recv_pdu(Domain, _Address, _PduType) when is_atom(Domain) -> + ?d("accept_recv -> entry with~n" + " Domain: ~p~n" + " Address: ~p~n" + " PduType: ~p", [Domain, _Address, _PduType]), + true; +accept_recv_pdu(_Addr, Port, _PduType) when is_integer(Port) -> + ?d("accept_recv_pdu -> entry with~n" + " Addr: ~p~n" + " Port: ~p~n" + " PduType: ~p", [_Addr, Port, _PduType]), true. accept_send_pdu(_Targets, _PduType) -> - ?d("accept_send_pdu -> entry with" - "~n Targets: ~p" - "~n PduType: ~p", [_Targets, _PduType]), + ?d("accept_send_pdu -> entry with~n" + " Targets: ~p~n" + " PduType: ~p", [_Targets, _PduType]), true. diff --git a/lib/snmp/src/agent/snmpa_network_interface_filter.erl b/lib/snmp/src/agent/snmpa_network_interface_filter.erl index 6fa131beee..90aa54a271 100644 --- a/lib/snmp/src/agent/snmpa_network_interface_filter.erl +++ b/lib/snmp/src/agent/snmpa_network_interface_filter.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2009. All Rights Reserved. +%% Copyright Ericsson AB 2007-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -23,7 +23,7 @@ behaviour_info(callbacks) -> - [{accept_recv, 2}, + [{accept_recv, 2}, {accept_send, 2}, {accept_recv_pdu, 3}, {accept_send_pdu, 2}]; @@ -31,20 +31,21 @@ behaviour_info(_) -> undefined. -%% accept_recv(address(), port()) -> boolean() +%% accept_recv({domain(), address()}) -> boolean() %% Called at the receiption of a message %% (before *any* processing has been done). %% -%% accept_send(address(), port()) -> boolean() +%% accept_send({domain(), address()}) -> boolean() %% Called before the sending of a message %% (after *all* processing has been done). %% -%% accept_recv_pdu(Addr, Port, pdu_type()) -> boolean() +%% accept_recv_pdu({domain(), address()}, pdu_type()) -> boolean() %% Called after the basic message processing (MPD) has been done, %% but before the pdu is handed over to the master-agent for %% primary processing. %% -%% accept_send_pdu(Targets, pdu_type()) -> boolean() | NewTargets +%% accept_send_pdu([{domain(), address()}, ...] = Targets, pdu_type()) -> +%% boolean() | NewTargets %% Called before the basic message processing (MPD) is done, %% when a pdu has been received from the master-agent. %% diff --git a/lib/snmp/src/agent/snmpa_trap.erl b/lib/snmp/src/agent/snmpa_trap.erl index b9a2496341..a79b150f57 100644 --- a/lib/snmp/src/agent/snmpa_trap.erl +++ b/lib/snmp/src/agent/snmpa_trap.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2012. All Rights Reserved. +%% Copyright Ericsson AB 1996-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -270,12 +270,13 @@ localise_type({VariableOid, Value}, Mib) when is_list(VariableOid) -> localise_type(X, _) -> X. %%----------------------------------------------------------------- -%% Func: make_v1_trap_pdu/4 +%% Func: make_v1_trap_pdu/5 %% Args: Enterprise = oid() %% Specific = integer() %% Varbinds is as returned from initiate_vars %% (but only {Oid, Type[, Value} permitted) %% SysUpTime = integer() +%% AgentIp = {A, B, C, D} %% Purpose: Make a #trappdu %% Checks the Varbinds to see that no symbolic names are %% present, and that each var has a type. Performs a get @@ -284,7 +285,7 @@ localise_type(X, _) -> X. %% Fails: yes %% NOTE: Executed at the MA %%----------------------------------------------------------------- -make_v1_trap_pdu(Enterprise, Specific, VarbindList, SysUpTime) -> +make_v1_trap_pdu(Enterprise, Specific, VarbindList, SysUpTime, AgentIp) -> {Enterp,Generic,Spec} = case Enterprise of ?snmp -> @@ -292,7 +293,6 @@ make_v1_trap_pdu(Enterprise, Specific, VarbindList, SysUpTime) -> _ -> {Enterprise,?enterpriseSpecific,Specific} end, - {value, AgentIp} = snmp_framework_mib:intAgentIpAddress(get), #trappdu{enterprise = Enterp, agent_addr = AgentIp, generic_trap = Generic, @@ -369,6 +369,7 @@ send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs, LocalEngineID, {tag, T}, {err, E}, {stacktrace, erlang:get_stacktrace()}], + ?vlog("snmpa_trap:send_trap exception: ~p", [Info]), {error, {failed_sending_trap, Info}} end. @@ -789,23 +790,19 @@ send_trap_pdus([], ContextName, {TrapRec, Vbs}, send_v1_trap(_TrapRec, [], _Vbs, _ExtraInfo, _NetIf, _SysUpTime) -> ok; -send_v1_trap(#trap{enterpriseoid = Enter, specificcode = Spec}, - V1Res, Vbs, ExtraInfo, NetIf, SysUpTime) -> +send_v1_trap( + #trap{enterpriseoid = Enter, specificcode = Spec}, + V1Res, Vbs, ExtraInfo, NetIf, SysUpTime) -> ?vdebug("prepare to send v1 trap " "~n '~p'" "~n with" "~n ~p" "~n to" "~n ~p", [Enter, Spec, V1Res]), - TrapPdu = make_v1_trap_pdu(Enter, Spec, Vbs, SysUpTime), - AddrCommunities = mk_addr_communities(V1Res), - lists:foreach(fun({Community, Addrs}) -> - ?vtrace("send v1 trap pdu to ~p",[Addrs]), - NetIf ! {send_pdu, 'version-1', TrapPdu, - {community, Community}, Addrs, ExtraInfo} - end, AddrCommunities); -send_v1_trap(#notification{oid = Oid}, V1Res, Vbs, ExtraInfo, NetIf, - SysUpTime) -> + do_send_v1_trap(Enter, Spec, V1Res, Vbs, ExtraInfo, NetIf, SysUpTime); +send_v1_trap( + #notification{oid = Oid}, + V1Res, Vbs, ExtraInfo, NetIf, SysUpTime) -> %% Use alg. in rfc2089 to map a v2 trap to a v1 trap % delete Counter64 objects from vbs ?vdebug("prepare to send v1 trap '~p'",[Oid]), @@ -822,14 +819,38 @@ send_v1_trap(#notification{oid = Oid}, V1Res, Vbs, ExtraInfo, NetIf, {lists:reverse(First),Last} end end, - TrapPdu = make_v1_trap_pdu(Enter, Spec, NVbs, SysUpTime), + do_send_v1_trap(Enter, Spec, V1Res, NVbs, ExtraInfo, NetIf, SysUpTime). + +do_send_v1_trap(Enter, Spec, V1Res, NVbs, ExtraInfo, NetIf, SysUpTime) -> + {value, Transports} = snmp_framework_mib:intAgentTransports(get), + {_Domain, {AgentIp, _AgentPort}} = + case lists:keyfind(snmpUDPDomain, 1, Transports) of + false -> + case lists:keyfind(transportDomainUdpIpv4, 1, Transports) of + false -> + ?vtrace( + "snmpa_trap: can not send v1 trap " + "without IPv4 domain: ~p", + [Transports]), + user_err( + "snmpa_trap: can not send v1 trap " + "without IPv4 domain: ~p", + [Transports]); + DomainAddr -> + DomainAddr + end; + DomainAddr -> + DomainAddr + end, + TrapPdu = make_v1_trap_pdu(Enter, Spec, NVbs, SysUpTime, AgentIp), AddrCommunities = mk_addr_communities(V1Res), - lists:foreach(fun({Community, Addrs}) -> - ?vtrace("send v1 trap to ~p",[Addrs]), - NetIf ! {send_pdu, 'version-1', TrapPdu, - {community, Community}, Addrs, ExtraInfo} - end, AddrCommunities). - + lists:foreach( + fun ({Community, Addrs}) -> + ?vtrace("send v1 trap to ~p",[Addrs]), + NetIf ! {send_pdu, 'version-1', TrapPdu, + {community, Community}, Addrs, ExtraInfo} + end, AddrCommunities). + send_v2_trap(_TrapRec, [], _Vbs, _Recv, _ExtraInfo, _NetIf, _SysUpTime) -> ok; send_v2_trap(TrapRec, V2Res, Vbs, Recv, ExtraInfo, NetIf, SysUpTime) -> @@ -1045,7 +1066,7 @@ deliver_recv(#snmpa_notification_delivery_info{tag = Tag, "~n DeliveryResult: ~p" "~n TAddr: ~p" "", [Tag, Mod, Extra, DeliveryResult, TAddr]), - Addr = transform_taddr(TAddr), + [Addr] = transform_taddrs([TAddr]), (catch Mod:delivery_info(Tag, Addr, DeliveryResult, Extra)); deliver_recv({Tag, Receiver}, MsgId, Result) -> ?vtrace("deliver_recv -> entry with" @@ -1072,35 +1093,90 @@ deliver_recv(Else, _MsgId, _Result) -> [Else]), user_err("snmpa: bad receiver, ~w\n", [Else]). -transform_taddrs(Addrs) -> - [transform_taddr(Addr) || Addr <- Addrs]. +transform_taddrs(TAddrs) -> + UseTDomain = + case snmp_framework_mib:intAgentTransportDomain(get) of + {value,snmpUDPDomain} -> + false; + {value,_} -> + true; + genErr -> + false + end, + DomAddrs = [transform_taddr(TAddr) || TAddr <- TAddrs], + case UseTDomain of + true -> + DomAddrs; + false -> + [Addr || {_Domain, Addr} <- DomAddrs] + end. -transform_taddr({?snmpUDPDomain, [A1, A2, A3, A4, P1, P2]}) -> % v2 - Addr = {A1, A2, A3, A4}, - Port = P1 bsl 8 + P2, - {Addr, Port}; -transform_taddr({?transportDomainUdpIpv4, [A1, A2, A3, A4, P1, P2]}) -> % v2 - Addr = {A1, A2, A3, A4}, +%% v2 +transform_taddr({?snmpUDPDomain, Addr}) -> + transform_taddr(transportDomainIdpIpv4, Addr); +transform_taddr({?transportDomainUdpIpv4, Addr}) -> + transform_taddr(transportDomainUdpIpv4, Addr); +transform_taddr({?transportDomainUdpIpv6, Addr}) -> + transform_taddr(transportDomainUdpIpv6, Addr); +%% v3 +transform_taddr({{?snmpUDPDomain, Addr}, _MsgData}) -> + transform_taddr(transportDomainUdpIpv4, Addr); +transform_taddr({{?transportDomainUdpIpv4, Addr}, _MsgData}) -> + transform_taddr(transportDomainUdpIpv4, Addr); +transform_taddr({{?transportDomainUdpIpv6, Addr}, _MsgData}) -> + transform_taddr(transportDomainUdpIpv6, Addr). + +transform_taddr( + transportDomainUdpIpv4 = Domain, + [A1,A2,A3,A4,P1,P2]) -> + Ip = {A1, A2, A3, A4}, Port = P1 bsl 8 + P2, - {Addr, Port}; -transform_taddr({?transportDomainUdpIpv6, - [A1, A2, A3, A4, A5, A6, A7, A8, P1, P2]}) -> % v2 - Addr = {A1, A2, A3, A4, A5, A6, A7, A8}, + {Domain, {Ip, Port}}; +transform_taddr( + transportDomainUdpIpv6 = Domain, + [A1, A2, A3, A4, A5, A6, A7, A8, P1, P2]) -> + Ip = {A1, A2, A3, A4, A5, A6, A7, A8}, Port = P1 bsl 8 + P2, - {Addr, Port}; -transform_taddr({{?snmpUDPDomain, [A1, A2, A3, A4, P1, P2]}, _MsgData}) -> % v3 - Addr = {A1, A2, A3, A4}, + {Domain, {Ip, Port}}; +transform_taddr( + transportDomainUdpIpv6 = Domain, + [A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, + P1, P2]) -> + Ip = + {(A1 bsl 8) bor A2, (A3 bsl 8) bor A4, + (A5 bsl 8) bor A6, (A7 bsl 8) bor A8, + (A9 bsl 8) bor A10, (A11 bsl 8) bor A12, + (A13 bsl 8) bor A14, (A15 bsl 8) bor A16}, Port = P1 bsl 8 + P2, - {Addr, Port}; -transform_taddr({{?transportDomainUdpIpv4, [A1, A2, A3, A4, P1, P2]}, _MsgData}) -> % v3 - Addr = {A1, A2, A3, A4}, - Port = P1 bsl 8 + P2, - {Addr, Port}; -transform_taddr({{?transportDomainUdpIpv6, - [A1, A2, A3, A4, A5, A6, A7, A8, P1, P2]}, _MsgData}) -> % v3 - Addr = {A1, A2, A3, A4, A5, A6, A7, A8}, - Port = P1 bsl 8 + P2, - {Addr, Port}. + {Domain, {Ip, Port}}. + +%% transform_taddr({?snmpUDPDomain, [A1, A2, A3, A4, P1, P2]}) -> % v2 +%% Addr = {A1, A2, A3, A4}, +%% Port = P1 bsl 8 + P2, +%% {Addr, Port}; +%% transform_taddr({?transportDomainUdpIpv4, [A1, A2, A3, A4, P1, P2]}) -> % v2 +%% Addr = {A1, A2, A3, A4}, +%% Port = P1 bsl 8 + P2, +%% {Addr, Port}; +%% transform_taddr({?transportDomainUdpIpv6, +%% [A1, A2, A3, A4, A5, A6, A7, A8, P1, P2]}) -> % v2 +%% Addr = {A1, A2, A3, A4, A5, A6, A7, A8}, +%% Port = P1 bsl 8 + P2, +%% {Addr, Port}; +%% transform_taddr({{?snmpUDPDomain, [A1, A2, A3, A4, P1, P2]}, _MsgData}) -> % v3 +%% Addr = {A1, A2, A3, A4}, +%% Port = P1 bsl 8 + P2, +%% {Addr, Port}; +%% transform_taddr({{?transportDomainUdpIpv4, [A1, A2, A3, A4, P1, P2]}, _MsgData}) -> % v3 +%% Addr = {A1, A2, A3, A4}, +%% Port = P1 bsl 8 + P2, +%% {Addr, Port}; +%% transform_taddr({{?transportDomainUdpIpv6, +%% [A1, A2, A3, A4, A5, A6, A7, A8, P1, P2]}, _MsgData}) -> % v3 +%% Addr = {A1, A2, A3, A4, A5, A6, A7, A8}, +%% Port = P1 bsl 8 + P2, +%% {Addr, Port}. + check_all_varbinds(#notification{oid = Oid}, Vbs, MibView) -> diff --git a/lib/snmp/src/app/snmp.appup.src b/lib/snmp/src/app/snmp.appup.src index babc33e6a5..ae79e3c1d1 100644 --- a/lib/snmp/src/app/snmp.appup.src +++ b/lib/snmp/src/app/snmp.appup.src @@ -28,6 +28,8 @@ %% {update, snmpa_local_db, soft, soft_purge, soft_purge, []} %% {add_module, snmpm_net_if_mt} [ + {"4.25.1", [{restart_application, snmp}]}, + {"4.25.0.1", [{restart_application, snmp}]}, {"4.25", [{restart_application, snmp}]}, {"4.24.2", [{restart_application, snmp}]}, {"4.24.1", [{restart_application, snmp}]}, @@ -40,6 +42,8 @@ %% {remove, {snmpm_net_if_mt, soft_purge, soft_purge}} [ + {"4.25.1", [{restart_application, snmp}]}, + {"4.25.0.1", [{restart_application, snmp}]}, {"4.25", [{restart_application, snmp}]}, {"4.24.2", [{restart_application, snmp}]}, {"4.24.1", [{restart_application, snmp}]}, diff --git a/lib/snmp/src/manager/snmpm.erl b/lib/snmp/src/manager/snmpm.erl index c97b635fc6..8976322c4e 100644 --- a/lib/snmp/src/manager/snmpm.erl +++ b/lib/snmp/src/manager/snmpm.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2013. All Rights Reserved. +%% Copyright Ericsson AB 2004-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -379,21 +379,33 @@ register_agent(UserId, Addr) -> register_agent(UserId, Addr, ?DEFAULT_AGENT_PORT, []). %% Backward compatibility -register_agent(UserId, Addr, Port, Config0) -> +register_agent(UserId, Domain, Addr, Config0) when is_atom(Domain) -> case lists:keymember(target_name, 1, Config0) of false -> - TargetName = mk_target_name(Addr, Port, Config0), - Config = [{reg_type, addr_port}, - {address, Addr}, {port, Port} | Config0], + TargetName = mk_target_name(Domain, Addr, Config0), + Config = + [{reg_type, addr_port}, + {tdomain, Domain}, {taddress, Addr} | Config0], do_register_agent(UserId, TargetName, ensure_engine_id(Config)); true -> {value, {_, TargetName}} = lists:keysearch(target_name, 1, Config0), Config1 = lists:keydelete(target_name, 1, Config0), - Config2 = [{reg_type, addr_port}, - {address, Addr}, {port, Port} | Config1], + Config2 = + [{reg_type, addr_port}, + {tdomain, Domain}, {taddress, Addr} | Config1], register_agent(UserId, TargetName, ensure_engine_id(Config2)) - end. + end; +register_agent(UserId, Ip, Port, Config) when is_integer(Port) -> + Domain = snmpm_config:default_transport_domain(), + Addr = + case snmp_conf:check_address(Domain, {Ip, Port}) of + ok -> + {Ip, Port}; + {ok, FixedAddr} -> + FixedAddr + end, + register_agent(UserId, Domain, Addr, Config). unregister_agent(UserId, TargetName) when is_list(TargetName) -> snmpm_config:unregister_agent(UserId, TargetName); @@ -402,8 +414,8 @@ unregister_agent(UserId, TargetName) when is_list(TargetName) -> unregister_agent(UserId, Addr) -> unregister_agent(UserId, Addr, ?DEFAULT_AGENT_PORT). -unregister_agent(UserId, Addr, Port) -> - case target_name(Addr, Port) of +unregister_agent(UserId, DomainIp, AddressPort) -> + case target_name(DomainIp, AddressPort) of {ok, TargetName} -> unregister_agent(UserId, TargetName); Error -> @@ -1264,14 +1276,17 @@ format_vb_value(Prefix, _Type, Val) -> %% --- Internal utility functions --- %% -target_name(Addr) -> - target_name(Addr, ?DEFAULT_AGENT_PORT). +target_name(Ip) -> + target_name(Ip, ?DEFAULT_AGENT_PORT). -target_name(Addr, Port) -> - snmpm_config:agent_info(Addr, Port, target_name). +target_name(DomainIp, AddressPort) -> + snmpm_config:agent_info(DomainIp, AddressPort, target_name). mk_target_name(Addr, Port, Config) -> - snmpm_config:mk_target_name(Addr, Port, Config). + R = snmpm_config:mk_target_name(Addr, Port, Config), + p(?MODULE_STRING":mk_target_name(~p, ~p, ~p) -> ~p.~n", + [Addr, Port, Config, R]), + R. ensure_engine_id(Config) -> case lists:keymember(engine_id, 1, Config) of @@ -1287,5 +1302,5 @@ ensure_engine_id(Config) -> %% p(F) -> %% p(F, []). -%% p(F, A) -> -%% io:format("~w:" ++ F ++ "~n", [?MODULE | A]). +p(F, A) -> + io:format("~w:" ++ F ++ "~n", [?MODULE | A]). diff --git a/lib/snmp/src/manager/snmpm_conf.erl b/lib/snmp/src/manager/snmpm_conf.erl index 5e2d9fdbf6..888f19aec6 100644 --- a/lib/snmp/src/manager/snmpm_conf.erl +++ b/lib/snmp/src/manager/snmpm_conf.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2013. All Rights Reserved. +%% Copyright Ericsson AB 2006-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -78,43 +78,26 @@ write_manager_config(Dir, Conf) -> Hdr = header() ++ Comment, write_manager_config(Dir, Hdr, Conf). -write_manager_config(Dir, Hdr, Conf) - when is_list(Dir) andalso is_list(Hdr) andalso is_list(Conf) -> - Verify = fun() -> verify_manager_conf(Conf) end, - Write = fun(Fid) -> write_manager_conf(Fid, Hdr, Conf) end, - write_config_file(Dir, ?MANAGER_CONF_FILE, Verify, Write). - +write_manager_config(Dir, Hdr, Conf) + when is_list(Dir), is_list(Hdr), is_list(Conf) -> + Order = fun snmpm_config:order_manager_config/2, + Check = fun snmpm_config:check_manager_config/2, + Write = fun (Fd, Entries) -> write_manager_conf(Fd, Hdr, Entries) end, + write_config_file(Dir, ?MANAGER_CONF_FILE, Order, Check, Write, Conf). append_manager_config(Dir, Conf) - when is_list(Dir) andalso is_list(Conf) -> - Verify = fun() -> verify_manager_conf(Conf) end, - Write = fun(Fid) -> write_manager_conf(Fid, Conf) end, - append_config_file(Dir, ?MANAGER_CONF_FILE, Verify, Write). - + when is_list(Dir), is_list(Conf) -> + Order = fun snmpm_config:order_manager_config/2, + Check = fun snmpm_config:check_manager_config/2, + Write = fun write_manager_conf/2, + append_config_file(Dir, ?MANAGER_CONF_FILE, Order, Check, Write, Conf). -read_manager_config(Dir) -> - Verify = fun(Entry) -> verify_manager_conf_entry(Entry) end, - read_config_file(Dir, ?MANAGER_CONF_FILE, Verify). +read_manager_config(Dir) when is_list(Dir) -> + Order = fun snmpm_config:order_manager_config/2, + Check = fun snmpm_config:check_manager_config/2, + read_config_file(Dir, ?MANAGER_CONF_FILE, Order, Check). -verify_manager_conf([]) -> - ok; -verify_manager_conf([H|T]) -> - verify_manager_conf_entry(H), - verify_manager_conf(T); -verify_manager_conf(X) -> - error({bad_manager_config, X}). - -verify_manager_conf_entry(Entry) -> - case snmpm_config:check_manager_config(Entry) of - ok -> - ok; -%% {ok, _} -> -%% ok; - Error -> - throw(Error) - end. - write_manager_conf(Fd, "", Conf) -> write_manager_conf(Fd, Conf); write_manager_conf(Fd, Hdr, Conf) -> @@ -127,14 +110,15 @@ write_manager_conf(Fd, [H|T]) -> do_write_manager_conf(Fd, H), write_manager_conf(Fd, T). -do_write_manager_conf(Fd, {address = Tag, Val}) -> - io:format(Fd, "{~w, ~w}.~n", [Tag, Val]); -do_write_manager_conf(Fd, {port = Tag, Val} ) -> +do_write_manager_conf(Fd, {Tag, Val}) + when Tag =:= domain; + Tag =:= address; + Tag =:= port; + Tag =:= max_message_size -> io:format(Fd, "{~w, ~w}.~n", [Tag, Val]); -do_write_manager_conf(Fd, {engine_id = Tag, Val} ) -> +do_write_manager_conf(Fd, {Tag, Val}) + when Tag =:= engine_id -> io:format(Fd, "{~w, \"~s\"}.~n", [Tag, Val]); -do_write_manager_conf(Fd, {max_message_size = Tag, Val} ) -> - io:format(Fd, "{~w, ~w}.~n", [Tag, Val]); do_write_manager_conf(_Fd, Crap) -> error({bad_manager_config, Crap}). @@ -167,36 +151,29 @@ write_users_config(Dir, Conf) -> Hdr = header() ++ Comment, write_users_config(Dir, Hdr, Conf). -write_users_config(Dir, Hdr, Conf) +write_users_config(Dir, Hdr, Conf) when is_list(Dir) andalso is_list(Hdr) andalso is_list(Conf) -> - Verify = fun() -> verify_users_conf(Conf) end, - Write = fun(Fd) -> write_users_conf(Fd, Hdr, Conf) end, - write_config_file(Dir, ?USERS_CONF_FILE, Verify, Write). - + Order = fun snmp_conf:no_order/2, + Check = fun check_user_config/2, + Write = fun (Fd, Entries) -> write_users_conf(Fd, Hdr, Entries) end, + write_config_file(Dir, ?USERS_CONF_FILE, Order, Check, Write, Conf). -append_users_config(Dir, Conf) +append_users_config(Dir, Conf) when is_list(Dir) andalso is_list(Conf) -> - Verify = fun() -> verify_users_conf(Conf) end, - Write = fun(Fd) -> write_users_conf(Fd, Conf) end, - append_config_file(Dir, ?USERS_CONF_FILE, Verify, Write). - + Order = fun snmp_conf:no_order/2, + Check = fun check_user_config/2, + Write = fun write_users_conf/2, + append_config_file(Dir, ?USERS_CONF_FILE, Order, Check, Write, Conf). read_users_config(Dir) when is_list(Dir) -> - Verify = fun(Entry) -> verify_users_conf_entry(Entry) end, - read_config_file(Dir, ?USERS_CONF_FILE, Verify). + Order = fun snmp_conf:no_order/2, + Check = fun check_user_config/2, + read_config_file(Dir, ?USERS_CONF_FILE, Order, Check). - -verify_users_conf([]) -> - ok; -verify_users_conf([H|T]) -> - verify_users_conf_entry(H), - verify_users_conf(T); -verify_users_conf(X) -> - error({bad_users_conf, X}). - -verify_users_conf_entry(Entry) -> - {ok, _} = snmpm_config:check_user_config(Entry), - ok. + +check_user_config(Entry, State) -> + {check_ok(snmpm_config:check_user_config(Entry)), + State}. write_users_conf(Fd, "", Conf) -> write_users_conf(Fd, Conf); @@ -239,36 +216,29 @@ write_agents_config(Dir, Conf) -> Hdr = header() ++ Comment, write_agents_config(Dir, Hdr, Conf). -write_agents_config(Dir, Hdr, Conf) +write_agents_config(Dir, Hdr, Conf) when is_list(Dir) andalso is_list(Hdr) andalso is_list(Conf) -> - Verify = fun() -> verify_agents_conf(Conf) end, - Write = fun(Fd) -> write_agents_conf(Fd, Hdr, Conf) end, - write_config_file(Dir, ?AGENTS_CONF_FILE, Verify, Write). + Order = fun snmp_conf:no_order/2, + Check = fun check_agent_config/2, + Write = fun (Fd, Entries) -> write_agents_conf(Fd, Hdr, Entries) end, + write_config_file(Dir, ?AGENTS_CONF_FILE, Order, Check, Write, Conf). - -append_agents_config(Dir, Conf) +append_agents_config(Dir, Conf) when is_list(Dir) andalso is_list(Conf) -> - Verify = fun() -> verify_agents_conf(Conf) end, - Write = fun(Fd) -> write_agents_conf(Fd, Conf) end, - append_config_file(Dir, ?AGENTS_CONF_FILE, Verify, Write). - + Order = fun snmp_conf:no_order/2, + Check = fun check_agent_config/2, + Write = fun write_agents_conf/2, + append_config_file(Dir, ?AGENTS_CONF_FILE, Order, Check, Write, Conf). read_agents_config(Dir) -> - Verify = fun(Entry) -> verify_agents_conf_entry(Entry) end, - read_config_file(Dir, ?AGENTS_CONF_FILE, Verify). + Order = fun snmp_conf:no_order/2, + Check = fun check_agent_config/2, + read_config_file(Dir, ?AGENTS_CONF_FILE, Order, Check). -verify_agents_conf([]) -> - ok; -verify_agents_conf([H|T]) -> - verify_agents_conf_entry(H), - verify_agents_conf(T); -verify_agents_conf(X) -> - error({bad_agents_config, X}). - -verify_agents_conf_entry(Entry) -> - {ok, _} = snmpm_config:check_agent_config(Entry), - ok. +check_agent_config(Entry, State) -> + {check_ok(snmpm_config:check_agent_config(Entry)), + State}. write_agents_conf(Fd, "", Conf) -> write_agents_conf(Fd, Conf); @@ -282,13 +252,15 @@ write_agents_conf(Fd, [H|T]) -> do_write_agents_conf(Fd, H), write_agents_conf(Fd, T). -do_write_agents_conf(Fd, - {UserId, - TargetName, Comm, Ip, Port, EngineID, - Timeout, MaxMessageSize, Version, - SecModel, SecName, SecLevel} = _A) -> - io:format(Fd, - "{~w, \"~s\", \"~s\", ~w, ~w, \"~s\", ~w, ~w, ~w, ~w, \"~s\", ~w}.~n", [UserId, TargetName, Comm, Ip, Port, EngineID, Timeout, MaxMessageSize, Version, SecModel, SecName, SecLevel]); +do_write_agents_conf( + Fd, + {UserId, TargetName, Comm, Ip, Port, EngineID, + Timeout, MaxMessageSize, Version, SecModel, SecName, SecLevel} = _A) -> + io:format( + Fd, + "{~w, \"~s\", \"~s\", ~w, ~w, \"~s\", ~w, ~w, ~w, ~w, \"~s\", ~w}.~n", + [UserId, TargetName, Comm, Ip, Port, EngineID, + Timeout, MaxMessageSize, Version, SecModel, SecName, SecLevel]); do_write_agents_conf(_Fd, Crap) -> error({bad_agents_config, Crap}). @@ -314,37 +286,30 @@ write_usm_config(Dir, Conf) -> Hdr = header() ++ Comment, write_usm_config(Dir, Hdr, Conf). -write_usm_config(Dir, Hdr, Conf) +write_usm_config(Dir, Hdr, Conf) when is_list(Dir) andalso is_list(Hdr) andalso is_list(Conf) -> - Verify = fun() -> verify_usm_conf(Conf) end, - Write = fun(Fd) -> write_usm_conf(Fd, Hdr, Conf) end, - write_config_file(Dir, ?USM_USERS_CONF_FILE, Verify, Write). + Order = fun snmp_conf:no_order/2, + Check = fun check_usm_user_config/2, + Write = fun (Fd, Entries) -> write_usm_conf(Fd, Hdr, Entries) end, + write_config_file(Dir, ?USM_USERS_CONF_FILE, Order, Check, Write, Conf). - -append_usm_config(Dir, Conf) +append_usm_config(Dir, Conf) when is_list(Dir) andalso is_list(Conf) -> - Verify = fun() -> verify_usm_conf(Conf) end, - Write = fun(Fd) -> write_usm_conf(Fd, Conf) end, - append_config_file(Dir, ?USM_USERS_CONF_FILE, Verify, Write). - + Order = fun snmp_conf:no_order/2, + Check = fun check_usm_user_config/2, + Write = fun write_usm_conf/2, + append_config_file(Dir, ?USM_USERS_CONF_FILE, Order, Check, Write, Conf). read_usm_config(Dir) when is_list(Dir) -> - Verify = fun(Entry) -> verify_usm_conf_entry(Entry) end, - read_config_file(Dir, ?USM_USERS_CONF_FILE, Verify). + Order = fun snmp_conf:no_order/2, + Check = fun check_usm_user_config/2, + read_config_file(Dir, ?USM_USERS_CONF_FILE, Order, Check). -verify_usm_conf([]) -> - ok; -verify_usm_conf([H|T]) -> - verify_usm_conf_entry(H), - verify_usm_conf(T); -verify_usm_conf(X) -> - error({bad_usm_conf, X}). - -verify_usm_conf_entry(Entry) -> - {ok, _} = snmpm_config:check_usm_user_config(Entry), - ok. +check_usm_user_config(Entry, State) -> + {check_ok(snmpm_config:check_usm_user_config(Entry)), + State}. write_usm_conf(Fd, "", Conf) -> write_usm_conf(Fd, Conf); @@ -358,41 +323,49 @@ write_usm_conf(Fd, [H|T]) -> do_write_usm_conf(Fd, H), write_usm_conf(Fd, T). -do_write_usm_conf(Fd, - {EngineID, UserName, AuthP, AuthKey, PrivP, PrivKey}) -> - io:format(Fd, "{\"~s\", \"~s\", ~w, ~w, ~w, ~w}.~n", - [EngineID, UserName, AuthP, AuthKey, PrivP, PrivKey]); -do_write_usm_conf(Fd, - {EngineID, UserName, SecName, - AuthP, AuthKey, PrivP, PrivKey}) -> - io:format(Fd, "{\"~s\", \"~s\", \"~s\", Ã~w, ~w, ~w, ~w}.~n", - [EngineID, UserName, SecName, AuthP, AuthKey, PrivP, PrivKey]); +do_write_usm_conf( + Fd, + {EngineID, UserName, AuthP, AuthKey, PrivP, PrivKey}) -> + io:format( + Fd, "{\"~s\", \"~s\", ~w, ~w, ~w, ~w}.~n", + [EngineID, UserName, AuthP, AuthKey, PrivP, PrivKey]); +do_write_usm_conf( + Fd, + {EngineID, UserName, SecName, + AuthP, AuthKey, PrivP, PrivKey}) -> + io:format( + Fd, "{\"~s\", \"~s\", \"~s\", Ã~w, ~w, ~w, ~w}.~n", + [EngineID, UserName, SecName, AuthP, AuthKey, PrivP, PrivKey]); do_write_usm_conf(_Fd, Crap) -> error({bad_usm_conf, Crap}). %% ---- config file wrapper functions ---- -write_config_file(Dir, File, Verify, Write) -> - snmp_config:write_config_file(Dir, File, Verify, Write). - -append_config_file(Dir, File, Verify, Write) -> - snmp_config:append_config_file(Dir, File, Verify, Write). +write_config_file(Dir, File, Order, Check, Write, Conf) -> + snmp_config:write_config_file(Dir, File, Order, Check, Write, Conf). -read_config_file(Dir, File, Verify) -> - snmp_config:read_config_file(Dir, File, Verify). +append_config_file(Dir, File, Order, Check, Write, Conf) -> + snmp_config:append_config_file(Dir, File, Order, Check, Write, Conf). +read_config_file(Dir, File, Order, Check) -> + snmp_config:read_config_file(Dir, File, Order, Check). %% ---- config file utility functions ---- +check_ok(ok) -> + ok; +check_ok({ok, _}) -> + ok. + header() -> {Y,Mo,D} = date(), {H,Mi,S} = time(), - io_lib:format("%% This file was generated by " - "~w (version-~s) ~w-~2.2.0w-~2.2.0w " - "~2.2.0w:~2.2.0w:~2.2.0w\n", - [?MODULE, ?version, Y, Mo, D, H, Mi, S]). - + io_lib:format( + "%% This file was generated by " + "~w (version-~s) ~w-~2.2.0w-~2.2.0w " + "~2.2.0w:~2.2.0w:~2.2.0w\n", + [?MODULE, ?version, Y, Mo, D, H, Mi, S]). error(R) -> throw({error, R}). diff --git a/lib/snmp/src/manager/snmpm_config.erl b/lib/snmp/src/manager/snmpm_config.erl index 2101ad46e1..013fefa4e2 100644 --- a/lib/snmp/src/manager/snmpm_config.erl +++ b/lib/snmp/src/manager/snmpm_config.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2013. All Rights Reserved. +%% Copyright Ericsson AB 2004-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -103,8 +103,10 @@ get_agent_mp_model/2 ]). --export([check_manager_config/1, - check_user_config/1, +-export([ + order_manager_config/2, + check_manager_config/2, + check_user_config/1, check_agent_config/1, check_usm_user_config/1]). @@ -165,7 +167,7 @@ %%%------------------------------------------------------------------- default_transport_domain() -> - transportDomainUdpIpv4. + snmpUDPDomain. start_link(Opts) -> @@ -190,7 +192,11 @@ register_user(UserId, UserMod, UserData, DefaultAgentConfig) when (UserId =/= ?DEFAULT_USER) andalso is_list(DefaultAgentConfig) -> case (catch verify_user_behaviour(UserMod)) of ok -> - Config = default_agent_config(DefaultAgentConfig), + {ok, SystemDefaultAgentConfig} = agent_info(), + Config = + ensure_config(SystemDefaultAgentConfig, + DefaultAgentConfig), +%% Config = default_agent_config(DefaultAgentConfig), call({register_user, UserId, UserMod, UserData, Config}); Error -> Error @@ -201,19 +207,19 @@ register_user(UserId, _UserMod, _UserData, DefaultAgentConfig) register_user(UserId, _, _, _) -> {error, {bad_user_id, UserId}}. -default_agent_config(DefaultAgentConfig) -> - {ok, SystemDefaultAgentConfig} = agent_info(), - default_agent_config(SystemDefaultAgentConfig, DefaultAgentConfig). +%% default_agent_config(DefaultAgentConfig) -> +%% {ok, SystemDefaultAgentConfig} = agent_info(), +%% default_agent_config(SystemDefaultAgentConfig, DefaultAgentConfig). -default_agent_config([], DefaultAgentConfig) -> - DefaultAgentConfig; -default_agent_config([{Key, _} = Entry|T], DefaultAgentConfig) -> - case lists:keysearch(Key, 1, DefaultAgentConfig) of - {value, _} -> - default_agent_config(T, DefaultAgentConfig); - false -> - default_agent_config(T, [Entry|DefaultAgentConfig]) - end. +%% default_agent_config([], DefaultAgentConfig) -> +%% DefaultAgentConfig; +%% default_agent_config([{Key, _} = Entry|T], DefaultAgentConfig) -> +%% case lists:keymember(Key, 1, DefaultAgentConfig) of +%% true -> +%% default_agent_config(T, DefaultAgentConfig); +%% false -> +%% default_agent_config(T, [Entry|DefaultAgentConfig]) +%% end. verify_user_behaviour(UserMod) -> @@ -280,9 +286,10 @@ do_user_info(_UserId, BadItem) -> %% A target-name constructed in this way is a string with the following: %% <IP-address>:<Port>-<Version> -%% This is intended for backward compatibility and therefor has +%% This is intended for backward compatibility and therefore has %% only support for IPv4 addresses and *no* other transport domain. -mk_target_name(Addr0, Port, Config) when is_list(Config) -> +mk_target_name(Domain, Addr, Config) + when is_atom(Domain), is_list(Config) -> Version = case lists:keysearch(version, 1, Config) of {value, {_, V}} -> @@ -290,18 +297,35 @@ mk_target_name(Addr0, Port, Config) when is_list(Config) -> false -> select_lowest_supported_version() end, - case normalize_address(Addr0) of - {A, B, C, D} -> - lists:flatten( - io_lib:format("~w.~w.~w.~w:~w-~w", [A, B, C, D, Port, Version])); - [A, B, C, D] -> + try + lists:flatten( + io_lib:format( + "~s-~w", [snmp_conf:mk_addr_string({Domain, Addr}), Version])) + catch + _ -> lists:flatten( - io_lib:format("~w.~w.~w.~w:~w-~w", [A, B, C, D, Port, Version])); - _ -> + io_lib:format("~p-~w", [Addr, Version])) + end; +mk_target_name(Ip, Port, Config) + when is_integer(Port), is_list(Config) -> + Domain = default_transport_domain(), + try fix_address(Domain, {Ip, Port}) of + Address -> + mk_target_name(Domain, Address, Config) + catch + _ -> + Version = + case lists:keysearch(version, 1, Config) of + {value, {_, V}} -> + V; + false -> + select_lowest_supported_version() + end, lists:flatten( - io_lib:format("~p:~w-~w", [Addr0, Port, Version])) + io_lib:format("~p:~w-~w", [Ip, Port, Version])) end. - + + select_lowest_supported_version() -> {ok, Versions} = system_info(versions), select_lowest_supported_version([v1, v2, v3], Versions). @@ -335,27 +359,17 @@ register_agent(UserId, TargetName, Config0) %% is not present %% 3) Check that there are no invalid or erroneous configs %% 4) Check that the manager is capable of using the selected version - case verify_agent_config(Config0) of - {ok, Config} -> - call({register_agent, UserId, TargetName, Config}); - Error -> - Error - end. - - -verify_agent_config(Conf0) -> try - begin - verify_mandatory(Conf0, [engine_id, address, reg_type]), - verify_invalid(Conf0, [user_id]), - Conf = verify_agent_config3(Conf0), - Vsns = versions(), - Vsn = which_version(Conf), - verify_version(Vsn, Vsns), - {ok, Conf} - end + verify_mandatory(Config0, [engine_id, reg_type]), + verify_someof(Config0, [address, taddress]), + verify_illegal(Config0, [user_id]), + Config = verify_agent_config(Config0), + Vsns = versions(), + Vsn = which_version(Config), + verify_version(Vsn, Vsns), + call({register_agent, UserId, TargetName, Config}) catch - throw:Error -> + Error -> Error end. @@ -381,52 +395,43 @@ verify_version(Vsn, Vsns) -> ok; false -> Reason = {version_not_supported_by_manager, Vsn, Vsns}, - throw({error, Reason}) - end. - -verify_agent_config3(Conf0) -> - %% Fix (transport) address and domain - {TDomain, Conf1} = - case lists:keysearch(tdomain, 1, Conf0) of - {value, {tdomain, Dom}} -> - {Dom, Conf0}; - false -> - Dom = default_transport_domain(), - {Dom, [{tdomain, Dom} | Conf0]} - end, - Conf2 = case lists:keysearch(address, 1, Conf1) of - {value, {address, Address}} -> - lists:keyreplace(address, 1, Conf1, - {address, {TDomain, Address}}); - false -> - %% This is a mandatory config option, - %% a later test will detect this - Conf1 - end, - case verify_agent2(Conf2) of - {ok, Conf} -> - Conf; - {error, _} = ERROR -> - throw(ERROR) + error(Reason) end. -verify_agent_config2(Conf) -> - verify_agent2(Conf). unregister_agent(UserId, TargetName) -> call({unregister_agent, UserId, TargetName}). %% This is the old style agent unregistration (using Addr and Port). -unregister_agent(UserId, Addr0, Port) -> - Addr = normalize_address(Addr0), - case do_agent_info(Addr, Port, target_name) of +unregister_agent(UserId, Domain, Address) when is_atom(Domain) -> + try fix_address(Domain, Address) of + NAddress -> + do_unregister_agent(UserId, Domain, NAddress) + catch + _ -> + {error, not_found} + end; +unregister_agent(UserId, Ip, Port) when is_integer(Port) -> + Domain = default_transport_domain(), + try fix_address(Domain, {Ip, Port}) of + Address -> + do_unregister_agent(UserId, Domain, Address) + catch + _ -> + {error, not_found} + end. + +do_unregister_agent(UserId, Domain, Address) -> + case do_agent_info(Domain, Address, target_name) of {ok, TargetName} -> unregister_agent(UserId, TargetName); Error -> Error end. + + agent_info() -> agent_info(?DEFAULT_TARGETNAME, all). @@ -444,20 +449,46 @@ agent_info(TargetName, Item) -> [] -> {error, not_found} end. - -agent_info(Addr0, Port, Item) -> - Addr = normalize_address(Addr0), - do_agent_info(Addr, Port, Item). -do_agent_info(Addr, Port, target_name = Item) -> - case ets:lookup(snmpm_agent_table, {Addr, Port, Item}) of +agent_info(Domain, Address, Item) when is_atom(Domain) -> + try fix_address(Domain, Address) of + NAddress -> + do_agent_info(Domain, NAddress, Item) + catch + _Thrown -> + p(?MODULE_STRING":agent_info(~p, ~p, ~p) throwed ~p at.~n" + " ~p", + [Domain, Address, Item, _Thrown, erlang:get_stacktrace()]), + {error, not_found} + end; +agent_info(Ip, Port, Item) -> + p(?MODULE_STRING":agent_info(~p, ~p, ~p) entry~n", + [Ip, Port, Item]), + Domain = default_transport_domain(), + try fix_address(Domain, {Ip, Port}) of + Address -> + do_agent_info(Domain, Address, Item) + catch + _Thrown -> + p(?MODULE_STRING":agent_info(~p, ~p, ~p) throwed ~p at.~n" + " ~p", + [Ip, Port, Item, _Thrown, erlang:get_stacktrace()]), + {error, not_found} + end. + +do_agent_info(Domain, Address, target_name = Item) -> + p(?MODULE_STRING":do_agent_info(~p, ~p, ~p) entry~n", + [Domain, Address, Item]), + case ets:lookup(snmpm_agent_table, {Domain, Address, Item}) of [{_, Val}] -> {ok, Val}; [] -> {error, not_found} end; -do_agent_info(Addr, Port, Item) -> - case do_agent_info(Addr, Port, target_name) of +do_agent_info(Domain, Address, Item) -> + p(?MODULE_STRING":do_agent_info(~p, ~p, ~p) entry~n", + [Domain, Address, Item]), + case do_agent_info(Domain, Address, target_name) of {ok, TargetName} -> agent_info(TargetName, Item); Error -> @@ -465,6 +496,19 @@ do_agent_info(Addr, Port, Item) -> end. +ensure_agent_info(_, [], Info) -> + Info; +ensure_agent_info(TargetName, [Item|Items], Info) -> + case lists:keymember(Item, 1, Info) of + true -> + ensure_agent_info(TargetName, Items, Info); + false -> + {ok, Value} = agent_info(TargetName, Item), + ensure_agent_info(TargetName, Items, [{Item, Value}|Info]) + end. + + + which_agents() -> which_agents('_'). @@ -474,38 +518,6 @@ which_agents(UserId) -> [TargetName || [TargetName] <- Agents]. -verify_agent_info(TargetName, Info0) -> - try - begin - verify_invalid(Info0, [user_id]), - %% Check if address is part of the list and - %% if so update it with the domain info. - Info = - case lists:keysearch(address, 1, Info0) of - {value, {address, Addr}} -> - %% If domain is part of the info, then use it. - %% If not, lookup what is already stored for - %% this agent and use that. - Domain = - case lists:keysearch(tdomain, 1, Info0) of - {value, {tdomain, Dom}} -> - Dom; - false -> - {ok, Dom} = - agent_info(TargetName, tdomain), - Dom - end, - Addr2 = {Domain, Addr}, - lists:keyreplace(address, 1, Info0, {address, Addr2}); - false -> - Info0 - end, - verify_agent2(Info) - end - catch - throw:Error -> - Error - end. update_agent_info(UserId, TargetName, Info) -> call({update_agent_info, UserId, TargetName, Info}). @@ -740,7 +752,7 @@ verify_usm_user_config(EngineID, Name, Config) -> try begin verify_mandatory(Config, []), - verify_invalid(Config, [engine_id, name]), + verify_illegal(Config, [engine_id, name]), verify_usm_user_config2(EngineID, Name, Config) end catch @@ -1073,7 +1085,11 @@ do_init(Opts) -> %% -- Prio (optional) -- Prio = get_opt(priority, Opts, normal), ets:insert(snmpm_config_table, {prio, Prio}), - process_flag(priority, Prio), + try process_flag(priority, Prio) + catch + error:badarg -> + error({invalid_priority,Prio}) + end, %% -- Server (optional) -- ServerOpts = get_opt(server, Opts, []), @@ -1506,7 +1522,9 @@ verify_versions([]) -> ok; verify_versions([Vsn|Vsns]) -> verify_version(Vsn), - verify_versions(Vsns). + verify_versions(Vsns); +verify_versions(Vsns) -> + error({invalid_versions, Vsns}). verify_version(v1) -> ok; @@ -1629,181 +1647,136 @@ init_agent_default() -> %% The purpose of the default_agent is only to have a place %% to store system wide default values related to agents. %% - - %% Port - init_agent_default(port, ?DEFAULT_AGENT_PORT), - - %% Timeout - init_agent_default(timeout, 10000), - - %% Max message (packet) size - init_agent_default(max_message_size, 484), - - %% MPModel - init_agent_default(version, v2), - - %% SecModel - init_agent_default(sec_model, v2c), - - %% SecName - init_agent_default(sec_name, "initial"), - - %% SecLevel - init_agent_default(sec_level, noAuthNoPriv), - - %% Community - init_agent_default(community, "all-rights"), - ok. - - -init_agent_default(Item, Val) when Item =/= user_id -> - case do_update_agent_info(default_agent, Item, Val) of - ok -> - ok; - {error, Reason} -> - error(Reason) - end. - + AgentDefaultConfig = + [{port, ?DEFAULT_AGENT_PORT}, % Port + {timeout, 10000}, % Timeout + {max_message_size, 484}, % Max message (packet) size + {version, v2}, % MPModel + {sec_model, v2c}, % SecModel + {sec_name, "initial"}, % SecName + {sec_level, noAuthPriv}, % SecLevel + {community, "all-rights"}], % Community + do_update_agent_info(default_agent, AgentDefaultConfig). + +%% %% Port +%% init_agent_default(port, ?DEFAULT_AGENT_PORT), + +%% %% Timeout +%% init_agent_default(timeout, 10000), + +%% %% Max message (packet) size +%% init_agent_default(max_message_size, 484), + +%% %% MPModel +%% init_agent_default(version, v2), + +%% %% SecModel +%% init_agent_default(sec_model, v2c), + +%% %% SecName +%% init_agent_default(sec_name, "initial"), + +%% %% SecLevel +%% init_agent_default(sec_level, noAuthNoPriv), + +%% %% Community +%% init_agent_default(community, "all-rights"), +%% ok. + + +%% init_agent_default(Item, Val) when Item =/= user_id -> +%% case do_update_agent_info(default_agent, Item, Val) of +%% ok -> +%% ok; +%% {error, Reason} -> +%% error(Reason) +%% end. + +%% read_agents_config_file(Dir) -> +%% Verify = fun check_agent_config2/1, +%% case read_file(Dir, "agents.conf", Verify, []) of +%% {ok, Conf} -> +%% Conf; +%% Error -> +%% ?vlog("agent config error: ~p", [Error]), +%% throw(Error) +%% end. + +%% check_agent_config2(Agent) -> +%% case (catch check_agent_config(Agent)) of +%% {ok, {UserId, TargetName, Conf, Version}} -> +%% {ok, Vsns} = system_info(versions), +%% case lists:member(Version, Vsns) of +%% true -> +%% {ok, {UserId, TargetName, Conf}}; +%% false -> +%% error({version_not_supported_by_manager, +%% Version, Vsns}) +%% end; +%% Err -> +%% throw(Err) +%% end. read_agents_config_file(Dir) -> - Check = fun(C) -> check_agent_config2(C) end, - case read_file(Dir, "agents.conf", Check, []) of - {ok, Conf} -> - Conf; - Error -> + Order = fun snmp_conf:no_order/2, + Check = fun check_agent_config/2, + try read_file(Dir, "agents.conf", Order, Check, []) + catch + throw:Error -> ?vlog("agent config error: ~p", [Error]), - throw(Error) + erlang:raise(throw, Error, erlang:get_stacktrace()) end. -check_agent_config2(Agent) -> - case (catch check_agent_config(Agent)) of - {ok, {UserId, TargetName, Conf, Version}} -> - {ok, Vsns} = system_info(versions), - case lists:member(Version, Vsns) of - true -> - {ok, {UserId, TargetName, Conf}}; - false -> - error({version_not_supported_by_manager, - Version, Vsns}) - end; - Err -> - throw(Err) +check_agent_config(Agent, State) -> + {ok, {UserId, TargetName, Conf, Version}} = check_agent_config(Agent), + {ok, Vsns} = system_info(versions), + case lists:member(Version, Vsns) of + true -> + {{ok, {UserId, TargetName, Conf}}, State}; + false -> + error({version_not_supported_by_manager, Version, Vsns}) end. %% For backward compatibility -check_agent_config({UserId, - TargetName, - Community, - Ip, Port, - EngineId, - Timeout, MaxMessageSize, - Version, SecModel, SecName, SecLevel}) -> - TDomain = default_transport_domain(), - check_agent_config({UserId, - TargetName, - Community, - TDomain, Ip, Port, - EngineId, - Timeout, MaxMessageSize, - Version, SecModel, SecName, SecLevel}); - -check_agent_config({UserId, - TargetName, - Community, - TDomain, Ip, Port, - EngineId, - Timeout, MaxMessageSize, - Version, SecModel, SecName, SecLevel}) -> - ?vtrace("check_agent_config -> entry with" - "~n UserId: ~p" - "~n TargetName: ~p" - "~n Community: ~p" - "~n TDomain: ~p" - "~n Ip: ~p" - "~n Port: ~p" - "~n EngineId: ~p" - "~n Timeout: ~p" - "~n MaxMessageSize: ~p" - "~n Version: ~p" - "~n SecModel: ~p" - "~n SecName: ~p" - "~n SecLevel: ~p", - [UserId, TargetName, Community, - TDomain, Ip, Port, - EngineId, Timeout, MaxMessageSize, - Version, SecModel, SecName, SecLevel]), - Addr = normalize_address(TDomain, Ip), - ?vtrace("check_agent_config -> Addr: ~p", [Addr]), - Agent = {UserId, - TargetName, - Community, - TDomain, Addr, Port, - EngineId, - Timeout, MaxMessageSize, - Version, SecModel, SecName, SecLevel}, - {ok, verify_agent(Agent)}; +check_agent_config( + {UserId, TargetName, Community, Ip, Port, + EngineId, Timeout, MaxMessageSize, + Version, SecModel, SecName, SecLevel}) -> + Domain = default_transport_domain(), + Addr = fix_address(Domain, {Ip, Port}), + check_agent_config( + UserId, TargetName, Community, Domain, Addr, + EngineId, Timeout, MaxMessageSize, + Version, SecModel, SecName, SecLevel); +check_agent_config( + {UserId, TargetName, Community, Domain, Ip, Port, + EngineId, Timeout, MaxMessageSize, + Version, SecModel, SecName, SecLevel}) -> + check_agent_config( + UserId, TargetName, Community, Domain, {Ip, Port}, + EngineId, Timeout, MaxMessageSize, + Version, SecModel, SecName, SecLevel); check_agent_config(Agent) -> error({bad_agent_config, Agent}). - -init_agents_config([]) -> - ok; -init_agents_config([Agent|Agents]) -> - init_agent_config(Agent), - init_agents_config(Agents). - -init_agent_config({_UserId, ?DEFAULT_TARGETNAME = TargetName, _Config}) -> - throw({error, {invalid_target_name, TargetName}}); -init_agent_config({UserId, TargetName, Config}) -> - case handle_register_agent(UserId, TargetName, Config) of - ok -> - ok; - Error -> - throw(Error) - end. - - -%% For backward compatibility -verify_agent({UserId, - TargetName, - Comm, - Ip, Port, - EngineId, - Timeout, MMS, - Version, SecModel, SecName, SecLevel}) -> - TDomain = default_transport_domain(), - verify_agent({UserId, - TargetName, - Comm, - TDomain, Ip, Port, - EngineId, - Timeout, MMS, - Version, SecModel, SecName, SecLevel}); - -verify_agent({UserId, - TargetName, - Comm, - TDomain, Ip, Port, - EngineId, - Timeout, MMS, - Version, SecModel, SecName, SecLevel}) -> - ?vdebug("verify_agent -> entry with" +check_agent_config( + UserId, TargetName, Comm, Domain, Addr, + EngineId, Timeout, MMS, + Version, SecModel, SecName, SecLevel) -> + ?vdebug("check_agent_config -> entry with" "~n UserId: ~p" "~n TargetName: ~p", [UserId, TargetName]), snmp_conf:check_string(TargetName, {gt, 0}), - snmp_conf:check_integer(Port, {gt, 0}), %% Note that the order of Conf *is* important. %% Some properties may depend on others, so that %% in order to verify one property, another must %% be already verified (and present). An example - %% of this is the property 'address', for which + %% of this is the property 'taddress', for which %% the property tdomain is needed. - Conf0 = + Conf = [{reg_type, target_name}, - {tdomain, TDomain}, - %% This should be taddress, but what the*... - {address, {TDomain, Ip}}, - {port, Port}, + {tdomain, Domain}, + {taddress, Addr}, {community, Comm}, {engine_id, EngineId}, {timeout, Timeout}, @@ -1813,40 +1786,186 @@ verify_agent({UserId, {sec_name, SecName}, {sec_level, SecLevel} ], - case verify_agent2(Conf0) of - {ok, Conf} -> - {UserId, TargetName, Conf, Version}; - Err -> - throw(Err) + {ok, {UserId, TargetName, verify_agent_config(Conf), Version}}. + + + +init_agents_config([]) -> + ok; +init_agents_config([Agent|Agents]) -> + init_agent_config(Agent), + init_agents_config(Agents). + +init_agent_config({_UserId, ?DEFAULT_TARGETNAME = TargetName, _Config}) -> + error({invalid_target_name, TargetName}); +init_agent_config({UserId, TargetName, Config}) -> + case handle_register_agent(UserId, TargetName, Config) of + ok -> + ok; + Error -> + throw(Error) end. -verify_agent2(Conf) -> - verify_agent2(Conf, []). -verify_agent2([], VerifiedConf) -> - {ok, VerifiedConf}; -verify_agent2([{Item, Val0}|Items], VerifiedConf) -> - case verify_val(Item, Val0) of - {ok, Val} -> - verify_agent2(Items, [{Item, Val} | VerifiedConf]); - Err -> - Err + +%% Sort 'tdomain' first then 'port' to ensure both +%% sorts before 'taddress'. Keep the order of other items. +order_agent(ItemA, ItemB) -> + snmp_conf:keyorder(1, ItemA, ItemB, [tdomain, port]). + +fix_agent_config(Conf) -> + ?vdebug("fix_agent_config -> entry with~n~n" + " Conf: ~p", [Conf]), + fix_agent_config(lists:sort(fun order_agent/2, Conf), []). + +fix_agent_config([], FixedConf) -> + Ret = lists:reverse(FixedConf), + ?vdebug("fix_agent_config -> returns:~n" + " ~p", [Ret]), + Ret; +fix_agent_config([{taddress = Item, Address} = Entry|Conf], FixedConf) -> + {value, {tdomain, TDomain}} = lists:keysearch(tdomain, 1, FixedConf), + {value, {port, DefaultPort}} = lists:keysearch(port, 1, FixedConf), + case snmp_conf:check_address(TDomain, Address, DefaultPort) of + ok -> + fix_agent_config(Conf, [Entry|FixedConf]); + {ok, NAddress} -> + fix_agent_config(Conf, [{Item, NAddress}|FixedConf]) end; -verify_agent2([Bad|_], _VerifiedConf) -> - {error, {bad_agent_config, Bad}}. +fix_agent_config([Entry|Conf], FixedConf) -> + fix_agent_config(Conf, [Entry|FixedConf]). + + + +verify_agent_config(Conf) -> + verify_agent_config(lists:sort(fun order_agent/2, Conf), []). + +verify_agent_config([], VerifiedConf) -> + Ret = lists:reverse(VerifiedConf), + ?vdebug("verify_agent_config -> returns:~n" + " ~p", [Ret]), + Ret; +verify_agent_config([{Item, _} = Entry|Conf], VerifiedConf) -> + verify_illegal(VerifiedConf, [Item]), % Duplicates are hereby illegal + verify_agent_config(Conf, VerifiedConf, Entry); +verify_agent_config([Bad|_], _VerifiedConf) -> + error({bad_agent_config, Bad}). + +verify_agent_config( + Conf, VerifiedConf, {taddress = Item, Address} = Entry) -> + verify_illegal(VerifiedConf, [address]), + {TDomain, VC} = + case lists:keysearch(tdomain, 1, VerifiedConf) of + {value, {tdomain,TD}} -> + {TD, VerifiedConf}; + _ -> + %% Insert tdomain since it is missing + TD = default_transport_domain(), + {TD, [{tdomain, TD}|VerifiedConf]} + end, + case snmp_conf:check_address(TDomain, Address, 0) of + ok -> + verify_agent_config(Conf, [Entry|VC]); + {ok, NAddress} -> + verify_agent_config(Conf, [{Item, NAddress}|VC]) + end; +verify_agent_config(Conf, VerifiedConf, {address, Address}) -> + Item = taddress, + verify_illegal(VerifiedConf, [Item]), + {TDomain, VC} = + case lists:keysearch(tdomain, 1, VerifiedConf) of + {value, {tdomain, TD}} -> + {TD, VerifiedConf}; + _ -> + %% Insert tdomain since it is missing + TD = default_transport_domain(), + {TD, [{tdomain, TD}|VerifiedConf]} + end, + case snmp_conf:check_address(TDomain, Address, 0) of + ok -> + verify_agent_config(Conf, [{Item, Address}|VC]); + {ok, NAddress} -> + verify_agent_config(Conf, [{Item, NAddress}|VC]) + end; +verify_agent_config(Conf, VerifiedConf, {Item, Val} = Entry) -> + case verify_agent_entry(Item, Val) of + ok -> + verify_agent_config(Conf, [Entry|VerifiedConf]); + {ok, NewVal} -> + verify_agent_config(Conf, [{Item, NewVal}|VerifiedConf]) + end. + +verify_agent_entry(user_id, _UserId) -> + ok; +verify_agent_entry(reg_type, RegType) -> + if + RegType =:= addr_port; + RegType =:= target_name -> + ok; + true -> + error({bad_reg_type, RegType}) + end; +verify_agent_entry(tdomain, TDomain) -> + snmp_conf:check_domain(TDomain); +verify_agent_entry(port, Port) -> + snmp_conf:check_port(Port); +verify_agent_entry(community, Comm) -> + snmp_conf:check_string(Comm); +verify_agent_entry(engine_id, EngineId) -> + case EngineId of + discovery -> + ok; + _ -> + snmp_conf:check_string(EngineId) + end; +verify_agent_entry(timeout, Timeout) -> + snmp_conf:check_timer(Timeout); +verify_agent_entry(max_message_size, MMS) -> + snmp_conf:check_packet_size(MMS); +verify_agent_entry(version, V) -> + if + V =:= v1; + V =:= v2; + V =:= v3 -> + ok; + true -> + error({bad_version, V}) + end; +verify_agent_entry(sec_model, Model) -> + snmp_conf:check_sec_model(Model); +verify_agent_entry(sec_name, Name) -> + try snmp_conf:check_string(Name) + catch + _ -> + error({bad_sec_name, Name}) + end; +verify_agent_entry(sec_level, Level) -> + snmp_conf:check_sec_level(Level); +verify_agent_entry(Item, _) -> + error({unknown_item, Item}). + +%% read_users_config_file(Dir) -> +%% Verify = fun check_user_config/1, +%% case read_file(Dir, "users.conf", Verify, []) of +%% {ok, Conf} -> +%% Conf; +%% Error -> +%% ?vlog("failure reading users config file: ~n ~p", [Error]), +%% throw(Error) +%% end. + read_users_config_file(Dir) -> - Check = fun(C) -> check_user_config(C) end, - case read_file(Dir, "users.conf", Check, []) of - {ok, Conf} -> - Conf; - Error -> + Order = fun snmp_conf:no_order/2, + Check = fun (User, State) -> {check_user_config(User), State} end, + try read_file(Dir, "users.conf", Order, Check, []) + catch + throw:Error -> ?vlog("failure reading users config file: ~n ~p", [Error]), - throw(Error) + erlang:raise(throw, Error, erlang:get_stacktrace()) end. - check_user_config({Id, Mod, Data}) -> ?vtrace("check_user_config -> entry with" "~n Id: ~p" @@ -1864,21 +1983,18 @@ check_user_config({Id, Mod, Data, DefaultAgentConfig} = _User) case (catch verify_user_behaviour(Mod)) of ok -> ?vtrace("check_user_config -> user behaviour verified", []), - case verify_user_agent_config(DefaultAgentConfig) of - {ok, DefAgentConf} -> - ?vtrace("check_user_config -> " - "user agent (default) config verified", []), - User2 = {Id, Mod, Data, DefAgentConf}, - {ok, User2}; - {error, Reason} -> - error({bad_default_agent_config, Reason}) - end; + DefAgentConf = + verify_default_agent_config(DefaultAgentConfig), + ?vtrace("check_user_config -> " + "user agent (default) config verified", []), + User2 = {Id, Mod, Data, DefAgentConf}, + {ok, User2}; Error -> throw(Error) end; check_user_config({Id, _Mod, _Data, DefaultAgentConfig}) when (Id =/= ?DEFAULT_USER) -> - {error, {bad_default_agent_config, DefaultAgentConfig}}; + error({bad_default_agent_config, DefaultAgentConfig}); check_user_config({Id, _Mod, _Data, _DefaultAgentConfig}) -> error({bad_user_id, Id}); check_user_config(User) -> @@ -1904,7 +2020,7 @@ init_user_config(User) -> error_msg("user config check failed: " "~n~w~n~w", [User, Reason]) end. - + verify_user({Id, UserMod, UserData}) -> verify_user({Id, UserMod, UserData, []}); verify_user({Id, UserMod, UserData, DefaultAgentConfig}) @@ -1917,15 +2033,24 @@ verify_user({Id, UserMod, UserData, DefaultAgentConfig}) [Id, UserMod, UserData, DefaultAgentConfig]), case (catch verify_user_behaviour(UserMod)) of ok -> - case verify_user_agent_config(DefaultAgentConfig) of - {ok, DefAgentConf} -> - Config = default_agent_config(DefAgentConf), - {ok, #user{id = Id, - mod = UserMod, - data = UserData, - default_agent_config = Config}}; - {error, Reason} -> - error({bad_default_agent_config, Reason}) + try + {ok, SystemDefaultAgentConfig} = agent_info(), + Config = + ensure_config( + SystemDefaultAgentConfig, + verify_default_agent_config(DefaultAgentConfig)), +%% Config = +%% default_agent_config( +%% verify_default_agent_config(DefaultAgentConfig)), + {ok, #user{id = Id, + mod = UserMod, + data = UserData, + default_agent_config = Config}} + catch + Error -> + ?vdebug("verify_user default_agent_config -> throw" + "~n Error: ~p", [Error]), + error({bad_default_agent_config, Error}) end; Error -> throw(Error) @@ -1936,27 +2061,32 @@ verify_user({Id, _UserMod, _UserData, DefaultAgentConfig}) verify_user({Id, _, _, _}) -> {error, {bad_user_id, Id}}. -verify_user_agent_config(Conf) -> +verify_default_agent_config(Conf) -> try - begin - verify_invalid(Conf, [user_id, engine_id, address]), - verify_agent_config2(Conf) - end + verify_illegal( + Conf, + [user_id, engine_id, address, tdomain, taddress]), + verify_agent_config(Conf) catch - throw:Error -> - ?vdebug("verify_user_agent_config -> throw" + Error -> + ?vdebug("verify_default_agent_config -> throw" "~n Error: ~p", [Error]), - Error + error({bad_default_agent_config, Error}) end. +%% read_usm_config_file(Dir) -> +%% Verify = fun check_usm_user_config/1, +%% case read_file(Dir, "usm.conf", Verify, []) of +%% {ok, Conf} -> +%% Conf; +%% Error -> +%% throw(Error) +%% end. + read_usm_config_file(Dir) -> - Check = fun(C) -> check_usm_user_config(C) end, - case read_file(Dir, "usm.conf", Check, []) of - {ok, Conf} -> - Conf; - Error -> - throw(Error) - end. + Order = fun snmp_conf:no_order/2, + Check = fun (User, State) -> {check_usm_user_config(User), State} end, + read_file(Dir, "usm.conf", Order, Check, []). %% Identity-function check_usm_user_config({EngineId, Name, @@ -2138,20 +2268,61 @@ is_crypto_supported(Func) -> snmp_misc:is_crypto_supported(Func). +%% read_manager_config_file(Dir) -> +%% Verify = fun check_manager_config/1, +%% case read_file(Dir, "manager.conf", Verify) of +%% {ok, Conf} -> +%% ?d("read_manager_config_file -> ok: " +%% "~n Conf: ~p", [Conf]), +%% %% If the address is not specified, then we assume +%% %% it should be the local host. +%% %% If the address is not possible to determine +%% %% that way, then we give up... +%% verify_mandatory(Conf, [port,engine_id,max_message_size]), +%% ensure_config(default_manager_config(), Conf); +%% %% check_mandatory_manager_config(Conf), +%% %% ensure_manager_config(Conf); +%% Error -> +%% throw(Error) +%% end. + read_manager_config_file(Dir) -> - Check = fun(Conf) -> check_manager_config(Conf) end, - case read_file(Dir, "manager.conf", Check) of - {ok, Conf} -> - ?d("read_manager_config_file -> ok: " - "~n Conf: ~p", [Conf]), - %% If the address is not specified, then we assume - %% it should be the local host. - %% If the address is not possible to determine - %% that way, then we give up... - check_mandatory_manager_config(Conf), - ensure_manager_config(Conf); - Error -> - throw(Error) + Order = fun order_manager_config/2, + Check = fun check_manager_config/2, + Conf = read_file(Dir, "manager.conf", Order, Check), + ?d("read_manager_config_file -> ok: " + "~n Conf: ~p", [Conf]), + %% If the address is not specified, then we assume + %% it should be the local host. + %% If the address is not possible to determine + %% that way, then we give up... + verify_mandatory(Conf, [port,engine_id,max_message_size]), + default_manager_config(Conf). + +default_manager_config(Conf) -> + %% Ensure address of right family + case lists:keyfind(address, 1, Conf) of + false -> + Domain = + case lists:keyfind(domain, 1, Conf) of + false -> + default_transport_domain(); + {_, D} -> + D + end, + Family = snmp_conf:tdomain_to_family(Domain), + {ok, HostName} = inet:gethostname(), + case inet:getaddr(HostName, Family) of + {ok, Address} -> + [{address, Address} | Conf]; + {error, _Reason} -> + ?d("default_manager_config -> " + "failed getting ~w address for ~s:~n" + " _Reason: ~p", [Family, HostName, _Reason]), + Conf + end; + _ -> + Conf end. default_manager_config() -> @@ -2164,46 +2335,66 @@ default_manager_config() -> "~n _Reason: ~p", [_Reason]), [] end. - -check_manager_config({address, Addr}) -> - snmp_conf:check_ip(Addr); + +order_manager_config(EntryA, EntryB) -> + snmp_conf:keyorder(1, EntryA, EntryB, [domain]). + +check_manager_config({domain, D}, _Domain) -> + {snmp_conf:check_domain(D), D}; +check_manager_config({address = Tag, Ip}, D) -> + Domain = + case D of + undefined -> + default_transport_domain(); + _ -> + D + end, + {case snmp_conf:check_ip(Domain, Ip) of + ok -> + ok; + {ok, FixedIp} -> + {ok, {Tag, FixedIp}} + end, Domain}; +check_manager_config(Entry, Domain) -> + {check_manager_config(Entry), Domain}. + check_manager_config({port, Port}) -> - snmp_conf:check_integer(Port, {gt, 0}); + snmp_conf:check_port(Port); check_manager_config({engine_id, EngineID}) -> snmp_conf:check_string(EngineID); check_manager_config({max_message_size, Max}) -> snmp_conf:check_integer(Max, {gte, 484}); check_manager_config(Conf) -> - {error, {unknown_config, Conf}}. + error({unknown_config, Conf}). -check_mandatory_manager_config(Conf) -> - Mand = [port, engine_id, max_message_size], - check_mandatory_manager_config(Mand, Conf). +%% check_mandatory_manager_config(Conf) -> +%% Mand = [port, engine_id, max_message_size], +%% check_mandatory_manager_config(Mand, Conf). -check_mandatory_manager_config([], _Conf) -> - ok; -check_mandatory_manager_config([Item|Mand], Conf) -> - case lists:keysearch(Item, 1, Conf) of - false -> - error({missing_mandatory_manager_config, Item}); - _ -> - check_mandatory_manager_config(Mand, Conf) - end. +%% check_mandatory_manager_config([], _Conf) -> +%% ok; +%% check_mandatory_manager_config([Item|Mand], Conf) -> +%% case lists:keysearch(Item, 1, Conf) of +%% false -> +%% error({missing_mandatory_manager_config, Item}); +%% _ -> +%% check_mandatory_manager_config(Mand, Conf) +%% end. -ensure_manager_config(Confs) -> - ensure_manager_config(Confs, default_manager_config()). +%% ensure_manager_config(Confs) -> +%% ensure_manager_config(Confs, default_manager_config()). -ensure_manager_config(Confs, []) -> - Confs; -ensure_manager_config(Confs, [{Key,_} = DefKeyVal|Defs]) -> - case lists:keysearch(Key, 1, Confs) of - false -> - ensure_manager_config([DefKeyVal|Confs], Defs); - {value, _Conf} -> - ensure_manager_config(Confs, Defs) - end. +%% ensure_manager_config(Confs, []) -> +%% Confs; +%% ensure_manager_config(Confs, [{Key,_} = DefKeyVal|Defs]) -> +%% case lists:keysearch(Key, 1, Confs) of +%% false -> +%% ensure_manager_config([DefKeyVal|Confs], Defs); +%% {value, _Conf} -> +%% ensure_manager_config(Confs, Defs) +%% end. % ensure_manager_config([], Defs, Confs) -> % Confs ++ Defs; @@ -2216,46 +2407,102 @@ ensure_manager_config(Confs, [{Key,_} = DefKeyVal|Defs]) -> % ensure_manager_config(Confs, Defs, [Conf|Acc]) % end. - - -read_file(Dir, FileName, Check, Default) -> - File = filename:join(Dir, FileName), - case file:read_file_info(File) of - {ok, _} -> - case (catch do_read(File, Check)) of - {ok, Conf} -> - {ok, Conf}; - Error -> - ?vtrace("read_file -> read failed:" - "~n Error: ~p", [Error]), - Error - end; - {error, Reason} -> +read_file(Dir, FileName, Order, Check, Default) -> + try snmp_conf:read(filename:join(Dir, FileName), Order, Check) + catch + {error, Reason} when element(1, Reason) =:= failed_open -> ?vlog("failed reading config from ~s: ~p", [FileName, Reason]), - {ok, Default} + Default end. -read_file(Dir, FileName, Check) -> - File = filename:join(Dir, FileName), - case file:read_file_info(File) of - {ok, _} -> - case (catch do_read(File, Check)) of - {ok, Conf} -> - ?vtrace("read_file -> read ok" - "~n Conf: ~p", [Conf]), - {ok, Conf}; - Error -> - ?vtrace("read_file -> read failed:" - "~n Error: ~p", [Error]), - Error - end; - {error, Reason} -> +read_file(Dir, FileName, Order, Check) -> + try snmp_conf:read(filename:join(Dir, FileName), Order, Check) + catch + throw:{error, Reason} = Error + when element(1, Reason) =:= failed_open -> error_msg("failed reading config from ~s: ~p", [FileName, Reason]), - {error, {failed_reading, FileName, Reason}} - end. + erlang:raise(throw, Error, erlang:get_stacktrace()) + end. + + + + + + +%% read_file(Dir, FileName, Verify, Default) -> +%% File = filename:join(Dir, FileName), +%% case file:read_file_info(File) of +%% {ok, _} -> +%% read_file(File, Verify); +%% {error, Reason} -> +%% ?vlog("failed reading config from ~s: ~p", [FileName, Reason]), +%% {ok, Default} +%% end. + +%% read_file(Dir, FileName, Verify) -> +%% File = filename:join(Dir, FileName), +%% case file:read_file_info(File) of +%% {ok, _} -> +%% read_file(File, Verify); +%% {error, Reason} -> +%% error_msg("failed reading config from ~s: ~p", [FileName, Reason]), +%% {error, {failed_reading, FileName, Reason}} +%% end. + +%% read_file(File, Verify) -> +%% Check = fun (Config, State) -> {Verify(Config), State} end, +%% try snmp_conf:read(File, Check) of +%% Conf -> +%% ?vtrace("read_file -> read ok" +%% "~n Conf: ~p", [Conf]), +%% {ok, Conf} +%% catch +%% Error -> +%% ?vtrace("read_file -> read failed:" +%% "~n Error: ~p", [Error]), +%% Error +%% end. + +%% XXX remove + +%% read_file(Dir, FileName, Check, Default) -> +%% File = filename:join(Dir, FileName), +%% case file:read_file_info(File) of +%% {ok, _} -> +%% case (catch do_read(File, Check)) of +%% {ok, Conf} -> +%% {ok, Conf}; +%% Error -> +%% ?vtrace("read_file -> read failed:" +%% "~n Error: ~p", [Error]), +%% Error +%% end; +%% {error, Reason} -> +%% ?vlog("failed reading config from ~s: ~p", [FileName, Reason]), +%% {ok, Default} +%% end. + +%% read_file(Dir, FileName, Check) -> +%% File = filename:join(Dir, FileName), +%% case file:read_file_info(File) of +%% {ok, _} -> +%% case (catch do_read(File, Check)) of +%% {ok, Conf} -> +%% ?vtrace("read_file -> read ok" +%% "~n Conf: ~p", [Conf]), +%% {ok, Conf}; +%% Error -> +%% ?vtrace("read_file -> read failed:" +%% "~n Error: ~p", [Error]), +%% Error +%% end; +%% {error, Reason} -> +%% error_msg("failed reading config from ~s: ~p", [FileName, Reason]), +%% {error, {failed_reading, FileName, Reason}} +%% end. -do_read(File, Check) -> - {ok, snmp_conf:read(File, Check)}. +%% do_read(File, Check) -> +%% {ok, snmp_conf:read(File, Check)}. %%-------------------------------------------------------------------- @@ -2684,30 +2931,50 @@ handle_register_agent(UserId, TargetName, Config) -> "~n Config: ~p", [UserId, TargetName, Config]), case (catch agent_info(TargetName, user_id)) of {error, _} -> - ?vtrace("handle_register_agent -> user_id not found in config", []), + ?vtrace( + "handle_register_agent -> user_id not found in config", []), case ets:lookup(snmpm_user_table, UserId) of [#user{default_agent_config = DefConfig}] -> - ?vtrace("handle_register_agent -> " - "~n DefConfig: ~p", [DefConfig]), - %% First, insert this users default config - ?vtrace("handle_register_agent -> store default config", []), - do_handle_register_agent(TargetName, DefConfig), - %% Second, insert the config for this agent - ?vtrace("handle_register_agent -> store config", []), - do_handle_register_agent(TargetName, - [{user_id, UserId}|Config]), + ?vtrace("handle_register_agent ->~n" + " DefConfig: ~p", [DefConfig]), + FixedConfig = + fix_agent_config(ensure_config(DefConfig, Config)), + ?vtrace("handle_register_agent ->~n" + " FixedConfig: ~p", [FixedConfig]), + do_handle_register_agent( + TargetName, [{user_id, UserId}|FixedConfig]), %% <DIRTY-BACKWARD-COMPATIBILLITY> - %% And now for some (backward compatibillity) + %% And now for some (backward compatibillity) %% dirty crossref stuff - ?vtrace("handle_register_agent -> lookup address", []), - {ok, Addr} = agent_info(TargetName, address), - ?vtrace("handle_register_agent -> Addr: ~p, lookup Port", - [Addr]), - {ok, Port} = agent_info(TargetName, port), - ?vtrace("handle_register_agent -> register cross-ref fix", []), - ets:insert(snmpm_agent_table, - {{Addr, Port, target_name}, TargetName}), + {value, {_, Domain}} = + lists:keysearch(tdomain, 1, FixedConfig), + {value, {_, Address}} = + lists:keysearch(taddress, 1, FixedConfig), + ?vtrace( + "handle_register_agent -> register cross-ref fix", []), + ets:insert(snmpm_agent_table, + {{Domain, Address, target_name}, TargetName}), %% </DIRTY-BACKWARD-COMPATIBILLITY> + +%% %% First, insert this users default config +%% ?vtrace("handle_register_agent -> store default config", []), +%% do_handle_register_agent(TargetName, DefConfig), +%% %% Second, insert the config for this agent +%% ?vtrace("handle_register_agent -> store config", []), +%% do_handle_register_agent(TargetName, +%% [{user_id, UserId}|Config]), +%% %% <DIRTY-BACKWARD-COMPATIBILLITY> +%% %% And now for some (backward compatibillity) +%% %% dirty crossref stuff +%% ?vtrace("handle_register_agent -> lookup taddress", []), +%% {ok, {Addr, Port} = TAddress} = +%% agent_info(TargetName, taddress), +%% ?vtrace("handle_register_agent -> taddress: ~p", +%% [TAddress]), +%% ?vtrace("handle_register_agent -> register cross-ref fix", []), +%% ets:insert(snmpm_agent_table, +%% {{Addr, Port, target_name}, TargetName}), +%% %% </DIRTY-BACKWARD-COMPATIBILLITY> ok; _ -> {error, {not_found, UserId}} @@ -2729,7 +2996,7 @@ handle_register_agent(UserId, TargetName, Config) -> do_handle_register_agent(_TargetName, []) -> ok; do_handle_register_agent(TargetName, [{Item, Val}|Rest]) -> - ?vtrace("handle_register_agent -> entry with" + ?vtrace("do_handle_register_agent -> entry with" "~n TargetName: ~p" "~n Item: ~p" "~n Val: ~p" @@ -2738,7 +3005,7 @@ do_handle_register_agent(TargetName, [{Item, Val}|Rest]) -> ok -> do_handle_register_agent(TargetName, Rest); {error, Reason} -> - ?vtrace("handle_register_agent -> failed updating ~p" + ?vtrace("do_handle_register_agent -> failed updating ~p" "~n Item: ~p" "~n Reason: ~p", [Item, Reason]), ets:match_delete(snmpm_agent_table, {TargetName, '_'}), @@ -2762,9 +3029,9 @@ handle_unregister_agent(UserId, TargetName) -> %% <DIRTY-BACKWARD-COMPATIBILLITY> %% And now for some (backward compatibillity) %% dirty crossref stuff - {ok, Addr} = agent_info(TargetName, address), - {ok, Port} = agent_info(TargetName, port), - ets:delete(snmpm_agent_table, {Addr, Port, target_name}), + {ok, Domain} = agent_info(TargetName, tdomain), + {ok, Address} = agent_info(TargetName, taddress), + ets:delete(snmpm_agent_table, {Domain, Address, target_name}), %% </DIRTY-BACKWARD-COMPATIBILLITY> ets:match_delete(snmpm_agent_table, {{TargetName, '_'}, '_'}), ok; @@ -2790,21 +3057,26 @@ handle_update_agent_info(UserId, TargetName, Info) -> Error end. -handle_update_agent_info(TargetName, Info0) -> +handle_update_agent_info(TargetName, Info) -> ?vtrace("handle_update_agent_info -> entry with" "~n TargetName: ~p" - "~n Info0: ~p", [TargetName, Info0]), + "~n Info: ~p", [TargetName, Info]), %% Verify info - try verify_agent_info(TargetName, Info0) of - {ok, Info} -> - do_update_agent_info(TargetName, Info); + try + verify_illegal(Info, [user_id]), + %% If port or domain is part of the info, then use it. + %% If not, lookup what is already stored for + %% this agent and use that. + do_update_agent_info( + TargetName, + fix_agent_config( + verify_agent_config( + ensure_agent_info(TargetName, [port,tdomain], Info)))) + catch Error -> - Error - catch - throw:Error -> Error; T:E -> - {error, {failed_info_verification, Info0, T, E}} + {error, {failed_info_verification, Info, T, E}} end. handle_update_agent_info(UserId, TargetName, Item, Val) -> @@ -2816,6 +3088,9 @@ handle_update_agent_info(UserId, TargetName, Item, Val) -> handle_update_agent_info(TargetName, [{Item, Val}]). do_update_agent_info(TargetName, Info) -> + ?vtrace("do_update_agent_info -> entry with~n" + " TargetName: ~p~n" + " Info: ~p", [TargetName,Info]), InsertItem = fun({Item, Val}) -> ets:insert(snmpm_agent_table, {{TargetName, Item}, Val}) @@ -2997,109 +3272,42 @@ verify_mandatory(Conf, [Mand|Mands]) -> true -> verify_mandatory(Conf, Mands); false -> - throw({error, {missing_mandatory_config, Mand}}) + error({missing_mandatory_config, Mand}) end. -verify_invalid(_, []) -> +verify_illegal(_, []) -> ok; -verify_invalid(Conf, [Inv|Invs]) -> +verify_illegal(Conf, [Inv|Invs]) -> case lists:member(Inv, Conf) of false -> - verify_invalid(Conf, Invs); + verify_illegal(Conf, Invs); true -> - throw({error, {illegal_config, Inv}}) + error({illegal_config, Inv}) end. - -verify_val(user_id, UserId) -> - {ok, UserId}; -verify_val(reg_type, RegType) - when (RegType =:= addr_port) orelse (RegType =:= target_name) -> - {ok, RegType}; -verify_val(tdomain = Item, snmpUDPDomain = _Domain) -> - verify_val(Item, transportDomainUdpIpv4); -verify_val(tdomain, Domain) -> - case lists:member(Domain, ?SUPPORTED_DOMAINS) of +verify_someof(Conf, [Mand|Mands]) -> + case lists:keymember(Mand, 1, Conf) of true -> - {ok, Domain}; + ok; false -> - case lists:member(Domain, snmp_conf:all_domains()) of - true -> - error({unsupported_domain, Domain}); - false -> - error({unknown_domain, Domain}) + case Mands of + [] -> + error({missing_mandatory_config, Mand}); + _ -> + verify_someof(Conf, Mands) end - end; -verify_val(address, {Domain, Addr0}) -> - case normalize_address(Domain, Addr0) of - {_A1, _A2, _A3, _A4} = Addr -> - {ok, Addr}; - {_A1, _A2, _A3, _A4, _A5, _A6, _A7, _A8} = Addr -> - {ok, Addr}; - _ when is_list(Addr0) -> - case (catch snmp_conf:check_ip(Addr0)) of - ok -> - {ok, list_to_tuple(Addr0)}; - Err -> - Err - end; - _ -> - error({bad_address, Addr0}) - end; -verify_val(address, BadAddress) -> - error({bad_address, BadAddress}); -verify_val(port, Port) -> - case (catch snmp_conf:check_integer(Port, {gt, 0})) of - ok -> - {ok, Port}; - Err -> - Err - end; -verify_val(community, Comm) -> - case (catch snmp_conf:check_string(Comm)) of - ok -> - {ok, Comm}; - Err -> - Err - end; -verify_val(engine_id, discovery = EngineId) -> - {ok, EngineId}; -verify_val(engine_id, EngineId) -> - case (catch snmp_conf:check_string(EngineId)) of - ok -> - {ok, EngineId}; - Err -> - Err - end; -verify_val(timeout, Timeout) -> - (catch snmp_conf:check_timer(Timeout)); -verify_val(max_message_size, MMS) -> - case (catch snmp_conf:check_packet_size(MMS)) of - ok -> - {ok, MMS}; - Err -> - Err - end; -verify_val(version, V) - when (V =:= v1) orelse (V =:= v2) orelse (V =:= v3) -> - {ok, V}; -verify_val(version, BadVersion) -> - error({bad_version, BadVersion}); -verify_val(sec_model, Model) -> - (catch snmp_conf:check_sec_model(Model)); -verify_val(sec_name, Name) when is_list(Name) -> - case (catch snmp_conf:check_string(Name)) of - ok -> - {ok, Name}; - Err -> - Err - end; -verify_val(sec_name, BadName) -> - error({bad_sec_name, BadName}); -verify_val(sec_level, Level) -> - (catch snmp_conf:check_sec_level(Level)); -verify_val(Item, _) -> - {error, {unknown_item, Item}}. + end. + +ensure_config([], Config) -> + Config; +ensure_config([Default|Defaults], Config) -> + case lists:keymember(element(1, Default), 1, Config) of + true -> + ensure_config(Defaults, Config); + false -> + ensure_config(Defaults, [Default|Config]) + end. + %%%------------------------------------------------------------------- @@ -3257,31 +3465,14 @@ init_mini_mib_elems(MibName, [_|T], Res) -> %%---------------------------------------------------------------------- -normalize_address(Addr) -> - normalize_address(snmpUDPDomain, Addr). - -normalize_address(snmpUDPDomain, Addr) -> - normalize_address(transportDomainUdpIpv4, Addr); - -normalize_address(Domain, Addr) -> - case inet:getaddr(Addr, td2fam(Domain)) of - {ok, Addr2} -> - Addr2; - _ when is_list(Addr) -> - case (catch snmp_conf:check_ip(Domain, Addr)) of - ok -> - list_to_tuple(Addr); - _ -> - Addr - end; - _ -> - Addr +fix_address(Domain, Address) -> + case snmp_conf:check_address(Domain, Address) of + ok -> + Address; + {ok, NAddress} -> + NAddress end. -td2fam(transportDomainUdpIpv4) -> inet; -td2fam(transportDomainUdpIpv6) -> inet6. - - %%---------------------------------------------------------------------- call(Req) -> @@ -3389,6 +3580,6 @@ error_msg(F, A) -> %% p(F) -> %% p(F, []). -%% p(F, A) -> -%% io:format("~w:" ++ F ++ "~n", [?MODULE | A]). +p(F, A) -> + io:format("~w:" ++ F ++ "~n", [?MODULE | A]). diff --git a/lib/snmp/src/manager/snmpm_mpd.erl b/lib/snmp/src/manager/snmpm_mpd.erl index 953c94ab54..f8a7441c0a 100644 --- a/lib/snmp/src/manager/snmpm_mpd.erl +++ b/lib/snmp/src/manager/snmpm_mpd.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2012. All Rights Reserved. +%% Copyright Ericsson AB 2004-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -21,7 +21,7 @@ -export([init/1, - process_msg/7, + process_msg/7, process_msg/6, generate_msg/5, generate_response_msg/4, next_msg_id/0, @@ -92,8 +92,10 @@ reset(#state{v3 = V3}) -> %% Purpose: This is the main Message Dispatching function. (see %% section 4.2.1 in rfc2272) %%----------------------------------------------------------------- -process_msg(Msg, Domain, Addr, Port, State, NoteStore, Logger) -> +process_msg(Msg, Domain, Ip, Port, State, NoteStore, Logger) -> + process_msg(Msg, Domain, {Ip, Port}, State, NoteStore, Logger). +process_msg(Msg, Domain, Addr, State, NoteStore, Logger) -> inc(snmpInPkts), case (catch snmp_pdus:dec_message_only(binary_to_list(Msg))) of @@ -102,17 +104,17 @@ process_msg(Msg, Domain, Addr, Port, State, NoteStore, Logger) -> #message{version = 'version-1', vsn_hdr = Community, data = Data} when State#state.v1 =:= true -> HS = ?empty_msg_size + length(Community), - process_v1_v2c_msg('version-1', NoteStore, Msg, - Domain, Addr, Port, - Community, Data, HS, Logger); + process_v1_v2c_msg( + 'version-1', NoteStore, Msg, Domain, Addr, + Community, Data, HS, Logger); %% Version 2 #message{version = 'version-2', vsn_hdr = Community, data = Data} when State#state.v2c =:= true -> HS = ?empty_msg_size + length(Community), - process_v1_v2c_msg('version-2', NoteStore, Msg, - Domain, Addr, Port, - Community, Data, HS, Logger); + process_v1_v2c_msg( + 'version-2', NoteStore, Msg, Domain, Addr, + Community, Data, HS, Logger); %% Version 3 #message{version = 'version-3', vsn_hdr = H, data = Data} @@ -122,7 +124,7 @@ process_msg(Msg, Domain, Addr, Port, State, NoteStore, Logger) -> "~n msgFlags: ~p" "~n msgSecModel: ~p", [H#v3_hdr.msgID,H#v3_hdr.msgFlags,H#v3_hdr.msgSecurityModel]), - process_v3_msg(NoteStore, Msg, H, Data, Addr, Port, Logger); + process_v3_msg(NoteStore, Msg, H, Data, Addr, Logger); %% Crap {'EXIT', {bad_version, Vsn}} -> @@ -148,32 +150,27 @@ process_msg(Msg, Domain, Addr, Port, State, NoteStore, Logger) -> %%----------------------------------------------------------------- %% Handles a Community based message (v1 or v2c). %%----------------------------------------------------------------- -process_v1_v2c_msg(Vsn, _NoteStore, Msg, Domain, - Addr, Port, - Community, Data, HS, Log) -> +process_v1_v2c_msg( + Vsn, _NoteStore, Msg, Domain, Addr, Community, Data, HS, Log) -> ?vdebug("process_v1_v2c_msg -> entry with" "~n Vsn: ~p" "~n Domain: ~p" "~n Addr: ~p" - "~n Port: ~p" "~n Community: ~p" - "~n HS: ~p", [Vsn, Domain, Addr, Port, Community, HS]), - + "~n HS: ~p", [Vsn, Domain, Addr, Community, HS]), + {TDomain, TAddress} = try - begin - TD = snmp_conf:mk_tdomain(Domain), - TA = snmp_conf:mk_taddress(Domain, Addr, Port), - {TD, TA} - end + {snmp_conf:mk_tdomain(Domain), + snmp_conf:mk_taddress(Domain, Addr)} catch throw:{error, TReason} -> throw({discarded, {badarg, Domain, TReason}}) end, Max = get_max_message_size(), - AgentMax = get_agent_max_message_size(Addr, Port), + AgentMax = get_agent_max_message_size(Domain, Addr), PduMS = pdu_ms(Max, AgentMax, HS), ?vtrace("process_v1_v2c_msg -> PduMS: ~p", [PduMS]), @@ -213,13 +210,12 @@ sec_model('version-2') -> ?SEC_V2C. %% Handles a SNMPv3 Message, following the procedures in rfc2272, %% section 4.2 and 7.2 %%----------------------------------------------------------------- -process_v3_msg(NoteStore, Msg, Hdr, Data, Addr, Port, Log) -> +process_v3_msg(NoteStore, Msg, Hdr, Data, Address, Log) -> + ?vdebug( + "process_v3_msg -> entry with~n" + " Hdr: ~p~n" + " Address: ~p", [Hdr, Address]), - ?vdebug("process_v3_msg -> entry with" - "~n Hdr: ~p" - "~n Addr: ~p" - "~n Port: ~p", [Hdr, Addr, Port]), - %% 7.2.3 #v3_hdr{msgID = MsgID, msgMaxSize = MMS, @@ -352,8 +348,8 @@ process_v3_msg(NoteStore, Msg, Hdr, Data, Addr, Port, Log) -> %% 4.2.2.1.1 - we don't handle proxys yet => we only %% handle CtxEngineID to ourselves %% Check that we actually know of an agent with this - %% CtxEngineID and Addr/Port - case is_known_engine_id(CtxEngineID, Addr, Port) of + %% CtxEngineID and Address + case is_known_engine_id(CtxEngineID, Address) of true -> ?vtrace("and the agent EngineID (~p) " "is know to us", [CtxEngineID]), @@ -866,14 +862,23 @@ get_max_message_size() -> end. %% The the MMS of the agent -get_agent_max_message_size(Addr, Port) -> - case snmpm_config:get_agent_engine_max_message_size(Addr, Port) of +get_agent_max_message_size(Domain, Addr) -> + case snmpm_config:get_agent_engine_max_message_size(Domain, Addr) of {ok, MMS} -> MMS; _Error -> - ?vlog("unknown agent: ~w:~w", [Addr, Port]), + ?vlog("unknown agent: ~s", + [snmp_conf:mk_addr_string({Domain, Addr})]), get_max_message_size() end. +%% get_agent_max_message_size(Addr, Port) -> +%% case snmpm_config:get_agent_engine_max_message_size(Addr, Port) of +%% {ok, MMS} -> +%% MMS; +%% _Error -> +%% ?vlog("unknown agent: ~w:~w", [Addr, Port]), +%% get_max_message_size() +%% end. %% Get "our" (manager) engine id get_engine_id() -> @@ -888,9 +893,12 @@ get_engine_id() -> get_agent_engine_id(Name) -> snmpm_config:get_agent_engine_id(Name). -is_known_engine_id(EngineID, Addr, Port) -> +is_known_engine_id(EngineID, {Addr, Port}) -> snmpm_config:is_known_engine_id(EngineID, Addr, Port). +%% is_known_engine_id(EngineID, Addr, Port) -> +%% snmpm_config:is_known_engine_id(EngineID, Addr, Port). + % get_agent_engine_id(Addr, Port) -> % case snmpm_config:get_agent_engine_id(Addr, Port) of % {ok, Id} -> diff --git a/lib/snmp/src/manager/snmpm_net_if.erl b/lib/snmp/src/manager/snmpm_net_if.erl index 4d6bd9aa33..860b0b83dd 100644 --- a/lib/snmp/src/manager/snmpm_net_if.erl +++ b/lib/snmp/src/manager/snmpm_net_if.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2011. All Rights Reserved. +%% Copyright Ericsson AB 2004-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -27,9 +27,9 @@ -export([ start_link/2, stop/1, - send_pdu/6, % Backward compatibillity - send_pdu/7, % Backward compatibillity - send_pdu/8, + send_pdu/6, % Backward compatibility + send_pdu/7, % Partly backward compatibility + send_pdu/8, % Backward compatibility inform_response/4, @@ -55,11 +55,12 @@ %% -define(VMODULE,"NET_IF"). -include("snmp_verbosity.hrl"). --record(state, +-record(state, { server, note_store, - sock, + domain, + sock, mpd_state, log, irb = auto, % auto | {user, integer()} @@ -99,30 +100,32 @@ start_link(Server, NoteStore) -> stop(Pid) -> call(Pid, stop). -send_pdu(Pid, Pdu, Vsn, MsgData, Addr, Port) -> - send_pdu(Pid, Pdu, Vsn, MsgData, Addr, Port, ?DEFAULT_EXTRA_INFO). +send_pdu(Pid, Pdu, Vsn, MsgData, Domain_or_Ip, Addr_or_Port) -> + send_pdu( + Pid, Pdu, Vsn, MsgData, Domain_or_Ip, Addr_or_Port, ?DEFAULT_EXTRA_INFO). -send_pdu(Pid, Pdu, Vsn, MsgData, Addr, Port, ExtraInfo) -> - Domain = snmpm_config:default_transport_domain(), - send_pdu(Pid, Pdu, Vsn, MsgData, Domain, Addr, Port, ExtraInfo). - -send_pdu(Pid, Pdu, Vsn, MsgData, Domain, Addr, Port, ExtraInfo) +send_pdu(Pid, Pdu, Vsn, MsgData, Domain_or_Ip, Addr_or_Port, ExtraInfo) when is_record(Pdu, pdu) -> - ?d("send_pdu -> entry with" - "~n Pid: ~p" - "~n Pdu: ~p" - "~n Vsn: ~p" - "~n MsgData: ~p" - "~n Domain: ~p" - "~n Addr: ~p" - "~n Port: ~p", [Pid, Pdu, Vsn, MsgData, Domain, Addr, Port]), - cast(Pid, {send_pdu, Pdu, Vsn, MsgData, Domain, Addr, Port, ExtraInfo}). + ?d("send_pdu -> entry with~n" + " Pid: ~p~n" + " Pdu: ~p~n" + " Vsn: ~p~n" + " MsgData: ~p~n" + " Domain/IP: ~p~n" + " Addr/Port: ~p", + [Pid, Pdu, Vsn, MsgData, Domain_or_Ip, Addr_or_Port]), + {Domain, Addr} = address(Domain_or_Ip, Addr_or_Port), + cast(Pid, {send_pdu, Pdu, Vsn, MsgData, Domain, Addr, ExtraInfo}). + +send_pdu(Pid, Pdu, Vsn, MsgData, Domain, Ip, Port, ExtraInfo) -> + send_pdu(Pid, Pdu, Vsn, MsgData, Domain, {Ip, Port}, ExtraInfo). note_store(Pid, NoteStore) -> call(Pid, {note_store, NoteStore}). -inform_response(Pid, Ref, Addr, Port) -> - cast(Pid, {inform_response, Ref, Addr, Port}). +inform_response(Pid, Ref, Domain_or_Ip, Addr_or_Port) -> + {Domain, Addr} = address(Domain_or_Ip, Addr_or_Port), + cast(Pid, {inform_response, Ref, Domain, Addr}). info(Pid) -> call(Pid, info). @@ -199,7 +202,14 @@ do_init(Server, NoteStore) -> BindTo = get_opt(Opts, bind_to, false), NoReuse = get_opt(Opts, no_reuse, false), {ok, Port} = snmpm_config:system_info(port), - {ok, Sock} = do_open_port(Port, SndBuf, RecBuf, BindTo, NoReuse), + Domain = + case snmpm_config:system_info(domain) of + {ok, D} -> + D; + _ -> + snmpm_config:default_transport_domain() + end, + {ok, Sock} = do_open_port(Port, SndBuf, RecBuf, Domain, BindTo, NoReuse), %% Flow control -- FilterOpts = get_opt(Opts, filter, []), @@ -217,6 +227,7 @@ do_init(Server, NoteStore) -> State = #state{server = Server, note_store = NoteStore, mpd_state = MpdState, + domain = Domain, sock = Sock, log = Log, irb = IRB, @@ -227,18 +238,23 @@ do_init(Server, NoteStore) -> %% Open port -do_open_port(Port, SendSz, RecvSz, BindTo, NoReuse) -> - ?vtrace("do_open_port -> entry with" - "~n Port: ~p" - "~n SendSz: ~p" - "~n RecvSz: ~p" - "~n BindTo: ~p" - "~n NoReuse: ~p", [Port, SendSz, RecvSz, BindTo, NoReuse]), +do_open_port(Port, SendSz, RecvSz, Domain, BindTo, NoReuse) -> + ?vtrace("do_open_port -> entry with~n" + " Port: ~p~n" + " SendSz: ~p~n" + " RecvSz: ~p~n" + " Domain: ~p~n" + " BindTo: ~p~n" + " NoReuse: ~p", + [Port, SendSz, RecvSz, Domain, BindTo, NoReuse]), IpOpts1 = bind_to(BindTo), IpOpts2 = no_reuse(NoReuse), IpOpts3 = recbuf(RecvSz), IpOpts4 = sndbuf(SendSz), - IpOpts = [binary | IpOpts1 ++ IpOpts2 ++ IpOpts3 ++ IpOpts4], + IpOpts = + [binary, + snmp_conf:tdomain_to_family(Domain) | + IpOpts1 ++ IpOpts2 ++ IpOpts3 ++ IpOpts4], OpenRes = case init:get_argument(snmpm_fd) of {ok, [[FdStr]]} -> @@ -386,25 +402,24 @@ handle_call(Req, From, State) -> %% {noreply, State, Timeout} | %% {stop, Reason, State} (terminate/2 is called) %%-------------------------------------------------------------------- -handle_cast({send_pdu, Pdu, Vsn, MsgData, Domain, Addr, Port, ExtraInfo}, +handle_cast({send_pdu, Pdu, Vsn, MsgData, Domain, Addr, ExtraInfo}, State) -> - ?vlog("received send_pdu message with" - "~n Pdu: ~p" - "~n Vsn: ~p" - "~n MsgData: ~p" - "~n Domain: ~p" - "~n Addr: ~p" - "~n Port: ~p", [Pdu, Vsn, MsgData, Domain, Addr, Port]), - maybe_process_extra_info(ExtraInfo), - maybe_handle_send_pdu(Pdu, Vsn, MsgData, Domain, Addr, Port, State), + ?vlog("received send_pdu message with~n" + " Pdu: ~p~n" + " Vsn: ~p~n" + " MsgData: ~p~n" + " Domain: ~p~n" + " Addr : ~p", [Pdu, Vsn, MsgData, Domain, Addr]), + maybe_process_extra_info(ExtraInfo), + maybe_handle_send_pdu(Pdu, Vsn, MsgData, Domain, Addr, State), {noreply, State}; -handle_cast({inform_response, Ref, Addr, Port}, State) -> - ?vlog("received inform_response message with" - "~n Ref: ~p" - "~n Addr: ~p" - "~n Port: ~p", [Ref, Addr, Port]), - handle_inform_response(Ref, Addr, Port, State), +handle_cast({inform_response, Ref, Domain, Addr}, State) -> + ?vlog("received inform_response message with~n" + " Ref: ~p~n" + " Domain: ~p~n" + " Addr: ~p", [Ref, Domain, Addr]), + handle_inform_response(Ref, Domain, Addr, State), {noreply, State}; handle_cast(filter_reset, State) -> @@ -423,9 +438,11 @@ handle_cast(Msg, State) -> %% {noreply, State, Timeout} | %% {stop, Reason, State} (terminate/2 is called) %%-------------------------------------------------------------------- -handle_info({udp, Sock, Ip, Port, Bytes}, #state{sock = Sock} = State) -> +handle_info( + {udp, Sock, Ip, Port, Bytes}, + #state{sock = Sock, domain = Domain} = State) -> ?vlog("received ~w bytes from ~p:~p [~w]", [size(Bytes), Ip, Port, Sock]), - maybe_handle_recv_msg(Ip, Port, Bytes, State), + maybe_handle_recv_msg(Domain, {Ip, Port}, Bytes, State), {noreply, State}; handle_info(inform_response_gc, State) -> @@ -531,48 +548,50 @@ code_change(_Vsn, State, _Extra) -> %%% Internal functions %%%------------------------------------------------------------------- -maybe_handle_recv_msg(Addr, Port, Bytes, #state{filter = FilterMod} = State) -> - case (catch FilterMod:accept_recv(Addr, Port)) of +maybe_handle_recv_msg( + Domain, Addr, Bytes, + #state{filter = FilterMod, domain = ManagerDomain} = State) -> + {Arg1, Arg2} = fix_filter_address(ManagerDomain, {Domain, Addr}), + case (catch FilterMod:accept_recv(Arg1, Arg2)) of false -> %% Drop the received packet inc(netIfMsgInDrops), ok; _ -> - handle_recv_msg(Addr, Port, Bytes, State) + handle_recv_msg(Domain, Addr, Bytes, State) end. -handle_recv_msg(Addr, Port, Bytes, #state{server = Pid}) +handle_recv_msg(Domain, Addr, Bytes, #state{server = Pid}) when is_binary(Bytes) andalso (size(Bytes) =:= 0) -> - Pid ! {snmp_error, {empty_message, Addr, Port}, Addr, Port}, + Pid ! {snmp_error, {empty_message, Domain, Addr}, Domain, Addr}, ok; -handle_recv_msg(Addr, Port, Bytes, - #state{server = Pid, - note_store = NoteStore, - mpd_state = MpdState, - sock = Sock, - log = Log} = State) -> - Domain = snmp_conf:which_domain(Addr), % What the ****... - Logger = logger(Log, read, Addr, Port), - case (catch snmpm_mpd:process_msg(Bytes, Domain, Addr, Port, +handle_recv_msg( + Domain, Addr, Bytes, + #state{server = Pid, + note_store = NoteStore, + mpd_state = MpdState, + log = Log} = State) -> + Logger = logger(Log, read, Domain, Addr), + case (catch snmpm_mpd:process_msg(Bytes, Domain, Addr, MpdState, NoteStore, Logger)) of {ok, Vsn, Pdu, MS, ACM} -> - maybe_handle_recv_pdu(Addr, Port, Vsn, Pdu, MS, ACM, + maybe_handle_recv_pdu(Domain, Addr, Vsn, Pdu, MS, ACM, Logger, State); {discarded, Reason, Report} -> ?vdebug("discarded: ~p", [Reason]), ErrorInfo = {failed_processing_message, Reason}, - Pid ! {snmp_error, ErrorInfo, Addr, Port}, - maybe_udp_send(State#state.filter, Sock, Addr, Port, Report), + Pid ! {snmp_error, ErrorInfo, Domain, Addr}, + maybe_udp_send(Domain, Addr, Report, State), ok; {discarded, Reason} -> ?vdebug("discarded: ~p", [Reason]), ErrorInfo = {failed_processing_message, Reason}, - Pid ! {snmp_error, ErrorInfo, Addr, Port}, + Pid ! {snmp_error, ErrorInfo, Domain, Addr}, ok; Error -> @@ -582,88 +601,94 @@ handle_recv_msg(Addr, Port, Bytes, end. -maybe_handle_recv_pdu(Addr, Port, - Vsn, #pdu{type = Type} = Pdu, PduMS, ACM, - Logger, - #state{filter = FilterMod} = State) -> - case (catch FilterMod:accept_recv_pdu(Addr, Port, Type)) of +maybe_handle_recv_pdu( + Domain, Addr, Vsn, #pdu{type = Type} = Pdu, PduMS, ACM, Logger, + #state{filter = FilterMod, domain = ManagerDomain} = State) -> + {Arg1, Arg2} = fix_filter_address(ManagerDomain, {Domain, Addr}), + case (catch FilterMod:accept_recv_pdu(Arg1, Arg2, Type)) of false -> inc(netIfPduInDrops), ok; _ -> - handle_recv_pdu(Addr, Port, Vsn, Pdu, PduMS, ACM, Logger, State) + handle_recv_pdu( + Domain, Addr, Vsn, Pdu, PduMS, ACM, Logger, State) end; -maybe_handle_recv_pdu(Addr, Port, Vsn, Trap, PduMS, ACM, Logger, - #state{filter = FilterMod} = State) +maybe_handle_recv_pdu( + Domain, Addr, Vsn, Trap, PduMS, ACM, Logger, + #state{filter = FilterMod, domain = ManagerDomain} = State) when is_record(Trap, trappdu) -> - case (catch FilterMod:accept_recv_pdu(Addr, Port, trappdu)) of + {Arg1, Arg2} = fix_filter_address(ManagerDomain, {Domain, Addr}), + case (catch FilterMod:accept_recv_pdu(Arg1, Arg2, trappdu)) of false -> inc(netIfPduInDrops), ok; _ -> - handle_recv_pdu(Addr, Port, Vsn, Trap, PduMS, ACM, Logger, State) + handle_recv_pdu( + Domain, Addr, Vsn, Trap, PduMS, ACM, Logger, State) end; -maybe_handle_recv_pdu(Addr, Port, Vsn, Pdu, PduMS, ACM, Logger, State) -> - handle_recv_pdu(Addr, Port, Vsn, Pdu, PduMS, ACM, Logger, State). - - -handle_recv_pdu(Addr, Port, - Vsn, #pdu{type = 'inform-request'} = Pdu, _PduMS, ACM, - Logger, #state{server = Pid, irb = IRB} = State) -> - handle_inform_request(IRB, Pid, Vsn, Pdu, ACM, - Addr, Port, Logger, State); -handle_recv_pdu(Addr, Port, - _Vsn, #pdu{type = report} = Pdu, _PduMS, ok, - _Logger, - #state{server = Pid} = _State) -> +maybe_handle_recv_pdu( + Domain, Addr, Vsn, Pdu, PduMS, ACM, Logger, State) -> + handle_recv_pdu(Domain, Addr, Vsn, Pdu, PduMS, ACM, Logger, State). + + +handle_recv_pdu( + Domain, Addr, Vsn, + #pdu{type = 'inform-request'} = Pdu, _PduMS, ACM, Logger, + #state{server = Pid, irb = IRB} = State) -> + handle_inform_request( + IRB, Pid, Vsn, Pdu, ACM, Domain, Addr, Logger, State); +handle_recv_pdu( + Domain, Addr, _Vsn, + #pdu{type = report} = Pdu, _PduMS, ok, _Logger, + #state{server = Pid} = _State) -> ?vtrace("received report - ok", []), - Pid ! {snmp_report, {ok, Pdu}, Addr, Port}; -handle_recv_pdu(Addr, Port, - _Vsn, #pdu{type = report} = Pdu, _PduMS, - {error, ReqId, Reason}, - _Logger, - #state{server = Pid} = _State) -> + Pid ! {snmp_report, {ok, Pdu}, Domain, Addr}; +handle_recv_pdu( + Domain, Addr, _Vsn, + #pdu{type = report} = Pdu, _PduMS, {error, ReqId, Reason}, _Logger, + #state{server = Pid} = _State) -> ?vtrace("received report - error", []), - Pid ! {snmp_report, {error, ReqId, Reason, Pdu}, Addr, Port}; -handle_recv_pdu(Addr, Port, - _Vsn, #pdu{type = 'snmpv2-trap'} = Pdu, _PduMS, _ACM, - _Logger, - #state{server = Pid} = _State) -> + Pid ! {snmp_report, {error, ReqId, Reason, Pdu}, Domain, Addr}; +handle_recv_pdu( + Domain, Addr, _Vsn, + #pdu{type = 'snmpv2-trap'} = Pdu, _PduMS, _ACM, _Logger, + #state{server = Pid} = _State) -> ?vtrace("received snmpv2-trap", []), - Pid ! {snmp_trap, Pdu, Addr, Port}; -handle_recv_pdu(Addr, Port, - _Vsn, Trap, _PduMS, _ACM, - _Logger, - #state{server = Pid} = _State) when is_record(Trap, trappdu) -> + Pid ! {snmp_trap, Pdu, Domain, Addr}; +handle_recv_pdu( + Domain, Addr, _Vsn, Trap, _PduMS, _ACM, _Logger, + #state{server = Pid} = _State) when is_record(Trap, trappdu) -> ?vtrace("received trappdu", []), - Pid ! {snmp_trap, Trap, Addr, Port}; -handle_recv_pdu(Addr, Port, - _Vsn, Pdu, _PduMS, _ACM, - _Logger, - #state{server = Pid} = _State) when is_record(Pdu, pdu) -> + Pid ! {snmp_trap, Trap, Domain, Addr}; +handle_recv_pdu( + Domain, Addr, _Vsn, Pdu, _PduMS, _ACM, _Logger, + #state{server = Pid} = _State) when is_record(Pdu, pdu) -> ?vtrace("received pdu", []), - Pid ! {snmp_pdu, Pdu, Addr, Port}; -handle_recv_pdu(_Addr, _Port, _Vsn, Pdu, _PduMS, ACM, _Logger, _State) -> + Pid ! {snmp_pdu, Pdu, Domain, Addr}; +handle_recv_pdu( + _Domain, _Addr, _Vsn, Pdu, _PduMS, ACM, _Logger, _State) -> ?vlog("received unexpected pdu: " - "~n Pdu: ~p" - "~n ACM: ~p", [Pdu, ACM]). + "~n Pdu: ~p" + "~n ACM: ~p", [Pdu, ACM]). -handle_inform_request(auto, Pid, Vsn, Pdu, ACM, Addr, Port, Logger, State) -> +handle_inform_request( + auto, Pid, Vsn, Pdu, ACM, Domain, Addr, Logger, State) -> ?vtrace("received inform-request (true)", []), - Pid ! {snmp_inform, ignore, Pdu, Addr, Port}, + Pid ! {snmp_inform, ignore, Pdu, Domain, Addr}, RePdu = make_response_pdu(Pdu), - maybe_send_inform_response(RePdu, Vsn, ACM, Addr, Port, Logger, State); -handle_inform_request({user, To}, Pid, Vsn, #pdu{request_id = ReqId} = Pdu, - ACM, Addr, Port, _Logger, _State) -> + maybe_send_inform_response(RePdu, Vsn, ACM, Domain, Addr, Logger, State); +handle_inform_request( + {user, To}, Pid, Vsn, #pdu{request_id = ReqId} = Pdu, + ACM, Domain, Addr, _Logger, _State) -> ?vtrace("received inform-request (false)", []), - Pid ! {snmp_inform, ReqId, Pdu, Addr, Port}, + Pid ! {snmp_inform, ReqId, Pdu, Domain, Addr}, %% Before we go any further, we need to check that we have not %% already received this message (possible resend). - Key = {ReqId, Addr, Port}, + Key = {ReqId, Domain, Addr}, case ets:lookup(snmpm_inform_request_table, Key) of [_] -> %% OK, we already know about this. We assume this @@ -676,39 +701,43 @@ handle_inform_request({user, To}, Pid, Vsn, #pdu{request_id = ReqId} = Pdu, Rec = {Key, Expire, {Vsn, ACM, RePdu}}, ets:insert(snmpm_inform_request_table, Rec) end. - -handle_inform_response(Ref, Addr, Port, State) -> - Key = {Ref, Addr, Port}, + +handle_inform_response(Ref, Domain, Addr, State) -> + Key = {Ref, Domain, Addr}, case ets:lookup(snmpm_inform_request_table, Key) of [{Key, _, {Vsn, ACM, RePdu}}] -> - Logger = logger(State#state.log, read, Addr, Port), + Logger = logger(State#state.log, read, Domain, Addr), ets:delete(snmpm_inform_request_table, Key), - maybe_send_inform_response(RePdu, Vsn, ACM, Addr, Port, - Logger, State); + maybe_send_inform_response( + RePdu, Vsn, ACM, Domain, Addr, Logger, State); [] -> %% Already acknowledged, or the user was to slow to reply... ok end, ok. -maybe_send_inform_response(RePdu, Vsn, ACM, Addr, Port, Logger, - #state{server = Pid, - sock = Sock, - filter = FilterMod}) -> - case (catch FilterMod:accept_send_pdu(Addr, Port, pdu_type_of(RePdu))) of +maybe_send_inform_response( + RePdu, Vsn, ACM, Domain, Addr, Logger, + #state{server = Pid, + filter = FilterMod, + domain = ManagerDomain} = State) -> + {Arg1, Arg2} = fix_filter_address(ManagerDomain, {Domain, Addr}), + case (catch FilterMod:accept_send_pdu( + Arg1, Arg2, pdu_type_of(RePdu))) + of false -> inc(netIfPduOutDrops), ok; _ -> case snmpm_mpd:generate_response_msg(Vsn, RePdu, ACM, Logger) of {ok, Msg} -> - maybe_udp_send(FilterMod, Sock, Addr, Port, Msg); + maybe_udp_send(Domain, Addr, Msg, State); {discarded, Reason} -> ?vlog("failed generating response message:" "~n Reason: ~p", [Reason]), ReqId = RePdu#pdu.request_id, ErrorInfo = {failed_generating_response, {RePdu, Reason}}, - Pid ! {snmp_error, ReqId, ErrorInfo, Addr, Port}, + Pid ! {snmp_error, ReqId, ErrorInfo, Domain, Addr}, ok end end. @@ -743,28 +772,29 @@ irgc_stop(Ref) -> (catch erlang:cancel_timer(Ref)). -maybe_handle_send_pdu(Pdu, Vsn, MsgData, Domain, Addr, Port, - #state{filter = FilterMod} = State) -> - case (catch FilterMod:accept_send_pdu(Addr, Port, pdu_type_of(Pdu))) of +maybe_handle_send_pdu( + Pdu, Vsn, MsgData, Domain, Addr, + #state{filter = FilterMod, domain = ManagerDomain} = State) -> + {Arg1, Arg2} = fix_filter_address(ManagerDomain, {Domain, Addr}), + case (catch FilterMod:accept_send_pdu(Arg1, Arg2, pdu_type_of(Pdu))) of false -> inc(netIfPduOutDrops), ok; _ -> - handle_send_pdu(Pdu, Vsn, MsgData, Domain, Addr, Port, State) + handle_send_pdu(Pdu, Vsn, MsgData, Domain, Addr, State) end. -handle_send_pdu(Pdu, Vsn, MsgData, _Domain, Addr, Port, - #state{server = Pid, - note_store = NoteStore, - sock = Sock, - log = Log, - filter = FilterMod}) -> - Logger = logger(Log, write, Addr, Port), - case (catch snmpm_mpd:generate_msg(Vsn, NoteStore, - Pdu, MsgData, Logger)) of +handle_send_pdu( + Pdu, Vsn, MsgData, Domain, Addr, + #state{server = Pid, + note_store = NoteStore, + log = Log} = State) -> + Logger = logger(Log, write, Domain, Addr), + case (catch snmpm_mpd:generate_msg( + Vsn, NoteStore, Pdu, MsgData, Logger)) of {ok, Msg} -> ?vtrace("handle_send_pdu -> message generated", []), - maybe_udp_send(FilterMod, Sock, Addr, Port, Msg); + maybe_udp_send(Domain, Addr, Msg, State); {discarded, Reason} -> ?vlog("PDU not sent: " "~n PDU: ~p" @@ -774,28 +804,34 @@ handle_send_pdu(Pdu, Vsn, MsgData, _Domain, Addr, Port, end. -maybe_udp_send(FilterMod, Sock, Addr, Port, Msg) -> - case (catch FilterMod:accept_send(Addr, Port)) of +maybe_udp_send( + Domain, Addr, Msg, + #state{sock = Sock, filter = FilterMod, domain = ManagerDomain}) -> + {Arg1, Arg2} = fix_filter_address(ManagerDomain, {Domain, Addr}), + case (catch FilterMod:accept_send(Arg1, Arg2)) of false -> inc(netIfMsgOutDrops), ok; _ -> - udp_send(Sock, Addr, Port, Msg) + %% XXX There should be some kind of lookup of socket + %% from transport domain here + {Ip, Port} = Addr, + udp_send(Sock, Ip, Port, Msg) end. -udp_send(Sock, Addr, Port, Msg) -> - case (catch gen_udp:send(Sock, Addr, Port, Msg)) of +udp_send(Sock, Ip, Port, Msg) -> + case (catch gen_udp:send(Sock, Ip, Port, Msg)) of ok -> ?vdebug("sent ~w bytes to ~w:~w [~w]", - [sz(Msg), Addr, Port, Sock]), + [sz(Msg), Ip, Port, Sock]), ok; {error, Reason} -> error_msg("failed sending message to ~p:~p: " - "~n ~p",[Addr, Port, Reason]); + "~n ~p",[Ip, Port, Reason]); Error -> error_msg("failed sending message to ~p:~p: " - "~n ~p",[Addr, Port, Error]) + "~n ~p",[Ip, Port, Error]) end. sz(B) when is_binary(B) -> @@ -989,6 +1025,26 @@ handle_set_log_type(State, _NewType) -> {State, {error, not_enabled}}. +%% If the manager uses legacy snmpUDPDomain e.g has not set +%% {domain, _}, then make sure snmpm_network_interface_filter +%% gets legacy arguments to not break backwards compatibility. +%% +fix_filter_address(snmpUDPDomain, {Domain, Addr}) + when Domain =:= snmpUDPDomain; + Domain =:= transportDomainUdpIpv4 -> + Addr; +fix_filter_address(_ManagerDomain, {Domain, _} = Address) + when is_atom(Domain) -> + Address; +fix_filter_address(snmpUDPDomain, {_, Port} = Addr) + when is_integer(Port) -> + Addr. + +address(Domain, Addr) when is_atom(Domain) -> + {Domain, Addr}; +address(Ip, Port) when is_integer(Port) -> + {snmpm_config:default_transport_domain(), {Ip, Port}}. + %% ------------------------------------------------------------------- make_response_pdu(#pdu{request_id = ReqId, varbinds = Vbs}) -> @@ -1029,15 +1085,17 @@ t() -> %% ------------------------------------------------------------------- -logger(undefined, _Type, _Addr, _Port) -> +logger(undefined, _Type, _Domain, _Addr) -> fun(_) -> ok end; -logger({Log, Types}, Type, Addr, Port) -> +logger({Log, Types}, Type, Domain, Addr) -> case lists:member(Type, Types) of true -> + AddrString = + iolist_to_binary(snmp_conf:mk_addr_string({Domain, Addr})), fun(Msg) -> - snmp_log:log(Log, Msg, Addr, Port) + snmp_log:log(Log, Msg, AddrString) end; false -> fun(_) -> diff --git a/lib/snmp/src/manager/snmpm_net_if_filter.erl b/lib/snmp/src/manager/snmpm_net_if_filter.erl index eb0c6efb11..d96ae5c145 100644 --- a/lib/snmp/src/manager/snmpm_net_if_filter.erl +++ b/lib/snmp/src/manager/snmpm_net_if_filter.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009. All Rights Reserved. +%% Copyright Ericsson AB 2009-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -25,29 +25,51 @@ -include("snmp_debug.hrl"). -accept_recv(_Addr, _Port) -> - ?d("accept_recv -> entry with" - "~n Addr: ~p" - "~n Port: ~p", [_Addr, _Port]), +accept_recv(Domain, _Address) when is_atom(Domain) -> + ?d("accept_recv -> entry with~n" + " Domain: ~p~n" + " Address: ~p", [Domain, _Address]), + true; +accept_recv(_Addr, Port) when is_integer(Port) -> + ?d("accept_recv -> entry with~n" + " Addr: ~p~n" + " Port: ~p", [_Addr, Port]), true. -accept_send(_Addr, _Port) -> - ?d("accept_send -> entry with" - "~n Addr: ~p" - "~n Port: ~p", [_Addr, _Port]), +accept_send(Domain, _Address) when is_atom(Domain) -> + ?d("accept_send -> entry with~n" + " Domain: ~p~n" + " Address: ~p", [Domain, _Address]), + true; +accept_send(_Addr, Port) when is_integer(Port) -> + ?d("accept_send -> entry with~n" + " Addr: ~p~n" + " Port: ~p", [_Addr, Port]), true. -accept_recv_pdu(_Addr, _Port, _PduType) -> - ?d("accept_recv_pdu -> entry with" - "~n Addr: ~p" - "~n Port: ~p" - "~n PduType: ~p", [_Addr, _Port, _PduType]), +accept_recv_pdu(Domain, _Address, _PduType) when is_atom(Domain) -> + ?d("accept_recv_pdu -> entry with~n" + " Domain: ~p~n" + " Address: ~p~n" + " PduType: ~p", [Domain, _Address, _PduType]), + true; +accept_recv_pdu(_Addr, Port, _PduType) when is_integer(Port) -> + ?d("accept_recv_pdu -> entry with~n" + " Addr: ~p~n" + " Port: ~p~n" + " PduType: ~p", [_Addr, Port, _PduType]), true. -accept_send_pdu(_Addr, _Port, _PduType) -> - ?d("accept_send_pdu -> entry with" - "~n Addr: ~p" - "~n Port: ~p" - "~n PduType: ~p", [_Addr, _Port, _PduType]), +accept_send_pdu(Domain, _Address, _PduType) when is_atom(Domain) -> + ?d("accept_send_pdu -> entry with~n" + " Domain: ~p~n" + " Address: ~p~n" + " PduType: ~p", [Domain, _Address, _PduType]), + true; +accept_send_pdu(_Addr, Port, _PduType) when is_integer(Port) -> + ?d("accept_send_pdu -> entry with~n" + " Addr: ~p~n" + " Port: ~p~n" + " PduType: ~p", [_Addr, Port, _PduType]), true. diff --git a/lib/snmp/src/manager/snmpm_net_if_mt.erl b/lib/snmp/src/manager/snmpm_net_if_mt.erl index 3e87f6a7fb..2937f5cc87 100644 --- a/lib/snmp/src/manager/snmpm_net_if_mt.erl +++ b/lib/snmp/src/manager/snmpm_net_if_mt.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2012. All Rights Reserved. +%% Copyright Ericsson AB 2004-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -27,9 +27,9 @@ -export([ start_link/2, stop/1, - send_pdu/6, % Backward compatibillity - send_pdu/7, % Backward compatibillity - send_pdu/8, + send_pdu/6, % Backward compatibility + send_pdu/7, % Partly backward compatibility + send_pdu/8, % Backward compatibility inform_response/4, @@ -55,13 +55,14 @@ %% -define(VMODULE,"NET_IF"). -include("snmp_verbosity.hrl"). --record(state, +-record(state, { server, note_store, - sock, + domain, + sock, mpd_state, - log, + log, irb = auto, % auto | {user, integer()} irgc, filter @@ -99,30 +100,32 @@ start_link(Server, NoteStore) -> stop(Pid) -> call(Pid, stop). -send_pdu(Pid, Pdu, Vsn, MsgData, Addr, Port) -> - send_pdu(Pid, Pdu, Vsn, MsgData, Addr, Port, ?DEFAULT_EXTRA_INFO). +send_pdu(Pid, Pdu, Vsn, MsgData, Domain_or_Ip, Addr_or_Port) -> + send_pdu( + Pid, Pdu, Vsn, MsgData, Domain_or_Ip, Addr_or_Port, ?DEFAULT_EXTRA_INFO). -send_pdu(Pid, Pdu, Vsn, MsgData, Addr, Port, ExtraInfo) -> - Domain = snmpm_config:default_transport_domain(), - send_pdu(Pid, Pdu, Vsn, MsgData, Domain, Addr, Port, ExtraInfo). - -send_pdu(Pid, Pdu, Vsn, MsgData, Domain, Addr, Port, ExtraInfo) +send_pdu(Pid, Pdu, Vsn, MsgData, Domain_or_Ip, Addr_or_Port, ExtraInfo) when is_record(Pdu, pdu) -> - ?d("send_pdu -> entry with" - "~n Pid: ~p" - "~n Pdu: ~p" - "~n Vsn: ~p" - "~n MsgData: ~p" - "~n Domain: ~p" - "~n Addr: ~p" - "~n Port: ~p", [Pid, Pdu, Vsn, MsgData, Domain, Addr, Port]), - cast(Pid, {send_pdu, Pdu, Vsn, MsgData, Domain, Addr, Port, ExtraInfo}). + ?d("send_pdu -> entry with~n" + " Pid: ~p~n" + " Pdu: ~p~n" + " Vsn: ~p~n" + " MsgData: ~p~n" + " Domain/IP: ~p~n" + " Addr/Port : ~p", + [Pid, Pdu, Vsn, MsgData, Domain_or_Ip, Addr_or_Port]), + {Domain, Addr} = address(Domain_or_Ip, Addr_or_Port), + cast(Pid, {send_pdu, Pdu, Vsn, MsgData, Domain, Addr, ExtraInfo}). + +send_pdu(Pid, Pdu, Vsn, MsgData, Domain, Ip, Port, ExtraInfo) -> + send_pdu(Pid, Pdu, Vsn, MsgData, Domain, {Ip, Port}, ExtraInfo). note_store(Pid, NoteStore) -> call(Pid, {note_store, NoteStore}). -inform_response(Pid, Ref, Addr, Port) -> - cast(Pid, {inform_response, Ref, Addr, Port}). +inform_response(Pid, Ref, Domain_or_Ip, Addr_or_Port) -> + {Domain, Addr} = address(Domain_or_Ip, Addr_or_Port), + cast(Pid, {inform_response, Ref, Domain, Addr}). info(Pid) -> call(Pid, info). @@ -202,7 +205,14 @@ do_init(Server, NoteStore) -> BindTo = get_opt(Opts, bind_to, false), NoReuse = get_opt(Opts, no_reuse, false), {ok, Port} = snmpm_config:system_info(port), - {ok, Sock} = do_open_port(Port, SndBuf, RecBuf, BindTo, NoReuse), + Domain = + case snmpm_config:system_info(domain) of + {ok, D} -> + D; + _ -> + snmpm_config:default_transport_domain() + end, + {ok, Sock} = do_open_port(Port, SndBuf, RecBuf, Domain, BindTo, NoReuse), %% Flow control -- FilterOpts = get_opt(Opts, filter, []), @@ -218,10 +228,11 @@ do_init(Server, NoteStore) -> init_counters(), %% -- We are done --- - State = #state{server = Server, - note_store = NoteStore, + State = #state{server = Server, + note_store = NoteStore, mpd_state = MpdState, - sock = Sock, + domain = Domain, + sock = Sock, log = Log, irb = IRB, irgc = IrGcRef, @@ -231,19 +242,24 @@ do_init(Server, NoteStore) -> %% Open port -do_open_port(Port, SendSz, RecvSz, BindTo, NoReuse) -> - ?vtrace("do_open_port -> entry with" - "~n Port: ~p" - "~n SendSz: ~p" - "~n RecvSz: ~p" - "~n BindTo: ~p" - "~n NoReuse: ~p", [Port, SendSz, RecvSz, BindTo, NoReuse]), +do_open_port(Port, SendSz, RecvSz, Domain, BindTo, NoReuse) -> + ?vtrace("do_open_port -> entry with~n" + " Port: ~p~n" + " SendSz: ~p~n" + " RecvSz: ~p~n" + " Domain: ~p~n" + " BindTo: ~p~n" + " NoReuse: ~p", + [Port, SendSz, RecvSz, Domain, BindTo, NoReuse]), IpOpts1 = bind_to(BindTo), IpOpts2 = no_reuse(NoReuse), IpOpts3 = recbuf(RecvSz), IpOpts4 = sndbuf(SendSz), - IpOpts = [binary | IpOpts1 ++ IpOpts2 ++ IpOpts3 ++ IpOpts4], - OpenRes = + IpOpts = + [binary, + snmp_conf:tdomain_to_family(Domain) | + IpOpts1 ++ IpOpts2 ++ IpOpts3 ++ IpOpts4], + OpenRes = case init:get_argument(snmpm_fd) of {ok, [[FdStr]]} -> Fd = list_to_integer(FdStr), @@ -396,25 +412,24 @@ handle_call(Req, From, State) -> %% {noreply, State, Timeout} | %% {stop, Reason, State} (terminate/2 is called) %%-------------------------------------------------------------------- -handle_cast({send_pdu, Pdu, Vsn, MsgData, Domain, Addr, Port, ExtraInfo}, +handle_cast({send_pdu, Pdu, Vsn, MsgData, Domain, Addr, ExtraInfo}, State) -> - ?vlog("received send_pdu message with" - "~n Pdu: ~p" - "~n Vsn: ~p" - "~n MsgData: ~p" - "~n Domain: ~p" - "~n Addr: ~p" - "~n Port: ~p", [Pdu, Vsn, MsgData, Domain, Addr, Port]), - maybe_process_extra_info(ExtraInfo), - handle_send_pdu(Pdu, Vsn, MsgData, Domain, Addr, Port, State), + ?vlog("received send_pdu message with~n" + " Pdu: ~p~n" + " Vsn: ~p~n" + " MsgData: ~p~n" + " Domain: ~p~n" + " Addr: ~p", [Pdu, Vsn, MsgData, Domain, Addr]), + maybe_process_extra_info(ExtraInfo), + handle_send_pdu(Pdu, Vsn, MsgData, Domain, Addr, State), {noreply, State}; -handle_cast({inform_response, Ref, Addr, Port}, State) -> - ?vlog("received inform_response message with" - "~n Ref: ~p" - "~n Addr: ~p" - "~n Port: ~p", [Ref, Addr, Port]), - handle_inform_response(Ref, Addr, Port, State), +handle_cast({inform_response, Ref, Domain, Addr}, State) -> + ?vlog("received inform_response message with~n" + " Ref: ~p~n" + " Domain: ~p~n" + " Addr: ~p", [Ref, Domain, Addr]), + handle_inform_response(Ref, Domain, Addr, State), {noreply, State}; handle_cast(filter_reset, State) -> @@ -433,9 +448,11 @@ handle_cast(Msg, State) -> %% {noreply, State, Timeout} | %% {stop, Reason, State} (terminate/2 is called) %%-------------------------------------------------------------------- -handle_info({udp, Sock, Ip, Port, Bytes}, #state{sock = Sock} = State) -> +handle_info( + {udp, Sock, Ip, Port, Bytes}, + #state{sock = Sock, domain = Domain} = State) -> ?vlog("received ~w bytes from ~p:~p", [size(Bytes), Ip, Port]), - handle_udp(Ip, Port, Bytes, State), + handle_udp(Domain, {Ip, Port}, Bytes, State), {noreply, State}; handle_info(inform_response_gc, State) -> @@ -500,60 +517,64 @@ code_change(_Vsn, State, _Extra) -> %%% Internal functions %%%------------------------------------------------------------------- -handle_udp(Addr, Port, Bytes, State) -> - Verbosity = get(verbosity), - spawn_opt(fun() -> - Log = worker_init(State, Verbosity), - Res = (catch maybe_handle_recv_msg( - Addr, Port, Bytes, - State#state{log = Log})), - worker_exit(udp, {Addr, Port}, Res) - end, - [monitor]). - - -maybe_handle_recv_msg(Addr, Port, Bytes, #state{filter = FilterMod} = State) -> - case (catch FilterMod:accept_recv(Addr, Port)) of +handle_udp(Domain, Addr, Bytes, State) -> + Verbosity = get(verbosity), + spawn_opt( + fun() -> + Log = worker_init(State, Verbosity), + Res = + (catch maybe_handle_recv_msg( + Domain, Addr, Bytes, + State#state{log = Log})), + worker_exit(udp, {Domain, Addr}, Res) + end, + [monitor]). + + +maybe_handle_recv_msg( + Domain, Addr, Bytes, + #state{filter = FilterMod, domain = ManagerDomain} = State) -> + {Arg1, Arg2} = fix_filter_address(ManagerDomain, {Domain, Addr}), + case (catch FilterMod:accept_recv(Arg1, Arg2)) of false -> - %% Drop the received packet + %% Drop the received packet inc(netIfMsgInDrops), ok; _ -> - handle_recv_msg(Addr, Port, Bytes, State) + handle_recv_msg(Domain, Addr, Bytes, State) end. -handle_recv_msg(Addr, Port, Bytes, #state{server = Pid}) +handle_recv_msg(Domain, Addr, Bytes, #state{server = Pid}) when is_binary(Bytes) andalso (size(Bytes) =:= 0) -> - Pid ! {snmp_error, {empty_message, Addr, Port}, Addr, Port}, + Pid ! {snmp_error, {empty_message, Domain, Addr}, Domain, Addr}, ok; -handle_recv_msg(Addr, Port, Bytes, - #state{server = Pid, - note_store = NoteStore, - mpd_state = MpdState, - sock = Sock, - log = Log} = State) -> - Domain = snmp_conf:which_domain(Addr), % What the ****... - Logger = logger(Log, read, Addr, Port), - case (catch snmpm_mpd:process_msg(Bytes, Domain, Addr, Port, +handle_recv_msg( + Domain, Addr, Bytes, + #state{server = Pid, + note_store = NoteStore, + mpd_state = MpdState, + log = Log} = State) -> + Logger = logger(Log, read, Domain, Addr), + case (catch snmpm_mpd:process_msg(Bytes, Domain, Addr, MpdState, NoteStore, Logger)) of {ok, Vsn, Pdu, MS, ACM} -> - maybe_handle_recv_pdu(Addr, Port, Vsn, Pdu, MS, ACM, + maybe_handle_recv_pdu(Domain, Addr, Vsn, Pdu, MS, ACM, Logger, State); {discarded, Reason, Report} -> ?vdebug("discarded: ~p", [Reason]), ErrorInfo = {failed_processing_message, Reason}, - Pid ! {snmp_error, ErrorInfo, Addr, Port}, - maybe_udp_send(State#state.filter, Sock, Addr, Port, Report), + Pid ! {snmp_error, ErrorInfo, Domain, Addr}, + maybe_udp_send(Domain, Addr, Report, State), ok; {discarded, Reason} -> ?vdebug("discarded: ~p", [Reason]), ErrorInfo = {failed_processing_message, Reason}, - Pid ! {snmp_error, ErrorInfo, Addr, Port}, + Pid ! {snmp_error, ErrorInfo, Domain, Addr}, ok; Error -> @@ -563,94 +584,100 @@ handle_recv_msg(Addr, Port, Bytes, end. -maybe_handle_recv_pdu(Addr, Port, - Vsn, #pdu{type = Type} = Pdu, PduMS, ACM, - Logger, - #state{filter = FilterMod} = State) -> - case (catch FilterMod:accept_recv_pdu(Addr, Port, Type)) of +maybe_handle_recv_pdu( + Domain, Addr, Vsn, #pdu{type = Type} = Pdu, PduMS, ACM, Logger, + #state{filter = FilterMod, domain = ManagerDomain} = State) -> + {Arg1, Arg2} = fix_filter_address(ManagerDomain, {Domain, Addr}), + case (catch FilterMod:accept_recv_pdu(Arg1, Arg2, Type)) of false -> inc(netIfPduInDrops), ok; _ -> - handle_recv_pdu(Addr, Port, Vsn, Pdu, PduMS, ACM, Logger, State) + handle_recv_pdu( + Domain, Addr, Vsn, Pdu, PduMS, ACM, Logger, State) end; -maybe_handle_recv_pdu(Addr, Port, Vsn, Trap, PduMS, ACM, Logger, - #state{filter = FilterMod} = State) +maybe_handle_recv_pdu( + Domain, Addr, Vsn, Trap, PduMS, ACM, Logger, + #state{filter = FilterMod, domain = ManagerDomain} = State) when is_record(Trap, trappdu) -> - case (catch FilterMod:accept_recv_pdu(Addr, Port, trappdu)) of + {Arg1, Arg2} = fix_filter_address(ManagerDomain, {Domain, Addr}), + case (catch FilterMod:accept_recv_pdu(Arg1, Arg2, trappdu)) of false -> inc(netIfPduInDrops), ok; _ -> - handle_recv_pdu(Addr, Port, Vsn, Trap, PduMS, ACM, Logger, State) + handle_recv_pdu( + Domain, Addr, Vsn, Trap, PduMS, ACM, Logger, State) end; -maybe_handle_recv_pdu(Addr, Port, Vsn, Pdu, PduMS, ACM, Logger, State) -> - handle_recv_pdu(Addr, Port, Vsn, Pdu, PduMS, ACM, Logger, State). - - -handle_recv_pdu(Addr, Port, - Vsn, #pdu{type = 'inform-request'} = Pdu, _PduMS, ACM, - Logger, #state{server = Pid, irb = IRB} = State) -> - handle_inform_request(IRB, Pid, Vsn, Pdu, ACM, - Addr, Port, Logger, State); -handle_recv_pdu(Addr, Port, - _Vsn, #pdu{type = report} = Pdu, _PduMS, ok, - _Logger, - #state{server = Pid} = _State) -> +maybe_handle_recv_pdu( + Domain, Addr, Vsn, Pdu, PduMS, ACM, Logger, State) -> + handle_recv_pdu(Domain, Addr, Vsn, Pdu, PduMS, ACM, Logger, State). + + +handle_recv_pdu( + Domain, Addr, Vsn, + #pdu{type = 'inform-request'} = Pdu, _PduMS, ACM, Logger, + #state{server = Pid, irb = IRB} = State) -> + handle_inform_request( + IRB, Pid, Vsn, Pdu, ACM, Domain, Addr, Logger, State); +handle_recv_pdu( + Domain, Addr, _Vsn, + #pdu{type = report} = Pdu, _PduMS, ok, _Logger, + #state{server = Pid} = _State) -> ?vtrace("received report - ok", []), - Pid ! {snmp_report, {ok, Pdu}, Addr, Port}, + Pid ! {snmp_report, {ok, Pdu}, Domain, Addr}, ok; -handle_recv_pdu(Addr, Port, - _Vsn, #pdu{type = report} = Pdu, _PduMS, - {error, ReqId, Reason}, - _Logger, - #state{server = Pid} = _State) -> +handle_recv_pdu( + Domain, Addr, _Vsn, + #pdu{type = report} = Pdu, _PduMS, {error, ReqId, Reason}, _Logger, + #state{server = Pid} = _State) -> ?vtrace("received report - error", []), - Pid ! {snmp_report, {error, ReqId, Reason, Pdu}, Addr, Port}, + Pid ! {snmp_report, {error, ReqId, Reason, Pdu}, Domain, Addr}, ok; -handle_recv_pdu(Addr, Port, - _Vsn, #pdu{type = 'snmpv2-trap'} = Pdu, _PduMS, _ACM, - _Logger, - #state{server = Pid} = _State) -> +handle_recv_pdu( + Domain, Addr, _Vsn, + #pdu{type = 'snmpv2-trap'} = Pdu, _PduMS, _ACM, _Logger, + #state{server = Pid} = _State) -> ?vtrace("received snmpv2-trap", []), - Pid ! {snmp_trap, Pdu, Addr, Port}, + Pid ! {snmp_trap, Pdu, Domain, Addr}, ok; -handle_recv_pdu(Addr, Port, - _Vsn, Trap, _PduMS, _ACM, - _Logger, - #state{server = Pid} = _State) when is_record(Trap, trappdu) -> +handle_recv_pdu( + Domain, Addr, _Vsn, Trap, _PduMS, _ACM, _Logger, + #state{server = Pid} = _State) when is_record(Trap, trappdu) -> ?vtrace("received trappdu", []), - Pid ! {snmp_trap, Trap, Addr, Port}, + Pid ! {snmp_trap, Trap, Domain, Addr}, ok; -handle_recv_pdu(Addr, Port, - _Vsn, Pdu, _PduMS, _ACM, - _Logger, - #state{server = Pid} = _State) when is_record(Pdu, pdu) -> +handle_recv_pdu( + Domain, Addr, _Vsn, Pdu, _PduMS, _ACM, _Logger, + #state{server = Pid} = _State) when is_record(Pdu, pdu) -> ?vtrace("received pdu", []), - Pid ! {snmp_pdu, Pdu, Addr, Port}, + Pid ! {snmp_pdu, Pdu, Domain, Addr}, ok; -handle_recv_pdu(_Addr, _Port, _Vsn, Pdu, _PduMS, ACM, _Logger, _State) -> +handle_recv_pdu( + _Domain, _Addr, _Vsn, Pdu, _PduMS, ACM, _Logger, _State) -> ?vlog("received unexpected pdu: " "~n Pdu: ~p" "~n ACM: ~p", [Pdu, ACM]), ok. -handle_inform_request(auto, Pid, Vsn, Pdu, ACM, Addr, Port, Logger, State) -> +handle_inform_request( + auto, Pid, Vsn, Pdu, ACM, Domain, Addr, Logger, State) -> ?vtrace("received inform-request (true)", []), - Pid ! {snmp_inform, ignore, Pdu, Addr, Port}, + Pid ! {snmp_inform, ignore, Pdu, Domain, Addr}, RePdu = make_response_pdu(Pdu), - maybe_send_inform_response(RePdu, Vsn, ACM, Addr, Port, Logger, State); -handle_inform_request({user, To}, Pid, Vsn, #pdu{request_id = ReqId} = Pdu, - ACM, Addr, Port, _Logger, _State) -> + maybe_send_inform_response(RePdu, Vsn, ACM, Domain, Addr, Logger, State); +handle_inform_request( + {user, To}, Pid, Vsn, #pdu{request_id = ReqId} = Pdu, + ACM, Domain, Addr, _Logger, _State) -> ?vtrace("received inform-request (false)", []), - Pid ! {snmp_inform, ReqId, Pdu, Addr, Port}, + Pid ! {snmp_inform, ReqId, Pdu, Domain, Addr}, %% Before we go any further, we need to check that we have not %% already received this message (possible resend). - Key = {ReqId, Addr, Port}, + Key = {ReqId, Domain, Addr}, case ets:lookup(snmpm_inform_request_table, Key) of [_] -> %% OK, we already know about this. We assume this @@ -664,53 +691,58 @@ handle_inform_request({user, To}, Pid, Vsn, #pdu{request_id = ReqId} = Pdu, ets:insert(snmpm_inform_request_table, Rec) end, ok. - -handle_inform_response(Ref, Addr, Port, State) -> - Verbosity = get(verbosity), - spawn_opt(fun() -> - Log = worker_init(State, Verbosity), - Res = (catch do_handle_inform_response( - Ref, - Addr, Port, - State#state{log = Log})), - worker_exit(inform_reponse, {Addr, Port}, Res) - end, - [monitor]). - + +handle_inform_response(Ref, Domain, Addr, State) -> + Verbosity = get(verbosity), + spawn_opt( + fun() -> + Log = worker_init(State, Verbosity), + Res = (catch do_handle_inform_response( + Ref, Domain, Addr, State#state{log = Log})), + worker_exit(inform_response, {Domain, Addr}, Res) + end, + [monitor]). + -do_handle_inform_response(Ref, Addr, Port, State) -> - Key = {Ref, Addr, Port}, +do_handle_inform_response(Ref, Domain, Addr, State) -> + Key = {Ref, Domain, Addr}, case ets:lookup(snmpm_inform_request_table, Key) of [{Key, _, {Vsn, ACM, RePdu}}] -> - Logger = logger(State#state.log, read, Addr, Port), + Logger = logger(State#state.log, read, Domain, Addr), ets:delete(snmpm_inform_request_table, Key), - maybe_send_inform_response(RePdu, Vsn, ACM, Addr, Port, - Logger, State); + maybe_send_inform_response( + RePdu, Vsn, ACM, Domain, Addr, Logger, State); [] -> %% Already acknowledged, or the user was to slow to reply... ok end, ok. -maybe_send_inform_response(RePdu, Vsn, ACM, Addr, Port, Logger, - #state{server = Pid, - sock = Sock, - filter = FilterMod}) -> - case (catch FilterMod:accept_send_pdu(Addr, Port, pdu_type_of(RePdu))) of +maybe_send_inform_response( + RePdu, Vsn, ACM, Domain, Addr, Logger, + #state{server = Pid, + sock = Sock, + domain = ManagerDomain, + filter = FilterMod}) -> + {Arg1, Arg2} = fix_filter_address(ManagerDomain, {Domain, Addr}), + case (catch FilterMod:accept_send_pdu( + Arg1, Arg2, pdu_type_of(RePdu))) + of false -> inc(netIfPduOutDrops), ok; _ -> case snmpm_mpd:generate_response_msg(Vsn, RePdu, ACM, Logger) of {ok, Msg} -> - maybe_udp_send(FilterMod, Sock, Addr, Port, Msg); + maybe_udp_send( + Domain, Addr, Msg, Sock, FilterMod, ManagerDomain); {discarded, Reason} -> ?vlog("failed generating response message:" "~n Reason: ~p", [Reason]), ReqId = RePdu#pdu.request_id, ErrorInfo = {failed_generating_response, {RePdu, Reason}}, - Pid ! {snmp_error, ReqId, ErrorInfo, Addr, Port}, + Pid ! {snmp_error, ReqId, ErrorInfo, Domain, Addr}, ok end end. @@ -745,40 +777,42 @@ irgc_stop(Ref) -> (catch erlang:cancel_timer(Ref)). -handle_send_pdu(Pdu, Vsn, MsgData, Domain, Addr, Port, State) -> - Verbosity = get(verbosity), - spawn_opt(fun() -> - Log = worker_init(State, Verbosity), - Res = (catch maybe_handle_send_pdu( - Pdu, Vsn, MsgData, - Domain, Addr, Port, - State#state{log = Log})), - worker_exit(send_pdu, {Domain, Addr, Port}, Res) - end, - [monitor]). - -maybe_handle_send_pdu(Pdu, Vsn, MsgData, Domain, Addr, Port, - #state{filter = FilterMod} = State) -> - case (catch FilterMod:accept_send_pdu(Addr, Port, pdu_type_of(Pdu))) of +handle_send_pdu(Pdu, Vsn, MsgData, Domain, Addr, State) -> + Verbosity = get(verbosity), + spawn_opt( + fun() -> + Log = worker_init(State, Verbosity), + Res = (catch maybe_handle_send_pdu( + Pdu, Vsn, MsgData, + Domain, Addr, + State#state{log = Log})), + worker_exit(send_pdu, {Domain, Addr}, Res) + end, + [monitor]). + +maybe_handle_send_pdu( + Pdu, Vsn, MsgData, Domain, Addr, + #state{filter = FilterMod, domain = ManagerDomain} = State) -> + {Arg1, Arg2} = fix_filter_address(ManagerDomain, {Domain, Addr}), + case (catch FilterMod:accept_send_pdu(Arg1, Arg2, pdu_type_of(Pdu))) of false -> inc(netIfPduOutDrops), ok; _ -> - do_handle_send_pdu(Pdu, Vsn, MsgData, Domain, Addr, Port, State) + do_handle_send_pdu(Pdu, Vsn, MsgData, Domain, Addr, State) end. -do_handle_send_pdu(Pdu, Vsn, MsgData, _Domain, Addr, Port, - #state{server = Pid, - note_store = NoteStore, - sock = Sock, - log = Log, - filter = FilterMod}) -> - Logger = logger(Log, write, Addr, Port), - case (catch snmpm_mpd:generate_msg(Vsn, NoteStore, - Pdu, MsgData, Logger)) of +do_handle_send_pdu( + Pdu, Vsn, MsgData, Domain, Addr, + #state{server = Pid, + note_store = NoteStore, + log = Log} = State) -> + Logger = logger(Log, write, Domain, Addr), + case (catch snmpm_mpd:generate_msg( + Vsn, NoteStore, Pdu, MsgData, Logger)) of {ok, Msg} -> ?vtrace("do_handle_send_pdu -> message generated", []), - maybe_udp_send(FilterMod, Sock, Addr, Port, Msg); + maybe_udp_send(Domain, Addr, Msg, State); {discarded, Reason} -> ?vlog("PDU not sent: " "~n PDU: ~p" @@ -787,30 +821,38 @@ do_handle_send_pdu(Pdu, Vsn, MsgData, _Domain, Addr, Port, ok end. +maybe_udp_send( + Domain, Addr, Msg, + #state{sock = Sock, filter = FilterMod, domain = ManagerDomain}) -> + maybe_udp_send(Domain, Addr, Msg, Sock, FilterMod, ManagerDomain). -maybe_udp_send(FilterMod, Sock, Addr, Port, Msg) -> - case (catch FilterMod:accept_send(Addr, Port)) of +maybe_udp_send(Domain, Addr, Msg, Sock, FilterMod, ManagerDomain) -> + {Arg1, Arg2} = fix_filter_address(ManagerDomain, {Domain, Addr}), + case (catch FilterMod:accept_send(Arg1, Arg2)) of false -> inc(netIfMsgOutDrops), ok; _ -> - udp_send(Sock, Addr, Port, Msg) + %% XXX There should be some kind of lookup of socket + %% from transport domain here + {Ip, Port} = Addr, + udp_send(Sock, Ip, Port, Msg) end. -udp_send(Sock, Addr, Port, Msg) -> - case (catch gen_udp:send(Sock, Addr, Port, Msg)) of +udp_send(Sock, Ip, Port, Msg) -> + case (catch gen_udp:send(Sock, Ip, Port, Msg)) of ok -> ?vdebug("sent ~w bytes to ~w:~w [~w]", - [sz(Msg), Addr, Port, Sock]), + [sz(Msg), Ip, Port, Sock]), ok; {error, Reason} -> error_msg("failed sending message to ~p:~p: " - "~n ~p",[Addr, Port, Reason]), + "~n ~p", [Ip, Port, Reason]), ok; Error -> error_msg("failed sending message to ~p:~p: " - "~n ~p",[Addr, Port, Error]), + "~n ~p", [Ip, Port, Error]), ok end. @@ -1036,25 +1078,48 @@ worker_exit(Tag, Info, Result) -> handle_worker_exit(_, {_, _, ok}) -> ok; -handle_worker_exit(Pid, {udp, {Addr, Port}, ExitStatus}) -> - warning_msg("Worker process (~p) terminated " - "while processing (incomming) message from ~w:~w: " - "~n~p", [Pid, Addr, Port, ExitStatus]), +handle_worker_exit(Pid, {udp, {Domain, Addr}, ExitStatus}) -> + warning_msg( + "Worker process (~p) terminated " + "while processing (incomming) message from %s:~n" + "~p", [Pid, snmp_conf:mk_addr_string({Domain, Addr}), ExitStatus]), ok; -handle_worker_exit(Pid, {send_pdu, {Domain, Addr, Port}, ExitStatus}) -> - warning_msg("Worker process (~p) terminated " - "while processing (outgoing) pdu for [~w] ~w:~w: " - "~n~p", [Pid, Domain, Addr, Port, ExitStatus]), +handle_worker_exit(Pid, {send_pdu, {Domain, Addr}, ExitStatus}) -> + warning_msg( + "Worker process (~p) terminated " + "while processing (outgoing) pdu for %s:~n" + "~p", [Pid, snmp_conf:mk_addr_string({Domain, Addr}), ExitStatus]), ok; -handle_worker_exit(Pid, {inform_response, {Addr, Port}, ExitStatus}) -> - warning_msg("Worker process (~p) terminated " - "while processing (outgoing) inform response for ~w:~w: " - "~n~p", [Pid, Addr, Port, ExitStatus]), +handle_worker_exit(Pid, {inform_response, {Domain, Addr}, ExitStatus}) -> + warning_msg( + "Worker process (~p) terminated " + "while processing (outgoing) inform response for %s:~n" + "~p", [Pid, snmp_conf:mk_addr_string({Domain, Addr}), ExitStatus]), ok; handle_worker_exit(_, _) -> ok. +%% If the manager uses legacy snmpUDPDomain e.g has not set +%% {domain, _}, then make sure snmpm_network_interface_filter +%% gets legacy arguments to not break backwards compatibility. +%% +fix_filter_address(snmpUDPDomain, {Domain, Addr}) + when Domain =:= snmpUDPDomain; + Domain =:= transportDomainUdpIpv4 -> + Addr; +fix_filter_address(_ManagerDomain, {Domain, _} = Address) + when is_atom(Domain) -> + Address; +fix_filter_address(snmpUDPDomain, {_, Port} = Addr) + when is_integer(Port) -> + Addr. + +address(Domain, Addr) when is_atom(Domain) -> + {Domain, Addr}; +address(Ip, Port) when is_integer(Port) -> + {snmpm_config:default_transport_domain(), {Ip, Port}}. + %% ------------------------------------------------------------------- make_response_pdu(#pdu{request_id = ReqId, varbinds = Vbs}) -> @@ -1095,15 +1160,17 @@ t() -> %% ------------------------------------------------------------------- -logger(undefined, _Type, _Addr, _Port) -> +logger(undefined, _Type, _Domain, _Addr) -> fun(_) -> ok end; -logger({_Name, Log, Types}, Type, Addr, Port) -> +logger({_Name, Log, Types}, Type, Domain, Addr) -> case lists:member(Type, Types) of true -> + AddrString = + iolist_to_binary(snmp_conf:mk_addr_string({Domain, Addr})), fun(Msg) -> - snmp_log:log(Log, Msg, Addr, Port) + snmp_log:log(Log, Msg, Domain, AddrString) end; false -> fun(_) -> @@ -1256,4 +1323,3 @@ call(Pid, Req, Timeout) -> cast(Pid, Msg) -> gen_server:cast(Pid, Msg). - diff --git a/lib/snmp/src/manager/snmpm_server.erl b/lib/snmp/src/manager/snmpm_server.erl index 9c79df2748..ece5dad082 100644 --- a/lib/snmp/src/manager/snmpm_server.erl +++ b/lib/snmp/src/manager/snmpm_server.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2013. All Rights Reserved. +%% Copyright Ericsson AB 2004-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -163,8 +163,7 @@ reg_type, target, domain, - addr, - port, + address, type, data, ref, @@ -1033,14 +1032,14 @@ handle_info({snmp_error, Pdu, Reason}, State) -> handle_snmp_error(Pdu, Reason, State), {noreply, State}; -handle_info({snmp_error, Reason, Addr, Port}, State) -> +handle_info({snmp_error, Reason, Domain, Addr}, State) -> ?vlog("received snmp_error message", []), - handle_snmp_error(Addr, Port, -1, Reason, State), + handle_snmp_error(Domain, Addr, -1, Reason, State), {noreply, State}; -handle_info({snmp_error, ReqId, Reason, Addr, Port}, State) -> +handle_info({snmp_error, ReqId, Reason, Domain, Addr}, State) -> ?vlog("received snmp_error message", []), - handle_snmp_error(Addr, Port, ReqId, Reason, State), + handle_snmp_error(Domain, Addr, ReqId, Reason, State), {noreply, State}; %% handle_info({snmp_error, ReqId, Pdu, Reason, Addr, Port}, State) -> @@ -1049,30 +1048,30 @@ handle_info({snmp_error, ReqId, Reason, Addr, Port}, State) -> %% {noreply, State}; -handle_info({snmp_pdu, Pdu, Addr, Port}, State) -> +handle_info({snmp_pdu, Pdu, Domain, Addr}, State) -> ?vlog("received snmp_pdu message", []), - handle_snmp_pdu(Pdu, Addr, Port, State), + handle_snmp_pdu(Pdu, Domain, Addr, State), {noreply, State}; -handle_info({snmp_trap, Trap, Addr, Port}, State) -> +handle_info({snmp_trap, Trap, Domain, Addr}, State) -> ?vlog("received snmp_trap message", []), - handle_snmp_trap(Trap, Addr, Port, State), + handle_snmp_trap(Trap, Domain, Addr, State), {noreply, State}; -handle_info({snmp_inform, Ref, Pdu, Addr, Port}, State) -> +handle_info({snmp_inform, Ref, Pdu, Domain, Addr}, State) -> ?vlog("received snmp_inform message", []), - handle_snmp_inform(Ref, Pdu, Addr, Port, State), + handle_snmp_inform(Ref, Pdu, Domain, Addr, State), {noreply, State}; -handle_info({snmp_report, {ok, Pdu}, Addr, Port}, State) -> - handle_snmp_report(Pdu, Addr, Port, State), +handle_info({snmp_report, {ok, Pdu}, Domain, Addr}, State) -> + handle_snmp_report(Pdu, Domain, Addr, State), {noreply, State}; -handle_info({snmp_report, {error, ReqId, Info, Pdu}, Addr, Port}, State) -> - handle_snmp_report(ReqId, Pdu, Info, Addr, Port, State), +handle_info({snmp_report, {error, ReqId, Info, Pdu}, Domain, Addr}, State) -> + handle_snmp_report(ReqId, Pdu, Info, Domain, Addr, State), {noreply, State}; @@ -1176,11 +1175,11 @@ handle_sync_get(Pid, UserId, TargetName, Oids, SendOpts, From, State) -> "~n From: ~p", [Pid, UserId, TargetName, Oids, SendOpts, From]), case agent_data(TargetName, SendOpts) of - {ok, RegType, Domain, Addr, Port, Vsn, MsgData} -> + {ok, RegType, Domain, Addr, Vsn, MsgData} -> ?vtrace("handle_sync_get -> send a ~p message", [Vsn]), Extra = ?GET_EXTRA(SendOpts), ReqId = send_get_request(Oids, Vsn, MsgData, - Domain, Addr, Port, + Domain, Addr, Extra, State), ?vdebug("handle_sync_get -> ReqId: ~p", [ReqId]), Msg = {sync_timeout, ReqId, From}, @@ -1193,8 +1192,7 @@ handle_sync_get(Pid, UserId, TargetName, Oids, SendOpts, From, State) -> reg_type = RegType, target = TargetName, domain = Domain, - addr = Addr, - port = Port, + address = Addr, type = get, data = MsgData, ref = Ref, @@ -1230,11 +1228,11 @@ handle_sync_get_next(Pid, UserId, TargetName, Oids, SendOpts, "~n From: ~p", [Pid, UserId, TargetName, Oids, SendOpts, From]), case agent_data(TargetName, SendOpts) of - {ok, RegType, Domain, Addr, Port, Vsn, MsgData} -> + {ok, RegType, Domain, Addr, Vsn, MsgData} -> ?vtrace("handle_sync_get_next -> send a ~p message", [Vsn]), Extra = ?GET_EXTRA(SendOpts), ReqId = send_get_next_request(Oids, Vsn, MsgData, - Domain, Addr, Port, + Domain, Addr, Extra, State), ?vdebug("handle_sync_get_next -> ReqId: ~p", [ReqId]), Msg = {sync_timeout, ReqId, From}, @@ -1247,12 +1245,11 @@ handle_sync_get_next(Pid, UserId, TargetName, Oids, SendOpts, reg_type = RegType, target = TargetName, domain = Domain, - addr = Addr, - port = Port, + address = Addr, type = get_next, data = MsgData, ref = Ref, - mon = MonRef, + mon = MonRef, from = From}, ets:insert(snmpm_request_table, Req), ok; @@ -1290,11 +1287,11 @@ handle_sync_get_bulk(Pid, UserId, TargetName, NonRep, MaxRep, Oids, SendOpts, "~n From: ~p", [Pid, UserId, TargetName, NonRep, MaxRep, Oids, SendOpts, From]), case agent_data(TargetName, SendOpts) of - {ok, RegType, Domain, Addr, Port, Vsn, MsgData} -> + {ok, RegType, Domain, Addr, Vsn, MsgData} -> ?vtrace("handle_sync_get_bulk -> send a ~p message", [Vsn]), Extra = ?GET_EXTRA(SendOpts), ReqId = send_get_bulk_request(Oids, Vsn, MsgData, - Domain, Addr, Port, + Domain, Addr, NonRep, MaxRep, Extra, State), ?vdebug("handle_sync_get_bulk -> ReqId: ~p", [ReqId]), Msg = {sync_timeout, ReqId, From}, @@ -1307,8 +1304,7 @@ handle_sync_get_bulk(Pid, UserId, TargetName, NonRep, MaxRep, Oids, SendOpts, reg_type = RegType, target = TargetName, domain = Domain, - addr = Addr, - port = Port, + address = Addr, type = get_bulk, data = MsgData, ref = Ref, @@ -1346,11 +1342,11 @@ handle_sync_set(Pid, UserId, TargetName, VarsAndVals, SendOpts, From, State) -> "~n From: ~p", [Pid, UserId, TargetName, VarsAndVals, From]), case agent_data(TargetName, SendOpts) of - {ok, RegType, Domain, Addr, Port, Vsn, MsgData} -> + {ok, RegType, Domain, Addr, Vsn, MsgData} -> ?vtrace("handle_sync_set -> send a ~p message", [Vsn]), Extra = ?GET_EXTRA(SendOpts), ReqId = send_set_request(VarsAndVals, Vsn, MsgData, - Domain, Addr, Port, + Domain, Addr, Extra, State), ?vdebug("handle_sync_set -> ReqId: ~p", [ReqId]), Msg = {sync_timeout, ReqId, From}, @@ -1363,8 +1359,7 @@ handle_sync_set(Pid, UserId, TargetName, VarsAndVals, SendOpts, From, State) -> reg_type = RegType, target = TargetName, domain = Domain, - addr = Addr, - port = Port, + address = Addr, type = set, data = MsgData, ref = Ref, @@ -1400,11 +1395,11 @@ handle_async_get(Pid, UserId, TargetName, Oids, SendOpts, State) -> "~n SendOpts: ~p", [Pid, UserId, TargetName, Oids, SendOpts]), case agent_data(TargetName, SendOpts) of - {ok, RegType, Domain, Addr, Port, Vsn, MsgData} -> + {ok, RegType, Domain, Addr, Vsn, MsgData} -> ?vtrace("handle_async_get -> send a ~p message", [Vsn]), Extra = ?GET_EXTRA(SendOpts), ReqId = send_get_request(Oids, Vsn, MsgData, - Domain, Addr, Port, + Domain, Addr, Extra, State), ?vdebug("handle_async_get -> ReqId: ~p", [ReqId]), Expire = ?ASYNC_GET_TIMEOUT(SendOpts), @@ -1413,8 +1408,7 @@ handle_async_get(Pid, UserId, TargetName, Oids, SendOpts, State) -> reg_type = RegType, target = TargetName, domain = Domain, - addr = Addr, - port = Port, + address = Addr, type = get, data = MsgData, expire = t() + Expire}, @@ -1450,11 +1444,11 @@ handle_async_get_next(Pid, UserId, TargetName, Oids, SendOpts, State) -> "~n SendOpts: ~p", [Pid, UserId, TargetName, Oids, SendOpts]), case agent_data(TargetName, SendOpts) of - {ok, RegType, Domain, Addr, Port, Vsn, MsgData} -> + {ok, RegType, Domain, Addr, Vsn, MsgData} -> ?vtrace("handle_async_get_next -> send a ~p message", [Vsn]), Extra = ?GET_EXTRA(SendOpts), ReqId = send_get_next_request(Oids, Vsn, MsgData, - Domain, Addr, Port, + Domain, Addr, Extra, State), ?vdebug("handle_async_get_next -> ReqId: ~p", [ReqId]), Expire = ?ASYNC_GET_NEXT_TIMEOUT(SendOpts), @@ -1463,8 +1457,7 @@ handle_async_get_next(Pid, UserId, TargetName, Oids, SendOpts, State) -> reg_type = RegType, target = TargetName, domain = Domain, - addr = Addr, - port = Port, + address = Addr, type = get_next, data = MsgData, expire = t() + Expire}, @@ -1507,11 +1500,11 @@ handle_async_get_bulk(Pid, "~n SendOpts: ~p", [Pid, UserId, TargetName, NonRep, MaxRep, Oids, SendOpts]), case agent_data(TargetName, SendOpts) of - {ok, RegType, Domain, Addr, Port, Vsn, MsgData} -> + {ok, RegType, Domain, Addr, Vsn, MsgData} -> ?vtrace("handle_async_get_bulk -> send a ~p message", [Vsn]), Extra = ?GET_EXTRA(SendOpts), ReqId = send_get_bulk_request(Oids, Vsn, MsgData, - Domain, Addr, Port, + Domain, Addr, NonRep, MaxRep, Extra, State), ?vdebug("handle_async_get_bulk -> ReqId: ~p", [ReqId]), Expire = ?ASYNC_GET_BULK_TIMEOUT(SendOpts), @@ -1520,8 +1513,7 @@ handle_async_get_bulk(Pid, reg_type = RegType, target = TargetName, domain = Domain, - addr = Addr, - port = Port, + address = Addr, type = get_bulk, data = MsgData, expire = t() + Expire}, @@ -1556,11 +1548,11 @@ handle_async_set(Pid, UserId, TargetName, VarsAndVals, SendOpts, State) -> "~n SendOpts: ~p", [Pid, UserId, TargetName, VarsAndVals, SendOpts]), case agent_data(TargetName, SendOpts) of - {ok, RegType, Domain, Addr, Port, Vsn, MsgData} -> + {ok, RegType, Domain, Addr, Vsn, MsgData} -> ?vtrace("handle_async_set -> send a ~p message", [Vsn]), Extra = ?GET_EXTRA(SendOpts), ReqId = send_set_request(VarsAndVals, Vsn, MsgData, - Domain, Addr, Port, + Domain, Addr, Extra, State), ?vdebug("handle_async_set -> ReqId: ~p", [ReqId]), Expire = ?ASYNC_SET_TIMEOUT(SendOpts), @@ -1569,8 +1561,7 @@ handle_async_set(Pid, UserId, TargetName, VarsAndVals, SendOpts, State) -> reg_type = RegType, target = TargetName, domain = Domain, - addr = Addr, - port = Port, + address = Addr, type = set, data = MsgData, expire = t() + Expire}, @@ -1808,15 +1799,15 @@ handle_snmp_error(CrapError, Reason, _State) -> "~n~p~n~p", [CrapError, Reason]), ok. -handle_snmp_error(Addr, Port, ReqId, Reason, State) -> +handle_snmp_error(Domain, Addr, ReqId, Reason, State) -> - ?vtrace("handle_snmp_error -> entry with" - "~n Addr: ~p" - "~n Port: ~p" - "~n ReqId: ~p" - "~n Reason: ~p", [Addr, Port, ReqId, Reason]), + ?vtrace("handle_snmp_error -> entry with~n" + " Domain: ~p~n" + " Addr: ~p~n" + " ReqId: ~p~n" + " Reason: ~p", [Domain, Addr, ReqId, Reason]), - case snmpm_config:get_agent_user_id(Addr, Port) of + case snmpm_config:get_agent_user_id(Domain, Addr) of {ok, UserId} -> case snmpm_config:user_info(UserId) of {ok, UserMod, UserData} -> @@ -1831,7 +1822,7 @@ handle_snmp_error(Addr, Port, ReqId, Reason, State) -> error_msg("failed retreiving the default user " "info handling snmp error " "<~p,~p>: ~n~w~n~w", - [Addr, Port, ReqId, Reason]) + [Domain, Addr, ReqId, Reason]) end end; _Error -> @@ -1843,7 +1834,7 @@ handle_snmp_error(Addr, Port, ReqId, Reason, State) -> error_msg("failed retreiving the default user " "info handling snmp error " "<~p,~p>: ~n~w~n~w", - [Addr, Port, ReqId, Reason]) + [Domain, Addr, ReqId, Reason]) end end. @@ -1867,12 +1858,12 @@ handle_error(_UserId, Mod, Reason, ReqId, Data, _State) -> handle_snmp_pdu(#pdu{type = 'get-response', request_id = ReqId} = Pdu, - Addr, Port, State) -> + Domain, Addr, State) -> - ?vtrace("handle_snmp_pdu(get-response) -> entry with" - "~n Addr: ~p" - "~n Port: ~p" - "~n Pdu: ~p", [Addr, Port, Pdu]), + ?vtrace("handle_snmp_pdu(get-response) -> entry with~n" + " Domain: ~p~n" + " Addr: ~p~n" + " Pdu: ~p", [Domain, Addr, Pdu]), case ets:lookup(snmpm_request_table, ReqId) of @@ -1902,9 +1893,10 @@ handle_snmp_pdu(#pdu{type = 'get-response', request_id = ReqId} = Pdu, SnmpResponse = {EStatus, EIndex, Varbinds2}, case snmpm_config:user_info(UserId) of {ok, UserMod, UserData} -> - handle_pdu(UserId, UserMod, - RegType, Target, Addr, Port, - ReqId, SnmpResponse, UserData, State), + handle_pdu( + UserId, UserMod, + RegType, Target, Domain, Addr, + ReqId, SnmpResponse, UserData, State), maybe_delete(Disco, ReqId); _Error -> %% reply to outstanding request, for which there is no @@ -1912,15 +1904,16 @@ handle_snmp_pdu(#pdu{type = 'get-response', request_id = ReqId} = Pdu, %% Therefor send it to the default user case snmpm_config:user_info() of {ok, DefUserId, DefMod, DefData} -> - handle_pdu(DefUserId, DefMod, - RegType, Target, Addr, Port, - ReqId, SnmpResponse, DefData, State), + handle_pdu( + DefUserId, DefMod, + RegType, Target, Domain, Addr, + ReqId, SnmpResponse, DefData, State), maybe_delete(Disco, ReqId); Error -> error_msg("failed retreiving the default user " "info handling pdu from " "~p <~p,~p>: ~n~w~n~w", - [Target, Addr, Port, Error, Pdu]) + [Target, Domain, Addr, Error, Pdu]) end end; @@ -1974,7 +1967,7 @@ handle_snmp_pdu(#pdu{type = 'get-response', request_id = ReqId} = Pdu, varbinds = Varbinds} = Pdu, Varbinds2 = fix_vbs_BITS(Varbinds), SnmpInfo = {EStatus, EIndex, Varbinds2}, - case snmpm_config:get_agent_user_id(Addr, Port) of + case snmpm_config:get_agent_user_id(Domain, Addr) of {ok, UserId} -> %% A very late reply or a reply to a request %% that has been cancelled. @@ -1999,7 +1992,7 @@ handle_snmp_pdu(#pdu{type = 'get-response', request_id = ReqId} = Pdu, "user info handling (old) " "pdu from " "<~p,~p>: ~n~w~n~w", - [Addr, Port, Error, Pdu]) + [Domain, Addr, Error, Pdu]) end end; @@ -2016,28 +2009,30 @@ handle_snmp_pdu(#pdu{type = 'get-response', request_id = ReqId} = Pdu, "no agent info found", []), case snmpm_config:user_info() of {ok, DefUserId, DefMod, DefData} -> - handle_agent(DefUserId, DefMod, - Addr, Port, - pdu, ignore, - SnmpInfo, DefData, State); + handle_agent( + DefUserId, DefMod, + Domain, Addr, + pdu, ignore, + SnmpInfo, DefData, State); Error -> error_msg("failed retreiving the default user " "info handling (old) pdu when no user " "found from " "<~p,~p>: ~n~w~n~w", - [Addr, Port, Error, Pdu]) + [Domain, Addr, Error, Pdu]) end end end; -handle_snmp_pdu(CrapPdu, Addr, Port, _State) -> +handle_snmp_pdu(CrapPdu, Domain, Addr, _State) -> error_msg("received crap (snmp) Pdu from ~w:~w =>" - "~p", [Addr, Port, CrapPdu]), + "~p", [Domain, Addr, CrapPdu]), ok. -handle_pdu(_UserId, Mod, target_name = _RegType, TargetName, _Addr, _Port, - ReqId, SnmpResponse, Data, _State) -> +handle_pdu( + _UserId, Mod, target_name = _RegType, TargetName, _Domain, _Addr, + ReqId, SnmpResponse, Data, _State) -> ?vtrace("handle_pdu(target_name) -> entry when" "~n Mod: ~p", [Mod]), F = fun() -> @@ -2053,43 +2048,47 @@ handle_pdu(_UserId, Mod, target_name = _RegType, TargetName, _Addr, _Port, end, handle_callback(F), ok; -handle_pdu(_UserId, Mod, addr_port = _RegType, _TargetName, Addr, Port, - ReqId, SnmpResponse, Data, _State) -> +handle_pdu( + _UserId, Mod, addr_port = _RegType, _TargetName, _Domain, Addr, + ReqId, SnmpResponse, Data, _State) -> ?vtrace("handle_pdu(addr_port) -> entry when" "~n Mod: ~p", [Mod]), F = fun() -> - (catch Mod:handle_pdu(Addr, Port, ReqId, SnmpResponse, Data)) + {Ip, Port} = Addr, + (catch Mod:handle_pdu(Ip, Port, ReqId, SnmpResponse, Data)) end, handle_callback(F), ok. -handle_agent(UserId, Mod, Addr, Port, Type, Ref, SnmpInfo, Data, State) -> +handle_agent(UserId, Mod, Domain, Addr, Type, Ref, SnmpInfo, Data, State) -> ?vtrace("handle_agent -> entry when" "~n UserId: ~p" "~n Type: ~p" "~n Mod: ~p", [UserId, Type, Mod]), F = fun() -> - do_handle_agent(UserId, Mod, Addr, Port, + do_handle_agent(UserId, Mod, Domain, Addr, Type, Ref, SnmpInfo, Data, State) end, handle_callback(F), ok. do_handle_agent(DefUserId, DefMod, - Addr, Port, + Domain, Addr, Type, Ref, SnmpInfo, DefData, State) -> ?vdebug("do_handle_agent -> entry when" "~n DefUserId: ~p", [DefUserId]), - try DefMod:handle_agent(Addr, Port, Type, SnmpInfo, DefData) of + try DefMod:handle_agent(Domain, Addr, Type, SnmpInfo, DefData) of {register, UserId2, TargetName, Config} -> ?vtrace("do_handle_agent -> register: " "~n UserId2: ~p" "~n TargetName: ~p" "~n Config: ~p", [UserId2, TargetName, Config]), - Config2 = ensure_present([{address, Addr}, {port, Port}], Config), + Config2 = + ensure_present( + [{tdomain, Domain}, {taddress, Addr}], Config), Config3 = [{reg_type, target_name} | Config2], case snmpm_config:register_agent(UserId2, TargetName, Config3) of @@ -2099,7 +2098,7 @@ do_handle_agent(DefUserId, DefMod, error_msg("failed registering agent - " "handling agent " "~p <~p,~p>: ~n~w", - [TargetName, Addr, Port, Reason]), + [TargetName, Domain, Addr, Reason]), ok end; @@ -2108,31 +2107,33 @@ do_handle_agent(DefUserId, DefMod, ok; InvalidResult -> - CallbackArgs = [Addr, Port, Type, SnmpInfo, DefData], + CallbackArgs = [Domain, Addr, Type, SnmpInfo, DefData], handle_invalid_result(handle_agent, CallbackArgs, InvalidResult) catch error:{undef, _} when Type =:= pdu -> %% Maybe, still on the old API ?vdebug("do_handle_agent -> maybe still on the old api", []), - case (catch DefMod:handle_agent(Addr, Port, SnmpInfo, DefData)) of + {Ip, Port} = Addr, + case (catch DefMod:handle_agent(Ip, Port, SnmpInfo, DefData)) of {register, UserId2, Config} -> ?vtrace("do_handle_agent -> register: " "~n UserId2: ~p" "~n Config: ~p", [UserId2, Config]), - TargetName = mk_target_name(Addr, Port, Config), - Config2 = [{reg_type, addr_port}, - {address, Addr}, - {port, Port} | Config], - case snmpm_config:register_agent(UserId2, - TargetName, Config2) of + TargetName = mk_target_name(Domain, Addr, Config), + Config2 = + ensure_present( + [{tdomain, Domain}, {taddress, Addr}], Config), + Config3 = [{reg_type, addr_port} | Config2], + case snmpm_config:register_agent( + UserId2, TargetName, Config3) of ok -> ok; {error, Reason} -> error_msg("failed registering agent - " "handling agent " "~p <~p,~p>: ~n~w", - [TargetName, Addr, Port, Reason]), + [TargetName, Domain, Addr, Reason]), ok end; {register, UserId2, TargetName, Config} -> @@ -2141,18 +2142,19 @@ do_handle_agent(DefUserId, DefMod, "~n TargetName: ~p" "~n Config: ~p", [UserId2, TargetName, Config]), - Config2 = ensure_present([{address, Addr}, {port, Port}], - Config), + Config2 = + ensure_present( + [{tdomain, Domain}, {taddress, Addr}], Config), Config3 = [{reg_type, target_name} | Config2], - case snmpm_config:register_agent(UserId2, - TargetName, Config3) of + case snmpm_config:register_agent( + UserId2, TargetName, Config3) of ok -> ok; {error, Reason} -> error_msg("failed registering agent - " "handling agent " "~p <~p,~p>: ~n~w", - [TargetName, Addr, Port, Reason]), + [TargetName, Domain, Addr, Reason]), ok end; _Ignore -> @@ -2170,34 +2172,38 @@ do_handle_agent(DefUserId, DefMod, %% Backward compatibillity crap RegType = target_name, - Target = mk_target_name(Addr, Port, default_agent_config()), + Target = mk_target_name(Domain, Addr, default_agent_config()), case Type of report -> SnmpInform = SnmpInfo, - handle_report(DefUserId, DefMod, - RegType, Target, Addr, Port, - SnmpInform, DefData, State); + handle_report( + DefUserId, DefMod, + RegType, Target, Domain, Addr, + SnmpInform, DefData, State); inform -> SnmpInform = SnmpInfo, - handle_inform(DefUserId, DefMod, Ref, - RegType, Target, Addr, Port, - SnmpInform, DefData, State); + handle_inform( + DefUserId, DefMod, Ref, + RegType, Target, Domain, Addr, + SnmpInform, DefData, State); trap -> SnmpTrapInfo = SnmpInfo, - handle_trap(DefUserId, DefMod, - RegType, Target, Addr, Port, - SnmpTrapInfo, DefData, State); + handle_trap( + DefUserId, DefMod, + RegType, Target, Domain, Addr, + SnmpTrapInfo, DefData, State); _ -> - error_msg("failed delivering ~w info to default user - " - "regarding agent " - "<~p,~p>: ~n~w", [Type, Addr, Port, SnmpInfo]) + error_msg( + "failed delivering ~w info to default user - " + "regarding agent " + "<~p,~p>: ~n~w", [Type, Domain, Addr, SnmpInfo]) end; T:E -> - CallbackArgs = [Addr, Port, Type, SnmpInfo, DefData], + CallbackArgs = [Domain, Addr, Type, SnmpInfo, DefData], handle_invalid_result(handle_agent, CallbackArgs, T, E) end. @@ -2215,50 +2221,51 @@ ensure_present([{Key, _Val} = Elem|Ensure], Config) -> %% Retrieve user info for this agent. %% If this is an unknown agent, then use the default user -handle_snmp_trap(#trappdu{enterprise = Enteprise, - generic_trap = Generic, - specific_trap = Spec, - time_stamp = Timestamp, - varbinds = Varbinds} = Trap, - Addr, Port, State) -> - - ?vtrace("handle_snmp_trap [trappdu] -> entry with" - "~n Addr: ~p" - "~n Port: ~p" - "~n Trap: ~p", [Addr, Port, Trap]), +handle_snmp_trap( + #trappdu{enterprise = Enteprise, + generic_trap = Generic, + specific_trap = Spec, + time_stamp = Timestamp, + varbinds = Varbinds} = Trap, Domain, Addr, State) -> + + ?vtrace("handle_snmp_trap [trappdu] -> entry with~n" + " Domain: ~p~n" + " Addr: ~p~n" + " Trap: ~p", [Domain, Addr, Trap]), Varbinds2 = fix_vbs_BITS(Varbinds), SnmpTrapInfo = {Enteprise, Generic, Spec, Timestamp, Varbinds2}, - do_handle_snmp_trap(SnmpTrapInfo, Addr, Port, State); + do_handle_snmp_trap(SnmpTrapInfo, Domain, Addr, State); handle_snmp_trap(#pdu{error_status = EStatus, error_index = EIndex, varbinds = Varbinds} = Trap, - Addr, Port, State) -> + Domain, Addr, State) -> - ?vtrace("handle_snmp_trap [pdu] -> entry with" - "~n Addr: ~p" - "~n Port: ~p" - "~n Trap: ~p", [Addr, Port, Trap]), + ?vtrace("handle_snmp_trap [pdu] -> entry with~n" + " Domain: ~p~n" + " Addr: ~p~n" + " Trap: ~p", [Domain, Addr, Trap]), Varbinds2 = fix_vbs_BITS(Varbinds), SnmpTrapInfo = {EStatus, EIndex, Varbinds2}, - do_handle_snmp_trap(SnmpTrapInfo, Addr, Port, State); + do_handle_snmp_trap(SnmpTrapInfo, Domain, Addr, State); -handle_snmp_trap(CrapTrap, Addr, Port, _State) -> +handle_snmp_trap(CrapTrap, Domain, Addr, _State) -> error_msg("received crap (snmp) trap from ~w:~w =>" - "~p", [Addr, Port, CrapTrap]), + "~p", [Domain, Addr, CrapTrap]), ok. -do_handle_snmp_trap(SnmpTrapInfo, Addr, Port, State) -> - case snmpm_config:get_agent_user_info(Addr, Port) of +do_handle_snmp_trap(SnmpTrapInfo, Domain, Addr, State) -> + case snmpm_config:get_agent_user_info(Domain, Addr) of {ok, UserId, Target, RegType} -> ?vtrace("handle_snmp_trap -> found user: ~p", [UserId]), case snmpm_config:user_info(UserId) of {ok, Mod, Data} -> - handle_trap(UserId, Mod, - RegType, Target, Addr, Port, - SnmpTrapInfo, Data, State); + handle_trap( + UserId, Mod, + RegType, Target, Domain, Addr, + SnmpTrapInfo, Data, State); Error1 -> %% User no longer exists, unregister agent @@ -2270,66 +2277,72 @@ do_handle_snmp_trap(SnmpTrapInfo, Addr, Port, State) -> %% Try use the default user case snmpm_config:user_info() of {ok, DefUserId, DefMod, DefData} -> - handle_agent(DefUserId, DefMod, - Addr, Port, - trap, ignore, - SnmpTrapInfo, DefData, State); + handle_agent( + DefUserId, DefMod, + Domain, Addr, + trap, ignore, + SnmpTrapInfo, DefData, State); Error2 -> - error_msg("failed retreiving the default " - "user info handling report from " - "~p <~p,~p>: ~n~w~n~w", - [Target, Addr, Port, - Error2, SnmpTrapInfo]) + error_msg( + "failed retreiving the default " + "user info handling report from " + "~p <~p,~p>: ~n~w~n~w", + [Target, Domain, Addr, + Error2, SnmpTrapInfo]) end; Error3 -> %% Failed unregister agent, %% now its getting messy... - warning_msg("failed unregister agent ~p <~p,~p> " - "belonging to non-existing " - "user ~p, handling trap: " - "~n Error: ~w" - "~n Trap info: ~w", - [Target, Addr, Port, UserId, - Error3, SnmpTrapInfo]) + warning_msg( + "failed unregister agent ~p <~p,~p> " + "belonging to non-existing " + "user ~p, handling trap: " + "~n Error: ~w" + "~n Trap info: ~w", + [Target, Domain, Addr, UserId, + Error3, SnmpTrapInfo]) end end; Error4 -> %% Unknown agent, pass it on to the default user ?vlog("[trap] failed retreiving user id for agent <~p,~p>: " - "~n ~p", [Addr, Port, Error4]), + "~n ~p", [Domain, Addr, Error4]), case snmpm_config:user_info() of {ok, DefUserId, DefMod, DefData} -> - handle_agent(DefUserId, DefMod, - Addr, Port, - trap, ignore, - SnmpTrapInfo, DefData, State); + handle_agent( + DefUserId, DefMod, + Domain, Addr, + trap, ignore, + SnmpTrapInfo, DefData, State); Error5 -> - error_msg("failed retreiving " - "the default user info handling trap from " - "<~p,~p>: ~n~w~n~w", - [Addr, Port, Error5, SnmpTrapInfo]) + error_msg( + "failed retreiving " + "the default user info handling trap from " + "<~p,~p>: ~n~w~n~w", + [Domain, Addr, Error5, SnmpTrapInfo]) end end, ok. -handle_trap(UserId, Mod, - RegType, Target, Addr, Port, SnmpTrapInfo, Data, State) -> +handle_trap( + UserId, Mod, RegType, Target, Domain, Addr, SnmpTrapInfo, Data, State) -> ?vtrace("handle_trap -> entry with" "~n UserId: ~p" "~n Mod: ~p", [UserId, Mod]), F = fun() -> - do_handle_trap(UserId, Mod, - RegType, Target, Addr, Port, - SnmpTrapInfo, Data, State) + do_handle_trap( + UserId, Mod, + RegType, Target, Domain, Addr, + SnmpTrapInfo, Data, State) end, handle_callback(F), ok. -do_handle_trap(UserId, Mod, - RegType, Target, Addr, Port, SnmpTrapInfo, Data, _State) -> +do_handle_trap( + UserId, Mod, RegType, Target, Domain, Addr, SnmpTrapInfo, Data, _State) -> ?vdebug("do_handle_trap -> entry with" "~n UserId: ~p", [UserId]), {HandleTrap, CallbackArgs} = @@ -2338,8 +2351,9 @@ do_handle_trap(UserId, Mod, {fun() -> Mod:handle_trap(Target, SnmpTrapInfo, Data) end, [Target, SnmpTrapInfo, Data]}; addr_port -> - {fun() -> Mod:handle_trap(Addr, Port, SnmpTrapInfo, Data) end, - [Addr, Port, SnmpTrapInfo, Data]} + {Ip, Port} = Addr, + {fun() -> Mod:handle_trap(Ip, Port, SnmpTrapInfo, Data) end, + [Ip, Port, SnmpTrapInfo, Data]} end, try HandleTrap() of @@ -2347,9 +2361,10 @@ do_handle_trap(UserId, Mod, ?vtrace("do_handle_trap -> register: " "~n UserId2: ~p" "~n Config: ~p", [UserId2, Config]), - Target2 = mk_target_name(Addr, Port, Config), - Config2 = [{reg_type, target_name}, - {address, Addr}, {port, Port} | Config], + Target2 = mk_target_name(Domain, Addr, Config), + Config2 = + [{reg_type, target_name}, + {tdomain, Domain}, {taddress, Addr} | Config], case snmpm_config:register_agent(UserId2, Target2, Config2) of ok -> ok; @@ -2357,7 +2372,7 @@ do_handle_trap(UserId, Mod, error_msg("failed registering agent " "handling trap " "<~p,~p>: ~n~w", - [Addr, Port, Reason]), + [Domain, Addr, Reason]), ok end; {register, UserId2, Target2, Config} -> @@ -2375,20 +2390,19 @@ do_handle_trap(UserId, Mod, error_msg("failed registering agent " "handling trap " "~p <~p,~p>: ~n~w", - [Target2, Addr, Port, Reason]), + [Target2, Domain, Addr, Reason]), reply end; unregister -> ?vtrace("do_handle_trap -> unregister", []), - case snmpm_config:unregister_agent(UserId, - Addr, Port) of + case snmpm_config:unregister_agent(UserId, Domain, Addr) of ok -> ok; {error, Reason} -> error_msg("failed unregistering agent " "handling trap " "<~p,~p>: ~n~w", - [Addr, Port, Reason]), + [Domain, Addr, Reason]), ok end; ignore -> @@ -2405,28 +2419,30 @@ do_handle_trap(UserId, Mod, end. -handle_snmp_inform(Ref, - #pdu{error_status = EStatus, - error_index = EIndex, - varbinds = Varbinds} = Pdu, Addr, Port, State) -> +handle_snmp_inform( + Ref, + #pdu{error_status = EStatus, + error_index = EIndex, + varbinds = Varbinds} = Pdu, Domain, Addr, State) -> - ?vtrace("handle_snmp_inform -> entry with" - "~n Addr: ~p" - "~n Port: ~p" - "~n Pdu: ~p", [Addr, Port, Pdu]), + ?vtrace("handle_snmp_inform -> entry with~n" + " Domain: ~p~n" + " Addr: ~p~n" + " Pdu: ~p", [Domain, Addr, Pdu]), Varbinds2 = fix_vbs_BITS(Varbinds), SnmpInform = {EStatus, EIndex, Varbinds2}, - case snmpm_config:get_agent_user_info(Addr, Port) of + case snmpm_config:get_agent_user_info(Domain, Addr) of {ok, UserId, Target, RegType} -> case snmpm_config:user_info(UserId) of {ok, Mod, Data} -> ?vdebug("[inform] callback handle_inform with: " "~n UserId: ~p" "~n Mod: ~p", [UserId, Mod]), - handle_inform(UserId, Mod, Ref, - RegType, Target, Addr, Port, - SnmpInform, Data, State); + handle_inform( + UserId, Mod, Ref, + RegType, Target, Domain, Addr, + SnmpInform, Data, State); Error1 -> %% User no longer exists, unregister agent case snmpm_config:unregister_agent(UserId, Target) of @@ -2437,15 +2453,16 @@ handle_snmp_inform(Ref, "~n ~p", [UserId, Error1]), case snmpm_config:user_info() of {ok, DefUserId, DefMod, DefData} -> - handle_agent(DefUserId, DefMod, - Addr, Port, - inform, Ref, - SnmpInform, DefData, State); + handle_agent( + DefUserId, DefMod, + Domain, Addr, + inform, Ref, + SnmpInform, DefData, State); Error2 -> error_msg("failed retreiving the default " "user info handling inform from " "~p <~p,~p>: ~n~w~n~w", - [Target, Addr, Port, + [Target, Domain, Addr, Error2, Pdu]) end; Error3 -> @@ -2456,7 +2473,7 @@ handle_snmp_inform(Ref, "user ~p, handling inform: " "~n Error: ~w" "~n Pdu: ~w", - [Target, Addr, Port, UserId, + [Target, Domain, Addr, UserId, Error3, Pdu]) end end; @@ -2464,42 +2481,46 @@ handle_snmp_inform(Ref, Error4 -> %% Unknown agent, pass it on to the default user ?vlog("[inform] failed retreiving user id for agent <~p,~p>: " - "~n ~p", [Addr, Port, Error4]), + "~n ~p", [Domain, Addr, Error4]), case snmpm_config:user_info() of {ok, DefUserId, DefMod, DefData} -> - handle_agent(DefUserId, DefMod, - Addr, Port, - inform, Ref, - SnmpInform, DefData, State); + handle_agent( + DefUserId, DefMod, + Domain, Addr, + inform, Ref, + SnmpInform, DefData, State); Error5 -> error_msg("failed retreiving " "the default user info handling inform from " "<~p,~p>: ~n~w~n~w", - [Addr, Port, Error5, Pdu]) + [Domain, Addr, Error5, Pdu]) end end, ok; -handle_snmp_inform(_Ref, CrapInform, Addr, Port, _State) -> +handle_snmp_inform(_Ref, CrapInform, Domain, Addr, _State) -> error_msg("received crap (snmp) inform from ~w:~w =>" - "~p", [Addr, Port, CrapInform]), + "~p", [Domain, Addr, CrapInform]), ok. -handle_inform(UserId, Mod, Ref, - RegType, Target, Addr, Port, SnmpInform, Data, State) -> +handle_inform( + UserId, Mod, Ref, + RegType, Target, Domain, Addr, SnmpInform, Data, State) -> ?vtrace("handle_inform -> entry with" "~n UserId: ~p" "~n Mod: ~p", [UserId, Mod]), F = fun() -> - do_handle_inform(UserId, Mod, Ref, - RegType, Target, Addr, Port, SnmpInform, - Data, State) + do_handle_inform( + UserId, Mod, Ref, + RegType, Target, Domain, Addr, SnmpInform, + Data, State) end, handle_callback(F), ok. -do_handle_inform(UserId, Mod, Ref, - RegType, Target, Addr, Port, SnmpInform, Data, State) -> +do_handle_inform( + UserId, Mod, Ref, + RegType, Target, Domain, Addr, SnmpInform, Data, State) -> ?vdebug("do_handle_inform -> entry with" "~n UserId: ~p", [UserId]), {HandleInform, CallbackArgs} = @@ -2508,8 +2529,9 @@ do_handle_inform(UserId, Mod, Ref, {fun() -> Mod:handle_inform(Target, SnmpInform, Data) end, [Target, SnmpInform, Data]}; addr_port -> - {fun() -> Mod:handle_inform(Addr, Port, SnmpInform, Data) end, - [Addr, Port, SnmpInform, Data]} + {Ip, Port} = Addr, + {fun() -> Mod:handle_inform(Ip, Port, SnmpInform, Data) end, + [Ip, Port, SnmpInform, Data]} end, Rep = @@ -2520,9 +2542,11 @@ do_handle_inform(UserId, Mod, Ref, "~n Config: ~p", [UserId2, Config]), %% The only user which would do this is the %% default user - Target2 = mk_target_name(Addr, Port, Config), - Config2 = [{reg_type, target_name}, - {address, Addr}, {port, Port} | Config], + Target2 = mk_target_name(Domain, Addr, Config), + Config2 = + [{reg_type, target_name} | + ensure_present( + [{tdomain, Domain}, {taddress, Addr}], Config)], case snmpm_config:register_agent(UserId2, Target2, Config2) of ok -> reply; @@ -2530,7 +2554,7 @@ do_handle_inform(UserId, Mod, Ref, error_msg("failed registering agent " "handling inform " "~p <~p,~p>: ~n~w", - [Target2, Addr, Port, Reason]), + [Target2, Domain, Addr, Reason]), reply end; @@ -2549,21 +2573,21 @@ do_handle_inform(UserId, Mod, Ref, error_msg("failed registering agent " "handling inform " "~p <~p,~p>: ~n~w", - [Target2, Addr, Port, Reason]), + [Target2, Domain, Addr, Reason]), reply end; unregister -> ?vtrace("do_handle_inform -> unregister", []), - case snmpm_config:unregister_agent(UserId, - Addr, Port) of + case snmpm_config:unregister_agent( + UserId, Domain, Addr) of ok -> reply; {error, Reason} -> error_msg("failed unregistering agent " "handling inform " "<~p,~p>: ~n~w", - [Addr, Port, Reason]), + [Domain, Addr, Reason]), reply end; @@ -2576,8 +2600,8 @@ do_handle_inform(UserId, Mod, Ref, reply; InvalidResult -> - handle_invalid_result(handle_inform, CallbackArgs, - InvalidResult), + handle_invalid_result( + handle_inform, CallbackArgs, InvalidResult), reply catch @@ -2586,31 +2610,34 @@ do_handle_inform(UserId, Mod, Ref, reply end, - handle_inform_response(Rep, Ref, Addr, Port, State), + handle_inform_response(Rep, Ref, Domain, Addr, State), ok. -handle_inform_response(_, ignore, _Addr, _Port, _State) -> +handle_inform_response(_, ignore, _Domain, _Addr, _State) -> ignore; -handle_inform_response(no_reply, _Ref, _Addr, _Port, _State) -> +handle_inform_response(no_reply, _Ref, _Domain, _Addr, _State) -> no_reply; -handle_inform_response(_, Ref, Addr, Port, - #state{net_if = Pid, net_if_mod = Mod}) -> +handle_inform_response( + _, Ref, Domain, Addr, + #state{net_if = Pid, net_if_mod = Mod}) -> ?vdebug("handle_inform -> response", []), - (catch Mod:inform_response(Pid, Ref, Addr, Port)). + (catch Mod:inform_response(Pid, Ref, Domain, Addr)). -handle_snmp_report(#pdu{error_status = EStatus, - error_index = EIndex, - varbinds = Varbinds} = Pdu, Addr, Port, State) -> +handle_snmp_report( + #pdu{error_status = EStatus, + error_index = EIndex, + varbinds = Varbinds} = Pdu, + Domain, Addr, State) -> - ?vtrace("handle_snmp_report -> entry with" - "~n Addr: ~p" - "~n Port: ~p" - "~n Pdu: ~p", [Addr, Port, Pdu]), + ?vtrace("handle_snmp_report -> entry with~n" + " Domain: ~p~n" + " Addr: ~p~n" + " Pdu: ~p", [Domain, Addr, Pdu]), Varbinds2 = fix_vbs_BITS(Varbinds), SnmpReport = {EStatus, EIndex, Varbinds2}, - case snmpm_config:get_agent_user_info(Addr, Port) of + case snmpm_config:get_agent_user_info(Domain, Addr) of {ok, UserId, Target, RegType} -> case snmpm_config:user_info(UserId) of {ok, Mod, Data} -> @@ -2620,7 +2647,7 @@ handle_snmp_report(#pdu{error_status = EStatus, "~n ~p" "~n ~p", [UserId, Mod, Target, SnmpReport]), handle_report(UserId, Mod, - RegType, Target, Addr, Port, + RegType, Target, Domain, Addr, SnmpReport, Data, State); Error1 -> %% User no longer exists, unregister agent @@ -2633,7 +2660,7 @@ handle_snmp_report(#pdu{error_status = EStatus, case snmpm_config:user_info() of {ok, DefUserId, DefMod, DefData} -> handle_agent(DefUserId, DefMod, - Addr, Port, + Domain, Addr, report, ignore, SnmpReport, DefData, State); @@ -2641,7 +2668,7 @@ handle_snmp_report(#pdu{error_status = EStatus, error_msg("failed retreiving the default " "user info handling report from " "~p <~p,~p>: ~n~w~n~w", - [Target, Addr, Port, + [Target, Domain, Addr, Error2, Pdu]) end; Error3 -> @@ -2652,7 +2679,7 @@ handle_snmp_report(#pdu{error_status = EStatus, "user ~p, handling report: " "~n Error: ~w" "~n Report: ~w", - [Target, Addr, Port, UserId, + [Target, Domain, Addr, UserId, Error3, Pdu]) end end; @@ -2660,25 +2687,25 @@ handle_snmp_report(#pdu{error_status = EStatus, Error4 -> %% Unknown agent, pass it on to the default user ?vlog("[report] failed retreiving user id for agent <~p,~p>: " - "~n ~p", [Addr, Port, Error4]), + "~n ~p", [Domain, Addr, Error4]), case snmpm_config:user_info() of {ok, DefUserId, DefMod, DefData} -> handle_agent(DefUserId, DefMod, - Addr, Port, + Domain, Addr, report, ignore, SnmpReport, DefData, State); Error5 -> error_msg("failed retreiving " "the default user info handling report from " "<~p,~p>: ~n~w~n~w", - [Addr, Port, Error5, Pdu]) + [Domain, Addr, Error5, Pdu]) end end, ok; -handle_snmp_report(CrapReport, Addr, Port, _State) -> +handle_snmp_report(CrapReport, Domain, Addr, _State) -> error_msg("received crap (snmp) report from ~w:~w =>" - "~p", [Addr, Port, CrapReport]), + "~p", [Domain, Addr, CrapReport]), ok. %% This could be from a failed get-request, so we might have a user @@ -2686,20 +2713,20 @@ handle_snmp_report(CrapReport, Addr, Port, _State) -> %% get-response (except for tha data which is different). Otherwise, %% we handle it as an error (reported via the handle_error callback %% function). -handle_snmp_report(ReqId, - #pdu{error_status = EStatus, - error_index = EIndex, - varbinds = Varbinds} = Pdu, - {ReportReason, Info} = Rep, - Addr, Port, State) - when is_integer(ReqId) -> - - ?vtrace("handle_snmp_report -> entry with" - "~n Addr: ~p" - "~n Port: ~p" - "~n ReqId: ~p" - "~n Rep: ~p" - "~n Pdu: ~p", [Addr, Port, ReqId, Rep, Pdu]), +handle_snmp_report( + ReqId, + #pdu{error_status = EStatus, + error_index = EIndex, + varbinds = Varbinds} = Pdu, + {ReportReason, Info} = Rep, + Domain, Addr, State) when is_integer(ReqId) -> + + ?vtrace("handle_snmp_report -> entry with~n" + " Domain: ~p~n" + " Addr: ~p~n" + " ReqId: ~p~n" + " Rep: ~p~n" + " Pdu: ~p", [Domain, Addr, ReqId, Rep, Pdu]), Varbinds2 = fix_vbs_BITS(Varbinds), SnmpReport = {EStatus, EIndex, Varbinds2}, @@ -2744,7 +2771,7 @@ handle_snmp_report(ReqId, %% Either not a sync request or no such request. Either %% way, this is error info, so handle it as such. - case snmpm_config:get_agent_user_id(Addr, Port) of + case snmpm_config:get_agent_user_id(Domain, Addr) of {ok, UserId} -> case snmpm_config:user_info(UserId) of {ok, Mod, Data} -> @@ -2768,7 +2795,7 @@ handle_snmp_report(ReqId, "default user " "info handling report from " "<~p,~p>: ~n~w~n~w~n~w", - [Addr, Port, Error, + [Domain, Addr, Error, ReqId, Reason]) end end; @@ -2776,7 +2803,7 @@ handle_snmp_report(ReqId, %% Unknown agent, pass it on to the default user ?vlog("[report] failed retreiving user id for " "agent <~p,~p>: " - "~n ~p", [Addr, Port, Error]), + "~n ~p", [Domain, Addr, Error]), case snmpm_config:user_info() of {ok, DefUserId, DefMod, DefData} -> handle_error(DefUserId, DefMod, Reason, ReqId, @@ -2786,32 +2813,36 @@ handle_snmp_report(ReqId, "the default user info handling " "report from " "<~p,~p>: ~n~w~n~w~n~w", - [Addr, Port, Error, ReqId, Reason]) + [Domain, Addr, Error, ReqId, Reason]) end end end, ok; -handle_snmp_report(CrapReqId, CrapReport, CrapInfo, Addr, Port, _State) -> - error_msg("received crap (snmp) report from ~w:~w =>" - "~n~p~n~p~n~p", [Addr, Port, CrapReqId, CrapReport, CrapInfo]), +handle_snmp_report(CrapReqId, CrapReport, CrapInfo, Domain, Addr, _State) -> + error_msg( + "received crap (snmp) report from ~w:~w =>" + "~n~p~n~p~n~p", + [Domain, Addr, CrapReqId, CrapReport, CrapInfo]), ok. -handle_report(UserId, Mod, RegType, Target, Addr, Port, +handle_report(UserId, Mod, RegType, Target, Domain, Addr, SnmpReport, Data, State) -> ?vtrace("handle_report -> entry with" "~n UserId: ~p" "~n Mod: ~p", [UserId, Mod]), F = fun() -> - do_handle_report(UserId, Mod, RegType, Target, Addr, Port, - SnmpReport, Data, State) + do_handle_report( + UserId, Mod, RegType, Target, Domain, Addr, + SnmpReport, Data, State) end, handle_callback(F), ok. -do_handle_report(UserId, Mod, - RegType, Target, Addr, Port, SnmpReport, Data, _State) -> +do_handle_report( + UserId, Mod, RegType, Target, Domain, Addr, + SnmpReport, Data, _State) -> ?vdebug("do_handle_report -> entry with" "~n UserId: ~p", [UserId]), {HandleReport, CallbackArgs} = @@ -2820,8 +2851,9 @@ do_handle_report(UserId, Mod, {fun() -> Mod:handle_report(Target, SnmpReport, Data) end, [Target, SnmpReport, Data]}; addr_port -> - {fun() -> Mod:handle_report(Addr, Port, SnmpReport, Data) end, - [Addr, Port, SnmpReport, Data]} + {Ip, Port} = Addr, + {fun() -> Mod:handle_report(Ip, Port, SnmpReport, Data) end, + [Ip, Port, SnmpReport, Data]} end, try HandleReport() of @@ -2831,17 +2863,18 @@ do_handle_report(UserId, Mod, "~n Config: ~p", [UserId2, Config]), %% The only user which would do this is the %% default user - Target2 = mk_target_name(Addr, Port, Config), - Config2 = [{reg_type, target_name}, - {address, Addr}, {port, Port} | Config], + Target2 = mk_target_name(Domain, Addr, Config), + Config2 = + [{reg_type, target_name}, + {tdomain, Domain}, {taddress, Addr} | Config], case snmpm_config:register_agent(UserId2, Target2, Config2) of ok -> ok; {error, Reason} -> error_msg("failed registering agent " "handling report " - "<~p,~p>: ~n~w", - [Addr, Port, Reason]), + "<~p,~p>: ~n~w", + [Domain, Addr, Reason]), ok end; @@ -2860,21 +2893,20 @@ do_handle_report(UserId, Mod, error_msg("failed registering agent " "handling report " "~p <~p,~p>: ~n~w", - [Target2, Addr, Port, Reason]), + [Target2, Domain, Addr, Reason]), reply end; unregister -> ?vtrace("do_handle_trap -> unregister", []), - case snmpm_config:unregister_agent(UserId, - Addr, Port) of + case snmpm_config:unregister_agent(UserId, Domain, Addr) of ok -> ok; {error, Reason} -> error_msg("failed unregistering agent " "handling report " "<~p,~p>: ~n~w", - [Addr, Port, Reason]), + [Domain, Addr, Reason]), ok end; @@ -3012,50 +3044,49 @@ do_gc(Key, Now) -> %% %%---------------------------------------------------------------------- -send_get_request(Oids, Vsn, MsgData, Domain, Addr, Port, ExtraInfo, +send_get_request(Oids, Vsn, MsgData, Domain, Addr, ExtraInfo, #state{net_if = NetIf, net_if_mod = Mod, mini_mib = MiniMIB}) -> Pdu = make_pdu(get, Oids, MiniMIB), - ?vtrace("send_get_request -> send get-request:" - "~n Mod: ~p" - "~n NetIf: ~p" - "~n Pdu: ~p" - "~n Vsn: ~p" - "~n MsgData: ~p" - "~n Domain: ~p" - "~n Addr: ~p" - "~n Port: ~p", - [Mod, NetIf, Pdu, Vsn, MsgData, Domain, Addr, Port]), + ?vtrace("send_get_request -> send get-request:~n" + " Mod: ~p~n" + " NetIf: ~p~n" + " Pdu: ~p~n" + " Vsn: ~p~n" + " MsgData: ~p~n" + " Domain: ~p~n" + " Addr: ~p", + [Mod, NetIf, Pdu, Vsn, MsgData, Domain, Addr]), Res = (catch Mod:send_pdu(NetIf, Pdu, Vsn, MsgData, - Domain, Addr, Port, ExtraInfo)), + Domain, Addr, ExtraInfo)), ?vtrace("send_get_request -> send result:" "~n ~p", [Res]), Pdu#pdu.request_id. -send_get_next_request(Oids, Vsn, MsgData, Domain, Addr, Port, ExtraInfo, +send_get_next_request(Oids, Vsn, MsgData, Domain, Addr, ExtraInfo, #state{mini_mib = MiniMIB, net_if = NetIf, net_if_mod = Mod}) -> Pdu = make_pdu(get_next, Oids, MiniMIB), - Mod:send_pdu(NetIf, Pdu, Vsn, MsgData, Domain, Addr, Port, ExtraInfo), + Mod:send_pdu(NetIf, Pdu, Vsn, MsgData, Domain, Addr, ExtraInfo), Pdu#pdu.request_id. -send_get_bulk_request(Oids, Vsn, MsgData, Domain, Addr, Port, +send_get_bulk_request(Oids, Vsn, MsgData, Domain, Addr, NonRep, MaxRep, ExtraInfo, #state{mini_mib = MiniMIB, net_if = NetIf, net_if_mod = Mod}) -> Pdu = make_pdu(bulk, {NonRep, MaxRep, Oids}, MiniMIB), - Mod:send_pdu(NetIf, Pdu, Vsn, MsgData, Domain, Addr, Port, ExtraInfo), + Mod:send_pdu(NetIf, Pdu, Vsn, MsgData, Domain, Addr, ExtraInfo), Pdu#pdu.request_id. -send_set_request(VarsAndVals, Vsn, MsgData, Domain, Addr, Port, ExtraInfo, +send_set_request(VarsAndVals, Vsn, MsgData, Domain, Addr, ExtraInfo, #state{mini_mib = MiniMIB, net_if = NetIf, net_if_mod = Mod}) -> Pdu = make_pdu(set, VarsAndVals, MiniMIB), - Mod:send_pdu(NetIf, Pdu, Vsn, MsgData, Domain, Addr, Port, ExtraInfo), + Mod:send_pdu(NetIf, Pdu, Vsn, MsgData, Domain, Addr, ExtraInfo), Pdu#pdu.request_id. %% send_discovery(Vsn, MsgData, Addr, Port, ExtraInfo, @@ -3291,10 +3322,9 @@ agent_data(TargetName, SendOpts) -> {Comm, SecModel} end, Domain = agent_data_item(tdomain, TargetName), - Addr = agent_data_item(address, TargetName), - Port = agent_data_item(port, TargetName), + Addr = agent_data_item(taddress, TargetName), RegType = agent_data_item(reg_type, TargetName), - {ok, RegType, Domain, Addr, Port, version(Version), MsgData}; + {ok, RegType, Domain, Addr, version(Version), MsgData}; Error -> Error end. @@ -3440,9 +3470,9 @@ maybe_demonitor(MonRef) -> t() -> {A,B,C} = erlang:now(), A*1000000000+B*1000+(C div 1000). - -mk_target_name(Addr, Port, Config) -> - snmpm_config:mk_target_name(Addr, Port, Config). + +mk_target_name(Domain, Addr, Config) -> + snmpm_config:mk_target_name(Domain, Addr, Config). default_agent_config() -> case snmpm_config:agent_info() of diff --git a/lib/snmp/src/manager/snmpm_user.erl b/lib/snmp/src/manager/snmpm_user.erl index e6b0b6943e..8e5a874f77 100644 --- a/lib/snmp/src/manager/snmpm_user.erl +++ b/lib/snmp/src/manager/snmpm_user.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2013. All Rights Reserved. +%% Copyright Ericsson AB 2004-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -39,20 +39,25 @@ %% *** handle_error *** %% An "asynchronous" error has been detected --callback handle_error(ReqId :: integer(), - Reason :: {unexpected_pdu, SnmpInfo :: snmp_gen_info()} | - {invalid_sec_info, SecInfo :: term(), SnmpInfo :: snmp_gen_info()} | - {empty_message, Addr :: ip_address(), Port :: port_number()} | - term(), - UserData :: term()) -> +-callback handle_error( + ReqId :: integer(), + Reason :: {unexpected_pdu, SnmpInfo :: snmp_gen_info()} | + {invalid_sec_info, + SecInfo :: term(), + SnmpInfo :: snmp_gen_info()} | + {empty_message, + TransportDomain :: atom(), + {Addr :: ip_address(), Port :: port_number()}} | + term(), + UserData :: term()) -> snmp:void(). %% *** handle_agent *** %% A message was received from an unknown agent --callback handle_agent(Addr :: term(), - Port :: pos_integer(), +-callback handle_agent(Domain :: atom(), + Address :: term(), Type :: pdu | trap | inform | report, SnmpInfo :: snmp_gen_info() | snmp_v1_trap_info(), UserData :: term()) -> diff --git a/lib/snmp/src/manager/snmpm_user_default.erl b/lib/snmp/src/manager/snmpm_user_default.erl index 015198cb76..b827713f27 100644 --- a/lib/snmp/src/manager/snmpm_user_default.erl +++ b/lib/snmp/src/manager/snmpm_user_default.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2013. All Rights Reserved. +%% Copyright Ericsson AB 2004-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -36,13 +36,13 @@ handle_error(ReqId, Reason, UserData) -> ignore. -handle_agent(Addr, Port, Type, SnmpInfo, UserData) -> - info("received handle_agent:" - "~n Addr: ~p" - "~n Port: ~p" - "~n Type: ~p" - "~n SnmpInfo: ~p" - "~n UserData: ~p", [Addr, Port, Type, SnmpInfo, UserData]), +handle_agent(Domain, Address, Type, SnmpInfo, UserData) -> + info("received handle_agent:~n" + " Domain: ~p~n" + " Address: ~p~n" + " Type: ~p~n" + " SnmpInfo: ~p~n" + " UserData: ~p", [Domain, Address, Type, SnmpInfo, UserData]), ignore. diff --git a/lib/snmp/src/misc/snmp_conf.erl b/lib/snmp/src/misc/snmp_conf.erl index 46625989d5..f4483995cb 100644 --- a/lib/snmp/src/misc/snmp_conf.erl +++ b/lib/snmp/src/misc/snmp_conf.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2013. All Rights Reserved. +%% Copyright Ericsson AB 1996-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -25,35 +25,42 @@ %% External exports %% Avoid warning for local function error/1 clashing with autoimported BIF. -compile({no_auto_import,[error/1]}). --export([read_files/2, read/2]). +-export([read_files/2, no_gen/2, no_order/2, no_filter/1, keyorder/4]). +-export([read/2, read/3]). %% Basic (type) check functions -export([check_mandatory/2, check_integer/1, check_integer/2, - + check_string/1, check_string/2, - check_atom/2, + check_atom/2, check_timer/1, - all_domains/0, - check_domain/1, - all_tdomains/0, - check_tdomain/1, - mk_tdomain/1, - which_domain/1, - check_ip/1, check_ip/2, - check_taddress/1, check_taddress/2, - mk_taddress/3, - - check_packet_size/1, + all_domains/0, + check_domain/1, + domain_to_name/1, + all_tdomains/0, + check_tdomain/1, + mk_tdomain/0, mk_tdomain/1, + tdomain_to_family/1, tdomain_to_domain/1, + which_domain/1, + mk_addr_string/1, + check_ip/1, check_ip/2, + check_port/1, +%% ip_port_to_domaddr/2, + check_address/2, check_address/3, + check_taddress/2, + mk_taddress/1, mk_taddress/2, + + check_packet_size/1, check_oid/1, - check_imask/1, check_emask/1, - - check_mp_model/1, - check_sec_model/1, check_sec_model/2, check_sec_model/3, + check_imask/1, check_emask/1, + + check_mp_model/1, + check_sec_model/1, check_sec_model/2, check_sec_model/3, check_sec_level/1, all_integer/1 @@ -70,17 +77,53 @@ -include("snmp_verbosity.hrl"). +-define(is_word(P), (((P) band (bnot 65535)) =:= 0)). +-define(is_word(P0, P1), ((((P0) bor (P1)) band (bnot 255)) =:= 0)). + +mk_word(B0, B1) -> ((B0) bsl 8) bor (B1). +mk_bytes(W) -> [(W) bsr 8,(W) band 255]. + +-define( + is_ipv4_addr(A0, A1, A2, A3), + ((((A0) bor (A1) bor (A2) bor (A3)) band (bnot 255)) =:= 0)). + +-define( + is_ipv6_addr(A0, A1, A2, A3, A4, A5, A6, A7), + ((((A0) bor (A1) bor (A2) bor (A3) bor (A4) bor (A5) bor (A6) bor (A7)) + band (bnot 65535)) =:= 0)). +-define( + is_ipv6_addr( + A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15), + ((((A0) bor (A1) bor (A2) bor (A3) bor + (A4) bor (A5) bor (A6) bor (A7) bor + (A8) bor (A9) bor (A10) bor (A11) bor + (A12) bor (A13) bor (A14) bor (A15)) + band (bnot 65535)) =:= 0)). + + %%----------------------------------------------------------------- %% read_files(Dir, Files) -> Configs %% Dir - string() - Full path to the config dir. -%% Files - [{Gen, Filter, Check, FileName}] +%% Files - [{FileName, Gen, Order, Check, Filter}] +%% FileName - string() - Name of the config file. %% Gen - function/2 - In case of failure when reading the config file, %% this function is called to either generate a %% default file or issue the error. -%% Filter - function/1 - Filters all the config entries read from the file -%% Check - function/1 - Check each entry as they are read from the file. -%% FileName - string() - Name of the config file. +%% Returns a generated config list corresponding +%% to the written file. +%% (Dir, Error) -> Configs. +%% Order - function/2 - An ordering function that is used to process +%% the read config entries using lists:sort/2. +%% Returns true if arg 1 compares less than or +%% equal to arg 2, false otherwise. +%% Check - function/2 - Check each entry as they are read from the file. +%% (Entry, State) -> +%% {ok,NewState} | {{ok,NewEntry},NewState} | +%% throw(Error) +%% State =:= 'undefined' the first time. +%% Filter - function/1 - Process all the config entries read from the file +%% (Configs) -> [config_entry()]. %% Configs - [config_entry()] %% config_entry() - term() @@ -89,99 +132,143 @@ read_files(Dir, Files) when is_list(Dir) andalso is_list(Files) -> read_files(_Dir, [], Res) -> lists:reverse(Res); -read_files(Dir, [{Gen, Filter, Check, FileName}|Files], Res) - when is_function(Filter) andalso - is_function(Check) andalso - is_list(FileName) -> - ?vdebug("read_files -> entry with" - "~n FileName: ~p", [FileName]), +read_files(Dir, [{FileName, Gen, Order, Check, Filter}|Files], Res) + when is_list(FileName), + is_function(Gen), + is_function(Order), + is_function(Check), + is_function(Filter) -> + ?vdebug("read_files -> entry with~n" + " FileName: ~p", [FileName]), File = filename:join(Dir, FileName), - case file:read_file_info(File) of - {ok, _} -> - Confs = read(File, Check), - read_files(Dir, Files, [Filter(Confs)|Res]); - {error, R} -> - ?vlog("failed reading file info for ~s: " - "~n ~p", [FileName, R]), - Gen(Dir, R), - read_files(Dir, Files, [Filter([])|Res]) - end. - + Confs = + case file:read_file_info(File) of + {ok,_} -> + read(File, Order, Check); + {error, R} -> + ?vlog("failed reading file info for ~s: ~n" + " ~p", [FileName, R]), + Gen(Dir, R) + end, + read_files(Dir, Files, [Filter(Confs)|Res]). + + + +no_gen(_Dir, _R) -> []. +no_order(_, _) -> true. +no_filter(X) -> X. + +%% Order tuples on element N with Keys first in appearence order. +%% +%% An ordering function (A, B) shall return true iff +%% A is less than or equal to B i.e shall return +%% false iff A is to be ordered after B. +keyorder(N, A, B, _) when element(N, A) == element(N, B) -> + true; +keyorder(N, A, B, [Key | _]) + when tuple_size(A) >= 1, element(N, B) == Key -> + false; +keyorder(N, A, B, [Key | _]) + when element(N, A) == Key, tuple_size(B) >= 1 -> + true; +keyorder(N, A, B, [_ | Keys]) -> + keyorder(N, A, B, Keys); +keyorder(_, A, B, []) when tuple_size(A) >= 1, tuple_size(B) >= 1 -> + %% Do not order other keys + true; +keyorder(N, A, B, sort) -> + %% Order other keys according to standard sort order + element(N, A) =< element(N, B). + + +read(File, Verify) -> + Check = fun (Row, State) -> {Verify(Row), State} end, + read(File, fun no_order/2, Check). %% Ret. Res | exit(Reason) -read(File, Check) when is_function(Check) -> - ?vdebug("read -> entry with" - "~n File: ~p", [File]), - +read(File, Order, Check) when is_function(Order), is_function(Check) -> + ?vdebug("read -> entry with~n" + " File: ~p", [File]), Fd = open_file(File), + read_fd(File, Order, Check, Fd, 1, []). - case loop(Fd, [], Check, 1, File) of - {error, Reason} -> - file:close(Fd), - error(Reason); - {ok, Res} -> - file:close(Fd), - Res +read_fd(File, Order, Check, Fd, StartLine, Res) -> + case do_read(Fd, "", StartLine) of + {ok, Row, EndLine} -> + ?vtrace("read_fd ->~n" + " Row: ~p~n" + " EndLine: ~p", [Row,EndLine]), + read_fd( + File, Order, Check, Fd, EndLine, + [{StartLine, Row, EndLine}|Res]); + {error, Error, EndLine} -> + ?vtrace("read_fd -> read failure:~n" + " Error: ~p~n" + " EndLine: ~p", [Error,EndLine]), + file:close(Fd), + error({failed_reading, File, StartLine, EndLine, Error}); + {eof, _EndLine} -> + Lines = + lists:sort( + fun ({_, RowA, _}, {_, RowB, _}) -> + Order(RowA, RowB) + end, + lists:reverse(Res)), + ?vtrace("read_fd to read_check ->~n" + " Lines: ~p", [Lines]), + read_check(File, Check, Lines, undefined, []) end. -open_file(File) -> - case file:open(File, [read]) of - {ok, Fd} -> - Fd; - {error, Reason} -> - error({failed_open, File, Reason}) +read_check(_, _, [], _, Res) -> + lists:reverse(Res); +read_check(File, Check, [{StartLine, Row, EndLine}|Lines], State, Res) -> + try Check(Row, State) of + {Rows, NewState} when is_list(Rows) -> + ?vtrace("read_check -> ok:~n" + " Rows: ~p~n", [Rows]), + read_check(File, Check, Lines, NewState, Rows ++ Res); + {ok, NewState} -> + ?vtrace("read_check -> ok", []), + read_check(File, Check, Lines, NewState, [Row | Res]); + {{ok, NewRow}, NewState} -> + ?vtrace("read_check -> ok:~n" + " NewRow: ~p~n", [NewRow]), + read_check(File, Check, Lines, NewState, [NewRow | Res]) + catch + {error, Reason} -> + ?vtrace("read_check -> error:~n" + " Reason: ~p", [Reason]), + error({failed_check, File, StartLine, EndLine, Reason}); + Class:Reason -> + Error = {Class,Reason,erlang:get_stacktrace()}, + ?vtrace("read_check -> failure:~n" + " Error: ~p", [Error]), + error({failed_check, File, StartLine, EndLine, Error}) end. -loop(Fd, Res, Check, StartLine, File) -> - case do_read(Fd, "", StartLine) of - {ok, Row, EndLine} -> - ?vtrace("loop -> " - "~n Row: ~p" - "~n EndLine: ~p", [Row, EndLine]), - case (catch Check(Row)) of - ok -> - ?vtrace("loop -> ok", []), - loop(Fd, [Row | Res], Check, EndLine, File); - {ok, NewRow} -> - ?vtrace("loop -> ok: " - "~n NewRow: ~p", [NewRow]), - loop(Fd, [NewRow | Res], Check, EndLine, File); - {error, Reason} -> - ?vtrace("loop -> check error: " - "~n Reason: ~p", [Reason]), - {error, {failed_check, File, StartLine, EndLine, Reason}}; - Error -> - ?vtrace("loop -> check failure: " - "~n Error: ~p", [Error]), - {error, {failed_check, File, StartLine, EndLine, Error}} - end; - {error, EndLine, Error} -> - ?vtrace("loop -> read failure: " - "~n Error: ~p", [Error]), - {error, {failed_reading, File, StartLine, EndLine, Error}}; - eof -> - {ok, Res} +open_file(File) -> + case file:open(File, [read]) of + {ok, Fd} -> + Fd; + {error, Reason} -> + error({failed_open, File, Reason}) end. - do_read(Io, Prompt, StartLine) -> case io:request(Io, {get_until,Prompt,erl_scan,tokens,[StartLine]}) of - {ok, Toks, EndLine} -> - case erl_parse:parse_term(Toks) of - {ok, Term} -> - {ok, Term, EndLine}; - {error, {Line, erl_parse, Error}} -> - {error, Line, {parse_error, Error}} - end; - {error,E,EndLine} -> - {error, EndLine, E}; - {eof, _EndLine} -> - eof; - Other -> - Other + {ok, Toks, EndLine} -> + case erl_parse:parse_term(Toks) of + {ok, Term} -> + {ok, Term, EndLine}; + {error, {Line, erl_parse, Error}} -> + {error, {parse_error, Error}, Line} + end; + Other -> + Other end. + %%----------------------------------------------------------------- @@ -384,7 +471,7 @@ all_tdomains() -> check_tdomain(TDomain) -> SupportedTDomains = [ - ?snmpUDPDomain, + ?snmpUDPDomain, % Legacy ?transportDomainUdpIpv4, ?transportDomainUdpIpv6 ], @@ -404,6 +491,9 @@ check_tdomain(TDomain) -> %% --------- +mk_tdomain() -> + mk_tdomain(snmpUDPDomain). + mk_tdomain(snmpUDPDomain) -> mk_tdomain(transportDomainUdpIpv4); mk_tdomain(transportDomainUdpIpv4) -> @@ -416,40 +506,64 @@ mk_tdomain(BadDomain) -> %% --------- -check_taddress(X) -> - check_taddress(snmpUDPDomain, X). +tdomain_to_family(snmpUDPDomain) -> + inet; +tdomain_to_family(transportDomainUdpIpv4) -> + inet; +tdomain_to_family(transportDomainUdpIpv6) -> + inet6; +tdomain_to_family(?snmpUDPDomain) -> + inet; +tdomain_to_family(?transportDomainUdpIpv4) -> + inet; +tdomain_to_family(?transportDomainUdpIpv6) -> + inet6; +tdomain_to_family(BadDomain) -> + error({bad_domain, BadDomain}). + + +%% --------- + +tdomain_to_domain(?snmpUDPDomain) -> + snmpUDPDomain; +tdomain_to_domain(?transportDomainUdpIpv4) -> + transportDomainUdpIpv4; +tdomain_to_domain(?transportDomainUdpIpv6) -> + transportDomainUdpIpv6; +tdomain_to_domain(BadTDomain) -> + error({bad_tdomain, BadTDomain}). + + +%% --------- check_taddress(?snmpUDPDomain, X) -> check_taddress(transportDomainUdpIpv4, X); check_taddress(snmpUDPDomain, X) -> check_taddress(transportDomainUdpIpv4, X); - +%% check_taddress(?transportDomainUdpIpv4, X) -> check_taddress(transportDomainUdpIpv4, X); -check_taddress(transportDomainUdpIpv4, X) - when is_list(X) andalso (length(X) =:= 6) -> - case (catch all_integer(X)) of - true -> +check_taddress(transportDomainUdpIpv4, X) -> + case X of + [A0,A1,A2,A3,P0,P1] + when ?is_ipv4_addr(A0, A1, A2, A3), ?is_word(P0, P1) -> ok; - false -> + _ -> error({invalid_taddress, X}) end; -check_taddress(transportDomainUdpIpv4, X) -> - error({invalid_taddress, X}); - +%% check_taddress(?transportDomainUdpIpv6, X) -> check_taddress(transportDomainUdpIpv6, X); -check_taddress(transportDomainUdpIpv6, X) - when is_list(X) andalso (length(X) =:= 10) -> - case (catch all_integer(X)) of - true -> +check_taddress(transportDomainUdpIpv6, X) -> + case X of + [A0,A1,A2,A3,A4,A5,A6,A7,P0,P1] + when ?is_ipv6_addr(A0, A1, A2, A3, A4, A5, A6, A7), + ?is_word(P0, P1) -> ok; - false -> + _ -> error({invalid_taddress, X}) end; -check_taddress(transportDomainUdpIpv6, X) -> - error({invalid_taddress, X}); - +%% check_taddress(BadDomain, _X) -> error({invalid_tdomain, BadDomain}). @@ -512,96 +626,357 @@ all_domains() -> transportDomainSctpDns ]. +check_domain(snmpUDPDomain) -> ok; +check_domain(transportDomainUdpIpv4) -> ok; +check_domain(transportDomainUdpIpv6) -> ok; check_domain(Domain) -> - SupportedDomains = - [ - snmpUDPDomain, - transportDomainUdpIpv4, - transportDomainUdpIpv6 - ], - AllDomains = all_domains(), - case lists:member(Domain, SupportedDomains) of + case lists:member(Domain, all_domains()) of true -> - ok; + error({unsupported_domain, Domain}); false -> - case lists:member(Domain, AllDomains) of - true -> - error({unsupported_domain, Domain}); - false -> - error({unknown_domain, Domain}) - end + error({unknown_domain, Domain}) end. - + +domain_to_name(snmpUDPDomain) -> + undefined; +domain_to_name(transportDomainUdpIpv4) -> + udpIpv4; +domain_to_name(transportDomainUdpIpv6) -> + udpIpv6; +domain_to_name(transportDomainUdpIpv4z) -> + udpIpv4z; +domain_to_name(transportDomainUdpIpv6z) -> + udpIpv6z; +domain_to_name(transportDomainTcpIpv4) -> + tcpIpv4; +domain_to_name(transportDomainTcpIpv6) -> + tcpIpv6; +domain_to_name(transportDomainTcpIpv4z) -> + tcpIpv4z; +domain_to_name(transportDomainTcpIpv6z) -> + tcpIpv6z; +domain_to_name(transportDomainSctpIpv4) -> + sctpIpv4; +domain_to_name(transportDomainSctpIpv6) -> + sctpIpv6; +domain_to_name(transportDomainSctpIpv4z) -> + sctpIpv4z; +domain_to_name(transportDomainSctpIpv6z) -> + sctpIpv6z; +domain_to_name(transportDomainLocal) -> + local; +domain_to_name(transportDomainUdpDns) -> + udpDns; +domain_to_name(transportDomainTcpDns) -> + tcpDns; +domain_to_name(transportDomainSctpDns) -> + sctpDns; +domain_to_name(BadDomain) -> + error({bad_domain, BadDomain}). %% --------- -%% The values of Ip and Port has both been checked at this -%% point, so we dont need to do that again. -mk_taddress(snmpUDPDomain, Ip, Port) -> - mk_taddress(transportDomainUdpIpv4, Ip, Port); -mk_taddress(transportDomainUdpIpv4, Ip, Port) when is_list(Ip) -> - Ip ++ [Port div 256, Port rem 256]; -mk_taddress(transportDomainUdpIpv4 = Domain, Ip, Port) when is_tuple(Ip) -> - mk_taddress(Domain, tuple_to_list(Ip), Port); -mk_taddress(transportDomainUdpIpv6, Ip, Port) when is_list(Ip) -> - Ip ++ [Port div 256, Port rem 256]; -mk_taddress(transportDomainUdpIpv6 = Domain, Ip, Port) when is_tuple(Ip) -> - mk_taddress(Domain, tuple_to_list(Ip), Port); +mk_taddress(Address) -> + mk_taddress(snmpUDPDomain, Address). +%% The values of Domain, Ip and Port has both been checked at this +%% point, so we dont need to do that again, but this function is +%% also used on incoming packets from net_if so a little +%% check that net_if does not supply bad arguments is in order. +%% %% These are just for convenience -mk_taddress(?snmpUDPDomain, Ip, Port) -> - mk_taddress(snmpUDPDomain, Ip, Port); -mk_taddress(?transportDomainUdpIpv4, Ip, Port) -> - mk_taddress(transportDomainUdpIpv4, Ip, Port); -mk_taddress(?transportDomainUdpIpv6, Ip, Port) -> - mk_taddress(transportDomainUdpIpv6, Ip, Port); - +mk_taddress(?snmpUDPDomain, Address) -> + mk_taddress(snmpUDPDomain, Address); +mk_taddress(?transportDomainUdpIpv4, Address) -> + mk_taddress(transportDomainUdpIpv4, Address); +mk_taddress(?transportDomainUdpIpv6, Address) -> + mk_taddress(transportDomainUdpIpv6, Address); +%% +mk_taddress(snmpUDPDomain, Address) -> % Legacy + mk_taddress(transportDomainUdpIpv4, Address); +mk_taddress(transportDomainUdpIpv4 = Domain, Address) -> + case Address of + [] -> % Empty mask + []; + {Ip, Port} when tuple_size(Ip) =:= 4, is_integer(Port) -> + tuple_to_list(Ip) ++ mk_bytes(Port); + _ -> + erlang:error(badarg, [Domain,Address]) + end; +mk_taddress(transportDomainUdpIpv6 = Domain, Address) -> + case Address of + [] -> % Empty mask + []; + {{A, B, C, D, E, F, G, H}, Port} -> + [A bsr 8, A band 255, + B bsr 8, B band 255, + C bsr 8, C band 255, + D bsr 8, D band 255, + E bsr 8, E band 255, + F bsr 8, F band 255, + G bsr 8, G band 255, + H bsr 8, H band 255, + Port bsr 8, Port band 255]; + _ -> + erlang:error(badarg, [Domain,Address]) + end; %% Bad domain -mk_taddress(BadDomain, _Ip, _Port) -> +mk_taddress(BadDomain, _) -> error({bad_domain, BadDomain}). - + %% --------- -which_domain(Ip) when is_list(Ip) andalso (length(Ip) =:= 4) -> +%% XXX remove, when net_if handles one socket per transport domain + +which_domain([A0,A1,A2,A3]) + when ?is_ipv4_addr(A0, A1, A2, A3) -> transportDomainUdpIpv4; -which_domain(Ip) when is_tuple(Ip) andalso (size(Ip) =:= 4) -> +which_domain({A0, A1, A2, A3}) + when ?is_ipv4_addr(A0, A1, A2, A3) -> transportDomainUdpIpv4; -which_domain(Ip) when is_list(Ip) andalso (length(Ip) =:= 8) -> +which_domain([A0,A1,A2,A3,A4,A5,A6,A7]) + when ?is_ipv6_addr(A0, A1, A2, A3, A4, A5, A6, A7) -> + transportDomainUdpIpv6; +which_domain([A0,A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14,A15]) + when ?is_ipv6_addr( + A0, A1, A2, A3, A4, A5, A6, A7, + A8, A9, A10, A11, A12, A13, A14, A15) -> transportDomainUdpIpv6; -which_domain(Ip) when is_tuple(Ip) andalso (size(Ip) =:= 8) -> +which_domain({A0, A1, A2, A3, A4, A5, A6, A7}) + when ?is_ipv6_addr(A0, A1, A2, A3, A4, A5, A6, A7) -> transportDomainUdpIpv6. - %% --------- +mk_addr_string({_IP, Port} = Addr) when is_integer(Port) -> + mk_addr_string({snmpUDPDomain, Addr}); +mk_addr_string({Domain, Addr}) when is_atom(Domain) -> + %% XXX There is only code for IP domains here + case check_address_ip(Domain, Addr) of + false -> + case check_address_ip_port(Domain, Addr) of + false -> + error({bad_address, {Domain, Addr}}); + true -> + {IP, Port} = Addr, + mk_addr_string_ntoa(Domain, IP, Port); + {IP, Port} -> + mk_addr_string_ntoa(Domain, IP, Port) + end; + true -> + mk_addr_string_ntoa(Domain, Addr); + IP -> + mk_addr_string_ntoa(Domain, IP) + end. + + +mk_addr_string_ntoa({_, _, _, _} = IP) -> + inet:ntoa(IP); +mk_addr_string_ntoa(IP) -> + lists:flatten(io_lib:format("[~s]", [inet:ntoa(IP)])). + +mk_addr_string_ntoa(Domain, IP) -> + case domain_to_name(Domain) of + undefined -> + mk_addr_string_ntoa(IP); + Name -> + lists:flatten( + io_lib:format("~w://~s", [Name, mk_addr_string_ntoa(IP)])) + end. + +mk_addr_string_ntoa(Domain, IP, Port) -> + lists:flatten( + io_lib:format( + "~s:~w", [mk_addr_string_ntoa(Domain, IP), Port])). + +%% --------- + check_ip(X) -> check_ip(snmpUDPDomain, X). -check_ip(snmpUDPDomain, X) -> - check_ip(transportDomainUdpIpv4, X); -check_ip(transportDomainUdpIpv4, X) when is_list(X) andalso (length(X) =:= 4) -> - case (catch all_integer(X)) of - true -> +check_ip(Domain, IP) -> + %% XXX There is only code for IP domains here + case check_address_ip(Domain, IP) of + false -> + error({bad_address, {Domain, IP}}); + true -> ok; - false -> - error({invalid_ip_address, X}) - end; -check_ip(transportDomainUdpIpv4, X) -> - error({invalid_ip_address, X}); + FixedIP -> + {ok, FixedIP} + end. -check_ip(transportDomainUdpIpv6, X) when is_list(X) andalso (length(X) =:= 8) -> - case (catch all_integer(X)) of - true -> + +%% --------- + +check_port(Port) when ?is_word(Port) -> + ok; +check_port(Port) -> + error({bad_port, Port}). + +%% ip_port_to_domaddr(IP, Port) when ?is_word(Port) -> +%% %% XXX There is only code for IP domains here +%% case check_address_ip(transportDomainUdpIpv4, IP) of +%% false -> +%% case check_address_ip(transportDomainUdpIpv6, IP) of +%% false -> +%% error({bad_address, {transportDomainUdpIpv4, {IP, Port}}}); +%% true -> +%% {transportDomainUdpIpv6, {IP, Port}}; +%% FixedIP -> +%% {transportDomainUdpIpv6, {FixedIP, Port}} +%% end; +%% true -> +%% {transportDomainUdpIpv4, {IP, Port}}; +%% FixedIP -> +%% {transportDomainUdpIpv4, {FixedIP, Port}} +%% end; +%% ip_port_to_domaddr(IP, Port) -> +%% error({bad_address, {transportDomainUdpIpv4, {IP, Port}}}). + +%% Check a configuration term field from a file to see if it +%% can be fixed to be fed to mk_taddress/2. + +check_address(Domain, Address, DefaultPort) -> + %% If Address does not contain Port or contains Port =:= 0 + %% create an address containing DefaultPort + %% + %% XXX There is only code for IP domains here + case check_address_ip(Domain, Address) of + false -> + case check_address_ip_port(Domain, Address) of + false -> + error({bad_address, {Domain, Address}}); + true -> + case Address of + {IP, 0} -> + {ok, {IP, DefaultPort}}; + _ -> + ok + end; + {FixedIP, 0} -> + {ok, {FixedIP, DefaultPort}}; + FixedAddress -> + {ok, FixedAddress} + end; + true -> + {ok, {Address, DefaultPort}}; + FixedIP -> + {ok, {FixedIP, DefaultPort}} + end. + +check_address(Domain, Address) -> + %% Address has to contain Port + %% + %% XXX There is only code for IP domains here + case check_address_ip_port(Domain, Address) of + false -> + error({bad_address, {Domain, Address}}); + true -> ok; - false -> - error({invalid_ip_address, X}) + FixedAddress -> + {ok, FixedAddress} + end. + +%% -> IP +check_address_ip(Domain, Address) + when Domain =:= snmpUDPDomain; + Domain =:= transportDomainUdpIpv4 -> + case Address of + %% Erlang native format + {A0, A1, A2, A3} + when ?is_ipv4_addr(A0, A1, A2, A3) -> + true; + %% Erlangish format + [A0,A1,A2,A3] + when ?is_ipv4_addr(A0, A1, A2, A3) -> + {A0, A1, A2, A3}; + _ -> + false + end; +check_address_ip(transportDomainUdpIpv6, Address) -> + case Address of + %% Erlang native format + {A0, A1, A2, A3, A4, A5, A6, A7} + when ?is_ipv6_addr(A0, A1, A2, A3, A4, A5, A6, A7) -> + true; + %% Erlangish format + [A0,A1,A2,A3,A4,A5,A6,A7] + when ?is_ipv6_addr(A0, A1, A2, A3, A4, A5, A6, A7) -> + {A0, A1, A2, A3, A4, A5, A6, A7}; + %% SNMP standards format + [A0,A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14,A15] + when ?is_ipv6_addr( + A0, A1, A2, A3, A4, A5, A6, A7, + A8, A9, A10, A11, A12, A13, A14, A15) -> + {mk_word(A0, A1), mk_word(A2, A3), + mk_word(A4, A5), mk_word(A6, A7), + mk_word(A8, A9), mk_word(A10, A11), + mk_word(A12, A13), mk_word(A14, A15)}; + _ -> + false end; -check_ip(transportDomainUdpIpv6, X) -> - error({invalid_ip_address, X}); +check_address_ip(BadDomain, _) -> + error({bad_domain, BadDomain}). -check_ip(BadDomain, _X) -> - error({invalid_domain, BadDomain}). +%% -> {IP, Port} +check_address_ip_port(Domain, Address) + when Domain =:= snmpUDPDomain; + Domain =:= transportDomainUdpIpv4 -> + case Address of + {IP, Port} when ?is_word(Port) -> + case check_address_ip(Domain, IP) of + false -> + false; + true -> + true; + FixedIP -> + {FixedIP, Port} + end; + %% SNMP standards format + [A0,A1,A2,A3,P0,P1] + when ?is_ipv4_addr(A0, A1, A2, A3), ?is_word(P0, P1) -> + {{A0, A1, A2, A3}, mk_word(P0, P1)}; + _ -> + false + end; +check_address_ip_port(transportDomainUdpIpv6 = Domain, Address) -> + case Address of + {IP, Port} when ?is_word(Port) -> + case check_address_ip(Domain, IP) of + false -> + false; + true -> + true; + FixedIP -> + {FixedIP, Port} + end; + %% Erlang friendly list format + [A0,A1,A2,A3,A4,A5,A6,A7,P] + when ?is_ipv6_addr(A0, A1, A2, A3, A4, A5, A6, A7), + ?is_word(P) -> + {{A0, A1, A2, A3, A4, A5, A6, A7}, P}; + %% Strange hybrid format with port as bytes + [A0,A1,A2,A3,A4,A5,A6,A7,P0,P1] + when ?is_ipv6_addr(A0, A1, A2, A3, A4, A5, A6, A7), + ?is_word(P0, P1) -> + {{A0, A1, A2, A3, A4, A5, A6, A7}, mk_word(P0, P1)}; + %% SNMP standards format + [A0,A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14,A15,P0,P1] + when ?is_ipv6_addr( + A0, A1, A2, A3, A4, A5, A6, A7, + A8, A9, A10, A11, A12, A13, A14, A15), + ?is_word(P0, P1) -> + {{mk_word(A0, A1), mk_word(A2, A3), + mk_word(A4, A5), mk_word(A6, A7), + mk_word(A8, A9), mk_word(A10, A11), + mk_word(A12, A13), mk_word(A14, A15)}, + mk_word(P0, P1)}; + _ -> + false + end; +check_address_ip_port(BadDomain, _) -> + error({bad_domain, BadDomain}). diff --git a/lib/snmp/src/misc/snmp_config.erl b/lib/snmp/src/misc/snmp_config.erl index a222f842e5..9e9865f3b5 100644 --- a/lib/snmp/src/misc/snmp_config.erl +++ b/lib/snmp/src/misc/snmp_config.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2013. All Rights Reserved. +%% Copyright Ericsson AB 1996-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -26,16 +26,21 @@ -compile({no_auto_import,[error/1]}). -export([config/0]). --export([write_config_file/4, append_config_file/4, read_config_file/3]). +%%-export([write_config_file/4, append_config_file/4, read_config_file/4]). + +-export([write_config_file/6, append_config_file/6, read_config_file/4]). -export([write_agent_snmp_files/7, write_agent_snmp_files/12, + write_agent_snmp_files/6, write_agent_snmp_files/11, - write_agent_snmp_conf/5, + write_agent_snmp_conf/4, write_agent_snmp_conf/5, write_agent_snmp_context_conf/1, write_agent_snmp_community_conf/1, write_agent_snmp_standard_conf/2, - write_agent_snmp_target_addr_conf/4, - write_agent_snmp_target_addr_conf/6, + write_agent_snmp_target_addr_conf/3, + write_agent_snmp_target_addr_conf/4, + write_agent_snmp_target_addr_conf/5, + write_agent_snmp_target_addr_conf/6, write_agent_snmp_target_params_conf/2, write_agent_snmp_notify_conf/2, write_agent_snmp_usm_conf/5, @@ -90,9 +95,9 @@ ]). --export_type([void/0, - verify_config_entry_function/0, - verify_config_function/0, +-export_type([void/0, + order_config_entry_function/0, + check_config_entry_function/0, write_config_function/0]). @@ -567,11 +572,9 @@ config_agent_snmp(Dir, Vsns) -> end, NT end, - case (catch write_agent_snmp_files(Dir, - Vsns, ManagerIP, TrapUdp, - AgentIP, AgentUDP, - SysName, NotifType, SecType, - Passwd, EngineID, MMS)) of + case (catch write_agent_snmp_files( + Dir, Vsns, ManagerIP, TrapUdp, AgentIP, AgentUDP, SysName, + NotifType, SecType, Passwd, EngineID, MMS)) of ok -> i("~n- - - - - - - - - - - - -"), i("Info: 1. SecurityName \"initial\" has noAuthNoPriv read access~n" @@ -1580,35 +1583,63 @@ remove_newline(Str) -> %% File generation %%====================================================================== +write_agent_snmp_files( + Dir, Vsns, Domain, ManagerAddr, AgentAddr, SysName) + when is_list(Dir), + is_list(Vsns), + is_atom(Domain), + is_list(SysName) -> + write_agent_snmp_files( + Dir, Vsns, Domain, ManagerAddr, AgentAddr, SysName, + trap, none, "", "agentEngine", 484). + %%---------------------------------------------------------------------- %% Dir: string() (ex: "../conf/") %% ManagerIP, AgentIP: [int(),int(),int(),int()] %% TrapUdp, AgentUDP: integer() %% SysName: string() %%---------------------------------------------------------------------- -write_agent_snmp_files(Dir, Vsns, ManagerIP, TrapUdp, - AgentIP, AgentUDP, SysName) - when is_list(Dir) andalso - is_list(Vsns) andalso - is_list(ManagerIP) andalso - is_integer(TrapUdp) andalso - is_list(AgentIP) andalso - is_integer(AgentUDP) andalso +write_agent_snmp_files( + Dir, Vsns, ManagerIP, TrapUDP, AgentIP, AgentUDP, SysName) + when is_list(Dir) andalso + is_list(Vsns) andalso + is_list(ManagerIP) andalso + is_integer(TrapUDP) andalso + is_list(AgentIP) andalso + is_integer(AgentUDP) andalso is_list(SysName) -> - write_agent_snmp_files(Dir, Vsns, ManagerIP, TrapUdp, AgentIP, AgentUDP, - SysName, "trap", none, "", "agentEngine", 484). + write_agent_snmp_files( + Dir, Vsns, ManagerIP, TrapUDP, AgentIP, AgentUDP, SysName, + trap, none, "", "agentEngine", 484). %% %% ----- Agent config files generator functions ----- %% -write_agent_snmp_files(Dir, Vsns, ManagerIP, TrapUdp, AgentIP, AgentUDP, - SysName, NotifType, SecType, Passwd, EngineID, MMS) -> +write_agent_snmp_files( + Dir, Vsns, Domain, ManagerAddr, AgentAddr, SysName, + NotifType, SecType, Passwd, EngineID, MMS) -> + write_agent_snmp_conf(Dir, Domain, AgentAddr, EngineID, MMS), + write_agent_snmp_context_conf(Dir), + write_agent_snmp_community_conf(Dir), + write_agent_snmp_standard_conf(Dir, SysName), + write_agent_snmp_target_addr_conf(Dir, Domain, ManagerAddr, Vsns), + write_agent_snmp_target_params_conf(Dir, Vsns), + write_agent_snmp_notify_conf(Dir, NotifType), + write_agent_snmp_usm_conf(Dir, Vsns, EngineID, SecType, Passwd), + write_agent_snmp_vacm_conf(Dir, Vsns, SecType), + ok. + +write_agent_snmp_files( + Dir, Vsns, ManagerIP, TrapUDP, AgentIP, AgentUDP, SysName, + NotifType, SecType, Passwd, EngineID, MMS) -> + Domain = snmp_target_mib:default_domain(), + ManagerAddr = {ManagerIP, TrapUDP}, write_agent_snmp_conf(Dir, AgentIP, AgentUDP, EngineID, MMS), write_agent_snmp_context_conf(Dir), write_agent_snmp_community_conf(Dir), write_agent_snmp_standard_conf(Dir, SysName), - write_agent_snmp_target_addr_conf(Dir, ManagerIP, TrapUdp, Vsns), + write_agent_snmp_target_addr_conf(Dir, Domain, ManagerAddr, Vsns), write_agent_snmp_target_params_conf(Dir, Vsns), write_agent_snmp_notify_conf(Dir, NotifType), write_agent_snmp_usm_conf(Dir, Vsns, EngineID, SecType, Passwd), @@ -1616,11 +1647,38 @@ write_agent_snmp_files(Dir, Vsns, ManagerIP, TrapUdp, AgentIP, AgentUDP, ok. + %% %% ------ [agent] agent.conf ------ %% -write_agent_snmp_conf(Dir, AgentIP, AgentUDP, EngineID, MMS) -> +write_agent_snmp_conf(Dir, Transports, EngineID, MMS) -> + Conf = + [{intAgentTransports, Transports}, + {snmpEngineID, EngineID}, + {snmpEngineMaxMessageSize, MMS}], + do_write_agent_snmp_conf(Dir, Conf). + +write_agent_snmp_conf(Dir, Domain, AgentAddr, EngineID, MMS) + when is_atom(Domain) -> + {AgentIP, AgentUDP} = AgentAddr, + Conf = + [{intAgentTransportDomain, Domain}, + {intAgentUDPPort, AgentUDP}, + {intAgentIpAddress, AgentIP}, + {snmpEngineID, EngineID}, + {snmpEngineMaxMessageSize, MMS}], + do_write_agent_snmp_conf(Dir, Conf); +write_agent_snmp_conf(Dir, AgentIP, AgentUDP, EngineID, MMS) + when is_integer(AgentUDP) -> + Conf = + [{intAgentUDPPort, AgentUDP}, + {intAgentIpAddress, AgentIP}, + {snmpEngineID, EngineID}, + {snmpEngineMaxMessageSize, MMS}], + do_write_agent_snmp_conf(Dir, Conf). + +do_write_agent_snmp_conf(Dir, Conf) -> Comment = "%% This file defines the Agent local configuration info\n" "%% The data is inserted into the snmpEngine* variables defined\n" @@ -1635,11 +1693,7 @@ write_agent_snmp_conf(Dir, AgentIP, AgentUDP, EngineID, MMS) -> "%% {snmpEngineID, \"agentEngine\"}.\n" "%% {snmpEngineMaxMessageSize, 484}.\n" "%%\n\n", - Hdr = header() ++ Comment, - Conf = [{intAgentUDPPort, AgentUDP}, - {intAgentIpAddress, AgentIP}, - {snmpEngineID, EngineID}, - {snmpEngineMaxMessageSize, MMS}], + Hdr = header() ++ Comment, write_agent_config(Dir, Hdr, Conf). write_agent_config(Dir, Hdr, Conf) -> @@ -1745,17 +1799,19 @@ update_agent_standard_config(Dir, Conf) -> %% ------ target_addr.conf ------ %% -write_agent_snmp_target_addr_conf(Dir, ManagerIp, UDP, Vsns) -> - Timeout = 1500, - RetryCount = 3, - write_agent_snmp_target_addr_conf(Dir, ManagerIp, UDP, - Timeout, RetryCount, - Vsns). +write_agent_snmp_target_addr_conf(Dir, Addresses, Vsns) -> + Timeout = 1500, + RetryCount = 3, + write_agent_snmp_target_addr_conf( + Dir, Addresses, Timeout, RetryCount, Vsns). -write_agent_snmp_target_addr_conf(Dir, ManagerIp, UDP, - Timeout, RetryCount, - Vsns) -> - Comment = +write_agent_snmp_target_addr_conf(Dir, Domain_or_Ip, Addr_or_Port, Vsns) -> + Addresses = [{Domain_or_Ip, Addr_or_Port}], + write_agent_snmp_target_addr_conf(Dir, Addresses, Vsns). + +write_agent_snmp_target_addr_conf( + Dir, Addresses, Timeout, RetryCount, Vsns) -> + Comment = "%% This file defines the target address parameters.\n" "%% The data is inserted into the snmpTargetAddrTable defined\n" "%% in SNMP-TARGET-MIB, and in the snmpTargetAddrExtTable defined\n" @@ -1774,36 +1830,59 @@ write_agent_snmp_target_addr_conf(Dir, ManagerIp, UDP, "%% [127,0,0,0], 2048}.\n" "%%\n\n", Hdr = header() ++ Comment, - F = fun(v1 = Vsn, Acc) -> - [{mk_ip(ManagerIp, Vsn), - snmp_target_mib:default_domain(), - ManagerIp, UDP, Timeout, RetryCount, - "std_trap", mk_param(Vsn), "", [], 2048}| Acc]; - (v2 = Vsn, Acc) -> - [{mk_ip(ManagerIp, Vsn), - snmp_target_mib:default_domain(), - ManagerIp, UDP, Timeout, RetryCount, - "std_trap", mk_param(Vsn), "", [], 2048}, - {lists:flatten(io_lib:format("~s.2",[mk_ip(ManagerIp, Vsn)])), - ManagerIp, UDP, Timeout, RetryCount, - "std_inform", mk_param(Vsn), "", [], 2048}| Acc]; - (v3 = Vsn, Acc) -> - [{mk_ip(ManagerIp, Vsn), - snmp_target_mib:default_domain(), - ManagerIp, UDP, Timeout, RetryCount, - "std_trap", mk_param(Vsn), "", [], 2048}, - {lists:flatten(io_lib:format("~s.3",[mk_ip(ManagerIp, Vsn)])), - ManagerIp, UDP, Timeout, RetryCount, - "std_inform", mk_param(Vsn), "mgrEngine", [], 2048}| Acc] - end, - Conf = lists:foldl(F, [], Vsns), + Conf = + lists:foldl( + fun ({Domain_or_Ip, Addr_or_Port} = Address, OuterAcc) -> + lists:foldl( + fun(v1 = Vsn, Acc) -> + [{mk_name(Address, Vsn), + Domain_or_Ip, Addr_or_Port, + Timeout, RetryCount, + "std_trap", mk_param(Vsn), "", + [], 2048}| Acc]; + (v2 = Vsn, Acc) -> + [{mk_name(Address, Vsn), + Domain_or_Ip, Addr_or_Port, + Timeout, RetryCount, + "std_trap", mk_param(Vsn), "", + [], 2048}, + {lists:flatten( + io_lib:format( + "~s.2", [mk_name(Address, Vsn)])), + Domain_or_Ip, Addr_or_Port, + Timeout, RetryCount, + "std_inform", mk_param(Vsn), "", + [], 2048}| Acc]; + (v3 = Vsn, Acc) -> + [{mk_name(Address, Vsn), + Domain_or_Ip, Addr_or_Port, + Timeout, RetryCount, + "std_trap", mk_param(Vsn), "", + [], 2048}, + {lists:flatten( + io_lib:format( + "~s.3", [mk_name(Address, Vsn)])), + Domain_or_Ip, Addr_or_Port, + Timeout, RetryCount, + "std_inform", mk_param(Vsn), "mgrEngine", + [], 2048} | Acc] + end, OuterAcc, Vsns) + end, [], Addresses), write_agent_target_addr_config(Dir, Hdr, Conf). +write_agent_snmp_target_addr_conf( + Dir, Domain_or_Ip, Addr_or_Port, Timeout, RetryCount, Vsns) -> + Addresses = [{Domain_or_Ip, Addr_or_Port}], + write_agent_snmp_target_addr_conf( + Dir, Addresses, Timeout, RetryCount, Vsns). + mk_param(Vsn) -> lists:flatten(io_lib:format("target_~w", [Vsn])). -mk_ip([A,B,C,D], Vsn) -> - lists:flatten(io_lib:format("~w.~w.~w.~w ~w", [A,B,C,D,Vsn])). +mk_name(Address, Vsn) -> + lists:flatten( + io_lib:format( + "~s ~w", [snmp_conf:mk_addr_string(Address), Vsn])). write_agent_target_addr_config(Dir, Hdr, Conf) -> snmpa_conf:write_target_addr_config(Dir, Hdr, Conf). @@ -2049,10 +2128,19 @@ write_manager_snmp_conf(Dir, IP, Port, MMS, EngineID) -> "%% {max_message_size, 484}.\n" "%%\n\n", Hdr = header() ++ Comment, - Conf = [{port, Port}, - {address, IP}, - {engine_id, EngineID}, - {max_message_size, MMS}], + Conf = + case Port of + {Addr, P} when is_integer(P), is_atom(IP) -> + Domain = IP, + [{domain, Domain}, + {port, P}, + {address, Addr}]; + _ when is_integer(Port) -> + [{port, Port}, + {address, IP}] + end ++ + [{engine_id, EngineID}, + {max_message_size, MMS}], write_manager_config(Dir, Hdr, Conf). write_manager_config(Dir, Hdr, Conf) -> @@ -2410,83 +2498,92 @@ header() -> [?MODULE, ?version, Y, Mo, D, H, Mi, S]). -%% *If* these functions are successfull, they successfully return anything -%% (which is ignored), but they fail with either a throw or an exit or -%% something similar. - -%% Verification of one config entry read from a file --type(verify_config_entry_function() :: - fun((Entry :: term()) -> ok | {error, Reason :: term()})). - -%% Verification of config to be written --type(verify_config_function() :: - fun(() -> void())). - -%% Write config to file (as defined by Fd) --type(write_config_function() :: - fun((Fd :: file:io_device()) -> void())). - --spec write_config_file(Dir :: string(), - FileName :: string(), - Verify :: verify_config_function(), - Write :: write_config_function()) -> - ok | {error, Reason :: term()}. - -write_config_file(Dir, FileName, Verify, Write) - when (is_list(Dir) andalso - is_list(FileName) andalso - is_function(Verify) andalso - is_function(Write)) -> +%% *If* these functions are successfull, they successfully return +%% (value is ignored), but they fail preferably with +%% throw({error, Reason}). Other exceptions are also handled. + +%% Sorting order for config entries (see lists:sort/2) +-type(order_config_entry_function() :: + fun((term(), term()) -> boolean())). + +%% Check of config entries. Initial State is 'undefined' +-type(check_config_entry_function() :: + fun((Entry :: term(), State :: undefined | term()) -> + {ok | {ok, NewEntry :: term()}, NewState :: term()})). + +%% Write configuration entries to file descriptor Fd +-type(write_config_function() :: + fun((Fd :: file:io_device(), [Entry :: term()]) -> ok)). + +-spec write_config_file( + Dir :: string(), + FileName :: string(), + Order :: order_config_entry_function(), + Check :: check_config_entry_function(), + Write :: write_config_function(), + Entries :: [term()]) -> + ok | {error, term()}. + +write_config_file(Dir, FileName, Order, Check, Write, Entries) + when is_list(Dir), is_list(FileName), + is_function(Order), is_function(Check), is_function(Write), + is_list(Entries) -> try - begin - do_write_config_file(Dir, FileName, Verify, Write) - end + SortedEntries = lists:sort(Order, Entries), + _ = + lists:foldl( + fun (Entry, State) -> + case Check(Entry, State) of + {Ok, NewState} when is_list(Ok) -> + NewState; + {ok, NewState} -> + NewState; + {{ok, _}, NewState} -> + NewState + end + end, undefined, SortedEntries), + ok + of + _ -> + case file:open(filename:join(Dir, FileName), [write]) of + {ok, Fd} -> + write_config_file(Dir, FileName, Write, Entries, Fd); + Error -> + Error + end catch - throw:Error -> - Error; - T:E -> - {error, {failed_write, Dir, FileName, T, E}} - end. - - -do_write_config_file(Dir, FileName, Verify, Write) -> - Verify(), - case file:open(filename:join(Dir, FileName), [write]) of - {ok, Fd} -> - file_write_and_close(Write, Fd, Dir, FileName); Error -> - Error - end. - -append_config_file(Dir, FileName, Verify, Write) - when (is_list(Dir) andalso - is_list(FileName) andalso - is_function(Verify) andalso - is_function(Write)) -> - try - begin - do_append_config_file(Dir, FileName, Verify, Write) - end - catch - throw:Error -> + S = erlang:get_stacktrace(), + d("File write of ~s throwed: ~p~n ~p~n", + [FileName, Error, S]), Error; - T:E -> - {error, {failed_append, Dir, FileName, T, E}} + C:E -> + S = erlang:get_stacktrace(), + d("File write of ~s exception: ~p:~p~n ~p~n", + [FileName,C,E,S]), + {error, {failed_write, Dir, FileName, {C, E, S}}} end. -do_append_config_file(Dir, FileName, Verify, Write) -> - Verify(), - case file:open(filename:join(Dir, FileName), [read, write]) of - {ok, Fd} -> - file:position(Fd, eof), - file_write_and_close(Write, Fd, Dir, FileName); +write_config_file(Dir, FileName, Write, Entries, Fd) -> + try Write(Fd, Entries) of + ok -> + close_config_file(Dir, FileName, Fd) + catch Error -> - Error + S = erlang:get_stacktrace(), + d("File write of ~s throwed: ~p~n ~p~n", + [FileName, Error, S]), + close_config_file(Dir, FileName, Fd), + Error; + C:E -> + S = erlang:get_stacktrace(), + d("File write of ~s exception: ~p:~p~n ~p~n", + [FileName,C,E,S]), + close_config_file(Dir, FileName, Fd), + {error, {failed_write, Dir, FileName, {C, E, S}}} end. - -file_write_and_close(Write, Fd, Dir, FileName) -> - ok = Write(Fd), +close_config_file(Dir, FileName, Fd) -> case file:sync(Fd) of ok -> case file:close(Fd) of @@ -2496,63 +2593,159 @@ file_write_and_close(Write, Fd, Dir, FileName) -> {error, {failed_closing, Dir, FileName, Reason}} end; {error, Reason} -> + _ = file:close(Fd), {error, {failed_syncing, Dir, FileName, Reason}} end. --spec read_config_file(Dir :: string(), - FileName :: string(), - Verify :: verify_config_entry_function()) -> - {ok, Config :: list()} | {error, Reason :: term()}. -read_config_file(Dir, FileName, Verify) - when is_list(Dir) andalso is_list(FileName) andalso is_function(Verify) -> - (catch do_read_config_file(Dir, FileName, Verify)). +-spec append_config_file( + Dir :: string(), + FileName :: string(), + Order :: order_config_entry_function(), + Check :: check_config_entry_function(), + Write :: write_config_function(), + Entries :: [term()]) -> + ok | {error, term()}. + +append_config_file(Dir, FileName, Order, Check, Write, Entries) + when is_list(Dir), is_list(FileName), + is_function(Order), is_function(Check), is_function(Write), + is_list(Entries) -> + case file:open(filename:join(Dir, FileName), [read, write]) of + {ok, Fd} -> + append_config_file( + Dir, FileName, Order, Check, Write, Entries, Fd); + Error -> + Error + end. + +append_config_file(Dir, FileName, Order, Check, Write, Entries, Fd) -> + try + %% Verify the entries together with the file content + LinesInFileR = read_lines(Fd, [], 1), + StartLine = + case LinesInFileR of + [] -> + 1; + [{_, _, EndLine} | _] -> + EndLine + end, + LinesR = prepend_lines(LinesInFileR, Entries, StartLine), + SortedLines = sort_lines(lists:reverse(LinesR), Order), + _ = verify_lines(SortedLines, Check, undefined, []), + %% Append to the file + Write(Fd, Entries) + of + ok -> + close_config_file(Dir, FileName, Fd) + catch + Error -> + S = erlang:get_stacktrace(), + d("File append of ~s throwed: ~p~n ~p~n", + [FileName, Error, S]), + close_config_file(Dir, FileName, Fd), + Error; + C:E -> + S = erlang:get_stacktrace(), + d("File append of ~s exception: ~p:~p~n ~p~n", + [FileName,C,E,S]), + close_config_file(Dir, FileName, Fd), + {error, {failed_append, Dir, FileName, {C, E, S}}} + end. -do_read_config_file(Dir, FileName, Verify) -> +%% Fake line numbers, one per entry +prepend_lines(Lines, [], _) -> + Lines; +prepend_lines(Lines, [Entry | Entries], StartLine) -> + EndLine = StartLine + 1, + prepend_lines([{StartLine, Entry, EndLine} | Lines], Entries, EndLine). + + + +-spec read_config_file( + Dir :: string(), + FileName :: string(), + Order :: order_config_entry_function(), + Check :: check_config_entry_function()) -> + {ok, Config :: [Entry :: term()]} | + {error, Reason :: term()}. + +read_config_file(Dir, FileName, Order, Check) + when is_list(Dir), is_list(FileName), + is_function(Order), is_function(Check) -> case file:open(filename:join(Dir, FileName), [read]) of {ok, Fd} -> - Result = read_loop(Fd, [], Verify, 1), - file:close(Fd), - Result; + try + Lines = lists:reverse(read_lines(Fd, [], 1)), + SortedLines = sort_lines(Lines, Order), + {ok, verify_lines(SortedLines, Check, undefined, [])} + catch + Error -> + S = erlang:get_stacktrace(), + d("File read of ~s throwed: ~p~n ~p~n", + [FileName, Error, S]), + {error, Error}; + T:E -> + S = erlang:get_stacktrace(), + d("File read of ~s exception: ~p:~p~n ~p~n", + [FileName,T,E,S]), + {error, {failed_read, Dir, FileName, {T, E, S}}} + after + file:close(Fd) + end; {error, Reason} -> {error, {Reason, FileName}} end. -read_loop(Fd, Acc, Check, StartLine) -> - case read_term(Fd, StartLine) of +read_lines(Fd, Acc, StartLine) -> + case read_and_parse_term(Fd, StartLine) of {ok, Term, EndLine} -> - case (catch Check(Term)) of - ok -> - read_loop(Fd, [Term | Acc], Check, EndLine); - {error, Reason} -> - {error, {failed_check, StartLine, EndLine, Reason}}; - Error -> - {error, {failed_check, StartLine, EndLine, Error}} - end; - {error, EndLine, Error} -> - {error, {failed_reading, StartLine, EndLine, Error}}; - eof -> - {ok, lists:reverse(Acc)} + read_lines(Fd, [{StartLine, Term, EndLine}|Acc], EndLine); + {error, Error, EndLine} -> + throw({failed_reading, StartLine, EndLine, Error}); + {eof, _EndLine} -> + Acc end. - -read_term(Fd, StartLine) -> + +read_and_parse_term(Fd, StartLine) -> case io:request(Fd, {get_until, "", erl_scan, tokens, [StartLine]}) of {ok, Tokens, EndLine} -> case erl_parse:parse_term(Tokens) of {ok, Term} -> {ok, Term, EndLine}; {error, {Line, erl_parse, Error}} -> - {error, Line, {parse_error, Error}} + {error, {parse_error, Error}, Line} end; - {error, E, EndLine} -> - {error, EndLine, E}; - {eof, _EndLine} -> - eof; Other -> Other end. +sort_lines(Lines, Order) -> + lists:sort( + fun ({_, T1, _}, {_, T2, _}) -> + Order(T1, T2) + end, Lines). + +verify_lines([], _, _, Acc) -> + lists:reverse(Acc); +verify_lines( + [{StartLine, Term, EndLine}|Lines], Check, State, Acc) -> + try Check(Term, State) of + {Terms, NewState} when is_list(Terms) -> + verify_lines(Lines, Check, NewState, Terms ++ Acc); + {ok, NewState} -> + verify_lines(Lines, Check, NewState, [Term|Acc]); + {{ok, NewTerm}, NewState} -> + verify_lines(Lines, Check, NewState, [NewTerm|Acc]) + catch + {error, Reason} -> + throw({failed_check, StartLine, EndLine, Reason}); + C:R -> + S = erlang:get_stacktrace(), + throw({failed_check, StartLine, EndLine, {C, R, S}}) + end. + agent_snmp_mk_secret(Alg, Passwd, EngineID) -> snmp_usm:passwd2localized_key(Alg, Passwd, EngineID). @@ -2575,8 +2768,8 @@ ensure_started(App) -> %% ------------------------------------------------------------------------- -% d(F, A) -> -% i("DBG: " ++ F, A). +d(F, A) -> + i("DBG: " ++ F, A). i(F) -> i(F, []). diff --git a/lib/snmp/src/misc/snmp_log.erl b/lib/snmp/src/misc/snmp_log.erl index ae28df37fa..4b22281b89 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-2012. All Rights Reserved. +%% Copyright Ericsson AB 1997-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -23,7 +23,7 @@ -export([ create/4, create/5, create/6, open/1, open/2, change_size/2, close/1, sync/1, info/1, - log/4, + log/3, log/4, log_to_txt/6, log_to_txt/7, log_to_txt/8, log_to_io/5, log_to_io/6, log_to_io/7 ]). @@ -231,7 +231,20 @@ validate(Log, SeqNoReq) validate_seqno(PrevSN, SeqNo), {Timestamp, SeqNo}; - ({Timestamp, _Packet, _Addr, _Port}, {PrevTS, _PrevSN}) when SeqNoReq =:= true -> + ({Timestamp, SeqNo, _Packet, _AddrStr}, {PrevTS, PrevSN}) + when is_integer(SeqNo) -> + ?vtrace("validating log entry when" + "~n Timestamp: ~p" + "~n SeqNo: ~p" + "~n PrevTS: ~p" + "~n PrevSN: ~p", + [Timestamp, SeqNo, PrevTS, PrevSN]), + validate_timestamp(PrevTS, Timestamp), + validate_seqno(PrevSN, SeqNo), + {Timestamp, SeqNo}; + + ({Timestamp, _Packet, _Addr, _Port}, {PrevTS, _PrevSN}) + when SeqNoReq =:= true -> ?vtrace("validating log entry when" "~n Timestamp: ~p" "~n PrevTS: ~p", @@ -344,12 +357,20 @@ validate_loop(Error, _Log, _Write, _PrevTS, _PrevSN) -> %% log(Log, Packet, Addr, Port) %%----------------------------------------------------------------- -log(#snmp_log{id = Log, seqno = SeqNo}, Packet, Addr, Port) -> +log(#snmp_log{id = Log, seqno = SeqNo}, Packet, AddrStr) -> + ?vtrace( + "log -> entry with~n" + " Log: ~p~n" + " AddrStr: ~s", [Log, AddrStr]), + Entry = make_entry(SeqNo, Packet, AddrStr), + disk_log:alog(Log, Entry). + +log(#snmp_log{id = Log, seqno = SeqNo}, Packet, Ip, Port) -> ?vtrace("log -> entry with" "~n Log: ~p" - "~n Addr: ~p" - "~n Port: ~p", [Log, Addr, Port]), - Entry = make_entry(SeqNo, Packet, Addr, Port), + "~n Ip: ~p" + "~n Port: ~p", [Log, Ip, Port]), + Entry = make_entry(SeqNo, Packet, Ip, Port), %% io:format("log -> " %% "~n Entry: ~p" %% "~n Info: ~p" @@ -361,18 +382,35 @@ log(#snmp_log{id = Log, seqno = SeqNo}, Packet, Addr, Port) -> %% "~n", [Res, disk_log:info(Log)]), %% disk_log:sync(Log), Res. - -make_entry(SeqNoGen, Packet, Addr, Port) -> + +make_entry(SeqNoGen, Packet, AddrStr) + when is_integer(Packet); + is_tuple(AddrStr) -> + erlang:error(badarg, [SeqNoGen, Packet, AddrStr]); +make_entry(SeqNoGen, Packet, AddrStr) -> try next_seqno(SeqNoGen) of disabled -> - {timestamp(), Packet, Addr, Port}; - {ok, NextSeqNo} -> - {timestamp(), NextSeqNo, Packet, Addr, Port} + {timestamp(), Packet, AddrStr}; + {ok, NextSeqNo} when is_integer(NextSeqNo) -> + {timestamp(), NextSeqNo, Packet, AddrStr} catch _:_ -> - {timestamp(), Packet, Addr, Port} + {timestamp(), Packet, AddrStr} + end. + +make_entry(SeqNoGen, Packet, Ip, Port) when is_integer(Packet) -> + erlang:error(badarg, [SeqNoGen, Packet, Ip, Port]); +make_entry(SeqNoGen, Packet, Ip, Port) -> + try next_seqno(SeqNoGen) of + disabled -> + {timestamp(), Packet, Ip, Port}; + {ok, NextSeqNo} when is_integer(NextSeqNo) -> + {timestamp(), NextSeqNo, Packet, Ip, Port} + catch + _:_ -> + {timestamp(), Packet, Ip, Port} end. next_seqno({M, F, A}) -> @@ -674,60 +712,68 @@ format_msg(Entry, Mib, Start, Stop) -> end. %% This is an old-style entry, that never had the sequence-number -do_format_msg({Timestamp, Packet, {Addr, Port}}, Mib) -> - do_format_msg(Timestamp, Packet, Addr, Port, Mib); +do_format_msg({Timestamp, Packet, {Ip, Port}}, Mib) -> + do_format_msg(Timestamp, Packet, ipPort2Str(Ip, Port), Mib); +%% This is the format without sequence-number +do_format_msg({Timestamp, Packet, AddrStr}, Mib) -> + do_format_msg(Timestamp, Packet, AddrStr, Mib); +%% This is the format with sequence-number +do_format_msg({Timestamp, SeqNo, Packet, AddrStr}, Mib) + when is_integer(SeqNo) -> + do_format_msg(Timestamp, Packet, AddrStr, Mib); %% This is the format without sequence-number -do_format_msg({Timestamp, Packet, Addr, Port}, Mib) -> - do_format_msg(Timestamp, Packet, Addr, Port, Mib); +do_format_msg({Timestamp, Packet, Ip, Port}, Mib) -> + do_format_msg(Timestamp, Packet, ipPort2Str(Ip, Port), Mib); %% This is the format with sequence-number -do_format_msg({Timestamp, SeqNo, Packet, Addr, Port}, Mib) -> - do_format_msg(Timestamp, SeqNo, Packet, Addr, Port, Mib); +do_format_msg({Timestamp, SeqNo, Packet, Ip, Port}, Mib) -> + do_format_msg(Timestamp, SeqNo, Packet, ipPort2Str(Ip, Port), Mib); %% This is crap... do_format_msg(_, _) -> format_tab("** unknown entry in log file\n\n", []). -do_format_msg(TimeStamp, {V3Hdr, ScopedPdu}, Addr, Port, Mib) -> +do_format_msg(TimeStamp, {V3Hdr, ScopedPdu}, AddrStr, Mib) -> case (catch 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, Addr, Port, Mib); + f(ts2str(TimeStamp), "", Msg, AddrStr, Mib); {'EXIT', Reason} -> - format_tab("** error in log file at ~s from ~p:~w ~p\n\n", - [ts2str(TimeStamp), ip(Addr), Port, Reason]) + format_tab( + "** error in log file at ~s from ~s ~p\n\n", + [ts2str(TimeStamp), AddrStr, Reason]) end; -do_format_msg(TimeStamp, Packet, Addr, Port, Mib) -> +do_format_msg(TimeStamp, Packet, AddrStr, Mib) -> case (catch snmp_pdus:dec_message(binary_to_list(Packet))) of Msg when is_record(Msg, message) -> - f(ts2str(TimeStamp), "", Msg, Addr, Port, Mib); + f(ts2str(TimeStamp), "", Msg, AddrStr, Mib); {'EXIT', Reason} -> format_tab("** error in log file ~p\n\n", [Reason]) end. -do_format_msg(TimeStamp, SeqNo, {V3Hdr, ScopedPdu}, Addr, Port, Mib) -> +do_format_msg(TimeStamp, SeqNo, {V3Hdr, ScopedPdu}, AddrStr, Mib) -> case (catch 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, Addr, Port, Mib); + f(ts2str(TimeStamp), sn2str(SeqNo), Msg, AddrStr, Mib); {'EXIT', Reason} -> - format_tab("** error in log file at ~s from ~p:~w ~p\n\n", - [ts2str(TimeStamp), sn2str(SeqNo), - ip(Addr), Port, Reason]) + format_tab( + "** error in log file at ~s from ~s ~p\n\n", + [ts2str(TimeStamp), sn2str(SeqNo), AddrStr, Reason]) end; -do_format_msg(TimeStamp, SeqNo, Packet, Addr, Port, Mib) -> +do_format_msg(TimeStamp, SeqNo, Packet, AddrStr, Mib) -> case (catch snmp_pdus:dec_message(binary_to_list(Packet))) of Msg when is_record(Msg, message) -> - f(ts2str(TimeStamp), sn2str(SeqNo), Msg, Addr, Port, Mib); + f(ts2str(TimeStamp), sn2str(SeqNo), Msg, AddrStr, Mib); {'EXIT', Reason} -> - format_tab("** error in log file ~s from ~p:~w ~p\n\n", - [ts2str(TimeStamp), sn2str(SeqNo), - ip(Addr), Port, Reason]) + format_tab( + "** error in log file ~s from ~s ~p\n\n", + [ts2str(TimeStamp), sn2str(SeqNo), AddrStr, Reason]) end. @@ -771,44 +817,71 @@ do_format_msg(TimeStamp, SeqNo, Packet, Addr, Port, Mib) -> f(TimeStamp, SeqNo, #message{version = Vsn, vsn_hdr = VsnHdr, data = Data}, - Addr, Port, Mib) -> + AddrStr, 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. + Class = + case get_type(Data) of + trappdu -> + trap; + 'snmpv2-trap' -> + trap; + 'inform-request' -> + inform; + 'get-response' -> + response; + report -> + report; + _ -> + request + 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_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_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]). +%% 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]). -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_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_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]). +%% 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 %% @@ -909,8 +982,10 @@ get_type(#pdu{type = Type}) -> Type. -ip({A,B,C,D}) -> - io_lib:format("~w.~w.~w.~w", [A,B,C,D]). +%% 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]). diff --git a/lib/snmp/src/misc/snmp_pdus.erl b/lib/snmp/src/misc/snmp_pdus.erl index 15156f7467..90fa4c0dea 100644 --- a/lib/snmp/src/misc/snmp_pdus.erl +++ b/lib/snmp/src/misc/snmp_pdus.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2012. All Rights Reserved. +%% Copyright Ericsson AB 1996-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -174,7 +174,7 @@ dec_pdu_tag(168) -> dec_pdu([164 | Bytes]) -> % It's a trap Bytes2 = get_data_bytes(Bytes), {Enterprise, Rest1} = dec_oid_tag(Bytes2), - {{'IpAddress', AgentAddr}, Rest2} = dec_value(Rest1), + {{'IpAddress', [_, _, _, _] = AgentAddr}, Rest2} = dec_value(Rest1), {GenericTrap, Rest3} = dec_int_tag(Rest2), {SpecificTrap, Rest4} = dec_int_tag(Rest3), {{'TimeTicks', TimeStamp}, VBBytes} = dec_value(Rest4), @@ -664,7 +664,9 @@ enc_value('BITS', Val) -> enc_oct_str_tag(bits_to_str(Val)); enc_value('OBJECT IDENTIFIER', Val) -> enc_oid_tag(Val); -enc_value('IpAddress', Val) -> +enc_value('IpAddress', {A, B, C, D}) -> + enc_value('IpAddress', [A,B,C,D]); +enc_value('IpAddress', Val) when is_list(Val) -> Bytes2 = enc_oct_str_notag(Val), Len2 = elength(length(Bytes2)), lists:append([64 | Len2],Bytes2); diff --git a/lib/snmp/test/Makefile b/lib/snmp/test/Makefile index 7bc9dd07d4..a9bbe7fe62 100644 --- a/lib/snmp/test/Makefile +++ b/lib/snmp/test/Makefile @@ -2,7 +2,7 @@ # %CopyrightBegin% # -# Copyright Ericsson AB 1997-2012. All Rights Reserved. +# Copyright Ericsson AB 1997-2014. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -36,7 +36,7 @@ VSN = $(SNMP_VSN) include modules.mk SNMP_ROOT = .. -SNMP_SUITE = snmp_SUITE +SNMP_SUITE = snmp_SUITE ERL_FILES = $(MODULES:%=%.erl) @@ -239,6 +239,7 @@ release_tests_spec: opt $(INSTALL_DATA) $(RELTEST_FILES) $(COVER_SPEC_FILE) "$(RELSYSDIR)" chmod -R u+w "$(RELSYSDIR)" tar cf - snmp_test_data | (cd "$(RELSYSDIR)"; tar xf -) + tar cf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -) release_docs_spec: diff --git a/lib/snmp/test/klas3.erl b/lib/snmp/test/klas3.erl index ec78d19dbb..4cbd852b2d 100644 --- a/lib/snmp/test/klas3.erl +++ b/lib/snmp/test/klas3.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% Copyright Ericsson AB 1997-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -67,11 +67,15 @@ fname(get) -> end, case snmpa:current_address() of {value, {[_A,_B,_C,_D], E}} when is_integer(E) -> ok; - {value, _} -> throw("bad_ip"); - _ -> throw("bad_adr") + {value, {D, _}} when is_atom(D) -> ok; + {value, Ip} -> + throw(format_string("bad_ip: ~p", [Ip])); + Other -> + throw(format_string("bad_adr: ~p", [Other])) end, case snmpa:current_net_if_data() of {value, []} -> ok; + {value, [{request_ref, R}]} when is_reference(R) -> ok; {value, _} -> throw("bad_nil"); _ -> throw("bad_nid") end, @@ -160,3 +164,6 @@ ftab2(get_next, [9], _Cols) -> % bad return value io:format("** Here comes Error Report get_next 3 bad return~n"), [{[1,5],1},{[2,5],3},{[2,6],3}]. + +format_string(Format, Args) -> + lists:flatten(io_lib:format(Format, Args)). diff --git a/lib/snmp/test/modules.mk b/lib/snmp/test/modules.mk index fd8315ec4d..1bf08a9729 100644 --- a/lib/snmp/test/modules.mk +++ b/lib/snmp/test/modules.mk @@ -19,6 +19,7 @@ SUITE_MODULES = \ snmp_SUITE \ + snmp_to_snmpnet_SUITE \ snmp_app_test \ snmp_appup_test \ snmp_compiler_test \ diff --git a/lib/snmp/test/snmp_SUITE.erl b/lib/snmp/test/snmp_SUITE.erl index 22b9c64588..6fabf6410f 100644 --- a/lib/snmp/test/snmp_SUITE.erl +++ b/lib/snmp/test/snmp_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2012. All Rights Reserved. +%% Copyright Ericsson AB 1997-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -80,7 +80,8 @@ groups() -> {group, note_store_test}]}, {agent, [], [{group, mibs_test}, {group, nfilter_test}, - {group, agent_test}]}, + {group, agent_test}, + {group, snmpnet_test}]}, {manager, [], [{group, manager_config_test}, {group, manager_user_test}, {group, manager_test}]}, @@ -95,6 +96,7 @@ groups() -> {mibs_test, [], [{snmp_agent_mibs_test, all}]}, {nfilter_test, [], [{snmp_agent_nfilter_test, all}]}, {agent_test, [], [{snmp_agent_test, all}]}, + {snmpnet_test, [], [{snmp_to_snmpnet_SUITE, all}]}, {manager_config_test, [], [{snmp_manager_config_test, all}]}, {manager_user_test, [], [{snmp_manager_user_test, all}]}, {manager_test, [], [{snmp_manager_test, all}]} @@ -107,15 +109,18 @@ init_per_group(GroupName, Config0) -> "~n GroupName: ~p" "~n Config0: ~p", [GroupName, Config0]), - %% Group name is not really the suite name - %% (but it is a good enough approximation), - %% but it does not matter since we only need - %% it to be unique. - snmp_test_lib:init_suite_top_dir(GroupName, Config0). - - + case GroupName of + snmpnet_test -> + Config0; + _ -> + %% Group name is not really the suite name + %% (but it is a good enough approximation), + %% but it does not matter since we only need + %% it to be unique. + snmp_test_lib:init_suite_top_dir(GroupName, Config0) + end. + +end_per_group(snmpnet_test, Config) -> + Config; end_per_group(_GroupName, Config) -> lists:keydelete(snmp_suite_top_dir, 1, Config). - - - diff --git a/lib/snmp/test/snmp_agent_test.erl b/lib/snmp/test/snmp_agent_test.erl index 2a9f2e842d..9a9258aa91 100644 --- a/lib/snmp/test/snmp_agent_test.erl +++ b/lib/snmp/test/snmp_agent_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2013. All Rights Reserved. +%% Copyright Ericsson AB 2003-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -37,7 +37,7 @@ v1_processing/1, big/1, big2/1, - loop_mib_1/1, + loop_mib_1/1, api/1, subagent/1, mnesia/1, @@ -298,7 +298,6 @@ %% tickets2 otp8395/1, otp9884/1 - ]). %% Internal exports @@ -390,9 +389,9 @@ usm_read/0, usm_del_user/0, usm_bad/0, - loop_mib_1_test/0, - loop_mib_2_test/0, - loop_mib_3_test/0, + loop_mib_1_test/0, + loop_mib_2_test/0, + loop_mib_3_test/0, otp_1129_i/1, otp_1162_test/0, otp_1131_test/0, @@ -518,9 +517,13 @@ groups() -> {mib_storage_varm_mnesia, [], varm_mib_storage_mnesia_cases()}, {misc, [], misc_cases()}, {test_v1, [], v1_cases()}, + {test_v1_ipv6, [], v1_cases_ipv6()}, {test_v2, [], v2_cases()}, + {test_v2_ipv6, [], v2_cases_ipv6()}, {test_v1_v2, [], v1_v2_cases()}, + {test_v1_v2_ipv6, [], v1_v2_cases()}, {test_v3, [], v3_cases()}, + {test_v3_ipv6, [], v3_cases_ipv6()}, {test_multi_threaded, [], mt_cases()}, {multiple_reqs, [], mul_cases()}, {multiple_reqs_2, [], mul_cases_2()}, @@ -611,6 +614,14 @@ init_per_group(test_v2 = GroupName, Config) -> init_v2(snmp_test_lib:init_group_top_dir(GroupName, Config)); init_per_group(test_v1 = GroupName, Config) -> init_v1(snmp_test_lib:init_group_top_dir(GroupName, Config)); +init_per_group(test_v1_ipv6 = GroupName, Config) -> + init_per_group_ipv6(GroupName, Config, fun init_v1/1); +init_per_group(test_v2_ipv6 = GroupName, Config) -> + init_per_group_ipv6(GroupName, Config, fun init_v2/1); +init_per_group(test_v1_v2_ipv6 = GroupName, Config) -> + init_per_group_ipv6(GroupName, Config, fun init_v1_v2/1); +init_per_group(test_v3_ipv6 = GroupName, Config) -> + init_per_group_ipv6(GroupName, Config, fun init_v3/1); init_per_group(misc = GroupName, Config) -> init_misc(snmp_test_lib:init_group_top_dir(GroupName, Config)); init_per_group(mib_storage_varm_mnesia = GroupName, Config) -> @@ -637,6 +648,18 @@ init_per_group(mib_storage_ets = GroupName, Config) -> init_per_group(GroupName, Config) -> snmp_test_lib:init_group_top_dir(GroupName, Config). +init_per_group_ipv6(GroupName, Config, Init) -> + case ct:require(ipv6_hosts) of + ok -> + Init( + snmp_test_lib:init_group_top_dir( + GroupName, + [{ipfamily, inet6}, + {ip, ?LOCALHOST(inet6)} | lists:keydelete(ip, 1, Config)])); + _ -> + {skip, "Host does not support IPV6"} + end. + end_per_group(all_tcs, Config) -> finish_all(Config); end_per_group(otp7157, Config) -> @@ -655,31 +678,39 @@ end_per_group(multiple_reqs_3, Config) -> finish_mul(Config); end_per_group(test_multi_threaded, Config) -> finish_mt(Config); -end_per_group(test_v3, Config) -> +end_per_group(test_v3_ipv6, Config) -> + finish_v3(Config); +end_per_group(test_v1_v2_ipv6, Config) -> + finish_v1_v2(Config); +end_per_group(test_v2_ipv6, Config) -> + finish_v2(Config); +end_per_group(test_v1_ipv6, Config) -> + finish_v1(Config); +end_per_group(test_v3, Config) -> finish_v3(Config); -end_per_group(test_v1_v2, Config) -> +end_per_group(test_v1_v2, Config) -> finish_v1_v2(Config); -end_per_group(test_v2, Config) -> +end_per_group(test_v2, Config) -> finish_v2(Config); -end_per_group(test_v1, Config) -> +end_per_group(test_v1, Config) -> finish_v1(Config); -end_per_group(misc, Config) -> +end_per_group(misc, Config) -> finish_misc(Config); -end_per_group(mib_storage_varm_mnesia, Config) -> +end_per_group(mib_storage_varm_mnesia, Config) -> finish_varm_mib_storage_mnesia(Config); -end_per_group(mib_storage_varm_dets, Config) -> +end_per_group(mib_storage_varm_dets, Config) -> finish_varm_mib_storage_dets(Config); -end_per_group(mib_storage_size_check_mnesia, Config) -> +end_per_group(mib_storage_size_check_mnesia, Config) -> finish_size_check_msm(Config); -end_per_group(mib_storage_size_check_dets, Config) -> +end_per_group(mib_storage_size_check_dets, Config) -> finish_size_check_msd(Config); -end_per_group(mib_storage_size_check_ets, Config) -> +end_per_group(mib_storage_size_check_ets, Config) -> finish_size_check_mse(Config); -end_per_group(mib_storage_mnesia, Config) -> +end_per_group(mib_storage_mnesia, Config) -> finish_mib_storage_mnesia(Config); -end_per_group(mib_storage_dets, Config) -> +end_per_group(mib_storage_dets, Config) -> finish_mib_storage_dets(Config); -end_per_group(mib_storage_ets, Config) -> +end_per_group(mib_storage_ets, Config) -> finish_mib_storage_ets(Config); end_per_group(_GroupName, Config) -> Config. @@ -810,6 +841,10 @@ cases() -> {group, test_v2}, {group, test_v1_v2}, {group, test_v3}, + {group, test_v1_ipv6}, + {group, test_v2_ipv6}, + {group, test_v1_v2_ipv6}, + {group, test_v3_ipv6}, {group, test_multi_threaded}, {group, mib_storage}, {group, tickets1} @@ -865,8 +900,8 @@ start_v2_agent(Config) -> start_v2_agent(Config, Opts) -> snmp_agent_test_lib:start_v2_agent(Config, Opts). -start_v3_agent(Config) -> - snmp_agent_test_lib:start_v3_agent(Config). +%% start_v3_agent(Config) -> +%% snmp_agent_test_lib:start_v3_agent(Config). start_v3_agent(Config, Opts) -> snmp_agent_test_lib:start_v3_agent(Config, Opts). @@ -1636,7 +1671,7 @@ del_dir(Dir, Depth) -> ok end. -%v1_cases() -> [loop_mib]; +%v1_cases() -> [loop_mib_1]; v1_cases() -> [ simple, @@ -1644,7 +1679,7 @@ v1_cases() -> v1_processing, big, big2, - loop_mib_1, + loop_mib_1, api, subagent, mnesia, @@ -1662,14 +1697,40 @@ v1_cases() -> change_target_addr_config ]. +v1_cases_ipv6() -> + [ + simple, + v1_processing, + loop_mib_1, +%% big, +%% big2, + api, + subagent, +%% mnesia, +%% {group, multiple_reqs}, + sa_register, +%% v1_trap, % sends v1 trap +%% sa_error, + next_across_sa, + undo, +%% {group, reported_bugs}, + {group, standard_mibs}, % snmp_standard_mib still failing, sends v1 trap + sparse_table, +%% cnt_64, % sends v1 trap + opaque +%% change_target_addr_config % sends v1 trap + ]. + init_v1(Config) when is_list(Config) -> ?line SaNode = ?config(snmp_sa, Config), ?line create_tables(SaNode), ?line AgentConfDir = ?config(agent_conf_dir, Config), ?line MgrDir = ?config(mgr_dir, Config), ?line Ip = ?config(ip, Config), - ?line config([v1], MgrDir, AgentConfDir, - tuple_to_list(Ip), tuple_to_list(Ip)), + ?line IpFamily = config_ipfamily(Config), + ?line config( + [v1], MgrDir, AgentConfDir, + tuple_to_list(Ip), tuple_to_list(Ip), IpFamily), [{vsn, v1} | start_v1_agent(Config)]. finish_v1(Config) when is_list(Config) -> @@ -1706,14 +1767,43 @@ v2_cases() -> v2_caps ]. +v2_cases_ipv6() -> + [ + simple_2, + v2_processing, +%% big_2, +%% big2_2, + loop_mib_2, + api_2, + subagent_2, +%% mnesia_2, +%% {group, multiple_reqs_2}, + sa_register_2, + v2_trap, + {group, v2_inform}, +%% sa_error_2, + next_across_sa_2, + undo_2, +%% {group, reported_bugs_2}, + {group, standard_mibs_2}, + v2_types, + implied, + sparse_table_2, + cnt_64_2, + opaque_2, + v2_caps + ]. + init_v2(Config) when is_list(Config) -> SaNode = ?config(snmp_sa, Config), create_tables(SaNode), AgentConfDir = ?config(agent_conf_dir, Config), MgrDir = ?config(mgr_dir, Config), Ip = ?config(ip, Config), - config([v2], MgrDir, AgentConfDir, - tuple_to_list(Ip), tuple_to_list(Ip)), + IpFamily = config_ipfamily(Config), + config( + [v2], MgrDir, AgentConfDir, + tuple_to_list(Ip), tuple_to_list(Ip), IpFamily), [{vsn, v2} | start_v2_agent(Config)]. finish_v2(Config) when is_list(Config) -> @@ -1732,8 +1822,9 @@ init_v1_v2(Config) when is_list(Config) -> AgentConfDir = ?config(agent_conf_dir, Config), MgrDir = ?config(mgr_dir, Config), Ip = ?config(ip, Config), + IpFamily = config_ipfamily(Config), config([v1,v2], MgrDir, AgentConfDir, - tuple_to_list(Ip), tuple_to_list(Ip)), + tuple_to_list(Ip), tuple_to_list(Ip), IpFamily), [{vsn, bilingual} | start_bilingual_agent(Config)]. finish_v1_v2(Config) when is_list(Config) -> @@ -1771,6 +1862,34 @@ v3_cases() -> v2_caps_3 ]. +v3_cases_ipv6() -> + [ + simple_3, + v3_processing, +%% big_3, +%% big2_3, + api_3, + subagent_3, +%% mnesia_3, + loop_mib_3, +%% {group, multiple_reqs_3}, + sa_register_3, + v3_trap, + {group, v3_inform}, +%% sa_error_3, + next_across_sa_3, + undo_3, +%% {group, reported_bugs_3}, + {group, standard_mibs_3}, + {group, v3_security}, + v2_types_3, + implied_3, + sparse_table_3, + cnt_64_3, + opaque_3, + v2_caps_3 + ]. + init_v3(Config) when is_list(Config) -> %% Make sure crypto works, otherwise start_agent will fail %% and we will be stuck with a bunch of mnesia tables for @@ -1792,9 +1911,16 @@ init_v3(Config) when is_list(Config) -> AgentConfDir = ?config(agent_conf_dir, Config), MgrDir = ?config(mgr_dir, Config), Ip = ?config(ip, Config), - ?line ok = config([v3], MgrDir, AgentConfDir, - tuple_to_list(Ip), tuple_to_list(Ip)), - [{vsn, v3} | start_v3_agent(Config)]. + IpFamily = config_ipfamily(Config), + ?line ok = + config( + [v3], MgrDir, AgentConfDir, + tuple_to_list(Ip), tuple_to_list(Ip), IpFamily), + Opts = + [{master_agent_verbosity, trace}, + {agent_verbosity, trace}, + {net_if_verbosity, trace}], + [{vsn, v3} | start_v3_agent(Config, Opts)]. finish_v3(Config) when is_list(Config) -> delete_tables(), @@ -5546,7 +5672,7 @@ usm_bad() -> %%----------------------------------------------------------------- loop_mib_1(suite) -> []; loop_mib_1(Config) when is_list(Config) -> - ?P(loop_mib_1), + ?P(loop_mib_1), ?LOG("loop_mib_1 -> initiate case",[]), %% snmpa:verbosity(master_agent,debug), %% snmpa:verbosity(mib_server,info), @@ -5554,7 +5680,7 @@ loop_mib_1(Config) when is_list(Config) -> ?DBG("loop_mib_1 -> ~n" "\tSaNode: ~p~n" "\tMgrNode: ~p~n" - "\tMibDir: ~p", [_SaNode, _MgrNode, _MibDir]), + "\tMibDir: ~p",[_SaNode, _MgrNode, _MibDir]), ?DBG("loop_mib_1 -> load mib SNMP-COMMUNITY-MIB",[]), ?line load_master_std("SNMP-COMMUNITY-MIB"), ?DBG("loop_mib_1 -> load mib SNMP-MPD-MIB",[]), @@ -6378,8 +6504,6 @@ otp_4394_config(AgentConfDir, MgrDir, Ip0) -> ?line write_notify_conf(AgentConfDir), ok. - - otp_4394_finish(Config) when is_list(Config) -> ?DBG("finish_otp_4394 -> entry", []), C1 = stop_agent(Config), @@ -6532,6 +6656,7 @@ otp8395({init, Config}) when is_list(Config) -> %% SubAgentHost = ?HPSTNAME(SubAgentNode), ManagerHost = ?HOSTNAME(ManagerNode), + IpFamily = inet, Host = snmp_test_lib:hostname(), Ip = ?LOCALHOST(), {ok, AgentIP0} = snmp_misc:ip(AgentHost), @@ -6549,9 +6674,7 @@ otp8395({init, Config}) when is_list(Config) -> Vsns = [v1], AgentConfDir = ?config(agent_conf_dir, Config), ManagerConfDir = ?config(manager_top_dir, Config), - snmp_agent_test_lib:config(Vsns, - ManagerConfDir, AgentConfDir, - ManagerIP, AgentIP), + config(Vsns, ManagerConfDir, AgentConfDir, ManagerIP, AgentIP, IpFamily), %% -- @@ -6560,6 +6683,7 @@ otp8395({init, Config}) when is_list(Config) -> Config2 = start_agent([{host, Host}, {ip, Ip}, + {ipfamily, IpFamily}, {agent_node, AgentNode}, {agent_host, AgentHost}, {agent_ip, AgentIP}, @@ -6639,6 +6763,7 @@ otp8395(Config) when is_list(Config) -> put(mib_dir, ?config(mib_dir, Config)), put(vsn, v1), put(master_host, ?config(agent_host, Config)), + put(ipfamily, ?config(ipfamily, Config)), try_test(simple_standard_test), ?SLEEP(1000), @@ -6666,126 +6791,12 @@ otp8395(Config) when is_list(Config) -> otp9884({init, Config}) when is_list(Config) -> ?DBG("otp9884(init) -> entry with" "~n Config: ~p", [Config]), - - %% -- - %% Start nodes - %% - - {ok, AgentNode} = start_node(agent), - - %% We don't use a manager in this test but the (common) config - %% function takes an argument that is derived from this - {ok, ManagerNode} = start_node(manager), - - %% -- - %% Mnesia init - %% - - AgentDbDir = ?config(agent_db_dir, Config), - AgentMnesiaDir = join([AgentDbDir, "mnesia"]), - mnesia_init(AgentNode, AgentMnesiaDir), - - mnesia_create_schema(AgentNode, [AgentNode]), - - mnesia_start(AgentNode), - - %% -- - %% Host & IP - %% - - AgentHost = ?HOSTNAME(AgentNode), - ManagerHost = ?HOSTNAME(ManagerNode), - - Host = snmp_test_lib:hostname(), - Ip = ?LOCALHOST(), - {ok, AgentIP0} = snmp_misc:ip(AgentHost), - AgentIP = tuple_to_list(AgentIP0), - {ok, ManagerIP0} = snmp_misc:ip(ManagerHost), - ManagerIP = tuple_to_list(ManagerIP0), - - - %% -- - %% Write agent config - %% - - Vsns = [v1], - ManagerConfDir = ?config(manager_top_dir, Config), - AgentConfDir = ?config(agent_conf_dir, Config), - AgentTopDir = ?config(agent_top_dir, Config), - AgentBkpDir1 = join([AgentTopDir, backup1]), - AgentBkpDir2 = join([AgentTopDir, backup2]), - ok = file:make_dir(AgentBkpDir1), - ok = file:make_dir(AgentBkpDir2), - AgentBkpDirs = [AgentBkpDir1, AgentBkpDir2], - snmp_agent_test_lib:config(Vsns, - ManagerConfDir, AgentConfDir, - ManagerIP, AgentIP), - - - %% -- - %% Start the agent - %% - - Config2 = start_agent([{host, Host}, - {ip, Ip}, - {agent_node, AgentNode}, - {agent_host, AgentHost}, - {agent_ip, AgentIP}, - {agent_backup_dirs, AgentBkpDirs}|Config]), - - %% -- - %% Create watchdog - %% - - Dog = ?WD_START(?MINS(1)), - - [{watchdog, Dog} | Config2]; + init_v1_agent([{ipfamily, inet} | Config]); otp9884({fin, Config}) when is_list(Config) -> ?DBG("otp9884(fin) -> entry with" "~n Config: ~p", [Config]), - - AgentNode = ?config(agent_node, Config), - ManagerNode = ?config(manager_node, Config), - - %% - - %% Stop agent (this is the nice way to do it, - %% so logs and files can be closed in the proper way). - %% - - AgentSup = ?config(agent_sup, Config), - ?DBG("otp9884(fin) -> stop (stand-alone) agent: ~p", [AgentSup]), - stop_stdalone_agent(AgentSup), - - %% - - %% Stop mnesia - %% - ?DBG("otp9884(fin) -> stop mnesia", []), - mnesia_stop(AgentNode), - - - %% - - %% Stop the agent node - %% - - ?DBG("otp9884(fin) -> stop agent node", []), - stop_node(AgentNode), - - - %% SubAgentNode = ?config(sub_agent_node, Config), - %% stop_node(SubAgentNode), - - - %% - - %% Stop the manager node - %% - - ?DBG("otp9884(fin) -> stop manager node", []), - stop_node(ManagerNode), - - Dog = ?config(watchdog, Config), - ?WD_STOP(Dog), - lists:keydelete(watchdog, 1, Config); + fin_v1_agent(Config); otp9884(doc) -> "OTP-9884 - Simlutaneous backup call should not work. "; @@ -6845,8 +6856,6 @@ otp9884_await_backup_completion(First, Second) end; otp9884_await_backup_completion(First, Second) -> throw({error, {bad_completion, First, Second}}). - - %%----------------------------------------------------------------- agent_log_validation(Node) -> @@ -7143,6 +7152,9 @@ delete_files(Config) -> config(Vsns, MgrDir, AgentDir, MIp, AIp) -> snmp_agent_test_lib:config(Vsns, MgrDir, AgentDir, MIp, AIp). +config(Vsns, MgrDir, AgentDir, MIp, AIp, IpFamily) -> + snmp_agent_test_lib:config(Vsns, MgrDir, AgentDir, MIp, AIp, IpFamily). + update_usm(Vsns, Dir) -> snmp_agent_test_lib:update_usm(Vsns, Dir). @@ -7387,3 +7399,124 @@ p(F, A) -> formated_timestamp() -> snmp_test_lib:formated_timestamp(). + +init_v1_agent(Config) -> + %% -- + %% Start nodes + %% + + {ok, AgentNode} = start_node(agent), + + %% We don't use a manager in this test but the (common) config + %% function takes an argument that is derived from this + {ok, ManagerNode} = start_node(manager), + + %% -- + %% Mnesia init + %% + + AgentDbDir = ?config(agent_db_dir, Config), + AgentMnesiaDir = join([AgentDbDir, "mnesia"]), + mnesia_init(AgentNode, AgentMnesiaDir), + + mnesia_create_schema(AgentNode, [AgentNode]), + + mnesia_start(AgentNode), + + %% -- + %% Host & IP + %% + + AgentHost = ?HOSTNAME(AgentNode), + ManagerHost = ?HOSTNAME(ManagerNode), + + Host = snmp_test_lib:hostname(), + IpFamily = config_ipfamily(Config), + Ip = ?LOCALHOST(IpFamily), + {ok, AgentIP0} = snmp_misc:ip(AgentHost, IpFamily), + AgentIP = tuple_to_list(AgentIP0), + {ok, ManagerIP0} = snmp_misc:ip(ManagerHost, IpFamily), + ManagerIP = tuple_to_list(ManagerIP0), + + + %% -- + %% Write agent config + %% + + Vsns = [v1], + ManagerConfDir = ?config(manager_top_dir, Config), + AgentConfDir = ?config(agent_conf_dir, Config), + AgentTopDir = ?config(agent_top_dir, Config), + AgentBkpDir1 = join([AgentTopDir, backup1]), + AgentBkpDir2 = join([AgentTopDir, backup2]), + ok = file:make_dir(AgentBkpDir1), + ok = file:make_dir(AgentBkpDir2), + AgentBkpDirs = [AgentBkpDir1, AgentBkpDir2], + config(Vsns, ManagerConfDir, AgentConfDir, ManagerIP, AgentIP, IpFamily), + + + %% -- + %% Start the agent + %% + + Config2 = start_agent([{host, Host}, + {ip, Ip}, + {agent_node, AgentNode}, + {agent_host, AgentHost}, + {agent_ip, AgentIP}, + {agent_backup_dirs, AgentBkpDirs}|Config]), + + %% -- + %% Create watchdog + %% + + Dog = ?WD_START(?MINS(1)), + + [{watchdog, Dog} | Config2]. + +fin_v1_agent(Config) -> + AgentNode = ?config(agent_node, Config), + ManagerNode = ?config(manager_node, Config), + + %% - + %% Stop agent (this is the nice way to do it, + %% so logs and files can be closed in the proper way). + %% + + AgentSup = ?config(agent_sup, Config), + stop_stdalone_agent(AgentSup), + + %% - + %% Stop mnesia + %% + mnesia_stop(AgentNode), + + + %% - + %% Stop the agent node + %% + stop_node(AgentNode), + + + %% SubAgentNode = ?config(sub_agent_node, Config), + %% stop_node(SubAgentNode), + + + %% - + %% Stop the manager node + %% + stop_node(ManagerNode), + + Dog = ?config(watchdog, Config), + ?WD_STOP(Dog), + lists:keydelete(watchdog, 1, Config). + + + +config_ipfamily(Config) -> + case ?config(ipfamily, Config) of + undefined -> + inet; + Value -> + Value + end. diff --git a/lib/snmp/test/snmp_agent_test_lib.erl b/lib/snmp/test/snmp_agent_test_lib.erl index d7109253f7..333fe6eb66 100644 --- a/lib/snmp/test/snmp_agent_test_lib.erl +++ b/lib/snmp/test/snmp_agent_test_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2013. All Rights Reserved. +%% Copyright Ericsson AB 2005-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -39,7 +39,7 @@ get_req/2, get_next_req/1, - config/5, + config/5, config/6, delete_files/1, copy_file/2, update_usm/2, @@ -232,13 +232,14 @@ init_case(Config) when is_list(Config) -> MgrNode = ?config(snmp_mgr, Config), MasterNode = ?config(snmp_master, Config), %% MasterNode = node(), - + IpFamily = proplists:get_value(ipfamily, Config, inet), + SaHost = ?HOSTNAME(SaNode), MgrHost = ?HOSTNAME(MgrNode), MasterHost = ?HOSTNAME(MasterNode), - {ok, MasterIP} = snmp_misc:ip(MasterHost), - {ok, MIP} = snmp_misc:ip(MgrHost), - {ok, SIP} = snmp_misc:ip(SaHost), + {ok, MasterIP} = snmp_misc:ip(MasterHost, IpFamily), + {ok, MIP} = snmp_misc:ip(MgrHost, IpFamily), + {ok, SIP} = snmp_misc:ip(SaHost, IpFamily), put(mgr_node, MgrNode), @@ -250,6 +251,7 @@ init_case(Config) when is_list(Config) -> put(mip, tuple_to_list(MIP)), put(masterip, tuple_to_list(MasterIP)), put(sip, tuple_to_list(SIP)), + put(ipfamily, IpFamily), MibDir = ?config(mib_dir, Config), put(mib_dir, MibDir), @@ -358,6 +360,7 @@ run(Mod, Func, Args, Opts) -> {packet_server_debug,true}, {debug,true}, {agent, get(master_host)}, + {ipfamily, get(ipfamily)}, {agent_udp, 4000}, {trap_udp, 5000}, {recbuf,65535}, @@ -1368,16 +1371,35 @@ stop_node(Node) -> %%%----------------------------------------------------------------- config(Vsns, MgrDir, AgentConfDir, MIp, AIp) -> + config(Vsns, MgrDir, AgentConfDir, MIp, AIp, inet). + +config(Vsns, MgrDir, AgentConfDir, MIp, AIp, IpFamily) -> ?LOG("config -> entry with" - "~n Vsns: ~p" - "~n MgrDir: ~p" - "~n AgentConfDir: ~p" - "~n MIp: ~p" - "~n AIp: ~p", - [Vsns, MgrDir, AgentConfDir, MIp, AIp]), - ?line snmp_config:write_agent_snmp_files(AgentConfDir, Vsns, - MIp, ?TRAP_UDP, AIp, 4000, - "test"), + "~n Vsns: ~p" + "~n MgrDir: ~p" + "~n AgentConfDir: ~p" + "~n MIp: ~p" + "~n AIp: ~p" + "~n IpFamily: ~p", + [Vsns, MgrDir, AgentConfDir, MIp, AIp, IpFamily]), + ?line {Domain, ManagerAddr} = + case IpFamily of + inet6 -> + Ipv6Domain = transportDomainUdpIpv6, + AgentIpv6Addr = {AIp, 4000}, + ManagerIpv6Addr = {MIp, ?TRAP_UDP}, + ?line ok = + snmp_config:write_agent_snmp_files( + AgentConfDir, Vsns, + Ipv6Domain, ManagerIpv6Addr, AgentIpv6Addr, "test"), + {Ipv6Domain, ManagerIpv6Addr}; + _ -> + ?line ok = + snmp_config:write_agent_snmp_files( + AgentConfDir, Vsns, MIp, ?TRAP_UDP, AIp, 4000, "test"), + {snmpUDPDomain, {MIp, ?TRAP_UDP}} + end, + ?line case update_usm(Vsns, AgentConfDir) of true -> ?line copy_file(join(AgentConfDir, "usm.conf"), @@ -1388,7 +1410,7 @@ config(Vsns, MgrDir, AgentConfDir, MIp, AIp) -> end, ?line update_community(Vsns, AgentConfDir), ?line update_vacm(Vsns, AgentConfDir), - ?line write_target_addr_conf(AgentConfDir, MIp, ?TRAP_UDP, Vsns), + ?line write_target_addr_conf(AgentConfDir, Domain, ManagerAddr, Vsns), ?line write_target_params_conf(AgentConfDir, Vsns), ?line write_notify_conf(AgentConfDir), ok. @@ -1486,7 +1508,7 @@ rewrite_usm_mgr(Dir, ShaKey, DesKey) -> {"mgrEngine", "newUser", "newUser", zeroDotZero, usmHMACSHAAuthProtocol, "", "", usmDESPrivProtocol, "", "", "", ShaKey, DesKey}], - ok = snmp_config:write_agent_usm_config(Dir, "", Conf). + ?line ok = snmp_config:write_agent_usm_config(Dir, "", Conf). reset_usm_mgr(Dir) -> ?line ok = file:rename(join(Dir,"usm.old"), @@ -1512,13 +1534,15 @@ update_vacm(_Vsn, Dir) -> write_community_conf(Dir, Conf) -> - snmp_config:write_agent_community_config(Dir, "", Conf). + ?line ok = snmp_config:write_agent_community_config(Dir, "", Conf). write_target_addr_conf(Dir, Conf) -> - snmp_config:write_agent_target_addr_config(Dir, "", Conf). + ?line ok = snmp_config:write_agent_target_addr_config(Dir, "", Conf). -write_target_addr_conf(Dir, ManagerIp, UDP, Vsns) -> - snmp_config:write_agent_snmp_target_addr_conf(Dir, ManagerIp, UDP, Vsns). +write_target_addr_conf(Dir, Ip_or_Domain, Port_or_Addr, Vsns) -> + ?line ok = + snmp_config:write_agent_snmp_target_addr_conf( + Dir, Ip_or_Domain, Port_or_Addr, Vsns). rewrite_target_addr_conf(Dir, NewPort) -> ?DBG("rewrite_target_addr_conf -> entry with" @@ -1534,8 +1558,7 @@ rewrite_target_addr_conf(Dir, NewPort) -> end, ?line [TrapAddr|Addrs] = - snmp_conf:read(TAFile, - fun(R) -> rewrite_target_addr_conf_check(R) end), + snmp_conf:read(TAFile, fun rewrite_target_addr_conf_check/1), ?DBG("rewrite_target_addr_conf -> TrapAddr: ~p",[TrapAddr]), @@ -1571,14 +1594,14 @@ write_target_params_conf(Dir, Vsns) -> (v3) -> {"target_v3", v3, usm, "all-rights", noAuthNoPriv} end, Conf = [F(Vsn) || Vsn <- Vsns], - snmp_config:write_agent_target_params_config(Dir, "", Conf). + ?line ok = snmp_config:write_agent_target_params_config(Dir, "", Conf). rewrite_target_params_conf(Dir, SecName, SecLevel) when is_list(SecName) andalso is_atom(SecLevel) -> ?line ok = file:rename(join(Dir,"target_params.conf"), join(Dir,"target_params.old")), Conf = [{"target_v3", v3, usm, SecName, SecLevel}], - snmp_config:write_agent_target_params_config(Dir, "", Conf). + ?line ok = snmp_config:write_agent_target_params_config(Dir, "", Conf). reset_target_params_conf(Dir) -> ?line ok = file:rename(join(Dir,"target_params.old"), @@ -1587,12 +1610,12 @@ reset_target_params_conf(Dir) -> write_notify_conf(Dir) -> Conf = [{"standard trap", "std_trap", trap}, {"standard inform", "std_inform", inform}], - snmp_config:write_agent_notify_config(Dir, "", Conf). + ?line ok = snmp_config:write_agent_notify_config(Dir, "", Conf). write_view_conf(Dir) -> Conf = [{2, [1,3,6], included, null}, {2, ?tDescr_instance, excluded, null}], - snmp_config:write_agent_view_config(Dir, "", Conf). + ?line ok = snmp_config:write_agent_view_config(Dir, "", Conf). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/lib/snmp/test/snmp_conf_test.erl b/lib/snmp/test/snmp_conf_test.erl index c4341d8d7e..7f5d11c0e7 100644 --- a/lib/snmp/test/snmp_conf_test.erl +++ b/lib/snmp/test/snmp_conf_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2010. All Rights Reserved. +%% Copyright Ericsson AB 2003-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -373,6 +373,8 @@ verify_ip(Val) -> case (catch snmp_conf:check_ip(Val)) of {error, Reason} -> ?FAIL({verify_ip, Val, Reason}); + {ok, _} -> + ok; ok -> ok end. @@ -401,7 +403,7 @@ check_taddress(Config) when is_list(Config) -> ok. verify_taddress(Val) -> - case (catch snmp_conf:check_taddress(Val)) of + case (catch snmp_conf:check_taddress(snmpUDPDomain, Val)) of {error, Reason} -> ?FAIL({verify_taddress, Val, Reason}); ok -> @@ -409,7 +411,7 @@ verify_taddress(Val) -> end. verify_not_taddress(Val) -> - case (catch snmp_conf:check_taddress(Val)) of + case (catch snmp_conf:check_taddress(snmpUDPDomain, Val)) of ok -> ?FAIL({verify_taddress, Val}); {error, _Reason} -> diff --git a/lib/snmp/test/snmp_manager_config_test.erl b/lib/snmp/test/snmp_manager_config_test.erl index 7b9924b83c..2f5c68d14d 100644 --- a/lib/snmp/test/snmp_manager_config_test.erl +++ b/lib/snmp/test/snmp_manager_config_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2013. All Rights Reserved. +%% Copyright Ericsson AB 2004-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -693,7 +693,7 @@ start_with_invalid_manager_conf_file1(Conf) when is_list(Conf) -> "arne_anka", "4001", "500", "\"bmkEngine\""), ?line {error, Reason12} = config_start(Opts), p("start failed (as expected): ~p", [Reason12]), - ?line {failed_check, _, _, 2, {invalid_ip_address, _}} = Reason12, + ?line {failed_check, _, _, 2, {bad_address, _}} = Reason12, await_config_not_running(), %% -- @@ -702,7 +702,7 @@ start_with_invalid_manager_conf_file1(Conf) when is_list(Conf) -> "9999", "4001", "500", "\"bmkEngine\""), ?line {error, Reason13} = config_start(Opts), p("start failed (as expected): ~p", [Reason13]), - ?line {failed_check, _, _, 2, {invalid_ip_address, _}} = Reason13, + ?line {failed_check, _, _, 2, {bad_address, _}} = Reason13, await_config_not_running(), %% -- @@ -720,7 +720,8 @@ start_with_invalid_manager_conf_file1(Conf) when is_list(Conf) -> "[134,138,177,189]", "-1", "500", "\"bmkEngine\""), ?line {error, Reason22} = config_start(Opts), p("start failed (as expected): ~p", [Reason22]), - ?line {failed_check, _, _, 3, {invalid_integer, _}} = Reason22, + io:format("Reason22: ~p~n", [Reason22]), + ?line {failed_check, _, _, 3, {bad_port, _}} = Reason22, await_config_not_running(), %% -- @@ -729,7 +730,7 @@ start_with_invalid_manager_conf_file1(Conf) when is_list(Conf) -> "[134,138,177,189]", "\"kalle-anka\"", "500", "\"bmkEngine\""), ?line {error, Reason23} = config_start(Opts), p("start failed (as expected): ~p", [Reason23]), - ?line {failed_check, _, _, 3, {invalid_integer, _}} = Reason23, + ?line {failed_check, _, _, 3, {bad_port, _}} = Reason23, await_config_not_running(), %% -- @@ -1073,7 +1074,7 @@ start_with_invalid_agents_conf_file1(Conf) when is_list(Conf) -> case config_start(Opts) of {error, Reason53} -> p("start failed (as expected): ~p", [Reason53]), - ?line {failed_check, _, _, _, {invalid_ip_address, _}} = Reason53, + ?line {failed_check, _, _, _, {bad_address, _}} = Reason53, await_config_not_running(); OK_53 -> exit({error, {unexpected_success, "53", OK_53}}) @@ -1086,7 +1087,7 @@ start_with_invalid_agents_conf_file1(Conf) when is_list(Conf) -> case config_start(Opts) of {error, Reason54} -> p("start failed (as expected): ~p", [Reason54]), - ?line {failed_check, _, _, _, {invalid_ip_address, _}} = Reason54, + ?line {failed_check, _, _, _, {bad_address, _}} = Reason54, await_config_not_running(); OK_54 -> exit({error, {unexpected_success, "54", OK_54}}) @@ -1098,7 +1099,7 @@ start_with_invalid_agents_conf_file1(Conf) when is_list(Conf) -> write_agents_conf(ConfDir, [Agent55]), ?line {error, Reason55} = config_start(Opts), p("start failed (as expected): ~p", [Reason55]), - ?line {failed_check, _, _, _, {invalid_ip_address, _}} = Reason55, + ?line {failed_check, _, _, _, {bad_address, _}} = Reason55, await_config_not_running(), %% -- @@ -1107,7 +1108,7 @@ start_with_invalid_agents_conf_file1(Conf) when is_list(Conf) -> write_agents_conf(ConfDir, [Agent61]), ?line {error, Reason61} = config_start(Opts), p("start failed (as expected): ~p", [Reason61]), - ?line {failed_check, _, _, _, {invalid_integer, _}} = Reason61, + ?line {failed_check, _, _, _, {bad_address, _}} = Reason61, await_config_not_running(), %% -- @@ -1116,7 +1117,7 @@ start_with_invalid_agents_conf_file1(Conf) when is_list(Conf) -> write_agents_conf(ConfDir, [Agent62]), ?line {error, Reason62} = config_start(Opts), p("start failed (as expected): ~p", [Reason62]), - ?line {failed_check, _, _, _, {invalid_integer, _}} = Reason62, + ?line {failed_check, _, _, _, {bad_address, _}} = Reason62, await_config_not_running(), %% -- @@ -1125,7 +1126,7 @@ start_with_invalid_agents_conf_file1(Conf) when is_list(Conf) -> write_agents_conf(ConfDir, [Agent63]), ?line {error, Reason63} = config_start(Opts), p("start failed (as expected): ~p", [Reason63]), - ?line {failed_check, _, _, _, {invalid_integer, _}} = Reason63, + ?line {failed_check, _, _, _, {bad_address, _}} = Reason63, await_config_not_running(), %% -- diff --git a/lib/snmp/test/snmp_manager_test.erl b/lib/snmp/test/snmp_manager_test.erl index 3a654a2805..78352e59cf 100644 --- a/lib/snmp/test/snmp_manager_test.erl +++ b/lib/snmp/test/snmp_manager_test.erl @@ -241,8 +241,11 @@ init_per_testcase2(Case, Config) -> AgLogDir = filename:join(AgTopDir, "log/"), ?line ok = file:make_dir(AgLogDir), + Family = proplists:get_value(ipfamily, Config, inet), + Conf = [{watchdog, ?WD_START(?MINS(5))}, - {ip, ?LOCALHOST()}, + {ipfamily, Family}, + {ip, ?LOCALHOST(Family)}, {case_top_dir, CaseTopDir}, {agent_dir, AgTopDir}, {agent_conf_dir, AgConfDir}, @@ -410,7 +413,9 @@ all() -> {group, event_tests}, {group, event_tests_mt}, discovery, - {group, tickets} + {group, tickets}, + {group, ipv6}, + {group, ipv6_mt} ]. groups() -> @@ -545,9 +550,29 @@ groups() -> [ otp8395_1 ] - } + }, + {ipv6, [], ipv6_tests()}, + {ipv6_mt, [], ipv6_tests()} + + ]. + +ipv6_tests() -> + [ + register_agent1, + simple_sync_get_next3, + simple_async_get2, + simple_sync_get3, + simple_async_get_next2, + simple_sync_set3, + simple_async_set2, + simple_sync_get_bulk2, + simple_async_get_bulk3, + misc_async2, + inform1, + inform_swarm ]. + init_per_group(request_tests_mt = GroupName, Config) -> snmp_test_lib:init_group_top_dir( GroupName, @@ -556,10 +581,26 @@ init_per_group(event_tests_mt = GroupName, Config) -> snmp_test_lib:init_group_top_dir( GroupName, [{manager_net_if_module, snmpm_net_if_mt} | Config]); +init_per_group(ipv6_mt = GroupName, Config) -> + case ct:require(ipv6_hosts) of + ok -> + ipv6_init( + snmp_test_lib:init_group_top_dir( + GroupName, + [{manager_net_if_module, snmpm_net_if_mt} | Config])); + _ -> + {skip, "Host does not support IPV6"} + end; +init_per_group(ipv6 = GroupName, Config) -> + case ct:require(ipv6_hosts) of + ok -> + ipv6_init(snmp_test_lib:init_group_top_dir(GroupName, Config)); + _ -> + {skip, "Host does not support IPV6"} + end; init_per_group(GroupName, Config) -> snmp_test_lib:init_group_top_dir(GroupName, Config). - - + end_per_group(_GroupName, Config) -> %% Do we really need to do this? lists:keydelete(snmp_group_top_dir, 1, Config). @@ -1508,7 +1549,7 @@ register_agent3(Config) when is_list(Config) -> TargetName2 = "agent3", ?line ok = mgr_register_agent(ManagerNode, user_alfa, TargetName2, [{tdomain, transportDomainUdpIpv6}, - {address, LocalHost}, + {address, {0,0,0,0,0,0,0,1}}, {port, 5002}, {engine_id, "agentEngineId-2"}]), TargetName3 = "agent4", @@ -5074,7 +5115,7 @@ inform_swarm_collector(N) -> inform_swarm_collector(N, SentAckCnt, RecvCnt, RespCnt, _) when ((N == SentAckCnt) and (N == RespCnt) and - (N >= RecvCnt)) -> + (N =< RecvCnt)) -> p("inform_swarm_collector -> done when" "~n N: ~w" "~n SentAckCnt: ~w" @@ -5750,12 +5791,24 @@ fin_mgr_user(Conf) -> init_mgr_user_data1(Conf) -> Node = ?config(manager_node, Conf), TargetName = ?config(manager_agent_target_name, Conf), - Addr = ?config(ip, Conf), + IpFamily = ?config(ipfamily, Conf), + Ip = ?config(ip, Conf), Port = ?AGENT_PORT, - ?line ok = mgr_user_register_agent(Node, TargetName, - [{address, Addr}, - {port, Port}, - {engine_id, "agentEngine"}]), + ?line ok = + case IpFamily of + inet -> + mgr_user_register_agent( + Node, TargetName, + [{address, Ip}, + {port, Port}, + {engine_id, "agentEngine"}]); + inet6 -> + mgr_user_register_agent( + Node, TargetName, + [{tdomain, transportDomainUdpIpv6}, + {taddress, {Ip, Port}}, + {engine_id, "agentEngine"}]) + end, _Agents = mgr_user_which_own_agents(Node), ?DBG("Own agents: ~p", [_Agents]), @@ -5780,12 +5833,24 @@ init_mgr_user_data2(Conf) -> "~n Conf: ~p", [Conf]), Node = ?config(manager_node, Conf), TargetName = ?config(manager_agent_target_name, Conf), - Addr = ?config(ip, Conf), + IpFamily = ?config(ipfamily, Conf), + Ip = ?config(ip, Conf), Port = ?AGENT_PORT, - ?line ok = mgr_user_register_agent(Node, TargetName, - [{address, Addr}, - {port, Port}, - {engine_id, "agentEngine"}]), + ?line ok = + case IpFamily of + inet -> + mgr_user_register_agent( + Node, TargetName, + [{address, Ip}, + {port, Port}, + {engine_id, "agentEngine"}]); + inet6 -> + mgr_user_register_agent( + Node, TargetName, + [{tdomain, transportDomainUdpIpv6}, + {taddress, {Ip, Port}}, + {engine_id, "agentEngine"}]) + end, _Agents = mgr_user_which_own_agents(Node), ?DBG("Own agents: ~p", [_Agents]), @@ -6182,10 +6247,16 @@ await_stopped(Node, N) -> write_manager_config(Config) -> Dir = ?config(manager_conf_dir, Config), - Ip = ?config(ip, Config), - Addr = tuple_to_list(Ip), - snmp_config:write_manager_snmp_files(Dir, Addr, ?MGR_PORT, - ?MGR_MMS, ?MGR_ENGINE_ID, [], [], []). + Ip = tuple_to_list(?config(ip, Config)), + {Addr, Port} = + case ?config(ipfamily, Config) of + inet -> + {Ip, ?MGR_PORT}; + inet6 -> + {transportDomainUdpIpv6, {Ip, ?MGR_PORT}} + end, + snmp_config:write_manager_snmp_files( + Dir, Addr, Port, ?MGR_MMS, ?MGR_ENGINE_ID, [], [], []). write_manager_conf(Dir) -> Port = "5000", @@ -6214,25 +6285,27 @@ write_manager_conf(Dir, Str) -> write_agent_config(Vsns, Conf) -> Dir = ?config(agent_conf_dir, Conf), - Ip = ?config(ip, Conf), - ?line Addr = tuple_to_list(Ip), - ?line ok = write_agent_config_files(Dir, Vsns, Addr), + ?line Ip = tuple_to_list(?config(ip, Conf)), + ?line Domain = + case ?config(ipfamily, Conf) of + inet -> + snmpUDPDomain; + inet6 -> + transportDomainUdpIpv6 + end, + ?line ok = write_agent_config_files(Dir, Vsns, Domain, Ip), ?line ok = update_agent_usm(Vsns, Dir), ?line ok = update_agent_community(Vsns, Dir), ?line ok = update_agent_vacm(Vsns, Dir), - ?line ok = write_agent_target_addr_conf(Dir, Addr, Vsns), + ?line ok = write_agent_target_addr_conf(Dir, Domain, Ip, Vsns), ?line ok = write_agent_target_params_conf(Dir, Vsns), ?line ok = write_agent_notify_conf(Dir), ok. -write_agent_config_files(Dir, Vsns, Addr) -> - snmp_config:write_agent_snmp_files(Dir, Vsns, - Addr, ?MGR_PORT, - Addr, ?AGENT_PORT, - "mgr-test", "trap", - none, "", - ?AGENT_ENGINE_ID, - ?AGENT_MMS). +write_agent_config_files(Dir, Vsns, Domain, Ip) -> + snmp_config:write_agent_snmp_files( + Dir, Vsns, Domain, {Ip, ?MGR_PORT}, {Ip, ?AGENT_PORT}, "mgr-test", + trap, none, "", ?AGENT_ENGINE_ID, ?AGENT_MMS). update_agent_usm(Vsns, Dir) -> case lists:member(v3, Vsns) of @@ -6300,9 +6373,9 @@ update_agent_vacm(_Vsns, Dir) -> excluded, null}], snmp_config:update_agent_vacm_config(Dir, Conf). -write_agent_target_addr_conf(Dir, Addr, Vsns) -> - snmp_config:write_agent_snmp_target_addr_conf(Dir, Addr, ?MGR_PORT, - 300, 3, Vsns). +write_agent_target_addr_conf(Dir, Domain, Ip, Vsns) -> + snmp_config:write_agent_snmp_target_addr_conf( + Dir, Domain, {Ip, ?MGR_PORT}, 300, 3, Vsns). write_agent_target_params_conf(Dir, Vsns) -> F = fun(v1) -> {"target_v1", v1, v1, "all-rights", noAuthNoPriv}; @@ -6426,3 +6499,5 @@ formated_timestamp() -> %% p(TName, F, A) -> %% io:format("~w -> " ++ F ++ "~n", [TName|A]). +ipv6_init(Config) when is_list(Config) -> + [{ipfamily, inet6} | Config]. diff --git a/lib/snmp/test/snmp_test_lib.erl b/lib/snmp/test/snmp_test_lib.erl index fbb891e40d..5e611340a3 100644 --- a/lib/snmp/test/snmp_test_lib.erl +++ b/lib/snmp/test/snmp_test_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2013. All Rights Reserved. +%% Copyright Ericsson AB 2002-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -22,7 +22,7 @@ -include_lib("kernel/include/file.hrl"). --export([hostname/0, hostname/1, localhost/0, os_type/0, sz/1, +-export([hostname/0, hostname/1, localhost/0, localhost/1, os_type/0, sz/1, display_suite_info/1]). -export([non_pc_tc_maybe_skip/4, os_based_skip/1]). -export([fix_data_dir/1, @@ -60,6 +60,9 @@ from(_H, []) -> []. localhost() -> {ok, Ip} = snmp_misc:ip(net_adm:localhost()), Ip. +localhost(Family) -> + {ok, Ip} = snmp_misc:ip(net_adm:localhost(), Family), + Ip. sz(L) when is_list(L) -> length(L); diff --git a/lib/snmp/test/snmp_test_lib.hrl b/lib/snmp/test/snmp_test_lib.hrl index 8cc3f75dc5..9b7609b831 100644 --- a/lib/snmp/test/snmp_test_lib.hrl +++ b/lib/snmp/test/snmp_test_lib.hrl @@ -1,5 +1,5 @@ %%<copyright> -%% <year>2002-2008</year> +%% <year>2002-2014</year> %% <holder>Ericsson AB, All Rights Reserved</holder> %%</copyright> %%<legalnotice> @@ -32,14 +32,15 @@ -define(APPLICATION, snmp). -endif. --define(SCONF(K,D,C), snmp_test_lib:set_config(K,D,C)). --define(GCONF(K,C), snmp_test_lib:get_config(K,C)). --define(RCONF(K,C,V), snmp_test_lib:replace_config(K,C,V)). --define(HOSTNAME(N), snmp_test_lib:hostname(N)). --define(LOCALHOST(), snmp_test_lib:localhost()). --define(SZ(X), snmp_test_lib:sz(X)). --define(OSTYPE(), snmp_test_lib:os_type()). --define(DISPLAY_SUITE_INFO(), snmp_test_lib:display_suite_info(?MODULE)). +-define(SCONF(K,D,C), snmp_test_lib:set_config(K,D,C)). +-define(GCONF(K,C), snmp_test_lib:get_config(K,C)). +-define(RCONF(K,C,V), snmp_test_lib:replace_config(K,C,V)). +-define(HOSTNAME(N), snmp_test_lib:hostname(N)). +-define(LOCALHOST(), snmp_test_lib:localhost()). +-define(LOCALHOST(Family), snmp_test_lib:localhost(Family)). +-define(SZ(X), snmp_test_lib:sz(X)). +-define(OSTYPE(), snmp_test_lib:os_type()). +-define(DISPLAY_SUITE_INFO(), snmp_test_lib:display_suite_info(?MODULE)). %% - Test case macros - diff --git a/lib/snmp/test/snmp_test_mgr.erl b/lib/snmp/test/snmp_test_mgr.erl index d4eb00ff91..cf62edba1c 100644 --- a/lib/snmp/test/snmp_test_mgr.erl +++ b/lib/snmp/test/snmp_test_mgr.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2012. All Rights Reserved. +%% Copyright Ericsson AB 1996-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -235,21 +235,23 @@ init({Options, CallerPid}) -> VsnHdrD = {Com, User, EngineId, CtxEngineId, mk_seclevel(SecLevel)}, io:format("[~w] ~p -> VsnHdrD: ~p~n", [?MODULE, self(), VsnHdrD]), + IpFamily = get_value(ipfamily, Options, inet), + io:format("[~w] ~p -> IpFamily: ~p~n", [?MODULE, self(), IpFamily]), AgIp = case snmp_misc:assq(agent, Options) of {value, Tuple4} when is_tuple(Tuple4) andalso (size(Tuple4) =:= 4) -> Tuple4; {value, Host} when is_list(Host) -> - {ok, Ip} = snmp_misc:ip(Host), + {ok, Ip} = snmp_misc:ip(Host, IpFamily), Ip end, io:format("[~w] ~p -> AgIp: ~p~n", [?MODULE, self(), AgIp]), Quiet = lists:member(quiet, Options), io:format("[~w] ~p -> Quiet: ~p~n", [?MODULE, self(), Quiet]), - PackServ = start_packet_server(Quiet, Options, CallerPid, - AgIp, Udp, TrapUdp, - VsnHdrD, Version, Dir, RecBufSz, - PacksDbg), + PackServ = + start_packet_server( + Quiet, Options, CallerPid, AgIp, Udp, TrapUdp, + VsnHdrD, Version, Dir, RecBufSz, PacksDbg, IpFamily), d("init -> packet server: ~p",[PackServ]), State = #state{parent = CallerPid, quiet = Quiet, @@ -263,23 +265,21 @@ init({Options, CallerPid}) -> end. start_packet_server(false, _Options, _CallerPid, AgIp, Udp, TrapUdp, - VsnHdrD, Version, Dir, RecBufSz, PacksDbg) -> + VsnHdrD, Version, Dir, RecBufSz, PacksDbg, IpFamily) -> d("start_packet_server -> entry", []), - ?PACK_SERV:start_link_packet({msg, self()}, - AgIp, Udp, TrapUdp, - VsnHdrD, Version, Dir, RecBufSz, - PacksDbg); + ?PACK_SERV:start_link_packet( + {msg, self()}, AgIp, Udp, TrapUdp, + VsnHdrD, Version, Dir, RecBufSz, PacksDbg, IpFamily); start_packet_server(true, Options, CallerPid, AgIp, Udp, TrapUdp, - VsnHdrD, Version, Dir, RecBufSz, PacksDbg) -> + VsnHdrD, Version, Dir, RecBufSz, PacksDbg, IpFamily) -> Type = get_value(receive_type, Options, pdu), d("start_packet_server -> entry with" "~n CallerPid: ~p" "~n when" "~n Type: ~p",[CallerPid, Type]), - ?PACK_SERV:start_link_packet({Type, CallerPid}, - AgIp, Udp, TrapUdp, - VsnHdrD, Version, Dir, RecBufSz, - PacksDbg). + ?PACK_SERV:start_link_packet( + {Type, CallerPid}, AgIp, Udp, TrapUdp, + VsnHdrD, Version, Dir, RecBufSz, PacksDbg, IpFamily). is_options_ok([{mibs,List}|Opts]) when is_list(List) -> is_options_ok(Opts); @@ -287,6 +287,10 @@ is_options_ok([quiet|Opts]) -> is_options_ok(Opts); is_options_ok([{agent,_}|Opts]) -> is_options_ok(Opts); +is_options_ok([{ipfamily,IpFamily}|Opts]) + when IpFamily =:= inet; + IpFamily =:= inet6 -> + is_options_ok(Opts); is_options_ok([{agent_udp,Int}|Opts]) when is_integer(Int) -> is_options_ok(Opts); is_options_ok([{trap_udp,Int}|Opts]) when is_integer(Int) -> diff --git a/lib/snmp/test/snmp_test_mgr_misc.erl b/lib/snmp/test/snmp_test_mgr_misc.erl index 5525c5c3ec..5274dcacd9 100644 --- a/lib/snmp/test/snmp_test_mgr_misc.erl +++ b/lib/snmp/test/snmp_test_mgr_misc.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2012. All Rights Reserved. +%% Copyright Ericsson AB 1996-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -23,7 +23,7 @@ -module(snmp_test_mgr_misc). %% API --export([start_link_packet/8, start_link_packet/9, +-export([start_link_packet/8, start_link_packet/9, start_link_packet/10, stop/1, send_discovery_pdu/2, send_pdu/2, send_msg/4, send_bytes/2, @@ -31,7 +31,7 @@ get_pdu/1, set_pdu/2, format_hdr/1]). %% internal exports --export([init_packet/10]). +-export([init_packet/11]). -compile({no_auto_import, [error/2]}). @@ -42,22 +42,26 @@ %%---------------------------------------------------------------------- %% The InHandler process will receive messages on the form {snmp_pdu, Pdu}. %%---------------------------------------------------------------------- -start_link_packet(InHandler, - AgentIp, UdpPort, TrapUdp, - VsnHdr, Version, Dir, BufSz) -> - start_link_packet(InHandler, - AgentIp, UdpPort, TrapUdp, - VsnHdr, Version, Dir, BufSz, - false). - -start_link_packet(InHandler, - AgentIp, UdpPort, TrapUdp, - VsnHdr, Version, Dir, BufSz, - Dbg) when is_integer(UdpPort) -> - Args = [self(), InHandler, - AgentIp, UdpPort, TrapUdp, - VsnHdr, Version, Dir, BufSz, - Dbg], +start_link_packet( + InHandler, AgentIp, UdpPort, TrapUdp, VsnHdr, Version, Dir, BufSz) -> + start_link_packet( + InHandler, AgentIp, UdpPort, TrapUdp, VsnHdr, Version, Dir, BufSz, + false). + +start_link_packet( + InHandler, AgentIp, UdpPort, TrapUdp, VsnHdr, Version, Dir, BufSz, + Dbg) -> + start_link_packet( + InHandler, AgentIp, UdpPort, TrapUdp, VsnHdr, Version, Dir, BufSz, + Dbg, inet). + +start_link_packet( + InHandler, AgentIp, UdpPort, TrapUdp, VsnHdr, Version, Dir, BufSz, + Dbg, IpFamily) when is_integer(UdpPort) -> + Args = + [self(), + InHandler, AgentIp, UdpPort, TrapUdp, VsnHdr, Version, Dir, BufSz, + Dbg, IpFamily], proc_lib:start_link(?MODULE, init_packet, Args). stop(Pid) -> @@ -90,12 +94,14 @@ send_bytes(Bytes, PacketPid) -> %%-------------------------------------------------- %% The SNMP encode/decode process %%-------------------------------------------------- -init_packet(Parent, SnmpMgr, - AgentIp, UdpPort, TrapUdp, - VsnHdr, Version, Dir, BufSz, DbgOptions) -> +init_packet( + Parent, + SnmpMgr, AgentIp, UdpPort, TrapUdp, VsnHdr, Version, Dir, BufSz, + DbgOptions, IpFamily) -> put(sname, mgr_misc), init_debug(DbgOptions), - {ok, UdpId} = gen_udp:open(TrapUdp, [{recbuf,BufSz},{reuseaddr, true}]), + {ok, UdpId} = + gen_udp:open(TrapUdp, [{recbuf,BufSz}, {reuseaddr, true}, IpFamily]), put(msg_id, 1), proc_lib:init_ack(Parent, self()), init_usm(Version, Dir), diff --git a/lib/snmp/test/snmp_to_snmpnet_SUITE.erl b/lib/snmp/test/snmp_to_snmpnet_SUITE.erl new file mode 100644 index 0000000000..6e9c57bce9 --- /dev/null +++ b/lib/snmp/test/snmp_to_snmpnet_SUITE.erl @@ -0,0 +1,433 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2014-2014. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% This test suite uses the following external programs: +%% snmpget From packet 'snmp' (in Ubuntu 12.04) +%% snmptrapd From packet 'snmpd' (in Ubuntu 12.04) +%% They originate from the Net-SNMP applications, see: +%% http://net-snmp.sourceforge.net/ + + +-module(snmp_to_snmpnet_SUITE). + +%% Note: This directive should only be used in test suites. +-compile(export_all). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("snmp/include/STANDARD-MIB.hrl"). + +-define(AGENT_ENGINE_ID, "ErlangSnmpAgent"). +-define(AGENT_PORT, 4000). +-define(MANAGER_PORT, 8989). +-define(DEFAULT_MAX_MESSAGE_SIZE, 484). + +expected(?sysDescr_instance = Oid, get) -> + OidStr = oid_str(Oid), + iolist_to_binary([OidStr | " = STRING: \"Erlang SNMP agent\""]). + +%%-------------------------------------------------------------------- +%% Common Test interface functions ----------------------------------- +%%-------------------------------------------------------------------- + +suite() -> [{ct_hooks,[ts_install_cth]}]. + +all() -> + [ + {group, ipv4}, + {group, ipv6}, + {group, ipv4_ipv6} + ]. + +groups() -> + [{ipv4, [], + [{group, get}, + {group, inform} + ]}, + {ipv6, [], + [{group, get}, + {group, inform} + ]}, + {ipv4_ipv6, [], + [{group, get}, + {group, inform} + ]}, + %% + {get, [], + [erlang_agent_netsnmp_get]}, + {inform, [], + [erlang_agent_netsnmp_inform]} + ]. + +init_per_suite(Config) -> + [{agent_port, ?AGENT_PORT}, {manager_port, ?MANAGER_PORT} | Config]. + +end_per_suite(_Config) -> + ok. + +init_per_group(ipv4, Config) -> + init_per_group_ip([inet], Config); +init_per_group(ipv6, Config) -> + init_per_group_ipv6([inet6], Config); +init_per_group(ipv4_ipv6, Config) -> + init_per_group_ipv6([inet, inet6], Config); +%% +init_per_group(get, Config) -> + %% From Ubuntu package snmp + find_executable(snmpget, Config); +init_per_group(inform, Config) -> + %% From Ubuntu package snmpd + find_executable(snmptrapd, Config); +%% +init_per_group(_, Config) -> + Config. + +init_per_group_ipv6(Families, Config) -> + case ct:require(ipv6_hosts) of + ok -> + init_per_group_ip(Families, Config); + _ -> + {skip, "Host does not support IPV6"} + end. + +init_per_group_ip(Families, Config) -> + Dir = ?config(priv_dir, Config), + AgentPort = ?config(agent_port, Config), + ManagerPort = ?config(manager_port, Config), + Versions = [v2], + {ok, Host} = inet:gethostname(), + Transports = + [begin + {ok, Addr} = inet:getaddr(Host, Family), + {domain(Family), {Addr, AgentPort}} + end || Family <- Families], + Targets = + [begin + {ok, Addr} = inet:getaddr(Host, Family), + {domain(Family), {Addr, ManagerPort}} + end || Family <- Families], + agent_config(Dir, Transports, Targets, Versions), + [{port, ?AGENT_PORT}, {snmp_versions, Versions}, + {transports, Transports}, {targets, Targets} + | Config]. + + + +end_per_group(_GroupName, Config) -> + Config. + +init_per_testcase(_Case, Config) -> + Dog = ct:timetrap(10000), + application:stop(snmp), + application:unload(snmp), + [{watchdog, Dog} | Config]. + +end_per_testcase(_, Config) -> + case application:stop(snmp) of + ok -> + ok; + E1 -> + ct:pal("application:stop(snmp) -> ~p", [E1]) + end, + case application:unload(snmp) of + ok -> + ok; + E2 -> + ct:pal("application:unload(snmp) -> ~p", [E2]) + end, + Config. + +find_executable(Exec, Config) -> + ExecStr = atom_to_list(Exec), + case os:find_executable(ExecStr) of + false -> + %% The sbin dirs are not in the PATH on all platforms... + find_sys_executable( + Exec, ExecStr, + [["usr", "local", "sbin"], + ["usr", "sbin"], + ["sbin"]], + Config); + Path -> + [{Exec, Path} | Config] + end. + +find_sys_executable(_Exec, ExecStr, [], _Config) -> + {skip, ExecStr ++ " not found"}; +find_sys_executable(Exec, ExecStr, [Dir | Dirs], Config) -> + case os:find_executable(filename:join(["/" | Dir] ++ [ExecStr])) of + false -> + find_sys_executable(Exec, ExecStr, Dirs, Config); + Path -> + [{Exec, Path} | Config] + end. + +start_agent(Config) -> + ok = application:load(snmp), + ok = application:set_env(snmp, agent, app_env(Config)), + ok = application:start(snmp). + +%%-------------------------------------------------------------------- +%% Test Cases -------------------------------------------------------- +%%-------------------------------------------------------------------- +erlang_agent_netsnmp_get() -> + [{doc,"Test that we can access erlang snmp agent " + "from snmpnet manager"}]. + +erlang_agent_netsnmp_get(Config) when is_list(Config) -> + Transports = ?config(transports, Config), + start_agent(Config), + Oid = ?sysDescr_instance, + Expected = expected(Oid, get), + [Expected = snmpget(Oid, Transport, Config) + || Transport <- Transports], + ok. + +%%-------------------------------------------------------------------- +erlang_agent_netsnmp_inform(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + Mib = "TestTrapv2", + + start_agent(Config), + ok = snmpa:load_mib(snmp_master_agent, filename:join(DataDir, Mib)), + + ProgHandle = start_snmptrapd(Mib, Config), + + snmpa:send_notification( + snmp_master_agent, testTrapv22, {erlang_agent_test, self()}), + + receive + {snmp_targets, erlang_agent_test, Addresses} -> + ct:pal("Notification sent to: ~p~n", [Addresses]), + erlang_agent_netsnmp_inform_responses(Addresses) + end, + stop_program(ProgHandle). + +erlang_agent_netsnmp_inform_responses([]) -> + receive + {snmp_notification, erlang_agent_test, _} = Unexpected -> + ct:pal("Unexpected response: ~p", [Unexpected]), + erlang_agent_netsnmp_inform_responses([]) + after 0 -> + ok + end; +erlang_agent_netsnmp_inform_responses([Address | Addresses]) -> + receive + {snmp_notification, erlang_agent_test, + {got_response, Address}} -> + ct:pal("Got response from: ~p~n", [Address]), + erlang_agent_netsnmp_inform_responses(Addresses); + {snmp_notification, erlang_agent_test, + {no_response, _} = NoResponse} -> + ct:fail(NoResponse) + end. + +%%-------------------------------------------------------------------- +%% Internal functions ------------------------------------------------ +%%-------------------------------------------------------------------- +snmpget(Oid, Transport, Config) -> + Versions = ?config(snmp_versions, Config), + + Args = + ["-c", "public", net_snmp_version(Versions), + "-m", "", + "-Cf", + net_snmp_addr_str(Transport), + oid_str(Oid)], + ProgHandle = start_program(snmpget, Args, none, Config), + {_, line, Line} = get_program_output(ProgHandle), + stop_program(ProgHandle), + Line. + +start_snmptrapd(Mibs, Config) -> + DataDir = ?config(data_dir, Config), + MibDir = filename:join(code:lib_dir(snmp), "mibs"), + Targets = ?config(targets, Config), + SnmptrapdArgs = + ["-f", "-Lo", "-C", + "-m", Mibs, + "-M", MibDir++":"++DataDir, + "--disableAuthorization=yes", + "--snmpTrapdAddr=" ++ net_snmp_addr_str(Targets)], + {ok, StartCheckMP} = re:compile("NET-SNMP version ", [anchored]), + start_program(snmptrapd, SnmptrapdArgs, StartCheckMP, Config). + +start_program(Prog, Args, StartCheckMP, Config) -> + Path = ?config(Prog, Config), + DataDir = ?config(data_dir, Config), + StartWrapper = filename:join(DataDir, "start_stop_wrapper"), + Parent = self(), + Pid = + spawn_link( + fun () -> + run_program(Parent, StartWrapper, [Path | Args]) + end), + start_check(Pid, erlang:monitor(process, Pid), StartCheckMP). + +start_check(Pid, Mon, none) -> + {Pid, Mon}; +start_check(Pid, Mon, StartCheckMP) -> + receive + {Pid, line, Line} -> + case re:run(Line, StartCheckMP, [{capture, none}]) of + match -> + {Pid, Mon}; + nomatch -> + start_check(Pid, Mon, StartCheckMP) + end; + {'DOWN', Mon, _, _, Reason} -> + ct:fail("Prog ~p start failed: ~p", [Pid, Reason]) + end. + +get_program_output({Pid, Mon}) -> + receive + {Pid, _, _} = Msg -> + Msg; + {'DOWN', Mon, _, _, Reason} -> + ct:fail("Prog ~p crashed: ~p", [Pid, Reason]) + end. + +stop_program({Pid, _} = Handle) -> + Pid ! {self(), stop}, + wait_program_stop(Handle). + +wait_program_stop({Pid, Mon}) -> + receive + {Pid, exit, ExitStatus} -> + receive + {'DOWN', Mon, _, _, _} -> + ExitStatus + end; + {'DOWN', Mon, _, _, Reason} -> + ct:fail("Prog stop: ~p", [Reason]) + end. + +run_program(Parent, StartWrapper, ProgAndArgs) -> + Port = + open_port( + {spawn_executable, StartWrapper}, + [{args, ProgAndArgs}, binary, stderr_to_stdout, {line, 80}, + exit_status]), + ct:pal("Prog ~p started: ~p", [Port, ProgAndArgs]), + run_program_loop(Parent, Port, []). + +run_program_loop(Parent, Port, Buf) -> + receive + {Parent, stop} -> + true = port_command(Port, <<"stop\n">>), + ct:pal("Prog ~p stop", [Port]), + run_program_loop(Parent, Port, Buf); + {Port, {data, {Flag, Data}}} -> + case Flag of + eol -> + Line = iolist_to_binary(lists:reverse(Buf, Data)), + ct:pal("Prog ~p output: ~s", [Port, Line]), + Parent ! {self(), line, Line}, + run_program_loop(Parent, Port, []); + noeol -> + run_program_loop(Parent, Port, [Data | Buf]) + end; + {Port, {exit_status,ExitStatus}} -> + ct:pal("Prog ~p exit: ~p", [Port, ExitStatus]), + catch port_close(Port), + Parent ! {self(), exit, ExitStatus}; + Unexpected -> + ct:pal("run_program_loop Unexpected: ~p", [Unexpected]), + run_program_loop(Parent, Port, Buf) + end. + + +app_env(Config) -> + Dir = ?config(priv_dir, Config), + Vsns = ?config(snmp_versions, Config), + [{versions, Vsns}, + {agent_type, master}, + {agent_verbosity, trace}, + {db_dir, Dir}, + {audit_trail_log, [{type, read_write}, + {dir, Dir}, + {size, {10240, 10}}]}, + {config, [{dir, Dir}, + {force_load, true}, + {verbosity, trace}]}, + {local_db, [{repair, true}, + {verbosity, silence}]}, + {mib_server, [{verbosity, silence}]}, + {symbolic_store, [{verbosity, silence}]}, + {note_store, [{verbosity, silence}]}, + {net_if, [{verbosity, trace}]}]. + +oid_str([1 | Ints]) -> + "iso." ++ oid_str_tl(Ints); +oid_str(Ints) -> + oid_str_tl(Ints). + +oid_str_tl([]) -> + ""; +oid_str_tl([Int]) -> + integer_to_list(Int); +oid_str_tl([Int | Ints]) -> + integer_to_list(Int) ++ "." ++ oid_str_tl(Ints). + +agent_config(Dir, Transports, TargetDomain, TargetAddr, Versions) -> + agent_config(Dir, Transports, [{TargetDomain, TargetAddr}], Versions). +%% +agent_config(Dir, Transports, Targets, Versions) -> + EngineID = ?AGENT_ENGINE_ID, + MMS = ?DEFAULT_MAX_MESSAGE_SIZE, + ok = snmp_config:write_agent_snmp_conf(Dir, Transports, EngineID, MMS), + ok = snmp_config:write_agent_snmp_context_conf(Dir), + ok = snmp_config:write_agent_snmp_community_conf(Dir), + ok = + snmp_config:write_agent_snmp_standard_conf( + Dir, "snmp_to_snmpnet_SUITE"), + ok = + snmp_config:write_agent_snmp_target_addr_conf( + Dir, Targets, Versions), + ok = snmp_config:write_agent_snmp_target_params_conf(Dir, Versions), + ok = snmp_config:write_agent_snmp_notify_conf(Dir, inform), + ok = snmp_config:write_agent_snmp_vacm_conf(Dir, Versions, none). + +net_snmp_version([v3 | _]) -> + "-v3"; +net_snmp_version([v2 | _]) -> + "-v2c"; +net_snmp_version([v1 | _]) -> + "-v1". + +domain(inet) -> + transportDomainUdpIpv4; +domain(inet6) -> + transportDomainUdpIpv6. + +net_snmp_addr_str([Target | Targets]) -> + net_snmp_addr_str(Target) ++ + case Targets of + [] -> + []; + [_ | _] -> + "," ++ net_snmp_addr_str(Targets) + end; +net_snmp_addr_str({transportDomainUdpIpv4, {Addr, Port}}) -> + "udp:" ++ + inet_parse:ntoa(Addr) ++ ":" ++ + integer_to_list(Port); +net_snmp_addr_str({transportDomainUdpIpv6, {Addr, Port}}) -> + "udp6:[" ++ + inet_parse:ntoa(Addr) ++ "]:" ++ + integer_to_list(Port). diff --git a/lib/snmp/test/snmp_to_snmpnet_SUITE_data/TestTrapv2.bin b/lib/snmp/test/snmp_to_snmpnet_SUITE_data/TestTrapv2.bin Binary files differnew file mode 100644 index 0000000000..9d0790498d --- /dev/null +++ b/lib/snmp/test/snmp_to_snmpnet_SUITE_data/TestTrapv2.bin diff --git a/lib/snmp/test/snmp_to_snmpnet_SUITE_data/TestTrapv2.mib b/lib/snmp/test/snmp_to_snmpnet_SUITE_data/TestTrapv2.mib new file mode 100644 index 0000000000..679ddc14b0 --- /dev/null +++ b/lib/snmp/test/snmp_to_snmpnet_SUITE_data/TestTrapv2.mib @@ -0,0 +1,71 @@ +TestTrapv2 DEFINITIONS ::= BEGIN + +IMPORTS + MODULE-IDENTITY, OBJECT-TYPE, NOTIFICATION-TYPE, + TimeTicks, Counter32, snmpModules, mib-2, enterprises, IpAddress, + Integer32 + FROM SNMPv2-SMI + DisplayString, TestAndIncr, TimeStamp, RowStatus, TruthValue, + TEXTUAL-CONVENTION + FROM SNMPv2-TC + MODULE-COMPLIANCE, OBJECT-GROUP, NOTIFICATION-GROUP + FROM SNMPv2-CONF + + system, snmp, ifIndex, ifAdminStatus, ifOperStatus + FROM RFC1213-MIB + snmpTraps + FROM SNMPv2-MIB; + +testTrapv2 MODULE-IDENTITY + LAST-UPDATED "9511090000Z" + ORGANIZATION "IETF SNMPv2 Working Group" + CONTACT-INFO + " Marshall T. Rose + + Postal: Dover Beach Consulting, Inc. + 420 Whisman Court + Mountain View, CA 94043-2186 + US + + Tel: +1 415 968 1052 + + E-mail: [email protected]" + DESCRIPTION + "The MIB module for SNMPv2 entities." + REVISION "9304010000Z" + DESCRIPTION + "The initial revision of this MIB module was published as + RFC 1450." + ::= { system 100 } + + +tst OBJECT IDENTIFIER ::= { system 0 } + +testTrapv21 NOTIFICATION-TYPE + STATUS current + DESCRIPTION + "This trap is exactly the v2 correspondance of testTrap1 in + TestTrap mib." + ::= { snmp 1 } + +testTrapv22 NOTIFICATION-TYPE + STATUS current + DESCRIPTION + "This trap is exactly the v2 correspondance of testTrap2 in + TestTrap mib." + ::= { system 0 1 } + +linkUp NOTIFICATION-TYPE + OBJECTS { ifIndex, ifAdminStatus, ifOperStatus } + STATUS current + DESCRIPTION + "A linkUp trap signifies that the SNMPv2 entity, + acting in an agent role, has detected that the + ifOperStatus object for one of its communication links + has transitioned out of the down state." + ::= { snmpTraps 4 } + + + + +END diff --git a/lib/snmp/test/snmp_to_snmpnet_SUITE_data/start_stop_wrapper b/lib/snmp/test/snmp_to_snmpnet_SUITE_data/start_stop_wrapper new file mode 100755 index 0000000000..f806ab5c12 --- /dev/null +++ b/lib/snmp/test/snmp_to_snmpnet_SUITE_data/start_stop_wrapper @@ -0,0 +1,47 @@ +#! /bin/sh +## +## %CopyrightBegin% +## +## Copyright Ericsson AB 2014-2014. All Rights Reserved. +## +## The contents of this file are subject to the Erlang Public License, +## Version 1.1, (the "License"); you may not use this file except in +## compliance with the License. You should have received a copy of the +## Erlang Public License along with this software. If not, it can be +## retrieved online at http://www.erlang.org/. +## +## Software distributed under the License is distributed on an "AS IS" +## basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +## the License for the specific language governing rights and limitations +## under the License. +## +## %CopyrightEnd% +## +# + +## Start the given executable, wait for stop command, +## stop the running executable and wait for exit. + +die () { + r=$? + echo "$0:" "$*" 1>&2 + exit $r +} + +test -x "$1" || die "Not Executable: $1" + +# Redirect stdin to make sure the stop command is read by us below +# and does not go to the executable +"$@" 0< /dev/null & +PID=$! + +# Wait for stop command +while read LINE; do + case :"$LINE" in + :"stop") + break;; + esac +done + +kill $PID +wait $PID diff --git a/lib/snmp/vsn.mk b/lib/snmp/vsn.mk index 04c3cc9392..fd10244386 100644 --- a/lib/snmp/vsn.mk +++ b/lib/snmp/vsn.mk @@ -18,6 +18,6 @@ # %CopyrightEnd% APPLICATION = snmp -SNMP_VSN = 4.25.1 +SNMP_VSN = 5.0 PRE_VSN = APP_VSN = "$(APPLICATION)-$(SNMP_VSN)$(PRE_VSN)" diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml index 0dbec7527a..60440d3a80 100644 --- a/lib/ssh/doc/src/notes.xml +++ b/lib/ssh/doc/src/notes.xml @@ -29,6 +29,27 @@ <file>notes.xml</file> </header> +<section><title>Ssh 3.0.4</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + When starting an ssh-daemon giving the option + {parallel_login, true}, the timeout for authentication + negotiation ({negotiation_timeout, integer()}) was never + removed.</p> + <p> + This caused the session to always be terminated after the + timeout if parallel_login was set.</p> + <p> + Own Id: OTP-12057 Aux Id: seq12663 </p> + </item> + </list> + </section> + +</section> + <section><title>Ssh 3.0.3</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl index 06866392da..86804c4436 100644 --- a/lib/ssh/src/ssh_connection_handler.erl +++ b/lib/ssh/src/ssh_connection_handler.erl @@ -104,21 +104,11 @@ start_connection(client = Role, Socket, Options, Timeout) -> start_connection(server = Role, Socket, Options, Timeout) -> try - Sups = proplists:get_value(supervisors, Options), - ConnectionSup = proplists:get_value(connection_sup, Sups), - Opts = [{supervisors, Sups}, {user_pid, self()} | proplists:get_value(ssh_opts, Options, [])], - {ok, Pid} = ssh_connection_sup:start_child(ConnectionSup, [Role, Socket, Opts]), - {_, Callback, _} = proplists:get_value(transport, Options, {tcp, gen_tcp, tcp_closed}), - socket_control(Socket, Pid, Callback), - case proplists:get_value(parallel_login, Opts, false) of + case proplists:get_value(parallel_login, Options, false) of true -> - spawn(fun() -> - Ref = erlang:monitor(process, Pid), - handshake(Pid, Ref, Timeout) - end); + spawn(fun() -> start_server_connection(Role, Socket, Options, Timeout) end); false -> - Ref = erlang:monitor(process, Pid), - handshake(Pid, Ref, Timeout) + start_server_connection(Role, Socket, Options, Timeout) end catch exit:{noproc, _} -> @@ -127,6 +117,18 @@ start_connection(server = Role, Socket, Options, Timeout) -> {error, Error} end. + +start_server_connection(server = Role, Socket, Options, Timeout) -> + Sups = proplists:get_value(supervisors, Options), + ConnectionSup = proplists:get_value(connection_sup, Sups), + Opts = [{supervisors, Sups}, {user_pid, self()} | proplists:get_value(ssh_opts, Options, [])], + {ok, Pid} = ssh_connection_sup:start_child(ConnectionSup, [Role, Socket, Opts]), + {_, Callback, _} = proplists:get_value(transport, Options, {tcp, gen_tcp, tcp_closed}), + socket_control(Socket, Pid, Callback), + Ref = erlang:monitor(process, Pid), + handshake(Pid, Ref, Timeout). + + start_link(Role, Socket, Options) -> {ok, proc_lib:spawn_link(?MODULE, init, [[Role, Socket, Options]])}. diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl index bf7fb4c73e..9242731924 100644 --- a/lib/ssh/test/ssh_basic_SUITE.erl +++ b/lib/ssh/test/ssh_basic_SUITE.erl @@ -53,13 +53,21 @@ all() -> {group, hardening_tests} ]. -groups() -> +groups() -> [{dsa_key, [], basic_tests()}, {rsa_key, [], basic_tests()}, {dsa_pass_key, [], [pass_phrase]}, {rsa_pass_key, [], [pass_phrase]}, {internal_error, [], [internal_error]}, - {hardening_tests, [], [max_sessions]} + {hardening_tests, [], [ssh_connect_nonegtimeout_connected_parallel, + ssh_connect_nonegtimeout_connected_sequential, + ssh_connect_negtimeout_parallel, + ssh_connect_negtimeout_sequential, + max_sessions_ssh_connect_parallel, + max_sessions_ssh_connect_sequential, + max_sessions_sftp_start_channel_parallel, + max_sessions_sftp_start_channel_sequential + ]} ]. @@ -743,6 +751,98 @@ ms_passed(N1={_,_,M1}, N2={_,_,M2}) -> 1000 * (Min*60 + Sec + (M2-M1)/1000000). %%-------------------------------------------------------------------- +ssh_connect_negtimeout_parallel(Config) -> ssh_connect_negtimeout(Config,true). +ssh_connect_negtimeout_sequential(Config) -> ssh_connect_negtimeout(Config,false). + +ssh_connect_negtimeout(Config, Parallel) -> + process_flag(trap_exit, true), + SystemDir = filename:join(?config(priv_dir, Config), system), + UserDir = ?config(priv_dir, Config), + NegTimeOut = 2000, % ms + ct:log("Parallel: ~p",[Parallel]), + + {_Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},{user_dir, UserDir}, + {parallel_login, Parallel}, + {negotiation_timeout, NegTimeOut}, + {failfun, fun ssh_test_lib:failfun/2}]), + + {ok,Socket} = gen_tcp:connect(Host, Port, []), + ct:pal("And now sleeping 1.2*NegTimeOut (~p ms)...", [round(1.2 * NegTimeOut)]), + receive after round(1.2 * NegTimeOut) -> ok end, + + case inet:sockname(Socket) of + {ok,_} -> ct:fail("Socket not closed"); + {error,_} -> ok + end. + +%%-------------------------------------------------------------------- +ssh_connect_nonegtimeout_connected_parallel() -> + [{doc, "Test that ssh connection does not timeout if the connection is established (parallel)"}]. +ssh_connect_nonegtimeout_connected_parallel(Config) -> + ssh_connect_nonegtimeout_connected(Config, true). + +ssh_connect_nonegtimeout_connected_sequential() -> + [{doc, "Test that ssh connection does not timeout if the connection is established (non-parallel)"}]. +ssh_connect_nonegtimeout_connected_sequential(Config) -> + ssh_connect_nonegtimeout_connected(Config, false). + + +ssh_connect_nonegtimeout_connected(Config, Parallel) -> + process_flag(trap_exit, true), + SystemDir = filename:join(?config(priv_dir, Config), system), + UserDir = ?config(priv_dir, Config), + NegTimeOut = 20000, % ms + ct:log("Parallel: ~p",[Parallel]), + + {_Pid, _Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},{user_dir, UserDir}, + {parallel_login, Parallel}, + {negotiation_timeout, NegTimeOut}, + {failfun, fun ssh_test_lib:failfun/2}]), + ct:sleep(500), + + IO = ssh_test_lib:start_io_server(), + Shell = ssh_test_lib:start_shell(Port, IO, UserDir), + receive + {'EXIT', _, _} -> + ct:fail(no_ssh_connection); + ErlShellStart -> + ct:pal("---Erlang shell start: ~p~n", [ErlShellStart]), + one_shell_op(IO, NegTimeOut), + one_shell_op(IO, NegTimeOut), + ct:pal("And now sleeping 1.2*NegTimeOut (~p ms)...", [round(1.2 * NegTimeOut)]), + receive after round(1.2 * NegTimeOut) -> ok end, + one_shell_op(IO, NegTimeOut) + end, + exit(Shell, kill). + + +one_shell_op(IO, TimeOut) -> + ct:pal("One shell op: Waiting for prompter"), + receive + ErlPrompt0 -> ct:log("Erlang prompt: ~p~n", [ErlPrompt0]) + after TimeOut -> ct:fail("Timeout waiting for promter") + end, + + IO ! {input, self(), "2*3*7.\r\n"}, + receive + Echo0 -> ct:log("Echo: ~p ~n", [Echo0]) + after TimeOut -> ct:fail("Timeout waiting for echo") + end, + + receive + ?NEWLINE -> ct:log("NEWLINE received", []) + after TimeOut -> + receive Any1 -> ct:log("Bad NEWLINE: ~p",[Any1]) + after 0 -> ct:fail("Timeout waiting for NEWLINE") + end + end, + + receive + Result0 -> ct:log("Result: ~p~n", [Result0]) + after TimeOut -> ct:fail("Timeout waiting for result") + end. + +%%-------------------------------------------------------------------- openssh_zlib_basic_test() -> [{doc, "Test basic connection with openssh_zlib"}]. @@ -763,40 +863,87 @@ openssh_zlib_basic_test(Config) -> %%-------------------------------------------------------------------- -max_sessions(Config) -> +max_sessions_ssh_connect_parallel(Config) -> + max_sessions(Config, true, connect_fun(ssh__connect,Config)). +max_sessions_ssh_connect_sequential(Config) -> + max_sessions(Config, false, connect_fun(ssh__connect,Config)). + +max_sessions_sftp_start_channel_parallel(Config) -> + max_sessions(Config, true, connect_fun(ssh_sftp__start_channel, Config)). +max_sessions_sftp_start_channel_sequential(Config) -> + max_sessions(Config, false, connect_fun(ssh_sftp__start_channel, Config)). + + +%%%---- helpers: +connect_fun(ssh__connect, Config) -> + fun(Host,Port) -> + ssh_test_lib:connect(Host, Port, + [{silently_accept_hosts, true}, + {user_dir, ?config(priv_dir,Config)}, + {user_interaction, false}, + {user, "carni"}, + {password, "meat"} + ]) + %% ssh_test_lib returns R when ssh:connect returns {ok,R} + end; +connect_fun(ssh_sftp__start_channel, _Config) -> + fun(Host,Port) -> + {ok,_Pid,ConnRef} = + ssh_sftp:start_channel(Host, Port, + [{silently_accept_hosts, true}, + {user, "carni"}, + {password, "meat"} + ]), + ConnRef + end. + + +max_sessions(Config, ParallelLogin, Connect) when is_function(Connect,2) -> SystemDir = filename:join(?config(priv_dir, Config), system), UserDir = ?config(priv_dir, Config), - MaxSessions = 2, - {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, + MaxSessions = 5, + {Pid, Host, Port} = ssh_test_lib:daemon([ + {system_dir, SystemDir}, {user_dir, UserDir}, {user_passwords, [{"carni", "meat"}]}, - {parallel_login, true}, + {parallel_login, ParallelLogin}, {max_sessions, MaxSessions} ]), - Connect = fun() -> - R=ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, - {user_dir, UserDir}, - {user_interaction, false}, - {user, "carni"}, - {password, "meat"} - ]), - ct:log("Connection ~p up",[R]) - end, - - try [Connect() || _ <- lists:seq(1,MaxSessions)] + try [Connect(Host,Port) || _ <- lists:seq(1,MaxSessions)] of - _ -> - ct:pal("Expect Info Report:",[]), - try Connect() + Connections -> + %% Step 1 ok: could set up max_sessions connections + ct:log("Connections up: ~p",[Connections]), + [_|_] = Connections, + + %% Now try one more than alowed: + ct:pal("Info Report might come here...",[]), + try Connect(Host,Port) of - _ConnectionRef -> + _ConnectionRef1 -> ssh:stop_daemon(Pid), {fail,"Too many connections accepted"} catch error:{badmatch,{error,"Connection closed"}} -> - ssh:stop_daemon(Pid), - ok + %% Step 2 ok: could not set up max_sessions+1 connections + %% This is expected + %% Now stop one connection and try to open one more + ok = ssh:close(hd(Connections)), + try Connect(Host,Port) + of + _ConnectionRef1 -> + %% Step 3 ok: could set up one more connection after killing one + %% Thats good. + ssh:stop_daemon(Pid), + ok + catch + error:{badmatch,{error,"Connection closed"}} -> + %% Bad indeed. Could not set up one more connection even after killing + %% one existing. Very bad. + ssh:stop_daemon(Pid), + {fail,"Does not decrease # active sessions"} + end end catch error:{badmatch,{error,"Connection closed"}} -> diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk index 8d1a7ae54f..9bef10a366 100644 --- a/lib/ssh/vsn.mk +++ b/lib/ssh/vsn.mk @@ -1,5 +1,5 @@ #-*-makefile-*- ; force emacs to enter makefile-mode -SSH_VSN = 3.0.3 +SSH_VSN = 3.0.4 APP_VSN = "ssh-$(SSH_VSN)" diff --git a/lib/ssl/doc/src/ssl_protocol.xml b/lib/ssl/doc/src/ssl_protocol.xml index cdfafe224b..80d9cc4ee8 100644 --- a/lib/ssl/doc/src/ssl_protocol.xml +++ b/lib/ssl/doc/src/ssl_protocol.xml @@ -83,7 +83,7 @@ <em>subject</em>. The certificate is signed with the private key of the issuer of the certificate. A chain of trust is build by having the issuer in its turn being - certified by an other certificate and so on until you reach the + certified by another certificate and so on until you reach the so called root certificate that is self signed i.e. issued by itself.</p> diff --git a/lib/ssl/src/ssl_certificate.erl b/lib/ssl/src/ssl_certificate.erl index b186a1015a..53366b060c 100644 --- a/lib/ssl/src/ssl_certificate.erl +++ b/lib/ssl/src/ssl_certificate.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2013. All Rights Reserved. +%% Copyright Ericsson AB 2007-2014 All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -232,7 +232,12 @@ find_issuer(OtpCert, CertDbHandle) -> IsIssuerFun = fun({_Key, {_Der, #'OTPCertificate'{} = ErlCertCandidate}}, Acc) -> case public_key:pkix_is_issuer(OtpCert, ErlCertCandidate) of true -> - throw(public_key:pkix_issuer_id(ErlCertCandidate, self)); + case verify_cert_signer(OtpCert, ErlCertCandidate#'OTPCertificate'.tbsCertificate) of + true -> + throw(public_key:pkix_issuer_id(ErlCertCandidate, self)); + false -> + Acc + end; false -> Acc end; @@ -254,3 +259,19 @@ is_valid_extkey_usage(KeyUse, client) -> is_valid_extkey_usage(KeyUse, server) -> %% Server wants to verify client is_valid_key_usage(KeyUse, ?'id-kp-clientAuth'). + +verify_cert_signer(OtpCert, SignerTBSCert) -> + PublicKey = public_key(SignerTBSCert#'OTPTBSCertificate'.subjectPublicKeyInfo), + public_key:pkix_verify(public_key:pkix_encode('OTPCertificate', OtpCert, otp), PublicKey). + +public_key(#'OTPSubjectPublicKeyInfo'{algorithm = #'PublicKeyAlgorithm'{algorithm = ?'id-ecPublicKey', + parameters = Params}, + subjectPublicKey = Point}) -> + {Point, Params}; +public_key(#'OTPSubjectPublicKeyInfo'{algorithm = #'PublicKeyAlgorithm'{algorithm = ?'rsaEncryption'}, + subjectPublicKey = Key}) -> + Key; +public_key(#'OTPSubjectPublicKeyInfo'{algorithm = #'PublicKeyAlgorithm'{algorithm = ?'id-dsa', + parameters = {params, Params}}, + subjectPublicKey = Key}) -> + {Key, Params}. diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index b018332df1..94ffd180c5 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -201,13 +201,13 @@ client_certificate_verify(OwnCert, MasterSecret, Version, end. %%-------------------------------------------------------------------- --spec certificate_request(ssl_cipher:erl_cipher_suite(), db_handle(), certdb_ref(), ssl_record:ssl_version()) -> +-spec certificate_request(ssl_cipher:cipher_suite(), db_handle(), certdb_ref(), ssl_record:ssl_version()) -> #certificate_request{}. %% %% Description: Creates a certificate_request message, called by the server. %%-------------------------------------------------------------------- certificate_request(CipherSuite, CertDbHandle, CertDbRef, Version) -> - Types = certificate_types(CipherSuite), + Types = certificate_types(ssl_cipher:suite_definition(CipherSuite), Version), HashSigns = advertised_hash_signs(Version), Authorities = certificate_authorities(CertDbHandle, CertDbRef), #certificate_request{ @@ -1098,19 +1098,31 @@ supported_ecc(_) -> %%-------------certificate handling -------------------------------- -certificate_types({KeyExchange, _, _, _}) - when KeyExchange == rsa; - KeyExchange == dhe_dss; - KeyExchange == dhe_rsa; - KeyExchange == ecdhe_rsa -> - <<?BYTE(?RSA_SIGN), ?BYTE(?DSS_SIGN)>>; +certificate_types(_, {N, M}) when N >= 3 andalso M >= 3 -> + case proplists:get_bool(ecdsa, + proplists:get_value(public_keys, crypto:supports())) of + true -> + <<?BYTE(?ECDSA_SIGN), ?BYTE(?RSA_SIGN), ?BYTE(?DSS_SIGN)>>; + false -> + <<?BYTE(?RSA_SIGN), ?BYTE(?DSS_SIGN)>> + end; + +certificate_types({KeyExchange, _, _, _}, _) when KeyExchange == rsa; + KeyExchange == dhe_rsa; + KeyExchange == ecdhe_rsa -> + <<?BYTE(?RSA_SIGN)>>; + +certificate_types({KeyExchange, _, _, _}, _) when KeyExchange == dhe_dss; + KeyExchange == srp_dss -> + <<?BYTE(?DSS_SIGN)>>; -certificate_types({KeyExchange, _, _, _}) - when KeyExchange == dh_ecdsa; - KeyExchange == dhe_ecdsa -> +certificate_types({KeyExchange, _, _, _}, _) when KeyExchange == dh_ecdsa; + KeyExchange == dhe_ecdsa; + KeyExchange == ecdh_ecdsa; + KeyExchange == ecdhe_ecdsa -> <<?BYTE(?ECDSA_SIGN)>>; -certificate_types(_) -> +certificate_types(_, _) -> <<?BYTE(?RSA_SIGN)>>. certificate_authorities(CertDbHandle, CertDbRef) -> diff --git a/lib/ssl/test/erl_make_certs.erl b/lib/ssl/test/erl_make_certs.erl index 22dc951ac1..daf4466f11 100644 --- a/lib/ssl/test/erl_make_certs.erl +++ b/lib/ssl/test/erl_make_certs.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011-2013. All Rights Reserved. +%% Copyright Ericsson AB 2011-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -325,14 +325,14 @@ sign_algorithm(#'RSAPrivateKey'{}, Opts) -> {Type, 'NULL'}; sign_algorithm(#'DSAPrivateKey'{p=P, q=Q, g=G}, _Opts) -> {?'id-dsa-with-sha1', {params,#'Dss-Parms'{p=P, q=Q, g=G}}}; -sign_algorithm(#'ECPrivateKey'{}, Opts) -> +sign_algorithm(#'ECPrivateKey'{parameters = Parms}, Opts) -> Type = case proplists:get_value(digest, Opts, sha1) of sha1 -> ?'ecdsa-with-SHA1'; sha512 -> ?'ecdsa-with-SHA512'; sha384 -> ?'ecdsa-with-SHA384'; sha256 -> ?'ecdsa-with-SHA256' end, - {Type, 'NULL'}. + {Type, Parms}. make_key(rsa, _Opts) -> %% (OBS: for testing only) diff --git a/lib/ssl/test/ssl_ECC_SUITE.erl b/lib/ssl/test/ssl_ECC_SUITE.erl index 608f2f11c3..77e4c80bbe 100644 --- a/lib/ssl/test/ssl_ECC_SUITE.erl +++ b/lib/ssl/test/ssl_ECC_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2013. All Rights Reserved. +%% Copyright Ericsson AB 2007-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -57,41 +57,51 @@ all_versions_groups ()-> ]. key_cert_combinations() -> - [client_ec_server_ec, - client_rsa_server_ec, - client_ec_server_rsa, - client_rsa_server_rsa]. + [client_ecdh_server_ecdh, + client_rsa_server_ecdh, + client_ecdh_server_rsa, + client_rsa_server_rsa, + client_ecdsa_server_ecdsa, + client_ecdsa_server_rsa, + client_rsa_server_ecdsa + ]. %%-------------------------------------------------------------------- -init_per_suite(Config) -> - catch crypto:stop(), +init_per_suite(Config0) -> + end_per_suite(Config0), try crypto:start() of ok -> - ssl:start(), - Config + %% make rsa certs using oppenssl + Result = + (catch make_certs:all(?config(data_dir, Config0), + ?config(priv_dir, Config0))), + ct:log("Make certs ~p~n", [Result]), + Config1 = ssl_test_lib:make_ecdsa_cert(Config0), + Config2 = ssl_test_lib:make_ecdh_rsa_cert(Config1), + ssl_test_lib:cert_options(Config2) catch _:_ -> {skip, "Crypto did not start"} end. end_per_suite(_Config) -> - ssl:stop(), + application:stop(ssl), application:stop(crypto). %%-------------------------------------------------------------------- -init_per_group(erlang_client, Config) -> +init_per_group(erlang_client = Group, Config) -> case ssl_test_lib:is_sane_ecc(openssl) of true -> - common_init_per_group(erlang_client, [{server_type, openssl}, - {client_type, erlang} | Config]); + common_init_per_group(Group, [{server_type, openssl}, + {client_type, erlang} | Config]); false -> {skip, "Known ECC bug in openssl"} end; -init_per_group(erlang_server, Config) -> +init_per_group(erlang_server = Group, Config) -> case ssl_test_lib:is_sane_ecc(openssl) of true -> - common_init_per_group(erlang_client, [{server_type, erlang}, - {client_type, openssl} | Config]); + common_init_per_group(Group, [{server_type, erlang}, + {client_type, openssl} | Config]); false -> {skip, "Known ECC bug in openssl"} end; @@ -99,11 +109,21 @@ init_per_group(erlang_server, Config) -> init_per_group(erlang = Group, Config) -> case ssl_test_lib:sufficient_crypto_support(Group) of true -> - common_init_per_group(erlang, [{server_type, erlang}, - {client_type, erlang} | Config]); + common_init_per_group(Group, [{server_type, erlang}, + {client_type, erlang} | Config]); + false -> + {skip, "Crypto does not support ECC"} + end; + +init_per_group(openssl = Group, Config) -> + case ssl_test_lib:sufficient_crypto_support(Group) of + true -> + common_init_per_group(Group, [{server_type, openssl}, + {client_type, openssl} | Config]); false -> {skip, "Crypto does not support ECC"} - end; + end; + init_per_group(Group, Config) -> common_init_per_group(Group, Config). @@ -121,76 +141,118 @@ end_per_group(_GroupName, Config) -> %%-------------------------------------------------------------------- -init_per_testcase(_TestCase, Config) -> +init_per_testcase(TestCase, Config) -> ct:log("TLS/SSL version ~p~n ", [tls_record:supported_protocol_versions()]), ct:log("Ciphers: ~p~n ", [ ssl:cipher_suites()]), + end_per_testcase(TestCase, Config), + ssl:start(), Config. -end_per_testcase(_TestCase, Config) -> +end_per_testcase(_TestCase, Config) -> + application:stop(ssl), Config. %%-------------------------------------------------------------------- %% Test Cases -------------------------------------------------------- %%-------------------------------------------------------------------- -client_ec_server_ec(Config) when is_list(Config) -> - basic_test("ec1.crt", "ec1.key", "ec2.crt", "ec2.key", Config). - -client_ec_server_rsa(Config) when is_list(Config) -> - basic_test("ec1.crt", "ec1.key", "rsa1.crt", "rsa1.key", Config). +client_ecdh_server_ecdh(Config) when is_list(Config) -> + COpts = ?config(client_ecdh_rsa_opts, Config), + SOpts = ?config(server_ecdh_rsa_verify_opts, Config), + basic_test(COpts, SOpts, Config). + +client_ecdh_server_rsa(Config) when is_list(Config) -> + COpts = ?config(client_ecdh_rsa_opts, Config), + SOpts = ?config(server_verification_opts, Config), + basic_test(COpts, SOpts, Config). + +client_rsa_server_ecdh(Config) when is_list(Config) -> + COpts = ?config(client_verification_opts, Config), + SOpts = ?config(server_ecdh_rsa_verify_opts, Config), + basic_test(COpts, SOpts, Config). + +client_rsa_server_rsa(Config) when is_list(Config) -> + COpts = ?config(client_verification_opts, Config), + SOpts = ?config(server_verification_opts, Config), + basic_test(COpts, SOpts, Config). + +client_ecdsa_server_ecdsa(Config) when is_list(Config) -> + COpts = ?config(client_ecdsa_opts, Config), + SOpts = ?config(server_ecdsa_verify_opts, Config), + basic_test(COpts, SOpts, Config). -client_rsa_server_ec(Config) when is_list(Config) -> - basic_test("rsa1.crt", "rsa1.key", "ec2.crt", "ec2.key", Config). +client_ecdsa_server_rsa(Config) when is_list(Config) -> + COpts = ?config(client_ecdsa_opts, Config), + SOpts = ?config(server_verification_opts, Config), + basic_test(COpts, SOpts, Config). -client_rsa_server_rsa(Config) when is_list(Config) -> - basic_test("rsa1.crt", "rsa1.key", "rsa2.crt", "rsa2.key", Config). +client_rsa_server_ecdsa(Config) when is_list(Config) -> + COpts = ?config(client_verification_opts, Config), + SOpts = ?config(server_ecdsa_verify_opts, Config), + basic_test(COpts, SOpts, Config). %%-------------------------------------------------------------------- %% Internal functions ------------------------------------------------ %%-------------------------------------------------------------------- -basic_test(ClientCert, ClientKey, ServerCert, ServerKey, Config) -> - DataDir = ?config(data_dir, Config), +basic_test(COpts, SOpts, Config) -> + basic_test(proplists:get_value(certfile, COpts), + proplists:get_value(keyfile, COpts), + proplists:get_value(cacertfile, COpts), + proplists:get_value(certfile, SOpts), + proplists:get_value(keyfile, SOpts), + proplists:get_value(cacertfile, SOpts), + Config). + +basic_test(ClientCert, ClientKey, ClientCA, ServerCert, ServerKey, ServerCA, Config) -> SType = ?config(server_type, Config), CType = ?config(client_type, Config), {Server, Port} = start_server(SType, - filename:join(DataDir, "CA.pem"), - filename:join(DataDir, ServerCert), - filename:join(DataDir, ServerKey), + ClientCA, ServerCA, + ServerCert, + ServerKey, Config), - Client = start_client(CType, Port, filename:join(DataDir, "CA.pem"), - filename:join(DataDir, ClientCert), - filename:join(DataDir, ClientKey), Config), - check_result(Server, SType, Client, CType). + Client = start_client(CType, Port, ServerCA, ClientCA, + ClientCert, + ClientKey, Config), + check_result(Server, SType, Client, CType), + close(Server, Client). -start_client(openssl, Port, CA, Cert, Key, _) -> +start_client(openssl, Port, CA, OwnCa, Cert, Key, Config) -> + PrivDir = ?config(priv_dir, Config), + NewCA = new_ca(filename:join(PrivDir, "new_ca.pem"), CA, OwnCa), Version = tls_record:protocol_version(tls_record:highest_protocol_version([])), - Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++ - " -cert " ++ Cert ++ " -CAfile " ++ CA - ++ " -key " ++ Key ++ " -host localhost -msg", + Cmd = "openssl s_client -verify 2 -port " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++ + " -cert " ++ Cert ++ " -CAfile " ++ NewCA + ++ " -key " ++ Key ++ " -host localhost -msg -debug", OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), true = port_command(OpenSslPort, "Hello world"), OpenSslPort; -start_client(erlang, Port, CA, Cert, Key, Config) -> +start_client(erlang, Port, CA, _, Cert, Key, Config) -> {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, [{verify, verify_peer}, {cacertfile, CA}, + {options, [{verify, verify_peer}, + {cacertfile, CA}, {certfile, Cert}, {keyfile, Key}]}]). -start_server(openssl, CA, Cert, Key, _) -> +start_server(openssl, CA, OwnCa, Cert, Key, Config) -> + PrivDir = ?config(priv_dir, Config), + NewCA = new_ca(filename:join(PrivDir, "new_ca.pem"), CA, OwnCa), + Port = ssl_test_lib:inet_port(node()), Version = tls_record:protocol_version(tls_record:highest_protocol_version([])), Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++ - " -cert " ++ Cert ++ " -CAfile " ++ CA - ++ " -key " ++ Key ++ " -Verify 2 -msg", + " -verify 2 -cert " ++ Cert ++ " -CAfile " ++ NewCA + ++ " -key " ++ Key ++ " -msg -debug", OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), ssl_test_lib:wait_for_openssl_server(), true = port_command(OpenSslPort, "Hello world"), {OpenSslPort, Port}; -start_server(erlang, CA, Cert, Key, Config) -> +start_server(erlang, CA, _, Cert, Key, Config) -> + {_, ServerNode, _} = ssl_test_lib:run_where(Config), Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, @@ -217,9 +279,31 @@ openssl_check(_, Config) -> TLSVersion = ?config(tls_version, Config), case ssl_test_lib:check_sane_openssl_version(TLSVersion) of true -> - ssl:start(), Config; false -> {skip, "TLS version not supported by openssl"} end. +close(Port1, Port2) when is_port(Port1), is_port(Port2) -> + ssl_test_lib:close_port(Port1), + ssl_test_lib:close_port(Port2); +close(Port, Pid) when is_port(Port) -> + ssl_test_lib:close_port(Port), + ssl_test_lib:close(Pid); +close(Pid, Port) when is_port(Port) -> + ssl_test_lib:close_port(Port), + ssl_test_lib:close(Pid); +close(Client, Server) -> + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%% Work around OpenSSL bug, apparently the same bug as we had fixed in +%% 11629690ba61f8e0c93ef9b2b6102fd279825977 +new_ca(FileName, CA, OwnCa) -> + {ok, P1} = file:read_file(CA), + E1 = public_key:pem_decode(P1), + {ok, P2} = file:read_file(OwnCa), + E2 = public_key:pem_decode(P2), + Pem = public_key:pem_encode(E2 ++E1), + file:write_file(FileName, Pem), + FileName. diff --git a/lib/ssl/test/ssl_ECC_SUITE_data/CA.pem b/lib/ssl/test/ssl_ECC_SUITE_data/CA.pem deleted file mode 100644 index f82efdefc5..0000000000 --- a/lib/ssl/test/ssl_ECC_SUITE_data/CA.pem +++ /dev/null @@ -1,14 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICGjCCAYegAwIBAgIQZIIqq4RXfpBKJXV69Jc4BjAJBgUrDgMCHQUAMB0xGzAZ -BgNVBAMTEklTQSBUZXN0IEF1dGhvcml0eTAeFw0xMjAzMjAxNzEzMjFaFw0zOTEy -MzEyMzU5NTlaMB0xGzAZBgNVBAMTEklTQSBUZXN0IEF1dGhvcml0eTCBnzANBgkq -hkiG9w0BAQEFAAOBjQAwgYkCgYEAqnt6FSyFQVSDyP7mY63IhCzgysTxBEg1qDb8 -nBHj9REReZA5UQ5iyEOdTbdLyOaSk2rJyA2wdTjYkNnLzK49nZFlpf89r3/bakAM -wZv69S3FJi9W2z9m4JPv/5+QCYnFNRSnnHw3maNElwoQyknx96I3W7EuVOvKtKhh -4DaD0WsCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zBOBgNVHQEERzBFgBBCHwn2 -8AmbN+cvJl1iJ1bsoR8wHTEbMBkGA1UEAxMSSVNBIFRlc3QgQXV0aG9yaXR5ghBk -giqrhFd+kEoldXr0lzgGMAkGBSsOAwIdBQADgYEAIlVecua5Cr1z/cdwQ8znlgOU -U+y/uzg0nupKkopzVnRYhwV4hxZt3izAz4C/SJZB7eL0bUKlg1ceGjbQsGEm0fzF -LEV3vym4G51bxv03Iecwo96G4NgjJ7+9/7ciBVzfxZyfuCpYG1M2LyrbOyuevtTy -2+vIueT0lv6UftgBfIE= ------END CERTIFICATE----- diff --git a/lib/ssl/test/ssl_ECC_SUITE_data/ec1.crt b/lib/ssl/test/ssl_ECC_SUITE_data/ec1.crt deleted file mode 100644 index 7d2b9cde9d..0000000000 --- a/lib/ssl/test/ssl_ECC_SUITE_data/ec1.crt +++ /dev/null @@ -1,11 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIBhjCB8AIBBjANBgkqhkiG9w0BAQUFADAdMRswGQYDVQQDExJJU0EgVGVzdCBB -dXRob3JpdHkwHhcNMTMwODA4MTAxNDI3WhcNMjMwODA2MTAxNDI3WjBFMQswCQYD -VQQGEwJVUzERMA8GA1UECBMIVmlyZ2luaWExFTATBgNVBAcTDEZvcnQgQmVsdm9p -cjEMMAoGA1UEAxMDZWMxMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEpiRIxUCESROR -P8IByg+vBv1fDdAg7yXfAh95GxFtvhBqZs6ATwaRKyLmZYgUm/4NUAyUeqmTBb7s -2msKo5mnNzANBgkqhkiG9w0BAQUFAAOBgQAmwzoB1DVO69FQOUdBVnyups4t0c1c -8h+1z/5P4EtPltk4o3mRn0AZogqdXCpNbuSGbSJh+dep5xW30VLxNHdc+tZSLK6j -pT7A3hymMk8qbi13hxeH/VpEP25y1EjHowow9Wmb6ebtT/v7qFQ9AAHD9ONcIM4I -FCC8vdFo7M5GgQ== ------END CERTIFICATE----- diff --git a/lib/ssl/test/ssl_ECC_SUITE_data/ec1.key b/lib/ssl/test/ssl_ECC_SUITE_data/ec1.key deleted file mode 100644 index 2dc9508b3c..0000000000 --- a/lib/ssl/test/ssl_ECC_SUITE_data/ec1.key +++ /dev/null @@ -1,8 +0,0 @@ ------BEGIN EC PARAMETERS----- -BgUrgQQACg== ------END EC PARAMETERS----- ------BEGIN EC PRIVATE KEY----- -MHQCAQEEIOO0WK8znNzLyZIoGRIlaKnCNr2Wy8uk9i+GGFIhDGNAoAcGBSuBBAAK -oUQDQgAEpiRIxUCESRORP8IByg+vBv1fDdAg7yXfAh95GxFtvhBqZs6ATwaRKyLm -ZYgUm/4NUAyUeqmTBb7s2msKo5mnNw== ------END EC PRIVATE KEY----- diff --git a/lib/ssl/test/ssl_ECC_SUITE_data/ec2.crt b/lib/ssl/test/ssl_ECC_SUITE_data/ec2.crt deleted file mode 100644 index b0558a0ebc..0000000000 --- a/lib/ssl/test/ssl_ECC_SUITE_data/ec2.crt +++ /dev/null @@ -1,11 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIBhjCB8AIBBzANBgkqhkiG9w0BAQUFADAdMRswGQYDVQQDExJJU0EgVGVzdCBB -dXRob3JpdHkwHhcNMTMwODA4MTAxNDM0WhcNMjMwODA2MTAxNDM0WjBFMQswCQYD -VQQGEwJVUzERMA8GA1UECBMIVmlyZ2luaWExFTATBgNVBAcTDEZvcnQgQmVsdm9p -cjEMMAoGA1UEAxMDZWMyMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEzXaYReUyvoYl -FwGOe0MJEXWCUncMfr2xG4GMjGYlfZsvLGEokefsJIvW+I+9jgUT2UFjxFXYNAvm -uD1A1iWVWjANBgkqhkiG9w0BAQUFAAOBgQBFa6iIlrT9DWptIdB8uSYvp7qwiHxN -hiVH5YhGIHHqjGZqtRHrSxqNEYMXXrgH9Hxc6gDbk9PsHZyVVoh/HgVWddqW1inh -tStZm420PAKCuH4T6Cfsk76GE2m7FRzJvw9TM1f2A5nIy9abyrpup8lZGcIL4Kmq -1Fix1LRtrmLNTA== ------END CERTIFICATE----- diff --git a/lib/ssl/test/ssl_ECC_SUITE_data/ec2.key b/lib/ssl/test/ssl_ECC_SUITE_data/ec2.key deleted file mode 100644 index 366d13648b..0000000000 --- a/lib/ssl/test/ssl_ECC_SUITE_data/ec2.key +++ /dev/null @@ -1,8 +0,0 @@ ------BEGIN EC PARAMETERS----- -BgUrgQQACg== ------END EC PARAMETERS----- ------BEGIN EC PRIVATE KEY----- -MHQCAQEEIPR3ORUpAFMTQhUJ0jllN38LKWziG8yP2H54Y/9vh1PwoAcGBSuBBAAK -oUQDQgAEzXaYReUyvoYlFwGOe0MJEXWCUncMfr2xG4GMjGYlfZsvLGEokefsJIvW -+I+9jgUT2UFjxFXYNAvmuD1A1iWVWg== ------END EC PRIVATE KEY----- diff --git a/lib/ssl/test/ssl_ECC_SUITE_data/rsa1.crt b/lib/ssl/test/ssl_ECC_SUITE_data/rsa1.crt deleted file mode 100644 index ed9beacf68..0000000000 --- a/lib/ssl/test/ssl_ECC_SUITE_data/rsa1.crt +++ /dev/null @@ -1,20 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDVjCCAr8CAQkwDQYJKoZIhvcNAQEFBQAwHTEbMBkGA1UEAxMSSVNBIFRlc3Qg -QXV0aG9yaXR5MB4XDTEzMDgwODEwMTUzNFoXDTQwMTIyNDEwMTUzNFowRjELMAkG -A1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMRUwEwYDVQQHEwxGb3J0IEJlbHZv -aXIxDTALBgNVBAMTBHJzYTEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC -AQC62v40w1AjV3oJuyYC2Fw6XhTOi1il6xZFnB9J1WhCmuxAB/VMhBcNypx38mNk -eQ7a/ERQ5ddhZey29DYeFYU8oqfDURgWx5USHufb90xBen9KPmX3VNuQ8ZFP2q8Q -b01/oRHBJQRBuaCtFHzpGIVBjC6dD5yeQgJsYaF4u+PBbonsIGROXMybcvUzXmjU -dwpy2NhjGQL5sWcOdIeRP43APSyRYvq4tuBUZk2XxWfBcvA8LpcoYPMlRTf6jGL1 -/fAAcCYJ9lh3h92w0NZ/7ZRa/ebTplxK6yqCftuSKui1KdL69m0WZqHl79AUSfs9 -lsOwx9lHkyYvJeMofyeDbZ+3OYLmVqEBG1fza2aV2XVh9zJ8fAwmXy/c2IDhw/oD -HAe/rSg/Sgt03ydIKqtZHbl3v0EexQQRlJRULIzdtON02dJMUd4EFUgQ9OUtEmC2 -Psj9Jdu1g5cevU7Mymu8Ot+fjHiGTcBUsXNuXFCbON3Gw7cIDl4+iv+cpDHHVC9L -HK3PMEq3vu3qOGXSz+LDOoqkfROcLG7BclBuN2zoVSsMHFkB4aJhwy7eHhGz0z2W -c6LTVd+GAApdY80kmjOjT//QxHEsX/n1useHza3OszQqZiArr4ub4rtq+l1DxAS/ -DWrZ/JGsbKL8cjWso6qBF94xTi8WhjkKuUYhsm+qLAbNOQIDAQABMA0GCSqGSIb3 -DQEBBQUAA4GBAIcuzqRkfypV/9Z85ZQCCoejPm5Urhv7dfg1/B3QtazogPBZLgL5 -e60fG1uAw5GmqTViHLvW06z73oQvJrFkrCLVvadDNtrKYKXnXqdkgVyk36F/B737 -A43HGnMfSxCfRhIOuKZB9clP5PiNlhw36yi3DratqT6TUvI69hg8a7jA ------END CERTIFICATE----- diff --git a/lib/ssl/test/ssl_ECC_SUITE_data/rsa1.key b/lib/ssl/test/ssl_ECC_SUITE_data/rsa1.key deleted file mode 100644 index 6e0d913d79..0000000000 --- a/lib/ssl/test/ssl_ECC_SUITE_data/rsa1.key +++ /dev/null @@ -1,51 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIJKAIBAAKCAgEAutr+NMNQI1d6CbsmAthcOl4UzotYpesWRZwfSdVoQprsQAf1 -TIQXDcqcd/JjZHkO2vxEUOXXYWXstvQ2HhWFPKKnw1EYFseVEh7n2/dMQXp/Sj5l -91TbkPGRT9qvEG9Nf6ERwSUEQbmgrRR86RiFQYwunQ+cnkICbGGheLvjwW6J7CBk -TlzMm3L1M15o1HcKctjYYxkC+bFnDnSHkT+NwD0skWL6uLbgVGZNl8VnwXLwPC6X -KGDzJUU3+oxi9f3wAHAmCfZYd4fdsNDWf+2UWv3m06ZcSusqgn7bkirotSnS+vZt -Fmah5e/QFEn7PZbDsMfZR5MmLyXjKH8ng22ftzmC5lahARtX82tmldl1YfcyfHwM -Jl8v3NiA4cP6AxwHv60oP0oLdN8nSCqrWR25d79BHsUEEZSUVCyM3bTjdNnSTFHe -BBVIEPTlLRJgtj7I/SXbtYOXHr1OzMprvDrfn4x4hk3AVLFzblxQmzjdxsO3CA5e -Por/nKQxx1QvSxytzzBKt77t6jhl0s/iwzqKpH0TnCxuwXJQbjds6FUrDBxZAeGi -YcMu3h4Rs9M9lnOi01XfhgAKXWPNJJozo0//0MRxLF/59brHh82tzrM0KmYgK6+L -m+K7avpdQ8QEvw1q2fyRrGyi/HI1rKOqgRfeMU4vFoY5CrlGIbJvqiwGzTkCAwEA -AQKCAgBkXyaWKSRvF5pSh9lPRfGk2MzMdkXUOofoNIkKHDy5KocljiDSTVIk8mVC -eU2ytuSn9UKtQgmEJEAXtu8rEdxUSftcC7+o3OTSqw9ZNWoc8jRWKVaUmVyoa1rn -Tk0jwuYaXOcwnTXAKHqK/qpqe+V45FhVvgEfcc3jcj5OoH8jdMFZubyn62ltRz83 -rMsa9icCskDqWpEil40IUshP2ZfHYBUEs+qCNpoiPCIKGNw3KgqqCUzhP9LcfmYn -jCnMge/eDGAikdXLv4vyYvwWFATRK/pGTuLcy542IvbHeY0vY5wVezH2CoOFBGD9 -xQ/UcZwE5hVtQToNsYhoRIVxL/3Of0qDk1M6W2Plh2MAstyejIHE3ct0pPfW3rsu -j/9Z/H0P9Q5ghSjarwOp2qGrrz6/4LVbbTDY8V1L928l4SqbUMtEQxcxTBN8YFoD -mPV3Jc3zls9wiiEX53RcH8MK5tjrcRwWqurTZvi/pkLfXlGDgKGCOaa3HgWVQyU+ -L6jVZM+u1nwN+jNXQYGeLEro/6tvG8WQbRMHQoxLG+rm4V3/SwH0DcfrVFDTg+i6 -3wMU1GC/aQEdTFWXvHAkpwrf4M9QWvjtheiaSxtBUoAY6l+ixCVHKrIk6glKLEjx -92HxmcJdopQScFETAyg8eVKV0kOGfVeFEpIqwq7hVedmTflpQQKCAQEA44h4dAta -cYeBqBr8eljWcgs79gmgwBEQxQUnwE/zuzLKn5NxAW324Kh25V/n/MupUzBlLPWn -91UHfw9PCXT8/HvgYQ4S5sXbKRbGmuPSsTmz4Rfe2ix6RggVNUOwORVNDyM7SQh7 -USdzZH5dMxKfF5L/b4Byx7eQZaoeKlfaXcqgikNZZ6pkhVCNxUKi9vvjS9r2wwCd -xtgu5MfTpdEci0zH1+uuRisVRcEbcRX9umUTCiZrmEeddZXNiwTAS3FtX7qGzuq9 -LKIeETwcOZrWj0E48UvbSfK4Axn7sf5J0n7/Qo7I089S5QQEI6ZDP501i71dNFhn -qfcY30c1k3TC7QKCAQEA0juuVHExKNLLNmQejNPfuHYoH0Uk2BH/8x96/Mkj6k6K -SUCHDS3iWOljXGw8YtpS8v5mGBGgMhJ+s/vCRM6R9eXYTc8u2ktY/kjyW0PgW8/Z -vb9VrQpn5svTNwj2Q8qYsTqXnQKO7YuL+hnQpQNAcID6FTeOASVLGObEf810qRfN -4y3RqCWUnYXXTyXj+cJdbXTxfF7HVZPIAQKqE7J5Qo9ynYILY62oSmUGC6m8VKyE -rrvDMK1IVi0X4w+Jx4HX0IC2+DBKxCaLWT69bE1IwjB06Q5zoTQPVi6c6qQp7K0H -kqSyLJ/ctwcEubu0DPNmvMlgWtAbAsoESA5GbIit/QKCAQEAxRzp9OYNAUM6AK74 -QOmLRZsT4+6tUxa1p2jy6fiZlnfG731kra9c630mG0n9iJPK6aWIUO20CGGiL+HM -P84YiIaseIgfucp4NV1kyrRJR31MptjuF6Xme5ru/IjaNmmMq2uDJZ7ybfi2T73k -8aTVLDANl8P4K6qLrnc00MvxAcXTVFRKNLN5h8CkQNqcoUjPvVxA3+g9xxBrd4jh -gsnoZ4kpq5WiEWmrcRV8t3gsqfh8CRQFrBOGhmIzgZapG/J0pTTLKqBTKEJ9t8KS -VRkdfVcshGWJ4MMjxJQS5zz7KR8Z9cgKlOwLzRiwmU2k/owr4hY3k2xuyeClrHBd -KpRBdQKCAQBvDk/dE55gbloi9WieBB6eluxC+IeqDHgkunCBsM9kKvEqGQg+kgqL -5V4zqImNvr8q1fCgrk7tpI+CDHBnYKgCOdS15cheUIdGbMp6I7UVSws/DR/5NRIF -/Y4p+HX/Abr/hHAq5PsTyS+8gn6RbNJRnBB/vMUrHcQ5902+JY6G9KgyZjXmmVOU -kutWSDHR8jbgZ3JZvMeYEWUKA5pMpW8hFh35zoStt0K7afpzlsqCAFBm7ZEC2cbo -nxGLRN4HojObVSNSoFAepi3eiyINYBYbXvWjV5sFgTbI0/7YhLgQ6qahdJcas6go -l3CLnPhUDxAqkkZwMpbSNl1kowXYt6sRAoIBAAOWnXgf9Bdb9OWKGgt42gVfC4cz -zj2JoLpbDTtbEdHNn8XQvPhGbpdtgnsuEMijIMy1UTlmv17jbFWdZTDeN31EUJrC -smgKX0OlVFKD90AI0BiIREK0hJUBV0pV4JoUjwnQBHGvranD06/wAtHEqgqF1Ipp -DCAKwxggM7qtB1R1vkrc/aLQej+mlwA8N6q92rnEsg+EnEbhtLDDZQcV/q5cSDCN -MMcnM+QdyjKwEeCVXHaqNfeSqKg/Ab2eZbS9VxA+XZD73+eUY/JeJsg7LfZrRz0T -ij5LCS7A+nVB5/B5tGkk4fcNhk2n356be6l46S98BEgtuwGLC9pqXf7zyp4= ------END RSA PRIVATE KEY----- diff --git a/lib/ssl/test/ssl_ECC_SUITE_data/rsa2.crt b/lib/ssl/test/ssl_ECC_SUITE_data/rsa2.crt deleted file mode 100644 index 06ca92dda3..0000000000 --- a/lib/ssl/test/ssl_ECC_SUITE_data/rsa2.crt +++ /dev/null @@ -1,20 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDVjCCAr8CAQowDQYJKoZIhvcNAQEFBQAwHTEbMBkGA1UEAxMSSVNBIFRlc3Qg -QXV0aG9yaXR5MB4XDTEzMDgwODEwMTYwMloXDTQwMTIyNDEwMTYwMlowRjELMAkG -A1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMRUwEwYDVQQHEwxGb3J0IEJlbHZv -aXIxDTALBgNVBAMTBHJzYTIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC -AQCjQUe0BGOpULjOAmLbXM4SSQzJvxJbCFi3tryyd+OARq6Fdp6/fslVhsr0PhWE -X8yRbAugIjseTpLwz+1OC6LavOGV1ixzGTI/9HDXGKbf8qoCrSdh28sqQJnmqGT4 -UCKLn6Rqjg2iyBBcSK3LrtKEPI4C7NaSOZUtANkppvziEMwm+0r16sgHh2Xx6mxd -22q01kq1lJqwEnIDPMSz3+ESUVQQ4T3ka7yFIhc9PYmILIXkZi0x7AiDeRkIILul -GQrduTWSPGY3prXeDAbmQNazxrHp8fcR2AfFSI6HYxMALq9jWxc4xDIkss6BO2Et -riJOIgXFpbyVsYCbkI1kXhEWFDt3uJBIcmtJKGzro4xv+XLG6BbUeTJgSHXMc7Cb -fX87+CBIFR5a/aqkEKh/mcvsDdaV+kpNKdr7q4wAuIQb8g7IyXEDuAm1VZjQs9WC -KFRGSq9sergEw9gna0iThRZjD+dzNzB17XmlAK4wa98a7MntwqpAt/GsCFOiPM8E -c+8gpuo8WqC0kP8OpImyw9cQhlZ3dca1qkr2cyKyAOGxUxyA67FgiHSsxJJ2Xhse -o49qeKTjMZd8zhSokM2TH6qEf7YfOePU51YRfAHUhzRmE31N/MExqDjFjklksEtM -iHhbPo+cOoxV8x1u13umdUvtTaAUSBA/DpvzWdnORvnaqQIDAQABMA0GCSqGSIb3 -DQEBBQUAA4GBAFD+O7h+5R5S1rIN9eC+oEGpvRhMG4v4G3pJp+c7bbtO7ifFx1WP -bta1b5YtiQYcKP0ORABm/3Kcvsb3VbaMH/zkxWEbASZsmIcBY3ml4f2kkn6WT2hD -Wc6VMIAR3N6Mj1b30yI1qYVIid+zIouiykMB+zqllm+Uar0SPNjKxDU/ ------END CERTIFICATE----- diff --git a/lib/ssl/test/ssl_ECC_SUITE_data/rsa2.key b/lib/ssl/test/ssl_ECC_SUITE_data/rsa2.key deleted file mode 100644 index d415ef0391..0000000000 --- a/lib/ssl/test/ssl_ECC_SUITE_data/rsa2.key +++ /dev/null @@ -1,51 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIJJwIBAAKCAgEAo0FHtARjqVC4zgJi21zOEkkMyb8SWwhYt7a8snfjgEauhXae -v37JVYbK9D4VhF/MkWwLoCI7Hk6S8M/tTgui2rzhldYscxkyP/Rw1xim3/KqAq0n -YdvLKkCZ5qhk+FAii5+kao4NosgQXEity67ShDyOAuzWkjmVLQDZKab84hDMJvtK -9erIB4dl8epsXdtqtNZKtZSasBJyAzzEs9/hElFUEOE95Gu8hSIXPT2JiCyF5GYt -MewIg3kZCCC7pRkK3bk1kjxmN6a13gwG5kDWs8ax6fH3EdgHxUiOh2MTAC6vY1sX -OMQyJLLOgTthLa4iTiIFxaW8lbGAm5CNZF4RFhQ7d7iQSHJrSShs66OMb/lyxugW -1HkyYEh1zHOwm31/O/ggSBUeWv2qpBCof5nL7A3WlfpKTSna+6uMALiEG/IOyMlx -A7gJtVWY0LPVgihURkqvbHq4BMPYJ2tIk4UWYw/nczcwde15pQCuMGvfGuzJ7cKq -QLfxrAhTojzPBHPvIKbqPFqgtJD/DqSJssPXEIZWd3XGtapK9nMisgDhsVMcgOux -YIh0rMSSdl4bHqOPanik4zGXfM4UqJDNkx+qhH+2Hznj1OdWEXwB1Ic0ZhN9TfzB -Mag4xY5JZLBLTIh4Wz6PnDqMVfMdbtd7pnVL7U2gFEgQPw6b81nZzkb52qkCAwEA -AQKCAgBORLHXwHL3bdfsDIDQooG5ioQzBQQL2MiP63A0L/5GNZzeJ6ycKnDkLCeJ -SWqPeE5fOemo8EBfm1QfV9BxpmqBbCTK7U+KLv5EYzDmLs9ydqjDd7h11iZlL2uZ -hgpCckjdn7/3xfsLm9ccJ0wLZtlOxKlhBaMpn6nBVbLHoWOEDoGR/tBFbjZQRb2+ -aaFirhtOb56Jx6ER4QYAP1Ye1qrVWWBwZ0yBApXzThDOL36MZqwagFISqRK71YcG -uoq78HGhM3ZXkdV/wNFYj3OPWG6W6h/KBVNqnqO7FbofdoRZhghYHgfYE1fm+ELA -+nLwr5eK1gzmYTs0mVELRBZFlEOkCfYNOnuRgysFezEklS+ICp3HzIhYXza3kyTf -B2ZBwZZVCv/94MKyibyANErmv1a5ugY5Hsn9/WKC8qTto+qLYoyFCvBjzj0PSaVX -/3cty2DY0SK16K1Y4AOPtJMYTXYB3tVX8Akgjz1F6REBtZSOXrSQ3Vhy1ORl3Hzf -WCBYDqL8K0hJiBVgkvneIyIjmFHsdM60Nr7EldBEnJ/UrPzsl2VuWFPZlnasfUaW -x+vq1H4Dfz+bHt8coBRHDjKgUvwkfFeBQOBR5DG3vMrxguVRA1EYYMRR5C3yxk2m -ARAtdh4VxUQDQjjrmr7Dl/y1rU34aInXIrrFWpuvIhl8Ht09sQKCAQEA1pXKK5f0 -HkKfM/qk5xzF+WdHClBrPXi0XwLN6UQ+WWMMNhkGZ+FMPXl/6IJDT91s6DA3tPhr -OZF64n9ZFaGgHNBXNiB+Txjv5vZeSBMFt3hSonqt42aijx6gXfmLnkA+TYpa6Wex -YCeEgdH8LocJa7Gj2vzrYliPYk3deh6SnZZ6N8bI+ciwK3ZGF/pkWaTX83dIFq3w -YyZ+0dEpNGbA9812wNVourPg3OfqG3/CdnTfvY1M9KCC3JalpyzQL4Zm5soXF0wj -36C2yTxA02AyFz3TvUIBrvsN6i0gmGfE79+UIp29JYrFRsIgBDt+ze2vQWUz2MX5 -GeX6/yCBgiTXtwKCAQEAwsNf6k2m5Cw+WtuLzzUfBBJCN+t1lrnYJ6lF0HubW6TZ -vX1kBWyc+Rpo4ljr/+f4R9aC/gTEQOmV/hNVZy1RU2dAI8cH+r6JWG9lgif+8h// -5R81txE7gnuK1Na7PmvnQPPN661zsQZ5e1ENPXS3TJmUW/M01JxAMqEQjvAPa/II -H2KjL5NX28k9Hiw9rP6n+qXAfG/LEwXgoVCcehPwfANqQ1l95UgOdKDmjG94dipI -h2DEK70ZbrsgQbT60Wd8I5h0yhiQsik2/bVkqLmcG4SSg0/5cf2vZMApgoH/adUz -rJFdthm7iGPLhwS6fbhXew17Af96FvzfkifUV+cgnwKCAQBNUlYyFSQKz1jMgxFu -kciokNVhWw75bIgaAEmwNz38OZuJ1sSfI+iz8hbr8hxNJ+15UP6RwD3q1YghG2A/ -Uij+mPgD8ftxhvvTDo10jR4vOTUVhP0phq8mwRNqKWRs1ptcl3Egz5NzoWm22bJ0 -FYaIfs8bNq2el2i7NHGM8n1EOZe6h2+dyfno/0pMk5YbUzHZce7Q9UY8g/+InUSq -tCfuYuPaokuFkxGAqDSMSiIJSx3gEI1dTIU69TGlppkxts1XdhSR+YanqyKSKpr1 -T6FdDJNCjAlNQvuFmVM4d5PYF4kqXApu/60MTSD6RXHwxCe1ecEP6G5VLbCew9jG -y33LAoIBAGsWyC9pwQEm/qYwn4AwYjx32acrtX1J9HtiTLvkqzjJvNu/DXcaEHm7 -tr32TNVp9A9z+JS5hDt49Hs+oC/aMCRe2lqRvmZ1y8kvfy4A1eLGC4stDPj65bDK -QzziURRyejYxmCElPz6wI63VlCUdfwgEThn88SiSPY5ZF2SwxJoC+8peDwJCzwVP -cmabxtHPOAfOibciNRPhoHCyhUdunUVjD1O26k1ewGwKaJoBVMgMWdLuNw8hq9FB -3OukGmF3uD9OPbE9rpn3pX/89Dr9y8MpsvG20J6H8Z/BNVHILus/SmlxiIhvP7kv -viIgTHaCHL/RWrhvg+8N3dRcSBqJQFsCggEAFe2TMEq2AlnBn4gsuAOIuZPYKQCg -2a+tl1grQzmNth6AGGQcIqShadICD6SnVMIS64HHV/m18Cuz7GhJ06ZVjXJsHueG -UpTE9wAmI2LxnNkupkLJu+SVcW3N86PujWmQBFpHkd+IRPLS51xjD9W5zLJ7HL4/ -fnKO+B+ZK6Imxbe5C5vJezkGfeOSyQoVtt6MT/XtSKNEGPBX+M6fLKgUMMg2H2Mt -/SsD7DkOzFteKXzaEg/K8oOTpsOPkVDwNl2KErlEqbJv0k7yEVw50mYmsn/OLjh8 -+9EibISwCODbPxB+PhV6u2ue1IvGLRqtsN60lFOvbGn+kSewy9EUVHHQDQ== ------END RSA PRIVATE KEY----- diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl index 150b5037d7..74d71263de 100644 --- a/lib/ssl/test/ssl_test_lib.erl +++ b/lib/ssl/test/ssl_test_lib.erl @@ -450,7 +450,7 @@ make_ecdsa_cert(Config) -> {cacertfile, ServerCaCertFile}, {certfile, ServerCertFile}, {keyfile, ServerKeyFile}]}, {server_ecdsa_verify_opts, [{ssl_imp, new},{reuseaddr, true}, - {cacertfile, ClientCaCertFile}, + {cacertfile, ServerCaCertFile}, {certfile, ServerCertFile}, {keyfile, ServerKeyFile}, {verify, verify_peer}]}, {client_ecdsa_opts, [{ssl_imp, new},{reuseaddr, true}, @@ -475,7 +475,7 @@ make_ecdh_rsa_cert(Config) -> {cacertfile, ServerCaCertFile}, {certfile, ServerCertFile}, {keyfile, ServerKeyFile}]}, {server_ecdh_rsa_verify_opts, [{ssl_imp, new},{reuseaddr, true}, - {cacertfile, ClientCaCertFile}, + {cacertfile, ServerCaCertFile}, {certfile, ServerCertFile}, {keyfile, ServerKeyFile}, {verify, verify_peer}]}, {client_ecdh_rsa_opts, [{ssl_imp, new},{reuseaddr, true}, @@ -1136,3 +1136,36 @@ filter_suites(Ciphers0) -> Supported1 = ssl_cipher:filter_suites(Supported0), Supported2 = [ssl:suite_definition(S) || S <- Supported1], [Cipher || Cipher <- Ciphers0, lists:member(Cipher, Supported2)]. + +-define(OPENSSL_QUIT, "Q\n"). +close_port(Port) -> + catch port_command(Port, ?OPENSSL_QUIT), + close_loop(Port, 500, false). + +close_loop(Port, Time, SentClose) -> + receive + {Port, {data,Debug}} when is_port(Port) -> + ct:log("openssl ~s~n",[Debug]), + close_loop(Port, Time, SentClose); + {ssl,_,Msg} -> + ct:log("ssl Msg ~s~n",[Msg]), + close_loop(Port, Time, SentClose); + {Port, closed} -> + ct:log("Port Closed~n",[]), + ok; + {'EXIT', Port, Reason} -> + ct:log("Port Closed ~p~n",[Reason]), + ok; + Msg -> + ct:log("Port Msg ~p~n",[Msg]), + close_loop(Port, Time, SentClose) + after Time -> + case SentClose of + false -> + ct:log("Closing port ~n",[]), + catch erlang:port_close(Port), + close_loop(Port, Time, true); + true -> + ct:log("Timeout~n",[]) + end + end. diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl index d36e441c7a..942c446ec4 100644 --- a/lib/ssl/test/ssl_to_openssl_SUITE.erl +++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl @@ -226,7 +226,7 @@ basic_erlang_client_openssl_server(Config) when is_list(Config) -> ssl_test_lib:check_result(Client, ok), %% Clean close down! Server needs to be closed first !! - close_port(OpensslPort), + ssl_test_lib:close_port(OpensslPort), ssl_test_lib:close(Client), process_flag(trap_exit, false). @@ -259,7 +259,7 @@ basic_erlang_server_openssl_client(Config) when is_list(Config) -> %% Clean close down! Server needs to be closed first !! ssl_test_lib:close(Server), - close_port(OpenSslPort), + ssl_test_lib:close_port(OpenSslPort), process_flag(trap_exit, false), ok. %%-------------------------------------------------------------------- @@ -298,7 +298,7 @@ erlang_client_openssl_server(Config) when is_list(Config) -> ssl_test_lib:check_result(Client, ok), %% Clean close down! Server needs to be closed first !! - close_port(OpensslPort), + ssl_test_lib:close_port(OpensslPort), ssl_test_lib:close(Client), process_flag(trap_exit, false). @@ -332,11 +332,9 @@ erlang_server_openssl_client(Config) when is_list(Config) -> %% Clean close down! Server needs to be closed first !! ssl_test_lib:close(Server), - close_port(OpenSslPort), + ssl_test_lib:close_port(OpenSslPort), process_flag(trap_exit, false). -%%-------------------------------------------------------------------- - erlang_client_openssl_server_dsa_cert() -> [{doc,"Test erlang server with openssl client"}]. erlang_client_openssl_server_dsa_cert(Config) when is_list(Config) -> @@ -376,7 +374,7 @@ erlang_client_openssl_server_dsa_cert(Config) when is_list(Config) -> ssl_test_lib:check_result(Client, ok), %% Clean close down! Server needs to be closed first !! - close_port(OpensslPort), + ssl_test_lib:close_port(OpensslPort), ssl_test_lib:close(Client), process_flag(trap_exit, false), ok. @@ -414,7 +412,7 @@ erlang_server_openssl_client_dsa_cert(Config) when is_list(Config) -> %% Clean close down! Server needs to be closed first !! ssl_test_lib:close(Server), - close_port(OpenSslPort), + ssl_test_lib:close_port(OpenSslPort), process_flag(trap_exit, false). %%-------------------------------------------------------------------- @@ -450,7 +448,7 @@ erlang_server_openssl_client_reuse_session(Config) when is_list(Config) -> %% Clean close down! Server needs to be closed first !! ssl_test_lib:close(Server), - close_port(OpenSslPort), + ssl_test_lib:close_port(OpenSslPort), process_flag(trap_exit, false), ok. @@ -496,7 +494,7 @@ erlang_client_openssl_server_renegotiate(Config) when is_list(Config) -> ssl_test_lib:check_result(Client, ok), %% Clean close down! Server needs to be closed first !! - close_port(OpensslPort), + ssl_test_lib:close_port(OpensslPort), ssl_test_lib:close(Client), process_flag(trap_exit, false), ok. @@ -542,7 +540,7 @@ erlang_client_openssl_server_nowrap_seqnum(Config) when is_list(Config) -> ssl_test_lib:check_result(Client, ok), %% Clean close down! Server needs to be closed first !! - close_port(OpensslPort), + ssl_test_lib:close_port(OpensslPort), ssl_test_lib:close(Client), process_flag(trap_exit, false). %%-------------------------------------------------------------------- @@ -581,7 +579,7 @@ erlang_server_openssl_client_nowrap_seqnum(Config) when is_list(Config) -> %% Clean close down! Server needs to be closed first !! ssl_test_lib:close(Server), - close_port(OpenSslPort), + ssl_test_lib:close_port(OpenSslPort), process_flag(trap_exit, false). %%-------------------------------------------------------------------- @@ -624,7 +622,7 @@ erlang_client_openssl_server_no_server_ca_cert(Config) when is_list(Config) -> ssl_test_lib:check_result(Client, ok), %% Clean close down! Server needs to be closed first !! - close_port(OpensslPort), + ssl_test_lib:close_port(OpensslPort), ssl_test_lib:close(Client), process_flag(trap_exit, false). @@ -666,7 +664,7 @@ erlang_client_openssl_server_client_cert(Config) when is_list(Config) -> ssl_test_lib:check_result(Client, ok), %% Clean close down! Server needs to be closed first !! - close_port(OpensslPort), + ssl_test_lib:close_port(OpensslPort), ssl_test_lib:close(Client), process_flag(trap_exit, false). @@ -708,7 +706,7 @@ erlang_server_openssl_client_client_cert(Config) when is_list(Config) -> ssl_test_lib:check_result(Server, ok), %% Clean close down! Server needs to be closed first !! - close_port(OpenSslPort), + ssl_test_lib:close_port(OpenSslPort), ssl_test_lib:close(Server), process_flag(trap_exit, false). @@ -821,7 +819,7 @@ erlang_client_bad_openssl_server(Config) when is_list(Config) -> [{versions, [Version]} | ClientOpts]}]), %% Clean close down! Server needs to be closed first !! - close_port(OpensslPort), + ssl_test_lib:close_port(OpensslPort), ssl_test_lib:close(Client1), process_flag(trap_exit, false), ok. @@ -878,7 +876,7 @@ expired_session(Config) when is_list(Config) -> {from, self()}, {options, ClientOpts}]), %% Clean close down! Server needs to be closed first !! - close_port(OpensslPort), + ssl_test_lib:close_port(OpensslPort), ssl_test_lib:close(Client2), process_flag(trap_exit, false). @@ -1089,7 +1087,7 @@ cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) -> Result = ssl_test_lib:wait_for_result(Client, ok), %% Clean close down! Server needs to be closed first !! - close_port(OpenSslPort), + ssl_test_lib:close_port(OpenSslPort), ssl_test_lib:close(Client), Return = case Result of @@ -1136,7 +1134,7 @@ start_erlang_client_and_openssl_server_with_opts(Config, ErlangClientOpts, Opens Callback(Client, OpensslPort), %% Clean close down! Server needs to be closed first !! - close_port(OpensslPort), + ssl_test_lib:close_port(OpensslPort), ssl_test_lib:close(Client), process_flag(trap_exit, false). @@ -1175,7 +1173,7 @@ start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, Callbac Callback(Client, OpensslPort), %% Clean close down! Server needs to be closed first !! - close_port(OpensslPort), + ssl_test_lib:close_port(OpensslPort), ssl_test_lib:close(Client), process_flag(trap_exit, false). @@ -1205,7 +1203,7 @@ start_erlang_server_and_openssl_client_for_npn_negotiation(Config, Data, Callbac ssl_test_lib:close(Server), - close_port(OpenSslPort), + ssl_test_lib:close_port(OpenSslPort), process_flag(trap_exit, false). @@ -1234,7 +1232,7 @@ start_erlang_server_and_openssl_client_with_opts(Config, ErlangServerOpts, OpenS ssl_test_lib:close(Server), - close_port(OpenSslPort), + ssl_test_lib:close_port(OpenSslPort), process_flag(trap_exit, false). @@ -1282,39 +1280,6 @@ delayed_send(Socket, [ErlData, OpenSslData]) -> ssl:send(Socket, ErlData), erlang_ssl_receive(Socket, OpenSslData). -close_port(Port) -> - catch port_command(Port, ?OPENSSL_QUIT), - close_loop(Port, 500, false). - -close_loop(Port, Time, SentClose) -> - receive - {Port, {data,Debug}} when is_port(Port) -> - ct:log("openssl ~s~n",[Debug]), - close_loop(Port, Time, SentClose); - {ssl,_,Msg} -> - ct:log("ssl Msg ~s~n",[Msg]), - close_loop(Port, Time, SentClose); - {Port, closed} -> - ct:log("Port Closed~n",[]), - ok; - {'EXIT', Port, Reason} -> - ct:log("Port Closed ~p~n",[Reason]), - ok; - Msg -> - ct:log("Port Msg ~p~n",[Msg]), - close_loop(Port, Time, SentClose) - after Time -> - case SentClose of - false -> - ct:log("Closing port ~n",[]), - catch erlang:port_close(Port), - close_loop(Port, Time, true); - true -> - ct:log("Timeout~n",[]) - end - end. - - server_sent_garbage(Socket) -> receive server_sent_garbage -> diff --git a/lib/stdlib/src/maps.erl b/lib/stdlib/src/maps.erl index 3f019aa35a..ba4d6a5c87 100644 --- a/lib/stdlib/src/maps.erl +++ b/lib/stdlib/src/maps.erl @@ -24,6 +24,7 @@ map/2, size/1, without/2, + with/2, get/3 ]). @@ -201,3 +202,13 @@ size(Map) when is_map(Map) -> without(Ks, M) when is_list(Ks), is_map(M) -> maps:from_list([{K,V}||{K,V} <- maps:to_list(M), not lists:member(K, Ks)]). + + +-spec with(Ks, Map1) -> Map2 when + Ks :: [K], + Map1 :: map(), + Map2 :: map(), + K :: term(). + +with(Ks, M) when is_list(Ks), is_map(M) -> + maps:from_list([{K,V}||{K,V} <- maps:to_list(M), lists:member(K, Ks)]). diff --git a/lib/stdlib/src/proc_lib.erl b/lib/stdlib/src/proc_lib.erl index 1eb6fc2e86..bf2a4e7ac5 100644 --- a/lib/stdlib/src/proc_lib.erl +++ b/lib/stdlib/src/proc_lib.erl @@ -216,10 +216,8 @@ ensure_link(SpawnOpts) -> init_p(Parent, Ancestors, Fun) when is_function(Fun) -> put('$ancestors', [Parent|Ancestors]), - {module,Mod} = erlang:fun_info(Fun, module), - {name,Name} = erlang:fun_info(Fun, name), - {arity,Arity} = erlang:fun_info(Fun, arity), - put('$initial_call', {Mod,Name,Arity}), + Mfa = erlang:fun_info_mfa(Fun), + put('$initial_call', Mfa), try Fun() catch diff --git a/lib/stdlib/src/stdlib.app.src b/lib/stdlib/src/stdlib.app.src index 3585eec342..aa9899da3b 100644 --- a/lib/stdlib/src/stdlib.app.src +++ b/lib/stdlib/src/stdlib.app.src @@ -103,7 +103,7 @@ dets]}, {applications, [kernel]}, {env, []}, - {runtime_dependencies, ["sasl-2.4","kernel-3.0.2","erts-6.1.2","crypto-3.3", + {runtime_dependencies, ["sasl-2.4","kernel-3.0.2","erts-6.2","crypto-3.3", "compiler-5.0"]} ]}. diff --git a/lib/wx/configure.in b/lib/wx/configure.in index a96f1f2632..4c4d4f41a8 100644 --- a/lib/wx/configure.in +++ b/lib/wx/configure.in @@ -677,6 +677,27 @@ if test "x$GCC" = xyes; then LM_TRY_ENABLE_CFLAG([-Werror=return-type], [CXXFLAGS]) fi +dnl ---------------------------------------------------------------------- +dnl Enable -fsanitize= flags. +dnl ---------------------------------------------------------------------- + +m4_define(DEFAULT_SANITIZERS, [address,undefined]) +AC_ARG_ENABLE( + sanitizers, + AS_HELP_STRING( + [--enable-sanitizers@<:@=comma-separated list of sanitizers@:>@], + [Default=DEFAULT_SANITIZERS]), +[ +case "$enableval" in + no) sanitizers= ;; + yes) sanitizers="-fsanitize=DEFAULT_SANITIZERS" ;; + *) sanitizers="-fsanitize=$enableval" ;; +esac +CFLAGS="$CFLAGS $sanitizers" +CXXFLAGS="$CXXFLAGS $sanitizers" +LDFLAGS="$LDFLAGS $sanitizers" +]) + ############################################################################# dnl |