diff options
Diffstat (limited to 'lib')
24 files changed, 1167 insertions, 537 deletions
diff --git a/lib/inets/src/http_client/httpc_handler.erl b/lib/inets/src/http_client/httpc_handler.erl index bfe9b14ef6..714fd6f16d 100644 --- a/lib/inets/src/http_client/httpc_handler.erl +++ b/lib/inets/src/http_client/httpc_handler.erl @@ -852,13 +852,14 @@ connect(SocketType, ToAddress, inet6fb4 -> Opts3 = [inet6 | Opts2], case http_transport:connect(SocketType, ToAddress, Opts3, Timeout) of - {error, _Reason} = Error -> + {error, Reason6} -> Opts4 = [inet | Opts2], case http_transport:connect(SocketType, ToAddress, Opts4, Timeout) of - {error, _} -> - %% Reply with the "original" error - Error; + {error, Reason4} -> + {error, {failed_connect, + [{inet6, Opts3, Reason6}, + {inet, Opts4, Reason4}]}}; OK -> OK end; @@ -867,7 +868,12 @@ connect(SocketType, ToAddress, end; _ -> Opts3 = [IpFamily | Opts2], - http_transport:connect(SocketType, ToAddress, Opts3, Timeout) + case http_transport:connect(SocketType, ToAddress, Opts3, Timeout) of + {error, Reason} -> + {error, {failed_connect, [{IpFamily, Opts3, Reason}]}}; + Else -> + Else + end end. connect_and_send_first_request(Address, Request, #state{options = Options} = State) -> diff --git a/lib/inets/src/http_server/mod_get.erl b/lib/inets/src/http_server/mod_get.erl index 5cb30e3d97..c58d1f3508 100644 --- a/lib/inets/src/http_server/mod_get.erl +++ b/lib/inets/src/http_server/mod_get.erl @@ -18,9 +18,16 @@ %% %% -module(mod_get). + -export([do/1]). + -include("httpd.hrl"). -include("httpd_internal.hrl"). +-include("inets_internal.hrl"). + +-define(VMODULE,"GET"). + + %% do do(Info) -> @@ -84,15 +91,16 @@ send_response(_Socket, _SocketType, Path, Info)-> file:close(FileDescriptor), {proceed,[{response,{already_sent,200, FileInfo#file_info.size}}, - {mime_type,MimeType}|Info#mod.data]}; + {mime_type,MimeType} | Info#mod.data]}; {error, Reason} -> + ?hdrt("send_response -> failed open file", + [{path, Path}, {reason, Reason}]), Status = httpd_file:handle_error(Reason, "open", Info, Path), - {proceed, - [{status, Status}| Info#mod.data]} + {proceed, [{status, Status} | Info#mod.data]} end. %% send - + send(#mod{socket = Socket, socket_type = SocketType} = Info, StatusCode, Headers, FileDescriptor) -> ?DEBUG("send -> send header",[]), diff --git a/lib/inets/src/inets_app/Makefile b/lib/inets/src/inets_app/Makefile index d99e33b4ea..6da6a1d79f 100644 --- a/lib/inets/src/inets_app/Makefile +++ b/lib/inets/src/inets_app/Makefile @@ -46,7 +46,8 @@ MODULES = \ inets_service \ inets_app \ inets_sup \ - inets_regexp + inets_regexp \ + inets_trace INTERNAL_HRL_FILES = inets_internal.hrl EXTERNAL_HRL_FILES = ../../include/httpd.hrl \ diff --git a/lib/inets/src/inets_app/inets.app.src b/lib/inets/src/inets_app/inets.app.src index 1db7ed2c30..4aea2ef3d7 100644 --- a/lib/inets/src/inets_app/inets.app.src +++ b/lib/inets/src/inets_app/inets.app.src @@ -18,14 +18,15 @@ %% {application,inets, - [{description,"INETS CXC 138 49"}, - {vsn,"%VSN%"}, + [{description, "INETS CXC 138 49"}, + {vsn, "%VSN%"}, {modules,[ inets, inets_sup, inets_app, inets_service, inets_regexp, + inets_trace, %% FTP ftp, diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src index 9d7b1e6c93..1be5a958ce 100644 --- a/lib/inets/src/inets_app/inets.appup.src +++ b/lib/inets/src/inets_app/inets.appup.src @@ -18,15 +18,21 @@ {"%VSN%", [ - {"5.8.1", + {"5.8.1", [ {load_module, httpd_conf, soft_purge, soft_purge, []}, {load_module, httpd_response, soft_purge, soft_purge, []}, - {load_module, httpd_script_env, soft_purge, soft_purge, []} + {load_module, httpd_script_env, soft_purge, soft_purge, []}, + + {load_module, inets, soft_purge, soft_purge, [inets_trace]}, + {update, httpc_handler, soft, soft_purge, soft_purge, []}, + {add_module, inets_trace} ] }, {"5.8", [ + {load_module, inets, soft_purge, soft_purge, [inets_trace]}, + {load_module, httpd_conf, soft_purge, soft_purge, []}, {load_module, httpd_response, soft_purge, soft_purge, []}, {load_module, httpd_script_env, soft_purge, soft_purge, []}, @@ -35,25 +41,33 @@ {update, httpc_handler, {advanced, upgrade_from_pre_5_8_1}, soft_purge, soft_purge, []}, {update, httpc_manager, {advanced, upgrade_from_pre_5_8_1}, - soft_purge, soft_purge, [httpc_handler]} + soft_purge, soft_purge, [httpc_handler]}, + + {add_module, inets_trace} ] }, {"5.7.2", [ {restart_application, inets} ] - } + } ], [ {"5.8.1", [ {load_module, httpd_conf, soft_purge, soft_purge, []}, {load_module, httpd_response, soft_purge, soft_purge, []}, - {load_module, httpd_script_env, soft_purge, soft_purge, []} + {load_module, httpd_script_env, soft_purge, soft_purge, []}, + + {load_module, inets, soft_purge, soft_purge, []}, + {update, httpc_handler, soft, soft_purge, soft_purge, []}, + {remove, {inets_trace, soft_purge, brutal_purge}} ] }, {"5.8", [ + {load_module, inets, soft_purge, soft_purge, []}, + {load_module, httpd_conf, soft_purge, soft_purge, []}, {load_module, httpd_response, soft_purge, soft_purge, []}, {load_module, httpd_script_env, soft_purge, soft_purge, []}, @@ -62,7 +76,9 @@ {update, httpc_handler, {advanced, upgrade_from_pre_5_8_1}, soft_purge, soft_purge, []}, {update, httpc_manager, {advanced, upgrade_from_pre_5_8_1}, - soft_purge, soft_purge, [httpc_handler]} + soft_purge, soft_purge, [httpc_handler]}, + + {remove, {inets_trace, soft_purge, brutal_purge}} ] }, {"5.7.2", diff --git a/lib/inets/src/inets_app/inets.erl b/lib/inets/src/inets_app/inets.erl index 054468e445..8e79f8d456 100644 --- a/lib/inets/src/inets_app/inets.erl +++ b/lib/inets/src/inets_app/inets.erl @@ -28,7 +28,7 @@ stop/0, stop/2, services/0, services_info/0, service_names/0]). --export([enable_trace/2, enable_trace/3, disable_trace/0, set_trace/1, +-export([enable_trace/2, enable_trace/3, disable_trace/0, set_trace/1, report_event/4]). -export([versions/0, print_version_info/0, print_version_info/1]). @@ -409,47 +409,8 @@ service_names() -> %% Severity withing Limit) will be written to stdout using io:format. %% %%----------------------------------------------------------------- -enable_trace(Level, Dest) -> - enable_trace(Level, Dest, all). - -enable_trace(Level, Dest, Service) -> - case valid_trace_service(Service) of - true -> - enable_trace2(Level, Dest, Service); - false -> - {error, {invalid_service, Service}} - end. - -enable_trace2(Level, File, Service) - when is_list(File) -> - case file:open(File, [write]) of - {ok, Fd} -> - HandleSpec = {fun handle_trace/2, {Service, Fd}}, - do_enable_trace(Level, process, HandleSpec); - Err -> - Err - end; -enable_trace2(Level, Port, _) when is_integer(Port) -> - do_enable_trace(Level, port, dbg:trace_port(ip, Port)); -enable_trace2(Level, io, Service) -> - HandleSpec = {fun handle_trace/2, {Service, standard_io}}, - do_enable_trace(Level, process, HandleSpec); -enable_trace2(Level, {Fun, _Data} = HandleSpec, _) when is_function(Fun) -> - do_enable_trace(Level, process, HandleSpec). - -do_enable_trace(Level, Type, HandleSpec) -> - case dbg:tracer(Type, HandleSpec) of - {ok, _} -> - set_trace(Level), - ok; - Error -> - Error - end. - -valid_trace_service(all) -> - true; -valid_trace_service(Service) -> - lists:member(Service, [httpc, httpd, ftpc, tftp]). +enable_trace(Level, Dest) -> inets_trace:enable(Level, Dest). +enable_trace(Level, Dest, Service) -> inets_trace:enable(Level, Dest, Service). %%----------------------------------------------------------------- @@ -458,12 +419,7 @@ valid_trace_service(Service) -> %% Description: %% This function is used to stop tracing. %%----------------------------------------------------------------- -disable_trace() -> - %% This is to make handle_trace/2 close the output file (if the - %% event gets there before dbg closes) - inets:report_event(100, "stop trace", stop_trace, [stop_trace]), - dbg:stop(). - +disable_trace() -> inets_trace:disable(). %%----------------------------------------------------------------- @@ -476,60 +432,7 @@ disable_trace() -> %% This function is used to change the trace level when tracing has %% already been started. %%----------------------------------------------------------------- -set_trace(Level) -> - set_trace(Level, all). - -set_trace(Level, Service) -> - Pat = make_pattern(?MODULE, Service, Level), - change_pattern(Pat). - -make_pattern(Mod, Service, Level) - when is_atom(Mod) andalso is_atom(Service) -> - case Level of - min -> - {Mod, Service, []}; - max -> - Head = ['$1', '_', '_', '_'], - Body = [], - Cond = [], - {Mod, Service, [{Head, Cond, Body}]}; - DetailLevel when is_integer(DetailLevel) -> - Head = ['$1', '_', '_', '_'], - Body = [], - Cond = [{ '=<', '$1', DetailLevel}], - {Mod, Service, [{Head, Cond, Body}]}; - _ -> - exit({bad_level, Level}) - end. - -change_pattern({Mod, Service, Pattern}) - when is_atom(Mod) andalso is_atom(Service) -> - MFA = {Mod, report_event, 4}, - case Pattern of - [] -> - try - error_to_exit(ctp, dbg:ctp(MFA)), - error_to_exit(p, dbg:p(all, clear)) - catch - exit:{Where, Reason} -> - {error, {Where, Reason}} - end; - List when is_list(List) -> - try - error_to_exit(ctp, dbg:ctp(MFA)), - error_to_exit(tp, dbg:tp(MFA, Pattern)), - error_to_exit(p, dbg:p(all, [call, timestamp])) - catch - exit:{Where, Reason} -> - {error, {Where, Reason}} - end - end, - ok. - -error_to_exit(_Where, {ok, _} = OK) -> - OK; -error_to_exit(Where, {error, Reason}) -> - exit({Where, Reason}). +set_trace(Level) -> inets_trace:set_level(Level). %%----------------------------------------------------------------- @@ -546,164 +449,8 @@ error_to_exit(Where, {error, Reason}) -> %% put trace on this function. %%----------------------------------------------------------------- -report_event(Severity, Label, Service, Content) - when (is_integer(Severity) andalso - (Severity >= 0) andalso (100 >= Severity)) andalso - is_list(Label) andalso - is_atom(Service) andalso - is_list(Content) -> - hopefully_traced. - - -%% ---------------------------------------------------------------------- -%% handle_trace(Event, Fd) -> Verbosity -%% -%% Parameters: -%% Event -> The trace event (only megaco 'trace_ts' events are printed) -%% Fd -> standard_io | file_descriptor() | trace_port() -%% -%% Description: -%% This function is used to "receive" and print the trace events. -%% Events are printed if: -%% - Verbosity is max -%% - Severity is =< Verbosity (e.g. Severity = 30, and Verbosity = 40) -%% Events are not printed if: -%% - Verbosity is min -%% - Severity is > Verbosity -%%----------------------------------------------------------------- - -handle_trace(_, closed_file = Fd) -> - Fd; -handle_trace({trace_ts, _Who, call, - {?MODULE, report_event, - [_Sev, "stop trace", stop_trace, [stop_trace]]}, - Timestamp}, - {_, standard_io} = Fd) -> - (catch io:format(standard_io, "stop trace at ~s~n", [format_timestamp(Timestamp)])), - Fd; -handle_trace({trace_ts, _Who, call, - {?MODULE, report_event, - [_Sev, "stop trace", stop_trace, [stop_trace]]}, - Timestamp}, - standard_io = Fd) -> - (catch io:format(Fd, "stop trace at ~s~n", [format_timestamp(Timestamp)])), - Fd; -handle_trace({trace_ts, _Who, call, - {?MODULE, report_event, - [_Sev, "stop trace", stop_trace, [stop_trace]]}, - Timestamp}, - {_Service, Fd}) -> - (catch io:format(Fd, "stop trace at ~s~n", [format_timestamp(Timestamp)])), - (catch file:close(Fd)), - closed_file; -handle_trace({trace_ts, _Who, call, - {?MODULE, report_event, - [_Sev, "stop trace", stop_trace, [stop_trace]]}, - Timestamp}, - Fd) -> - (catch io:format(Fd, "stop trace at ~s~n", [format_timestamp(Timestamp)])), - (catch file:close(Fd)), - closed_file; -handle_trace({trace_ts, Who, call, - {?MODULE, report_event, - [Sev, Label, Service, Content]}, Timestamp}, - Fd) -> - (catch print_inets_trace(Fd, Sev, Timestamp, Who, - Label, Service, Content)), - Fd; -handle_trace(Event, Fd) -> - (catch print_trace(Fd, Event)), - Fd. - - -print_inets_trace({Service, Fd}, - Sev, Timestamp, Who, Label, Service, Content) -> - do_print_inets_trace(Fd, Sev, Timestamp, Who, Label, Service, Content); -print_inets_trace({ServiceA, Fd}, - Sev, Timestamp, Who, Label, ServiceB, Content) - when (ServiceA =:= all) -> - do_print_inets_trace(Fd, Sev, Timestamp, Who, Label, ServiceB, Content); -print_inets_trace({ServiceA, _Fd}, - _Sev, _Timestamp, _Who, _Label, ServiceB, _Content) - when ServiceA =/= ServiceB -> - ok; -print_inets_trace(Fd, Sev, Timestamp, Who, Label, Service, Content) -> - do_print_inets_trace(Fd, Sev, Timestamp, Who, Label, Service, Content). - -do_print_inets_trace(Fd, Sev, Timestamp, Who, Label, Service, Content) -> - Ts = format_timestamp(Timestamp), - io:format(Fd, "[inets ~w trace ~w ~w ~s] ~s " - "~n Content: ~p" - "~n", - [Service, Sev, Who, Ts, Label, Content]). - -print_trace({_, Fd}, Event) -> - do_print_trace(Fd, Event); -print_trace(Fd, Event) -> - do_print_trace(Fd, Event). - -do_print_trace(Fd, {trace, Who, What, Where}) -> - io:format(Fd, "[trace]" - "~n Who: ~p" - "~n What: ~p" - "~n Where: ~p" - "~n", [Who, What, Where]); - -do_print_trace(Fd, {trace, Who, What, Where, Extra}) -> - io:format(Fd, "[trace]" - "~n Who: ~p" - "~n What: ~p" - "~n Where: ~p" - "~n Extra: ~p" - "~n", [Who, What, Where, Extra]); - -do_print_trace(Fd, {trace_ts, Who, What, Where, When}) -> - Ts = format_timestamp(When), - io:format(Fd, "[trace ~s]" - "~n Who: ~p" - "~n What: ~p" - "~n Where: ~p" - "~n", [Ts, Who, What, Where]); - -do_print_trace(Fd, {trace_ts, Who, What, Where, Extra, When}) -> - Ts = format_timestamp(When), - io:format(Fd, "[trace ~s]" - "~n Who: ~p" - "~n What: ~p" - "~n Where: ~p" - "~n Extra: ~p" - "~n", [Ts, Who, What, Where, Extra]); - -do_print_trace(Fd, {seq_trace, What, Where}) -> - io:format(Fd, "[seq trace]" - "~n What: ~p" - "~n Where: ~p" - "~n", [What, Where]); - -do_print_trace(Fd, {seq_trace, What, Where, When}) -> - Ts = format_timestamp(When), - io:format(Fd, "[seq trace ~s]" - "~n What: ~p" - "~n Where: ~p" - "~n", [Ts, What, Where]); - -do_print_trace(Fd, {drop, Num}) -> - io:format(Fd, "[drop trace] ~p~n", [Num]); - -do_print_trace(Fd, Trace) -> - io:format(Fd, "[trace] " - "~n ~p" - "~n", [Trace]). - - -format_timestamp({_N1, _N2, N3} = Now) -> - {Date, Time} = calendar:now_to_datetime(Now), - {YYYY,MM,DD} = Date, - {Hour,Min,Sec} = Time, - FormatDate = - io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w", - [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]), - lists:flatten(FormatDate). +report_event(Severity, Label, Service, Content) -> + inets_trace:report_event(Severity, Label, Service, Content). %%-------------------------------------------------------------------- diff --git a/lib/inets/src/inets_app/inets_internal.hrl b/lib/inets/src/inets_app/inets_internal.hrl index 55c3669e4a..e56af3b59d 100644 --- a/lib/inets/src/inets_app/inets_internal.hrl +++ b/lib/inets/src/inets_app/inets_internal.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2009. All Rights Reserved. +%% Copyright Ericsson AB 2005-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 @@ -24,8 +24,8 @@ %% Various trace macros -define(report(Severity, Label, Service, Content), - inets:report_event(Severity, Label, Service, - [{module, ?MODULE}, {line, ?LINE} | Content])). + inets_trace:report_event(Severity, Label, Service, + [{module, ?MODULE}, {line, ?LINE} | Content])). -define(report_important(Label, Service, Content), ?report(20, Label, Service, Content)). -define(report_verbose(Label, Service, Content), diff --git a/lib/inets/src/inets_app/inets_trace.erl b/lib/inets/src/inets_app/inets_trace.erl new file mode 100644 index 0000000000..8911f65897 --- /dev/null +++ b/lib/inets/src/inets_app/inets_trace.erl @@ -0,0 +1,357 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2011-2012. 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% +%% +%% +%%---------------------------------------------------------------------- +%% Purpose: Module for debug trace functions of the inets application +%%---------------------------------------------------------------------- + +-module(inets_trace). + +%% API +-export([enable/2, enable/3, + disable/0, + set_level/1, set_level/2, + report_event/4]). + + +%%==================================================================== +%% API +%%==================================================================== + +%%----------------------------------------------------------------- +%% enable(Level, Destination) -> void() +%% enable(Level, Destination, Service) -> void() +%% +%% Parameters: +%% Level -> max | min | integer() +%% Destination -> File | Port | io | HandlerSpec +%% Service -> httpc | httpd | ftpc | tftp | all +%% File -> string() +%% Port -> integer() +%% Verbosity -> true | false +%% HandlerSpec = {function(), Data} +%% Data = term() +%% +%% Description: +%% This function is used to start tracing at level Level and send +%% the result either to the file File, the port Port or to a +%% trace handler. +%% Note that it starts a tracer server. +%% When Destination is the atom io (or the tuple {io, Verbosity}), +%% all (printable) inets trace events (trace_ts events which has +%% Severity withing Limit) will be written to stdout using io:format. +%% +%%----------------------------------------------------------------- +enable(Level, Dest) -> + enable(Level, Dest, all). + +enable(Level, Dest, Service) -> + case valid_trace_service(Service) of + true -> + enable2(Level, Dest, Service); + false -> + {error, {invalid_service, Service}} + end. + +enable2(Level, File, Service) + when is_list(File) -> + case file:open(File, [write]) of + {ok, Fd} -> + HandleSpec = {fun handle_trace/2, {Service, Fd}}, + do_enable(Level, process, HandleSpec); + Err -> + Err + end; +enable2(Level, Port, _) when is_integer(Port) -> + do_enable(Level, port, dbg:trace_port(ip, Port)); +enable2(Level, io, Service) -> + HandleSpec = {fun handle_trace/2, {Service, standard_io}}, + do_enable(Level, process, HandleSpec); +enable2(Level, {Fun, _Data} = HandleSpec, _) when is_function(Fun) -> + do_enable(Level, process, HandleSpec). + +do_enable(Level, Type, HandleSpec) -> + case dbg:tracer(Type, HandleSpec) of + {ok, _} -> + set_level(Level), + ok; + Error -> + Error + end. + +valid_trace_service(all) -> + true; +valid_trace_service(Service) -> + lists:member(Service, [httpc, httpd, ftpc, tftp]). + + +%%----------------------------------------------------------------- +%% disable() -> void() +%% +%% Description: +%% This function is used to stop tracing. +%%----------------------------------------------------------------- + +disable() -> + %% This is to make handle_trace/2 close the output file (if the + %% event gets there before dbg closes) + inets_trace:report_event(100, "stop trace", stop_trace, [stop_trace]), + dbg:stop(). + + + +%%----------------------------------------------------------------- +%% set_level(Level) -> void() +%% +%% Parameters: +%% Level -> max | min | integer() +%% +%% Description: +%% This function is used to change the trace level when tracing has +%% already been started. +%%----------------------------------------------------------------- +set_level(Level) -> + set_level(Level, all). + +set_level(Level, Service) -> + Pat = make_pattern(?MODULE, Service, Level), + change_pattern(Pat). + +make_pattern(Mod, Service, Level) + when is_atom(Mod) andalso is_atom(Service) -> + case Level of + min -> + {Mod, Service, []}; + max -> + Head = ['$1', '_', '_', '_'], + Body = [], + Cond = [], + {Mod, Service, [{Head, Cond, Body}]}; + DetailLevel when is_integer(DetailLevel) -> + Head = ['$1', '_', '_', '_'], + Body = [], + Cond = [{ '=<', '$1', DetailLevel}], + {Mod, Service, [{Head, Cond, Body}]}; + _ -> + exit({bad_level, Level}) + end. + +change_pattern({Mod, Service, Pattern}) + when is_atom(Mod) andalso is_atom(Service) -> + MFA = {Mod, report_event, 4}, + case Pattern of + [] -> + try + error_to_exit(ctp, dbg:ctp(MFA)), + error_to_exit(p, dbg:p(all, clear)) + catch + exit:{Where, Reason} -> + {error, {Where, Reason}} + end; + List when is_list(List) -> + try + error_to_exit(ctp, dbg:ctp(MFA)), + error_to_exit(tp, dbg:tp(MFA, Pattern)), + error_to_exit(p, dbg:p(all, [call, timestamp])) + catch + exit:{Where, Reason} -> + {error, {Where, Reason}} + end + end. + +error_to_exit(_Where, {ok, _} = OK) -> + OK; +error_to_exit(Where, {error, Reason}) -> + exit({Where, Reason}). + + +%%----------------------------------------------------------------- +%% report_event(Severity, Label, Service, Content) +%% +%% Parameters: +%% Severity -> 0 =< integer() =< 100 +%% Label -> string() +%% Service -> httpd | httpc | ftp | tftp +%% Content -> [{tag, term()}] +%% +%% Description: +%% This function is used to generate trace events, that is, +%% put trace on this function. +%%----------------------------------------------------------------- + +report_event(Severity, Label, Service, Content) + when (is_integer(Severity) andalso + (Severity >= 0) andalso (100 >= Severity)) andalso + is_list(Label) andalso + is_atom(Service) andalso + is_list(Content) -> + hopefully_traced. + + +%% ---------------------------------------------------------------------- +%% handle_trace(Event, Fd) -> Verbosity +%% +%% Parameters: +%% Event -> The trace event +%% Fd -> standard_io | file_descriptor() | trace_port() +%% +%% Description: +%% This function is used to "receive" and pretty print the trace events. +%% Events are printed if: +%% - Verbosity is max +%% - Severity is =< Verbosity (e.g. Severity = 30, and Verbosity = 40) +%% Events are not printed if: +%% - Verbosity is min +%% - Severity is > Verbosity +%%----------------------------------------------------------------- + +handle_trace(_, closed_file = Fd) -> + Fd; +handle_trace({trace_ts, _Who, call, + {?MODULE, report_event, + [_Sev, "stop trace", stop_trace, [stop_trace]]}, + Timestamp}, + {_, standard_io} = Fd) -> + (catch io:format(standard_io, "stop trace at ~s~n", [format_timestamp(Timestamp)])), + Fd; +handle_trace({trace_ts, _Who, call, + {?MODULE, report_event, + [_Sev, "stop trace", stop_trace, [stop_trace]]}, + Timestamp}, + standard_io = Fd) -> + (catch io:format(Fd, "stop trace at ~s~n", [format_timestamp(Timestamp)])), + Fd; +handle_trace({trace_ts, _Who, call, + {?MODULE, report_event, + [_Sev, "stop trace", stop_trace, [stop_trace]]}, + Timestamp}, + {_Service, Fd}) -> + (catch io:format(Fd, "stop trace at ~s~n", [format_timestamp(Timestamp)])), + (catch file:close(Fd)), + closed_file; +handle_trace({trace_ts, _Who, call, + {?MODULE, report_event, + [_Sev, "stop trace", stop_trace, [stop_trace]]}, + Timestamp}, + Fd) -> + (catch io:format(Fd, "stop trace at ~s~n", [format_timestamp(Timestamp)])), + (catch file:close(Fd)), + closed_file; +handle_trace({trace_ts, Who, call, + {?MODULE, report_event, + [Sev, Label, Service, Content]}, Timestamp}, + Fd) -> + (catch print_inets_trace(Fd, Sev, Timestamp, Who, + Label, Service, Content)), + Fd; +handle_trace(Event, Fd) -> + (catch print_trace(Fd, Event)), + Fd. + + +print_inets_trace({Service, Fd}, + Sev, Timestamp, Who, Label, Service, Content) -> + do_print_inets_trace(Fd, Sev, Timestamp, Who, Label, Service, Content); +print_inets_trace({ServiceA, Fd}, + Sev, Timestamp, Who, Label, ServiceB, Content) + when (ServiceA =:= all) -> + do_print_inets_trace(Fd, Sev, Timestamp, Who, Label, ServiceB, Content); +print_inets_trace({ServiceA, _Fd}, + _Sev, _Timestamp, _Who, _Label, ServiceB, _Content) + when ServiceA =/= ServiceB -> + ok; +print_inets_trace(Fd, Sev, Timestamp, Who, Label, Service, Content) -> + do_print_inets_trace(Fd, Sev, Timestamp, Who, Label, Service, Content). + +do_print_inets_trace(Fd, Sev, Timestamp, Who, Label, Service, Content) -> + Ts = format_timestamp(Timestamp), + io:format(Fd, "[inets ~w trace ~w ~w ~s] ~s " + "~n Content: ~p" + "~n", + [Service, Sev, Who, Ts, Label, Content]). + +print_trace({_, Fd}, Event) -> + do_print_trace(Fd, Event); +print_trace(Fd, Event) -> + do_print_trace(Fd, Event). + +do_print_trace(Fd, {trace, Who, What, Where}) -> + io:format(Fd, "[trace]" + "~n Who: ~p" + "~n What: ~p" + "~n Where: ~p" + "~n", [Who, What, Where]); + +do_print_trace(Fd, {trace, Who, What, Where, Extra}) -> + io:format(Fd, "[trace]" + "~n Who: ~p" + "~n What: ~p" + "~n Where: ~p" + "~n Extra: ~p" + "~n", [Who, What, Where, Extra]); + +do_print_trace(Fd, {trace_ts, Who, What, Where, When}) -> + Ts = format_timestamp(When), + io:format(Fd, "[trace ~s]" + "~n Who: ~p" + "~n What: ~p" + "~n Where: ~p" + "~n", [Ts, Who, What, Where]); + +do_print_trace(Fd, {trace_ts, Who, What, Where, Extra, When}) -> + Ts = format_timestamp(When), + io:format(Fd, "[trace ~s]" + "~n Who: ~p" + "~n What: ~p" + "~n Where: ~p" + "~n Extra: ~p" + "~n", [Ts, Who, What, Where, Extra]); + +do_print_trace(Fd, {seq_trace, What, Where}) -> + io:format(Fd, "[seq trace]" + "~n What: ~p" + "~n Where: ~p" + "~n", [What, Where]); + +do_print_trace(Fd, {seq_trace, What, Where, When}) -> + Ts = format_timestamp(When), + io:format(Fd, "[seq trace ~s]" + "~n What: ~p" + "~n Where: ~p" + "~n", [Ts, What, Where]); + +do_print_trace(Fd, {drop, Num}) -> + io:format(Fd, "[drop trace] ~p~n", [Num]); + +do_print_trace(Fd, Trace) -> + io:format(Fd, "[trace] " + "~n ~p" + "~n", [Trace]). + + +format_timestamp({_N1, _N2, N3} = Now) -> + {Date, Time} = calendar:now_to_datetime(Now), + {YYYY,MM,DD} = Date, + {Hour,Min,Sec} = Time, + FormatDate = + io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w", + [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]), + lists:flatten(FormatDate). + + diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl index 881266b70a..734964698e 100644 --- a/lib/inets/test/httpc_SUITE.erl +++ b/lib/inets/test/httpc_SUITE.erl @@ -156,6 +156,9 @@ groups() -> %% variable, but should NOT alter/remove any existing entries. %%-------------------------------------------------------------------- init_per_suite(Config) -> + + ?PRINT_SYSTEM_INFO([]), + PrivDir = ?config(priv_dir, Config), DataDir = ?config(data_dir, Config), ServerRoot = filename:join(PrivDir, "server_root"), @@ -179,10 +182,11 @@ init_per_suite(Config) -> {ok, FileInfo} = file:read_file_info(Cgi), ok = file:write_file_info(Cgi, FileInfo#file_info{mode = 8#00755}), - [{server_root, ServerRoot}, - {doc_root, DocRoot}, - {local_port, ?IP_PORT}, - {local_ssl_port, ?SSL_PORT} | Config]. + [{has_ipv6_support, inets_test_lib:has_ipv6_support()}, + {server_root, ServerRoot}, + {doc_root, DocRoot}, + {local_port, ?IP_PORT}, + {local_ssl_port, ?SSL_PORT} | Config]. %%-------------------------------------------------------------------- @@ -198,6 +202,7 @@ end_per_suite(Config) -> application:stop(ssl), ok. + %%-------------------------------------------------------------------- %% Function: init_per_testcase(Case, Config) -> Config %% Case - atom() @@ -244,6 +249,7 @@ init_per_testcase(Case, Timeout, Config) -> io:format(user, "~n~n*** INIT ~w:~w[~w] ***" "~n~n", [?MODULE, Case, Timeout]), + PrivDir = ?config(priv_dir, Config), application:stop(inets), Dog = test_server:timetrap(inets_test_lib:minutes(Timeout)), @@ -355,6 +361,18 @@ init_per_testcase(Case, Timeout, Config) -> end; _ -> + %% Try inet6fb4 on windows... + tsp("init_per_testcase -> allways try IPv6 on windows"), + ?RUN_ON_WINDOWS( + fun() -> + tsp("init_per_testcase:set_options_fun -> " + "set-option ipfamily to inet6fb4"), + Res = httpc:set_options([{ipfamily, inet6fb4}]), + tsp("init_per_testcase:set_options_fun -> " + "~n Res: ~p", [Res]), + Res + end), + TmpConfig2 = lists:keydelete(local_server, 1, TmpConfig), %% Will start inets Server = start_http_server(PrivDir, IpConfFile), @@ -367,6 +385,9 @@ init_per_testcase(Case, Timeout, Config) -> inets:enable_trace(max, io, httpc), %% inets:enable_trace(max, io, all), %% snmp:set_trace([gen_tcp]), + tsp("init_per_testcase(~w) -> done when" + "~n NewConfig: ~p" + "~n~n", [Case, NewConfig]), NewConfig. @@ -456,22 +477,32 @@ http_head(doc) -> http_head(suite) -> []; http_head(Config) when is_list(Config) -> - case ?config(local_server, Config) of - ok -> - Port = ?config(local_port, Config), - URL = ?URL_START ++ integer_to_list(Port) ++ "/dummy.html", - case httpc:request(head, {URL, []}, [], []) of - {ok, {{_,200,_}, [_ | _], []}} -> - ok; - {ok, WrongReply} -> - tsf({wrong_reply, WrongReply}); - Error -> - tsf({failed, Error}) - end; - _ -> - {skip, "Failed to start local http-server"} - end. + tsp("http_head -> entry with" + "~n Config: ~p", [Config]), + Method = head, + Port = ?config(local_port, Config), + URL = ?URL_START ++ integer_to_list(Port) ++ "/dummy.html", + Request = {URL, []}, + HttpOpts = [], + Opts = [], + VerifyResult = + fun({ok, {{_,200,_}, [_ | _], []}}) -> + ok; + ({ok, UnexpectedReply}) -> + tsp("http_head:verify_fun -> Unexpected Reply: " + "~n ~p", [UnexpectedReply]), + tsf({unexpected_reply, UnexpectedReply}); + ({error, Reason} = Error) -> + tsp("http_head:verify_fun -> Error reply: " + "~n Reason: ~p", [Reason]), + tsf({bad_reply, Error}) + end, + simple_request_and_verify(Config, + Method, Request, HttpOpts, Opts, VerifyResult). + + %%------------------------------------------------------------------------- + http_get(doc) -> ["Test http get request against local server"]; http_get(suite) -> @@ -488,7 +519,8 @@ http_get(Config) when is_list(Config) -> Request = {URL, []}, Timeout = timer:seconds(1), ConnTimeout = Timeout + timer:seconds(1), - HttpOptions1 = [{timeout, Timeout}, {connect_timeout, ConnTimeout}], + HttpOptions1 = [{timeout, Timeout}, + {connect_timeout, ConnTimeout}], Options1 = [], Body = case httpc:request(Method, Request, HttpOptions1, Options1) of @@ -520,10 +552,11 @@ http_get(Config) when is_list(Config) -> end. %%------------------------------------------------------------------------- + http_post(doc) -> - ["Test http post request against local server. We do in this case" - " only care about the client side of the the post. The server" - " script will not actually use the post data."]; + ["Test http post request against local server. We do in this case " + "only care about the client side of the the post. The server " + "script will not actually use the post data."]; http_post(suite) -> []; http_post(Config) when is_list(Config) -> @@ -1136,9 +1169,20 @@ ssl_get(SslTag, Config) when is_list(Config) -> "~n URL: ~p" "~n SslTag: ~p" "~n SSLOptions: ~p", [URL, SslTag, SSLOptions]), - {ok, {{_,200, _}, [_ | _], Body = [_ | _]}} = - httpc:request(get, {URL, []}, [{ssl, SSLConfig}], []), - inets_test_lib:check_body(Body); + case httpc:request(get, {URL, []}, [{ssl, SSLConfig}], []) of + {ok, {{_,200, _}, [_ | _], Body = [_ | _]}} -> + inets_test_lib:check_body(Body), + ok; + {ok, {StatusLine, Headers, _Body}} -> + tsp("ssl_get -> unexpected result: " + "~n StatusLine: ~p" + "~n Headers: ~p", [StatusLine, Headers]), + tsf({unexpected_response, StatusLine, Headers}); + {error, Reason} -> + tsp("ssl_get -> request failed: " + "~n Reason: ~p", [Reason]), + tsf({request_failed, Reason}) + end; {ok, _} -> {skip, "local http-server not started"}; _ -> @@ -3813,6 +3857,34 @@ pick_header(Headers, Name) -> Val end. + +%% ------------------------------------------------------------------------- + +simple_request_and_verify(Config, + Method, Request, HttpOpts, Opts, VerifyResult) + when (is_list(Config) andalso + is_atom(Method) andalso + is_list(HttpOpts) andalso + is_list(Opts) andalso + is_function(VerifyResult, 1)) -> + tsp("request_and_verify -> entry with" + "~n Method: ~p" + "~n Request: ~p" + "~n HttpOpts: ~p" + "~n Opts: ~p", [Method, Request, HttpOpts, Opts]), + case ?config(local_server, Config) of + ok -> + tsp("request_and_verify -> local-server running"), + Result = (catch httpc:request(Method, Request, HttpOpts, Opts)), + VerifyResult(Result); + _ -> + tsp("request_and_verify -> local-server *not* running - skip"), + hard_skip("Local http-server not running") + end. + + + + not_implemented_yet() -> exit(not_implemented_yet). @@ -3864,6 +3936,8 @@ dummy_ssl_server_hang_loop(_) -> ok end. +hard_skip(Reason) -> + throw(skip(Reason)). skip(Reason) -> {skip, Reason}. diff --git a/lib/inets/test/httpd_SUITE.erl b/lib/inets/test/httpd_SUITE.erl index a4bb8f7159..907d58fd8c 100644 --- a/lib/inets/test/httpd_SUITE.erl +++ b/lib/inets/test/httpd_SUITE.erl @@ -314,6 +314,8 @@ init_per_suite(Config) -> "~n Config: ~p" "~n", [Config]), + ?PRINT_SYSTEM_INFO([]), + PrivDir = ?config(priv_dir, Config), SuiteTopDir = filename:join(PrivDir, ?MODULE), case file:make_dir(SuiteTopDir) of @@ -325,10 +327,11 @@ init_per_suite(Config) -> throw({error, {failed_creating_suite_top_dir, Error}}) end, - [{suite_top_dir, SuiteTopDir}, - {node, node()}, - {host, inets_test_lib:hostname()}, - {address, getaddr()} | Config]. + [{has_ipv6_support, inets_test_lib:has_ipv6_support()}, + {suite_top_dir, SuiteTopDir}, + {node, node()}, + {host, inets_test_lib:hostname()}, + {address, getaddr()} | Config]. %%-------------------------------------------------------------------- @@ -363,10 +366,9 @@ init_per_testcase(Case, Config) -> init_per_testcase2(Case, Config) -> - io:format(user, "~w:init_per_testcase2(~w) -> entry with" - "~n Config: ~p" - "~n", [?MODULE, Case, Config]), - + tsp("init_per_testcase2(~w) -> entry with" + "~n Config: ~p", [Case, Config]), + IpNormal = integer_to_list(?IP_PORT) ++ ".conf", IpHtaccess = integer_to_list(?IP_PORT) ++ "htaccess.conf", SslNormal = integer_to_list(?SSL_PORT) ++ ".conf", @@ -375,39 +377,33 @@ init_per_testcase2(Case, Config) -> DataDir = ?config(data_dir, Config), SuiteTopDir = ?config(suite_top_dir, Config), - io:format(user, "~w:init_per_testcase2(~w) -> " - "~n SuiteDir: ~p" - "~n DataDir: ~p" - "~n", [?MODULE, Case, SuiteTopDir, DataDir]), + tsp("init_per_testcase2(~w) -> " + "~n SuiteDir: ~p" + "~n DataDir: ~p", [Case, SuiteTopDir, DataDir]), TcTopDir = filename:join(SuiteTopDir, Case), ?line ok = file:make_dir(TcTopDir), - io:format(user, "~w:init_per_testcase2(~w) -> " - "~n TcTopDir: ~p" - "~n", [?MODULE, Case, TcTopDir]), + tsp("init_per_testcase2(~w) -> " + "~n TcTopDir: ~p", [Case, TcTopDir]), DataSrc = filename:join([DataDir, "server_root"]), ServerRoot = filename:join([TcTopDir, "server_root"]), - io:format(user, "~w:init_per_testcase2(~w) -> " - "~n DataSrc: ~p" - "~n ServerRoot: ~p" - "~n", [?MODULE, Case, DataSrc, ServerRoot]), + tsp("init_per_testcase2(~w) -> " + "~n DataSrc: ~p" + "~n ServerRoot: ~p", [Case, DataSrc, ServerRoot]), ok = file:make_dir(ServerRoot), ok = file:make_dir(filename:join([TcTopDir, "logs"])), NewConfig = [{tc_top_dir, TcTopDir}, {server_root, ServerRoot} | Config], - io:format(user, "~w:init_per_testcase2(~w) -> " - "copy DataSrc to ServerRoot~n", - [?MODULE, Case]), + tsp("init_per_testcase2(~w) -> copy DataSrc to ServerRoot", [Case]), inets_test_lib:copy_dirs(DataSrc, ServerRoot), - io:format(user, "~w:init_per_testcase2(~w) -> fix cgi~n", - [?MODULE, Case]), + tsp("init_per_testcase2(~w) -> fix cgi", [Case]), EnvCGI = filename:join([ServerRoot, "cgi-bin", "printenv.sh"]), {ok, FileInfo} = file:read_file_info(EnvCGI), ok = file:write_file_info(EnvCGI, @@ -427,16 +423,14 @@ init_per_testcase2(Case, Config) -> FileInfo1#file_info{mode = 8#00755}), %% To be used by IP test cases - io:format(user, "~w:init_per_testcase2(~w) -> ip testcase setups~n", - [?MODULE, Case]), + tsp("init_per_testcase2(~w) -> ip testcase setups", [Case]), create_config([{port, ?IP_PORT}, {sock_type, ip_comm} | NewConfig], normal_access, IpNormal), create_config([{port, ?IP_PORT}, {sock_type, ip_comm} | NewConfig], mod_htaccess, IpHtaccess), %% To be used by SSL test cases - io:format(user, "~w:init_per_testcase2(~w) -> ssl testcase setups~n", - [?MODULE, Case]), + tsp("init_per_testcase2(~w) -> ssl testcase setups", [Case]), SocketType = case atom_to_list(Case) of [X, $s, $s, $l | _] -> @@ -460,8 +454,7 @@ init_per_testcase2(Case, Config) -> %% when you run the whole test suite due to shortcomings %% of the test server. - io:format(user, "~w:init_per_testcase2(~w) -> " - "maybe generate IPv6 config file(s)", [?MODULE, Case]), + tsp("init_per_testcase2(~w) -> maybe generate IPv6 config file(s)", [Case]), NewConfig2 = case atom_to_list(Case) of "ipv6_" ++ _ -> @@ -502,15 +495,15 @@ init_per_testcase2(Case, Config) -> NewConfig end, - io:format(user, "~w:init_per_testcase2(~w) -> done~n", - [?MODULE, Case]), + tsp("init_per_testcase2(~w) -> done when" + "~n NewConfig2: ~p", [Case, NewConfig2]), NewConfig2. init_per_testcase3(Case, Config) -> - io:format(user, "~w:init_per_testcase3(~w) -> entry with" - "~n Config: ~p", [?MODULE, Case, Config]), + tsp("init_per_testcase3(~w) -> entry with" + "~n Config: ~p", [Case, Config]), %% %% Create a new fresh node to be used by the server in this test-case @@ -532,12 +525,10 @@ init_per_testcase3(Case, Config) -> %% Set trace level case lists:reverse(atom_to_list(Case)) of "tset_emit" ++ _Rest -> % test-cases ending with time_test - io:format(user, "~w:init_per_testcase3(~w) -> disabling trace", - [?MODULE, Case]), + tsp("init_per_testcase3(~w) -> disabling trace", [Case]), inets:disable_trace(); _ -> - io:format(user, "~w:init_per_testcase3(~w) -> enabling trace", - [?MODULE, Case]), + tsp("init_per_testcase3(~w) -> enabling trace", [Case]), %% TraceLevel = 70, TraceLevel = max, TraceDest = io, @@ -545,8 +536,7 @@ init_per_testcase3(Case, Config) -> end, %% Start initialization - io:format(user, "~w:init_per_testcase3(~w) -> start init", - [?MODULE, Case]), + tsp("init_per_testcase3(~w) -> start init", [Case]), Dog = test_server:timetrap(inets_test_lib:minutes(10)), @@ -627,26 +617,32 @@ init_per_testcase3(Case, Config) -> end end, - case CaseRest of - {skip, _} = Skip -> - Skip; - "mod_auth_" ++ _ -> - start_mnesia(?config(node, Config)), - [{watchdog, Dog} | NewConfig]; - "mod_htaccess" -> - ServerRoot = ?config(server_root, Config), - Path = filename:join([ServerRoot, "htdocs"]), - catch remove_htaccess(Path), - create_htaccess_data(Path, ?config(address, Config)), - [{watchdog, Dog} | NewConfig]; - "range" -> - ServerRoot = ?config(server_root, Config), - Path = filename:join([ServerRoot, "htdocs"]), - create_range_data(Path), - [{watchdog, Dog} | NewConfig]; - _ -> - [{watchdog, Dog} | NewConfig] - end. + InitRes = + case CaseRest of + {skip, _} = Skip -> + Skip; + "mod_auth_" ++ _ -> + start_mnesia(?config(node, Config)), + [{watchdog, Dog} | NewConfig]; + "mod_htaccess" -> + ServerRoot = ?config(server_root, Config), + Path = filename:join([ServerRoot, "htdocs"]), + catch remove_htaccess(Path), + create_htaccess_data(Path, ?config(address, Config)), + [{watchdog, Dog} | NewConfig]; + "range" -> + ServerRoot = ?config(server_root, Config), + Path = filename:join([ServerRoot, "htdocs"]), + create_range_data(Path), + [{watchdog, Dog} | NewConfig]; + _ -> + [{watchdog, Dog} | NewConfig] + end, + + tsp("init_per_testcase3(~w) -> done when" + "~n InitRes: ~p", [Case, InitRes]), + + InitRes. %%-------------------------------------------------------------------- @@ -664,16 +660,14 @@ end_per_testcase(Case, Config) -> ok. end_per_testcase2(Case, Config) -> - io:format(user, "~w:end_per_testcase2(~w) -> entry with" - "~n Config: ~p~n", - [?MODULE, Case, Config]), + tsp("end_per_testcase2(~w) -> entry with" + "~n Config: ~p", [Case, Config]), application:unset_env(inets, services), application:stop(inets), application:stop(ssl), application:stop(crypto), % used by the new ssl (essl test cases) cleanup_mnesia(), - io:format(user, "~w:end_per_testcase2(~w) -> done~n", - [?MODULE, Case]), + tsp("end_per_testcase2(~w) -> done", [Case]), ok. diff --git a/lib/inets/test/httpd_basic_SUITE.erl b/lib/inets/test/httpd_basic_SUITE.erl index 4cd38f2ec4..be0bcc67d5 100644 --- a/lib/inets/test/httpd_basic_SUITE.erl +++ b/lib/inets/test/httpd_basic_SUITE.erl @@ -202,8 +202,8 @@ escaped_url_in_error_body(Config) when is_list(Config) -> {ok, {200, _}} -> %% Don't care about the the body, just that we get a ok response ok; - {ok, UnexpectedOK1} -> - tsf({unexpected_ok_1, UnexpectedOK1}) + {ok, {StatusCode1, Body1}} -> + tsf({unexpected_ok_1, StatusCode1, Body1}) end, %% Request 2 @@ -216,8 +216,8 @@ escaped_url_in_error_body(Config) when is_list(Config) -> {ok, {200, _}} -> %% Don't care about the the body, just that we get a ok response ok; - {ok, UnexpectedOK2} -> - tsf({unexpected_ok_2, UnexpectedOK2}) + {ok, {StatusCode2, Body2}} -> + tsf({unexpected_ok_2, StatusCode2, Body2}) end, %% Request 3 @@ -238,7 +238,7 @@ escaped_url_in_error_body(Config) when is_list(Config) -> tsf({unexpected_path_3, HTMLEncodedPath, BadPath3}) end; {ok, UnexpectedOK3} -> - tsf({unexpected_ok_1, UnexpectedOK3}) + tsf({unexpected_ok_3, UnexpectedOK3}) end, %% Request 4 @@ -253,7 +253,7 @@ escaped_url_in_error_body(Config) when is_list(Config) -> HTMLEncodedPath -> ok; BadPath4 -> - tsf({unexpected_path_2, HTMLEncodedPath, BadPath4}) + tsf({unexpected_path_4, HTMLEncodedPath, BadPath4}) end; {ok, UnexpectedOK4} -> tsf({unexpected_ok_4, UnexpectedOK4}) diff --git a/lib/inets/test/httpd_mod.erl b/lib/inets/test/httpd_mod.erl index 5016cdb9e6..25a03ab9c8 100644 --- a/lib/inets/test/httpd_mod.erl +++ b/lib/inets/test/httpd_mod.erl @@ -39,14 +39,24 @@ %% Test cases starts here. %%------------------------------------------------------------------------- alias(Type, Port, Host, Node) -> -%% io:format(user, "~w:alias -> entry with" + %% io:format(user, "~w:alias -> entry with" %% "~n Type: ~p" %% "~n Port: ~p" %% "~n Host: ~p" %% "~n Node: ~p" %% "~n", [?MODULE, Type, Port, Host, Node]), - - ok = httpd_test_lib:verify_request(Type, Host, Port, Node, + + %% This is very crude, but... + tsp("alias -> Has IPv6 support: ~p", [inets_test_lib:has_ipv6_support()]), + Opts = case os:type() of + {win32, _} -> + [inet6fb4]; + _ -> + [] + end, + tsp("alias -> Opts: ~p", [Opts]), + + ok = httpd_test_lib:verify_request(Type, Host, Port, Opts, Node, "GET /pics/icon.sheet.gif " "HTTP/1.0\r\n\r\n", [{statuscode, 200}, @@ -55,7 +65,7 @@ alias(Type, Port, Host, Node) -> {header, "Date"}, {version, "HTTP/1.0"}]), - ok = httpd_test_lib:verify_request(Type, Host, Port, Node, + ok = httpd_test_lib:verify_request(Type, Host, Port, Opts, Node, "GET / HTTP/1.0\r\n\r\n", [{statuscode, 200}, {header, "Content-Type","text/html"}, @@ -63,7 +73,7 @@ alias(Type, Port, Host, Node) -> {header, "Date"}, {version, "HTTP/1.0"}]), - ok = httpd_test_lib:verify_request(Type,Host,Port,Node, + ok = httpd_test_lib:verify_request(Type, Host, Port, Opts, Node, "GET /misc/ HTTP/1.0\r\n\r\n", [{statuscode, 200}, {header, "Content-Type","text/html"}, @@ -71,8 +81,8 @@ alias(Type, Port, Host, Node) -> {header, "Date"}, {version, "HTTP/1.0"}]), - %% Check redirection if trailing slash is missing. - ok = httpd_test_lib:verify_request(Type,Host,Port,Node, + %% Check redirection if trailing slash is missing. + ok = httpd_test_lib:verify_request(Type, Host, Port, Opts, Node, "GET /misc HTTP/1.0\r\n\r\n", [{statuscode, 301}, {header, "Location"}, @@ -1032,9 +1042,10 @@ check_lists_members1(L1,L2) -> %% tsp(F) -> -%% tsp(F, []). -%% tsp(F, A) -> -%% test_server:format("~p ~p:" ++ F ++ "~n", [self(), ?MODULE | A]). +%% inets_test_lib:tsp(F). +tsp(F, A) -> + inets_test_lib:tsp(F, A). + tsf(Reason) -> test_server:fail(Reason). diff --git a/lib/inets/test/httpd_test_lib.erl b/lib/inets/test/httpd_test_lib.erl index 2f5867559a..ed6ee315b3 100644 --- a/lib/inets/test/httpd_test_lib.erl +++ b/lib/inets/test/httpd_test_lib.erl @@ -79,19 +79,19 @@ %%-------------------------------------------------------------------- %% API %%------------------------------------------------------------------ + verify_request(SocketType, Host, Port, Node, RequestStr, Options) -> - verify_request(SocketType, Host, Port, Node, RequestStr, - Options, 30000). + verify_request(SocketType, Host, Port, Node, RequestStr, Options, 30000). + verify_request(SocketType, Host, Port, TranspOpts, Node, RequestStr, Options) when is_list(TranspOpts) -> - verify_request(SocketType, Host, Port, TranspOpts, Node, RequestStr, - Options, 30000); + verify_request(SocketType, Host, Port, TranspOpts, Node, RequestStr, Options, 30000); + 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, TranspOpts, Node, RequestStr, - Options, TimeOut) -> + verify_request(SocketType, Host, Port, [], Node, RequestStr, Options, TimeOut). + +verify_request(SocketType, Host, Port, TranspOpts, Node, RequestStr, Options, TimeOut) -> tsp("verify_request -> entry with" "~n SocketType: ~p" "~n Host: ~p" @@ -117,15 +117,15 @@ verify_request(SocketType, Host, Port, TranspOpts, Node, RequestStr, case request(State#state{request = RequestStr, socket = Socket}, TimeOut) of {error, Reason} -> - tsp("request failed: " + tsp("verify_request -> request failed: " "~n Reason: ~p", [Reason]), {error, Reason}; NewState -> - tsp("validate reply: " + tsp("verify_request -> validate reply: " "~n NewState: ~p", [NewState]), ValidateResult = validate(RequestStr, NewState, Options, Node, Port), - tsp("validation result: " + tsp("verify_request -> validation result: " "~n ~p", [ValidateResult]), inets_test_lib:close(SocketType, Socket), ValidateResult diff --git a/lib/inets/test/inets_test_lib.erl b/lib/inets/test/inets_test_lib.erl index bbed35e1f8..b03127691d 100644 --- a/lib/inets/test/inets_test_lib.erl +++ b/lib/inets/test/inets_test_lib.erl @@ -34,39 +34,45 @@ -export([tsp/1, tsp/2, tsf/1]). -export([check_body/1]). -export([millis/0, millis_diff/2, hours/1, minutes/1, seconds/1, sleep/1]). --export([oscmd/1, has_ipv6_support/1]). +-export([oscmd/1, has_ipv6_support/0, has_ipv6_support/1, print_system_info/1]). +-export([run_on_os/2, run_on_windows/1]). -export([ensure_started/1]). -export([non_pc_tc_maybe_skip/4, os_based_skip/1, skip/3, fail/3]). -export([flush/0]). -export([start_node/1, stop_node/1]). + %% -- Misc os command and stuff +has_ipv6_support() -> + tsp("has_ipv6_support -> no ipv6_hosts config"), + {ok, Hostname} = inet:gethostname(), + case inet:getaddrs(Hostname, inet6) of + {ok, [Addr|_]} when is_tuple(Addr) andalso + (element(1, Addr) =/= 0) -> + %% We actually need to test that the addr can be used, + %% this is done by attempting to create a (tcp) + %% listen socket + tsp("has_ipv6_support -> check Addr: ~p", [Addr]), + case (catch gen_tcp:listen(0, [inet6, {ip, Addr}])) of + {ok, LSock} -> + tsp("has_ipv6_support -> we are ipv6 host"), + gen_tcp:close(LSock), + {ok, Addr}; + _ -> + undefined + end; + _ -> + undefined + end. + has_ipv6_support(Config) -> case lists:keysearch(ipv6_hosts, 1, Config) of false -> %% Do a basic check to se if %% our own host has a working IPv6 address... - tsp("has_ipv6_support -> no ipv6_hosts config"), - {ok, Hostname} = inet:gethostname(), - case inet:getaddrs(Hostname, inet6) of - {ok, [Addr|_]} when is_tuple(Addr) andalso - (element(1, Addr) =/= 0) -> - %% We actually need to test that the addr can be used, - %% this is done by attempting to create a (tcp) - %% listen socket - tsp("has_ipv6_support -> check Addr: ~p", [Addr]), - case (catch gen_tcp:listen(0, [inet6, {ip, Addr}])) of - {ok, LSock} -> - tsp("has_ipv6_support -> we are ipv6 host"), - gen_tcp:close(LSock), - {ok, Addr}; - _ -> - undefined - end; - _ -> - undefined - end; + has_ipv6_support(); + {value, {_, Hosts}} when is_list(Hosts) -> %% Check if our host is in the list of *known* IPv6 hosts tsp("has_ipv6_support -> Hosts: ~p", [Hosts]), @@ -88,6 +94,49 @@ has_ipv6_support(Config) -> oscmd(Cmd) -> string:strip(os:cmd(Cmd), right, $\n). + +print_system_info([]) -> + do_print_system_info("System Info"); +print_system_info(Prefix) when is_list(Prefix) -> + NewPrefix = lists:flatten(io_lib:format("~s: System Info", [Prefix])), + do_print_system_info(NewPrefix). + +do_print_system_info(Prefix) -> + tsp("~s => " + "~n" + "~n OS Type: ~p" + "~n OS version: ~p" + "~n Sys Arch: ~p" + "~n CPU Topology: ~p" + "~n Num logical procs: ~p" + "~n SMP support: ~p" + "~n Num schedulers: ~p" + "~n Scheduler bindings: ~p" + "~n Wordsize: ~p" + "~n~n", [Prefix, + os:type(), os:version(), + erlang:system_info(system_architecture), + erlang:system_info(cpu_topology), + erlang:system_info(logical_processors), + erlang:system_info(smp_support), + erlang:system_info(schedulers), + erlang:system_info(scheduler_bindings), + erlang:system_info(wordsize)]), + ok. + + +run_on_windows(Fun) -> + run_on_os(windows, Fun). + +run_on_os(windows, Fun) -> + case os:type() of + {win32, _} -> + Fun(); + _ -> + ok + end. + + %% -- Misc node operation wrapper functions -- start_node(Name) -> @@ -257,20 +306,49 @@ copy_files(FromDir, ToDir) -> copy_dirs(FromDirRoot, ToDirRoot) -> - {ok, Files} = file:list_dir(FromDirRoot), - lists:foreach( - fun(FileOrDir) -> - %% Check if it's a directory or a file - case filelib:is_dir(filename:join(FromDirRoot, FileOrDir)) of - true -> - FromDir = filename:join([FromDirRoot, FileOrDir]), - ToDir = filename:join([ToDirRoot, FileOrDir]), - ok = file:make_dir(ToDir), - copy_dirs(FromDir, ToDir); - false -> - copy_file(FileOrDir, FromDirRoot, ToDirRoot) - end - end, Files). + case file:list_dir(FromDirRoot) of + {ok, Files} -> + lists:foreach( + fun(FileOrDir) -> + %% Check if it's a directory or a file + case filelib:is_dir(filename:join(FromDirRoot, + FileOrDir)) of + true -> + FromDir = filename:join([FromDirRoot, FileOrDir]), + ToDir = filename:join([ToDirRoot, FileOrDir]), + case file:make_dir(ToDir) of + ok -> + copy_dirs(FromDir, ToDir); + {error, Reason} -> + tsp("<ERROR> Failed creating directory: " + "~n ToDir: ~p" + "~n Reason: ~p" + "~nwhen" + "~n ToDirRoot: ~p" + "~n ToDirRoot file info: ~p", + [ToDir, + Reason, + ToDirRoot, + file:read_file_info(ToDirRoot)]), + tsf({failed_copy_dir, ToDir, Reason}) + end; + false -> + copy_file(FileOrDir, FromDirRoot, ToDirRoot) + end + end, Files); + {error, Reason} -> + tsp("<ERROR> Failed get directory file list: " + "~n FromDirRoot: ~p" + "~n Reason: ~p" + "~nwhen" + "~n FromDirRoot file info: ~p", + [FromDirRoot, + Reason, + file:read_file_info(FromDirRoot)]), + tsf({failed_list_dir, FromDirRoot, Reason}) + end. + + del_dirs(Dir) -> case file:list_dir(Dir) of @@ -414,36 +492,64 @@ connect(ip_comm, Host, Port, Opts) -> "~n Host: ~p" "~n Port: ~p" "~n Opts: ~p", [Host, Port, Opts]), - case gen_tcp:connect(Host,Port, Opts) of - {ok, Socket} -> - tsp("connect success"), - {ok, Socket}; - {error, nxdomain} -> - tsp("connect error nxdomain when opts: ~p", [Opts]), - connect(ip_comm, Host, Port, lists:delete(inet6, Opts)); - {error, eafnosupport} -> - tsp("connect error eafnosupport when opts: ~p", [Opts]), - connect(ip_comm, Host, Port, lists:delete(inet6, Opts)); - {error, econnreset} -> - tsp("connect error econnreset when opts: ~p", [Opts]), - connect(ip_comm, Host, Port, lists:delete(inet6, Opts)); - {error, enetunreach} -> - tsp("connect error eafnosupport when opts: ~p", [Opts]), - connect(ip_comm, Host, Port, lists:delete(inet6, Opts)); - {error, {enfile,_}} -> - tsp("connect error enfile when opts: ~p", [Opts]), - {error, enfile}; - Error -> - tsp("Unexpected error: " - "~n Error: ~p" - "~nwhen" - "~n Host: ~p" - "~n Port: ~p" - "~n Opts: ~p" - "~n", [Error, Host, Port, Opts]), - Error - end. + + %% We check for precence of inet6fb4. + %% If found, we shall try inet6 and if that does not work + %% try inet (regardless of error reason) + case lists:delete(inet6fb4, Opts) of + Opts -> + %% Nope, run as usual, where we use error reason + %% to detect if we are on IPv6 or not... + case gen_tcp:connect(Host,Port, Opts) of + {ok, Socket} -> + tsp("connect success"), + {ok, Socket}; + {error, nxdomain} -> + tsp("connect error nxdomain when opts: ~p", [Opts]), + connect(ip_comm, Host, Port, lists:delete(inet6, Opts)); + {error, eafnosupport} -> + tsp("connect error eafnosupport when opts: ~p", [Opts]), + connect(ip_comm, Host, Port, lists:delete(inet6, Opts)); + {error, econnreset} -> + tsp("connect error econnreset when opts: ~p", [Opts]), + connect(ip_comm, Host, Port, lists:delete(inet6, Opts)); + {error, enetunreach} -> + tsp("connect error eafnosupport when opts: ~p", [Opts]), + connect(ip_comm, Host, Port, lists:delete(inet6, Opts)); + {error, {enfile,_}} -> + tsp("connect error enfile when opts: ~p", [Opts]), + {error, enfile}; + Error -> + tsp("connect(ip_conn) -> Unexpected error: " + "~n Error: ~p" + "~nwhen" + "~n Host: ~p" + "~n Port: ~p" + "~n Opts: ~p" + "~n", [Error, Host, Port, Opts]), + Error + end; + Opts2 -> + %% Yep, so try first with inet6 and if that fails inet + case gen_tcp:connect(Host, Port, [inet6|Opts2]) of + {ok, Socket} -> + tsp("connect success"), + {ok, Socket}; + {error, Reason_inet6} -> + tsp("inet6 connect failed: ~p", [Reason_inet6]), + case gen_tcp:connect(Host, Port, [inet|Opts2]) of + {ok, Socket} -> + tsp("connect success"), + {ok, Socket}; + {error, Reason_inet} -> + tsp("inet connect also failed: ~p", [Reason_inet]), + {error, {connect_failure, [{inet6, Reason_inet6}, + {inet, Reason_inet}]}} + end + end + end. + send(ssl, Socket, Data) -> ssl:send(Socket, Data); diff --git a/lib/inets/test/inets_test_lib.hrl b/lib/inets/test/inets_test_lib.hrl index c578398c55..6a86b1b764 100644 --- a/lib/inets/test/inets_test_lib.hrl +++ b/lib/inets/test/inets_test_lib.hrl @@ -50,6 +50,11 @@ -define(OSCMD(Cmd), inets_test_lib:oscmd(Cmd)). +-define(PRINT_SYSTEM_INFO(P), inets_test_lib:print_system_info(P)). + +-define(RUN_ON_OS(OS, FUN), inets_test_lib:run_on_os(OS, FUN)). +-define(RUN_ON_WINDOWS(FUN), inets_test_lib:run_on_windows(FUN)). + %% - Test case macros - diff --git a/lib/snmp/doc/src/notes.xml b/lib/snmp/doc/src/notes.xml index 942d943c3c..704ff0a20f 100644 --- a/lib/snmp/doc/src/notes.xml +++ b/lib/snmp/doc/src/notes.xml @@ -34,6 +34,64 @@ <section> + <title>SNMP Development Toolkit 4.21.7</title> + <p>Version 4.21.7 supports code replacement in runtime from/to + version 4.21.6, 4.21.5, 4.21.4, 4.21.3, 4.21.2, 4.21.1, 4.21, 4.20.1 and + 4.20. </p> + + <section> + <title>Improvements and new features</title> + <p>-</p> + + <!-- + <list type="bulleted"> + <item> + <p>[agent] DoS attack using GET-BULK with large value of + MaxRepetitions. + A preventive method has been implementing by simply + limit the number of varbinds that can be included in + a Get-BULK response message. This is specified by the + new config option, + <seealso marker="snmp_app#agent_gb_max_vbs">gb_max_vbs</seealso>. + </p> + <p>Own Id: OTP-9700</p> + </item> + + </list> + --> + + </section> + + <section> + <title>Reported Fixed Bugs and Malfunctions</title> + <!-- + <p>-</p> + --> + + <list type="bulleted"> + <item> + <p>[agent] Simultaneous + <seealso marker="snmpa#backup">snmpa:backup/1,2</seealso> + calls can interfere. + The master agent did not check if a backup was already in + progress when a backup request was accepted. </p> + <p>Own Id: OTP-9884</p> + <p>Aux Id: Seq 11995</p> + </item> + + </list> + + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + </section> + + </section> <!-- 4.21.7 --> + + + <section> <title>SNMP Development Toolkit 4.21.6</title> <p>Version 4.21.6 supports code replacement in runtime from/to version 4.21.5, 4.21.4, 4.21.3, 4.21.2, 4.21.1, 4.21, 4.20.1 and diff --git a/lib/snmp/doc/src/snmpa.xml b/lib/snmp/doc/src/snmpa.xml index 27d89ea4e3..2322af28cc 100644 --- a/lib/snmp/doc/src/snmpa.xml +++ b/lib/snmp/doc/src/snmpa.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>2004</year><year>2011</year> + <year>2004</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -198,12 +198,18 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} <type> <v>BackupDir = string()</v> <v>Agent = pid() | atom()</v> + <v>Reason = backup_in_progress | term()</v> </type> <desc> <p>Backup persistent/permanent data handled by the agent (such as local-db, mib-data and vacm). </p> <p>Data stored by mnesia is not handled. </p> <p>BackupDir cannot be identical to DbDir. </p> + <p>Simultaneous backup calls are <em>not</em> allowed. + That is, two different processes cannot simultaneously + successfully call this function. One of them will be first, + and succeed. The second will fail with the error reason + <c>backup_in_progress</c>. </p> <marker id="info"></marker> </desc> @@ -217,13 +223,13 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} </type> <desc> <p>Returns a list (a dictionary) containing information about - the agent. Information includes loaded MIBs, registered - sub-agents, some information about the memory allocation. </p> - <p>As of version 4.4 the format of the info has been changed. - To convert the info to the old format, call the - <seealso marker="#old_info_format">old_info_format</seealso> - function. </p> - + the agent. Information includes loaded MIBs, registered + sub-agents, some information about the memory allocation. </p> + <p>As of version 4.4 the format of the info has been changed. + To convert the info to the old format, call the + <seealso marker="#old_info_format">old_info_format</seealso> + function. </p> + <marker id="old_info_format"></marker> </desc> </func> diff --git a/lib/snmp/src/agent/snmpa_agent.erl b/lib/snmp/src/agent/snmpa_agent.erl index 17cb9c9fe3..9cc986cf47 100644 --- a/lib/snmp/src/agent/snmpa_agent.erl +++ b/lib/snmp/src/agent/snmpa_agent.erl @@ -1262,7 +1262,8 @@ handle_call(info, _From, S) -> handle_call(get_net_if, _From, S) -> {reply, get(net_if), S}; -handle_call({backup, BackupDir}, From, S) -> +%% Only accept a backup request if there is none already in progress +handle_call({backup, BackupDir}, From, #state{backup = undefined} = S) -> ?vlog("backup: ~p", [BackupDir]), Pid = self(), V = get(verbosity), @@ -1279,7 +1280,11 @@ handle_call({backup, BackupDir}, From, S) -> end), ?vtrace("backup server: ~p", [BackupServer]), {noreply, S#state{backup = {BackupServer, From}}}; - + +handle_call({backup, _BackupDir}, From, #state{backup = Backup} = S) -> + ?vinfo("backup already in progress: ~p", [Backup]), + {reply, {error, backup_in_progress}, S}; + handle_call(dump_mibs, _From, S) -> Reply = snmpa_mib:dump(get(mibserver)), {reply, Reply, S}; diff --git a/lib/snmp/src/agent/snmpa_local_db.erl b/lib/snmp/src/agent/snmpa_local_db.erl index 5b04c70054..1ec8dd3874 100644 --- a/lib/snmp/src/agent/snmpa_local_db.erl +++ b/lib/snmp/src/agent/snmpa_local_db.erl @@ -486,7 +486,11 @@ handle_call({match, Name, Db, Pattern}, _From, State) -> L1 = match(Db, Name, Pattern, State), {reply, lists:delete([undef], L1), State}; -handle_call({backup, BackupDir}, From, #state{dets = Dets} = State) -> +%% This check (that there is no backup already in progress) is also +%% done in the master agent process, but just in case a user issues +%% a backup call to this process directly, we add a similar check here. +handle_call({backup, BackupDir}, From, + #state{backup = undefined, dets = Dets} = State) -> ?vlog("backup: ~p",[BackupDir]), Pid = self(), V = get(verbosity), @@ -511,6 +515,10 @@ handle_call({backup, BackupDir}, From, #state{dets = Dets} = State) -> {reply, Error, State} end; +handle_call({backup, _BackupDir}, From, #state{backup = Backup} = S) -> + ?vinfo("backup already in progress: ~p", [Backup]), + {reply, {error, backup_in_progress}, S}; + handle_call(dump, _From, #state{dets = Dets} = State) -> ?vlog("dump",[]), dets_sync(Dets), diff --git a/lib/snmp/src/agent/snmpa_mib.erl b/lib/snmp/src/agent/snmpa_mib.erl index ce90db18b3..574467d38f 100644 --- a/lib/snmp/src/agent/snmpa_mib.erl +++ b/lib/snmp/src/agent/snmpa_mib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% Copyright Ericsson AB 1996-2012. 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 @@ -552,8 +552,12 @@ handle_call({dump, File}, _From, #state{data = Data} = State) -> Reply = snmpa_mib_data:dump(Data, File), {reply, Reply, State}; -handle_call({backup, BackupDir}, From, #state{data = Data} = State) -> - ?vlog("backup to ~s",[BackupDir]), +%% This check (that there is no backup already in progress) is also +%% done in the master agent process, but just in case a user issues +%% a backup call to this process directly, we add a similar check here. +handle_call({backup, BackupDir}, From, + #state{backup = undefined, data = Data} = State) -> + ?vlog("backup to ~s", [BackupDir]), Pid = self(), V = get(verbosity), case file:read_file_info(BackupDir) of @@ -576,6 +580,10 @@ handle_call({backup, BackupDir}, From, #state{data = Data} = State) -> {reply, Error, State} end; +handle_call({backup, _BackupDir}, From, #state{backup = Backup} = S) -> + ?vinfo("backup already in progress: ~p", [Backup]), + {reply, {error, backup_in_progress}, S}; + handle_call(stop, _From, State) -> ?vlog("stop",[]), {stop, normal, ok, State}; diff --git a/lib/snmp/src/agent/snmpa_mpd.erl b/lib/snmp/src/agent/snmpa_mpd.erl index 0305e1fbec..2d37ea56f0 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-2011. All Rights Reserved. +%% Copyright Ericsson AB 1997-2012. 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 diff --git a/lib/snmp/src/app/snmp.appup.src b/lib/snmp/src/app/snmp.appup.src index 254e697039..c8e5eec6db 100644 --- a/lib/snmp/src/app/snmp.appup.src +++ b/lib/snmp/src/app/snmp.appup.src @@ -22,15 +22,24 @@ %% ----- U p g r a d e ------------------------------------------------------- [ + {"4.21.6", + [ + {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, + {update, snmpa_mib, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []} + ] + }, {"4.21.5", [ {load_module, snmpa, soft_purge, soft_purge, []}, - {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]}, - {load_module, snmpa_mib_lib, soft_purge, soft_purge, []}, - {load_module, snmpa_trap, soft_purge, soft_purge, []}, - {load_module, snmpa_vacm, soft_purge, soft_purge, []}, + {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]}, + {load_module, snmpa_mib_lib, soft_purge, soft_purge, []}, + {load_module, snmpa_trap, soft_purge, soft_purge, []}, + {load_module, snmpa_vacm, soft_purge, soft_purge, []}, + {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, + {update, snmpa_mib, soft, soft_purge, soft_purge, []}, {update, snmpa_supervisor, soft, soft_purge, soft_purge, []}, - {update, snmpa_agent, soft, soft_purge, soft_purge, []} + {update, snmpa_agent, soft, soft_purge, soft_purge, []} ] }, {"4.21.4", @@ -44,7 +53,9 @@ {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []}, {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []}, {load_module, snmpa_vacm, soft_purge, soft_purge, []}, - {update, snmpa_agent, soft, soft_purge, soft_purge, []} + {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, + {update, snmpa_mib, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []} ] }, {"4.21.3", @@ -59,7 +70,8 @@ {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []}, {load_module, snmpa_vacm, soft_purge, soft_purge, []}, {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, - {update, snmpa_agent, soft, soft_purge, soft_purge, []} + {update, snmpa_mib, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []} ] }, {"4.21.2", @@ -76,7 +88,8 @@ {load_module, snmpa_trap, soft_purge, soft_purge, []}, {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []}, {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, - {update, snmpa_agent, soft, soft_purge, soft_purge, []} + {update, snmpa_mib, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []} ] }, {"4.21.1", @@ -92,8 +105,9 @@ {load_module, snmpa_set_lib, soft_purge, soft_purge, []}, {load_module, snmpa_trap, soft_purge, soft_purge, []}, {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []}, - {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, - {update, snmpa_agent, soft, soft_purge, soft_purge, []}, + {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, + {update, snmpa_mib, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []}, {update, snmp_note_store, soft, soft_purge, soft_purge, []} ] }, @@ -110,8 +124,9 @@ {load_module, snmpa_trap, soft_purge, soft_purge, []}, {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]}, {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []}, - {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, - {update, snmpa_agent, soft, soft_purge, soft_purge, []}, + {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, + {update, snmpa_mib, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []}, {update, snmp_note_store, soft, soft_purge, soft_purge, []} ] }, @@ -138,7 +153,8 @@ {update, snmp_note_store, soft, soft_purge, soft_purge, []}, {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []}, {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, - {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]}, + {update, snmpa_mib, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]}, {update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]}, {update, snmpm_server, soft, soft_purge, soft_purge, [snmpm_net_if, snmpm_mpd, snmpm_config]}, @@ -170,6 +186,7 @@ {update, snmp_note_store, soft, soft_purge, soft_purge, []}, {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []}, {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, + {update, snmpa_mib, soft, soft_purge, soft_purge, []}, {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]}, {update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]}, {update, snmpm_server, soft, soft_purge, soft_purge, @@ -183,15 +200,24 @@ %% ------D o w n g r a d e --------------------------------------------------- [ + {"4.21.6", + [ + {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, + {update, snmpa_mib, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []} + ] + }, {"4.21.5", [ {load_module, snmpa, soft_purge, soft_purge, []}, - {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]}, - {load_module, snmpa_mib_lib, soft_purge, soft_purge, []}, - {load_module, snmpa_trap, soft_purge, soft_purge, []}, - {load_module, snmpa_vacm, soft_purge, soft_purge, []}, + {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]}, + {load_module, snmpa_mib_lib, soft_purge, soft_purge, []}, + {load_module, snmpa_trap, soft_purge, soft_purge, []}, + {load_module, snmpa_vacm, soft_purge, soft_purge, []}, {update, snmpa_supervisor, soft, soft_purge, soft_purge, []}, - {update, snmpa_agent, soft, soft_purge, soft_purge, []} + {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, + {update, snmpa_mib, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []} ] }, {"4.21.4", @@ -205,7 +231,9 @@ {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []}, {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []}, {load_module, snmpa_vacm, soft_purge, soft_purge, []}, - {update, snmpa_agent, soft, soft_purge, soft_purge, []} + {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, + {update, snmpa_mib, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []} ] }, {"4.21.3", @@ -220,7 +248,8 @@ {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []}, {load_module, snmpa_vacm, soft_purge, soft_purge, []}, {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, - {update, snmpa_agent, soft, soft_purge, soft_purge, []} + {update, snmpa_mib, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []} ] }, {"4.21.2", @@ -237,7 +266,8 @@ {load_module, snmpa_trap, soft_purge, soft_purge, []}, {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []}, {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, - {update, snmpa_agent, soft, soft_purge, soft_purge, []} + {update, snmpa_mib, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []} ] }, {"4.21.1", @@ -253,8 +283,9 @@ {load_module, snmpa_set_lib, soft_purge, soft_purge, []}, {load_module, snmpa_trap, soft_purge, soft_purge, []}, {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []}, - {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, - {update, snmpa_agent, soft, soft_purge, soft_purge, []}, + {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, + {update, snmpa_mib, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []}, {update, snmp_note_store, soft, soft_purge, soft_purge, []} ] }, @@ -271,8 +302,9 @@ {load_module, snmpa_trap, soft_purge, soft_purge, []}, {load_module, snmp_target_mib, soft_purge, soft_purge, []}, {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []}, - {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, - {update, snmpa_agent, soft, soft_purge, soft_purge, []}, + {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, + {update, snmpa_mib, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []}, {update, snmp_note_store, soft, soft_purge, soft_purge, []} ] }, @@ -299,7 +331,8 @@ {update, snmp_note_store, soft, soft_purge, soft_purge, []}, {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []}, {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, - {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]}, + {update, snmpa_mib, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]}, {update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]}, {update, snmpm_server, soft, soft_purge, soft_purge, [snmpm_net_if, snmpm_mpd, snmpm_config]}, @@ -330,7 +363,8 @@ {update, snmp_note_store, soft, soft_purge, soft_purge, []}, {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []}, {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, - {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]}, + {update, snmpa_mib, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]}, {update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]}, {update, snmpm_server, soft, soft_purge, soft_purge, [snmpm_net_if, snmpm_mpd, snmpm_config]}, diff --git a/lib/snmp/test/snmp_agent_test.erl b/lib/snmp/test/snmp_agent_test.erl index abfd528639..e968bc65b1 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-2011. All Rights Reserved. +%% Copyright Ericsson AB 2003-2012. 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 @@ -222,7 +222,7 @@ groups() -> {group, otp_7157} ] }, - {tickets2, [], [otp8395]}, + {tickets2, [], [otp8395, otp9884]}, {otp_4394, [], [otp_4394_test]}, {otp_7157, [], [otp_7157_test] } @@ -322,6 +322,12 @@ init_per_testcase(otp8395 = Case, Config) when is_list(Config) -> "~n Config: ~p", [Case, Config]), Config2 = init_per_testcase2(Case, init_per_suite(Config)), otp8395({init, Config2}); +init_per_testcase(otp9884 = Case, Config) when is_list(Config) -> + ?DBG("init_per_testcase -> entry with" + "~n Case: ~p" + "~n Config: ~p", [Case, Config]), + Config2 = init_per_testcase2(Case, init_per_suite(Config)), + otp9884({init, Config2}); init_per_testcase(otp_7157_test = _Case, Config) when is_list(Config) -> ?DBG("init_per_testcase -> entry with" "~n Case: ~p" @@ -349,6 +355,8 @@ init_per_testcase(_Case, Config) when is_list(Config) -> end_per_testcase(otp8395, Config) when is_list(Config) -> otp8395({fin, Config}); +end_per_testcase(otp9884, Config) when is_list(Config) -> + otp9884({fin, Config}); end_per_testcase(_Case, Config) when is_list(Config) -> ?DBG("end_per_testcase -> entry with" "~n Case: ~p" @@ -5238,16 +5246,6 @@ loop_it_2(Oid, N) -> %%%----------------------------------------------------------------- - - - -%% These are (ticket) test cases where the initiation has to be done -%% individually. - - - - - %%----------------------------------------------------------------- %% Ticket: OTP-1128 %% Slogan: Bug in handling of createAndWait set-requests. @@ -5888,7 +5886,7 @@ otp_7157_test1(MA) -> otp8395({init, Config}) when is_list(Config) -> ?DBG("otp8395(init) -> entry with" "~n Config: ~p", [Config]), - + %% -- %% Start nodes %% @@ -5896,7 +5894,7 @@ otp8395({init, Config}) when is_list(Config) -> {ok, AgentNode} = start_node(agent), %% {ok, SubAgentNode} = start_node(sub_agent), {ok, ManagerNode} = start_node(manager), - + %% -- %% Mnesia init %% @@ -5904,10 +5902,10 @@ otp8395({init, Config}) when is_list(Config) -> AgentDbDir = ?config(agent_db_dir, Config), AgentMnesiaDir = filename:join([AgentDbDir, "mnesia"]), mnesia_init(AgentNode, AgentMnesiaDir), - -%% SubAgentDir = ?config(sub_agent_dir, Config), -%% SubAgentMnesiaDir = filename:join([SubAgentDir, "mnesia"]), -%% mnesia_init(SubAgentNode, SubAgentMnesiaDir), + + %% SubAgentDir = ?config(sub_agent_dir, Config), + %% SubAgentMnesiaDir = filename:join([SubAgentDir, "mnesia"]), + %% mnesia_init(SubAgentNode, SubAgentMnesiaDir), %% ok = mnesia_create_schema(AgentNode, [AgentNode, SubAgentNode]), %% ok = mnesia:create_schema([AgentNode, SubAgentNode]), @@ -5932,12 +5930,12 @@ otp8395({init, Config}) when is_list(Config) -> %% SubAgentIP = tuple_to_list(SubAgentIP0), {ok, ManagerIP0} = snmp_misc:ip(ManagerHost), ManagerIP = tuple_to_list(ManagerIP0), - + %% -- %% Write agent config %% - + Vsns = [v1], AgentConfDir = ?config(agent_conf_dir, Config), ManagerConfDir = ?config(manager_top_dir, Config), @@ -5961,7 +5959,7 @@ otp8395({init, Config}) when is_list(Config) -> {manager_node, ManagerNode}, {manager_host, ManagerHost}, {manager_ip, ManagerIP}|Config]), - + %% -- %% Create watchdog %% @@ -5973,7 +5971,7 @@ otp8395({init, Config}) when is_list(Config) -> otp8395({fin, Config}) when is_list(Config) -> ?DBG("otp8395(fin) -> entry with" "~n Config: ~p", [Config]), - + AgentNode = ?config(agent_node, Config), ManagerNode = ?config(manager_node, Config), @@ -5981,11 +5979,11 @@ otp8395({fin, Config}) when is_list(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("otp8395(fin) -> stop (stand-alone) agent: ~p", [AgentSup]), stop_stdalone_agent(AgentSup), - + %% - %% Stop mnesia %% @@ -6001,8 +5999,8 @@ otp8395({fin, Config}) when is_list(Config) -> stop_node(AgentNode), -%% SubAgentNode = ?config(sub_agent_node, Config), -%% stop_node(SubAgentNode), + %% SubAgentNode = ?config(sub_agent_node, Config), + %% stop_node(SubAgentNode), %% - @@ -6022,7 +6020,7 @@ otp8395(doc) -> otp8395(Config) when is_list(Config) -> ?DBG("otp8395 -> entry with" "~n Config: ~p", [Config]), - + ?SLEEP(1000), %% This is just to dirty trick for the ***old*** test-code @@ -6040,8 +6038,8 @@ otp8395(Config) when is_list(Config) -> {ok, LogInfo} = rpc:call(AgentNode, snmpa, log_info, []), ?DBG("otp8395 -> LogInfo: ~p", [LogInfo]), -%% SyncRes = rpc:call(AgentNode, snmp, log_sync, [?audit_trail_log_name]), -%% ?DBG("otp8395 -> SyncRes: ~p", [SyncRes]), + %% SyncRes = rpc:call(AgentNode, snmp, log_sync, [?audit_trail_log_name]), + %% ?DBG("otp8395 -> SyncRes: ~p", [SyncRes]), ok = agent_log_validation(AgentNode), LTTRes = @@ -6051,7 +6049,195 @@ otp8395(Config) when is_list(Config) -> ?SLEEP(1000), ?DBG("otp8395 -> done", []), ok. - + + +%%----------------------------------------------------------------- + +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 = filename: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 = filename:join([AgentTopDir, backup1]), + AgentBkpDir2 = filename: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]; + +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); + +otp9884(doc) -> + "OTP-9884 - Simlutaneous backup call should not work. "; + +otp9884(Config) when is_list(Config) -> + ?DBG("otp9884 -> entry with" + "~n Config: ~p", [Config]), + + AgentNode = ?config(agent_node, Config), + [AgentBkpDir1, AgentBkpDir2] = ?config(agent_backup_dirs, Config), + Self = self(), + timer:apply_after(1000, + ?MODULE, otp9884_backup, [AgentNode, Self, first, AgentBkpDir1]), + timer:apply_after(1000, + ?MODULE, otp9884_backup, [AgentNode, Self, second, AgentBkpDir2]), + otp9884_await_backup_completion(undefined, undefined), + + ?DBG("otp9884 -> done", []), + ok. + + +otp9884_backup(Node, Pid, Tag, Dir) -> + io:format("[~w] call backup function~n", [Tag]), + Res = rpc:call(Node, snmpa, backup, [Dir]), + io:format("[~w] backup result: ~p~n", [Tag, Res]), + Pid ! {otp9884_backup_complete, Tag, Res}. + +otp9884_await_backup_completion(ok, Second) + when ((Second =/= ok) andalso (Second =/= undefined)) -> + io:format("otp9884_await_backup_completion -> " + "first backup succeed and second failed (~p)~n", [Second]), + ok; +otp9884_await_backup_completion(First, ok) + when ((First =/= ok) andalso (First =/= undefined)) -> + io:format("otp9884_await_backup_completion -> " + "second backup succeed and first failed (~p)~n", [First]), + ok; +otp9884_await_backup_completion(First, Second) + when (((First =:= undefined) andalso (Second =:= undefined)) + orelse + ((First =:= undefined) andalso (Second =/= undefined)) + orelse + ((First =/= undefined) andalso (Second =:= undefined))) -> + io:format("otp9884_await_backup_completion -> await complete messages~n", []), + receive + {otp9884_backup_complete, first, Res} -> + io:format("otp9884_await_backup_completion -> " + "received complete message for first: ~p~n", [Res]), + otp9884_await_backup_completion(Res, Second); + {otp9884_backup_complete, second, Res} -> + io:format("otp9884_await_backup_completion -> " + "received complete message for second: ~p~n", [Res]), + otp9884_await_backup_completion(First, Res) + after 10000 -> + %% we have waited long enough + throw({error, {timeout, First, Second}}) + end; +otp9884_await_backup_completion(First, Second) -> + throw({error, {bad_completion, First, Second}}). + + +%%----------------------------------------------------------------- agent_log_validation(Node) -> rpc:call(Node, ?MODULE, agent_log_validation, []). diff --git a/lib/snmp/vsn.mk b/lib/snmp/vsn.mk index 1fbad654f7..fb1dcb6c41 100644 --- a/lib/snmp/vsn.mk +++ b/lib/snmp/vsn.mk @@ -18,7 +18,6 @@ # %CopyrightEnd% APPLICATION = snmp -SNMP_VSN = 4.21.6 +SNMP_VSN = 4.21.7 PRE_VSN = APP_VSN = "$(APPLICATION)-$(SNMP_VSN)$(PRE_VSN)" - |