diff options
78 files changed, 4736 insertions, 2454 deletions
diff --git a/erts/doc/src/erl.xml b/erts/doc/src/erl.xml index 02082e57c6..2cd1588a2f 100644 --- a/erts/doc/src/erl.xml +++ b/erts/doc/src/erl.xml @@ -738,6 +738,19 @@ <seealso marker="erlang#system_flag_scheduler_bind_type">erlang:system_flag(scheduler_bind_type, SchedulerBindType)</seealso>. </p> </item> + <tag><marker id="+scl"><c>+scl true|false</c></marker></tag> + <item> + <p>Enable or disable scheduler compaction of load. By default + scheduler compaction of load is enabled. When enabled, load + balancing will strive for a load distribution which causes + as many scheduler threads as possible to be fully loaded (i.e., + not run out of work). This is accomplished by migrating load + (e.g. runnable processes) into a smaller set of schedulers + when schedulers frequently run out of work. When disabled, + the frequency with which schedulers run out of work will + not be taken into account by the load balancing logic. + </p> + </item> <tag><marker id="+sct"><c>+sct CpuTopology</c></marker></tag> <item> <list type="bulleted"> diff --git a/erts/doc/src/notes.xml b/erts/doc/src/notes.xml index 4cef9669dd..1a79263928 100644 --- a/erts/doc/src/notes.xml +++ b/erts/doc/src/notes.xml @@ -30,6 +30,23 @@ </header> <p>This document describes the changes made to the ERTS application.</p> +<section><title>Erts 5.8.5.1</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + The <c>+scl</c> command line flag has been added. It can + be used for disabling compaction of scheduler load. For + more information see the <c>erl(1)</c> documentation.</p> + <p> + Own Id: OTP-9695</p> + </item> + </list> + </section> + +</section> + <section><title>Erts 5.8.5</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c index e5fd2547a0..ceaf08ff86 100644 --- a/erts/emulator/beam/erl_init.c +++ b/erts/emulator/beam/erl_init.c @@ -510,6 +510,8 @@ void erts_usage(void) erts_fprintf(stderr, "-rg amount set reader groups limit\n"); erts_fprintf(stderr, "-sbt type set scheduler bind type, valid types are:\n"); erts_fprintf(stderr, " u|ns|ts|ps|s|nnts|nnps|tnnps|db\n"); + erts_fprintf(stderr, "-scl bool enable/disable compaction of scheduler load,\n"); + erts_fprintf(stderr, " see the erl(1) documentation for more info.\n"); erts_fprintf(stderr, "-sct cput set cpu topology,\n"); erts_fprintf(stderr, " see the erl(1) documentation for more info.\n"); erts_fprintf(stderr, "-swt val set scheduler wakeup threshold, valid values are:\n"); @@ -605,6 +607,7 @@ early_init(int *argc, char **argv) /* int max_reader_groups; int reader_groups; + erts_sched_compact_load = 1; use_multi_run_queue = 1; erts_printf_eterm_func = erts_printf_term; erts_disable_tolerant_timeofday = 0; @@ -1152,6 +1155,19 @@ erl_start(int argc, char **argv) erts_usage(); } } + else if (has_prefix("cl", sub_param)) { + arg = get_arg(sub_param+2, argv[i+1], &i); + if (sys_strcmp("true", arg) == 0) + erts_sched_compact_load = 1; + else if (sys_strcmp("false", arg) == 0) + erts_sched_compact_load = 0; + else { + erts_fprintf(stderr, + "bad scheduler compact load value '%s'\n", + arg); + erts_usage(); + } + } else if (has_prefix("ct", sub_param)) { arg = get_arg(sub_param+2, argv[i+1], &i); res = erts_init_cpu_topology_string(arg); diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c index ba3b32dd97..93f3fb2845 100644 --- a/erts/emulator/beam/erl_process.c +++ b/erts/emulator/beam/erl_process.c @@ -111,6 +111,7 @@ static Sint p_serial; static Uint p_serial_mask; static Uint p_serial_shift; +int erts_sched_compact_load; Uint erts_no_schedulers; Uint erts_max_processes = ERTS_DEFAULT_MAX_PROCESSES; Uint erts_process_tab_index_mask; @@ -2208,6 +2209,9 @@ check_balance(ErtsRunQueue *c_rq) mmax_len = run_queue_info[qix].max_len; } + if (!erts_sched_compact_load) + goto all_active; + if (!forced && half_full_scheds != blnc_no_rqs) { int min = 1; if (min < half_full_scheds) diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h index 296acc7367..c7d89d3bb3 100644 --- a/erts/emulator/beam/erl_process.h +++ b/erts/emulator/beam/erl_process.h @@ -88,6 +88,7 @@ struct saved_calls { }; extern Export exp_send, exp_receive, exp_timeout; +extern int erts_sched_compact_load; extern Uint erts_no_schedulers; extern Uint erts_no_run_queues; extern int erts_sched_thread_suggested_stack_size; diff --git a/erts/etc/common/erlexec.c b/erts/etc/common/erlexec.c index 2bd576d8e8..95cb688b29 100644 --- a/erts/etc/common/erlexec.c +++ b/erts/etc/common/erlexec.c @@ -122,6 +122,7 @@ static char *plusM_other_switches[] = { /* +s arguments with values */ static char *pluss_val_switches[] = { "bt", + "cl", "ct", "wt", "ss", diff --git a/erts/vsn.mk b/erts/vsn.mk index 18799d2fba..224727b094 100644 --- a/erts/vsn.mk +++ b/erts/vsn.mk @@ -17,7 +17,7 @@ # %CopyrightEnd% # -VSN = 5.8.5 +VSN = 5.8.5.1 SYSTEM_VSN = R14B04 # Port number 4365 in 4.2 diff --git a/lib/ic/doc/src/notes.xml b/lib/ic/doc/src/notes.xml index de519d5f84..ff289bd76c 100644 --- a/lib/ic/doc/src/notes.xml +++ b/lib/ic/doc/src/notes.xml @@ -31,6 +31,22 @@ </header> <section> + <title>IC 4.2.28</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p> + Incorrect use of ets:match changed to ets:match_object.</p> + <p> + Own Id: OTP-9630 </p> + </item> + </list> + </section> + </section> + + <section> <title>IC 4.2.27</title> <section> diff --git a/lib/ic/src/ic_pragma.erl b/lib/ic/src/ic_pragma.erl index 7f2216b9dc..beaa2852ab 100644 --- a/lib/ic/src/ic_pragma.erl +++ b/lib/ic/src/ic_pragma.erl @@ -1601,7 +1601,7 @@ remove_inheriters(S,RS,InheriterList) -> ReducedInhList; _Other -> CleanList = - ets:match(S, {inherits,'_','_'}), + ets:match_object(S, {inherits,'_','_'}), % CodeOptList = % [X || X <- EtsList, element(1,X) == codeopt], NoInheriters =remove_inheriters2(S,ReducedInhList,CleanList), @@ -1648,7 +1648,7 @@ remove_inh([X],[Y],List,EtsList) -> %%%---------------------------------------------- remove_inherited(S,InheriterList) -> CleanList = - ets:match(S, {inherits, '_', '_'}), + ets:match_object(S, {inherits, '_', '_'}), remove_inherited(S,InheriterList,CleanList). @@ -1766,7 +1766,7 @@ inherits2(_X,Y,Z,EtsList) -> %% false otherwise %% is_inherited_by(Interface1,Interface2,PragmaTab) -> - InheritsList = ets:match(PragmaTab, {inherits, '_', '_'}), + InheritsList = ets:match_object(PragmaTab, {inherits, '_', '_'}), inherits(Interface2,Interface1,InheritsList). diff --git a/lib/ic/vsn.mk b/lib/ic/vsn.mk index 6561ccd2a7..703c8d29eb 100644 --- a/lib/ic/vsn.mk +++ b/lib/ic/vsn.mk @@ -1 +1 @@ -IC_VSN = 4.2.27 +IC_VSN = 4.2.28 diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml index 5b5dfdde21..487b9c6c00 100644 --- a/lib/inets/doc/src/notes.xml +++ b/lib/inets/doc/src/notes.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2002</year><year>2011</year> + <year>2002</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -32,6 +32,98 @@ <file>notes.xml</file> </header> + <section><title>Inets 5.7.3</title> + <section><title>Improvements and New Features</title> + <p>-</p> + +<!-- + <list> + <item> + <p>[httpc|httpd] Added support for IPv6 with ssl. </p> + <p>Own Id: OTP-5566</p> + </item> + + </list> +--> + + </section> + + <section><title>Fixed Bugs and Malfunctions</title> +<!-- + <p>-</p> +--> + + <list> + <item> + <p>[ftp] Fails to open IPv6 connection due to badly formatted + IPv6 address in EPRT command. The address part of the command + incorrectly contained decimal elements instead of hexadecimal. </p> + <p>Own Id: OTP-9827</p> + <p>Aux Id: Seq 11970 </p> + </item> + + <item> + <p>[httpc] Bad Keep Alive Mode. When selecting a session, + the "state" of the session (specifically if the server has + responded) was not taken into account. </p> + <p>Own Id: OTP-9847</p> + </item> + + <item> + <p>[httpc] The client incorrectly streams 404 responses. + The documentation specifies that only 200 and 206 responses + shall be streamed. </p> + <p>Shane Evens</p> + <p>Own Id: OTP-9860</p> + </item> + + </list> + </section> + + </section> <!-- 5.7.3 --> + + + <section><title>Inets 5.7.2</title> + <section><title>Improvements and New Features</title> + <p>-</p> + +<!-- + <list> + <item> + <p>[httpc|httpd] Added support for IPv6 with ssl. </p> + <p>Own Id: OTP-5566</p> + </item> + + </list> +--> + + </section> + + <section><title>Fixed Bugs and Malfunctions</title> +<!-- + <p>-</p> +--> + + <list> + <item> + <p>[httpd] XSS prevention did not work for hex-encoded URL's. </p> + <p>Own Id: OTP-9655</p> + </item> + + <item> + <p>[httpd] GET request with malformed header date caused + server crash (non-fatal) with no reply to client. Will + now result in a reply with status code 400. </p> + <p>Own Id: OTP-9674</p> + <p>Aux Id: seq11936</p> + </item> + + </list> + </section> + + </section> <!-- 5.7.2 --> + + <section><title>Inets 5.7.1</title> <section><title>Improvements and New Features</title> diff --git a/lib/inets/src/ftp/ftp.erl b/lib/inets/src/ftp/ftp.erl index ac72963347..3028cd800f 100644 --- a/lib/inets/src/ftp/ftp.erl +++ b/lib/inets/src/ftp/ftp.erl @@ -1912,17 +1912,14 @@ setup_ctrl_connection(Host, Port, Timeout, State) -> setup_data_connection(#state{mode = active, caller = Caller, csock = CSock} = State) -> - IntToString = fun(Element) -> integer_to_list(Element) end, - case (catch inet:sockname(CSock)) of {ok, {{_, _, _, _, _, _, _, _} = IP, _}} -> {ok, LSock} = gen_tcp:listen(0, [{ip, IP}, {active, false}, inet6, binary, {packet, 0}]), {ok, Port} = inet:port(LSock), - Cmd = mk_cmd("EPRT |2|~s:~s:~s:~s:~s:~s:~s:~s|~s|", - lists:map(IntToString, - tuple_to_list(IP) ++ [Port])), + IpAddress = inet_parse:ntoa(IP), + Cmd = mk_cmd("EPRT |2|~s|~p|", [IpAddress, Port]), send_ctrl_message(State, Cmd), activate_ctrl_connection(State), {noreply, State#state{caller = {setup_data_connection, diff --git a/lib/inets/src/http_client/httpc_handler.erl b/lib/inets/src/http_client/httpc_handler.erl index 587e24cc8d..7784060a2b 100644 --- a/lib/inets/src/http_client/httpc_handler.erl +++ b/lib/inets/src/http_client/httpc_handler.erl @@ -157,12 +157,12 @@ info(Pid) -> %% memory in vain.) %%-------------------------------------------------------------------- %% Request should not be streamed -stream(BodyPart, Request = #request{stream = none}, _) -> +stream(BodyPart, #request{stream = none} = Request, _) -> ?hcrt("stream - none", []), {BodyPart, Request}; %% Stream to caller -stream(BodyPart, Request = #request{stream = Self}, Code) +stream(BodyPart, #request{stream = Self} = Request, Code) when ((Code =:= 200) orelse (Code =:= 206)) andalso ((Self =:= self) orelse (Self =:= {self, once})) -> ?hcrt("stream - self", [{stream, Self}, {code, Code}]), @@ -170,17 +170,10 @@ stream(BodyPart, Request = #request{stream = Self}, Code) {Request#request.id, stream, BodyPart}), {<<>>, Request}; -stream(BodyPart, Request = #request{stream = Self}, 404) - when (Self =:= self) orelse (Self =:= {self, once}) -> - ?hcrt("stream - self with 404", [{stream, Self}]), - httpc_response:send(Request#request.from, - {Request#request.id, stream, BodyPart}), - {<<>>, Request}; - %% Stream to file %% This has been moved to start_stream/3 %% We keep this for backward compatibillity... -stream(BodyPart, Request = #request{stream = Filename}, Code) +stream(BodyPart, #request{stream = Filename} = Request, Code) when ((Code =:= 200) orelse (Code =:= 206)) andalso is_list(Filename) -> ?hcrt("stream - filename", [{stream, Filename}, {code, Code}]), case file:open(Filename, [write, raw, append, delayed_write]) of @@ -192,7 +185,7 @@ stream(BodyPart, Request = #request{stream = Filename}, Code) end; %% Stream to file -stream(BodyPart, Request = #request{stream = Fd}, Code) +stream(BodyPart, #request{stream = Fd} = Request, Code) when ((Code =:= 200) orelse (Code =:= 206)) -> ?hcrt("stream to file", [{stream, Fd}, {code, Code}]), case file:write(Fd, BodyPart) of @@ -295,7 +288,7 @@ handle_call(#request{address = Addr} = Request, _, %% Queue + current queue:len(NewPipeline) + 1, client_close = ClientClose}, - httpc_manager:insert_session(NewSession, ProfileName), + insert_session(NewSession, ProfileName), ?hcrd("session updated", []), {reply, ok, State#state{pipeline = NewPipeline, session = NewSession, @@ -363,7 +356,7 @@ handle_call(#request{address = Addr} = Request, _, %% Queue + current queue:len(NewKeepAlive) + 1, client_close = ClientClose}, - httpc_manager:insert_session(NewSession, ProfileName), + insert_session(NewSession, ProfileName), ?hcrd("session updated", []), {reply, ok, State#state{keep_alive = NewKeepAlive, session = NewSession, @@ -377,7 +370,7 @@ handle_call(#request{address = Addr} = Request, _, NewSession = Session#session{queue_length = 1, client_close = ClientClose}, - httpc_manager:insert_session(NewSession, ProfileName), + insert_session(NewSession, ProfileName), Relaxed = (Request#request.settings)#http_options.relaxed, MFA = {httpc_response, parse, @@ -766,23 +759,52 @@ deliver_answer(Request) -> %% Func: code_change(_OldVsn, State, Extra) -> {ok, NewState} %% Purpose: Convert process state when code is changed %%-------------------------------------------------------------------- -%% code_change(_, #state{request = Request, pipeline = Queue} = State, -%% [{from, '5.0.1'}, {to, '5.0.2'}]) -> -%% Settings = new_http_options(Request#request.settings), -%% NewRequest = Request#request{settings = Settings}, -%% NewQueue = new_queue(Queue, fun new_http_options/1), -%% {ok, State#state{request = NewRequest, pipeline = NewQueue}}; - -%% code_change(_, #state{request = Request, pipeline = Queue} = State, -%% [{from, '5.0.2'}, {to, '5.0.1'}]) -> -%% Settings = old_http_options(Request#request.settings), -%% NewRequest = Request#request{settings = Settings}, -%% NewQueue = new_queue(Queue, fun old_http_options/1), -%% {ok, State#state{request = NewRequest, pipeline = NewQueue}}; + +code_change(_, + #state{session = OldSession, + profile_name = ProfileName} = State, + upgrade_from_pre_5_7_3) -> + case OldSession of + {session, + Id, ClientClose, Scheme, Socket, SocketType, QueueLen, Type} -> + NewSession = #session{id = Id, + client_close = ClientClose, + scheme = Scheme, + socket = Socket, + socket_type = SocketType, + queue_length = QueueLen, + type = Type}, + insert_session(NewSession, ProfileName), + {ok, State#state{session = NewSession}}; + _ -> + {ok, State} + end; + +code_change(_, + #state{session = OldSession, + profile_name = ProfileName} = State, + downgrade_to_pre_5_7_3) -> + case OldSession of + #session{id = Id, + client_close = ClientClose, + scheme = Scheme, + socket = Socket, + socket_type = SocketType, + queue_length = QueueLen, + type = Type} -> + NewSession = {session, + Id, ClientClose, Scheme, Socket, SocketType, + QueueLen, Type}, + insert_session(NewSession, ProfileName), + {ok, State#state{session = NewSession}}; + _ -> + {ok, State} + end; code_change(_, State, _) -> {ok, State}. + %% new_http_options({http_options, TimeOut, AutoRedirect, SslOpts, %% Auth, Relaxed}) -> %% {http_options, "HTTP/1.1", TimeOut, AutoRedirect, SslOpts, @@ -1181,7 +1203,7 @@ handle_pipeline(#state{status = pipeline, case queue:out(State#state.pipeline) of {empty, _} -> - ?hcrd("epmty pipeline queue", []), + ?hcrd("pipeline queue empty", []), %% The server may choose too teminate an idle pipeline %% in this case we want to receive the close message @@ -1191,9 +1213,8 @@ handle_pipeline(#state{status = pipeline, %% If a pipeline that has been idle for some time is not %% closed by the server, the client may want to close it. - NewState = activate_queue_timeout(TimeOut, State), - NewSession = Session#session{queue_length = 0}, - httpc_manager:insert_session(NewSession, ProfileName), + NewState = activate_queue_timeout(TimeOut, State), + update_session(ProfileName, Session, #session.queue_length, 0), %% Note mfa will be initilized when a new request %% arrives. {noreply, @@ -1203,6 +1224,7 @@ handle_pipeline(#state{status = pipeline, headers = undefined, body = undefined}}; {{value, NextRequest}, Pipeline} -> + ?hcrd("pipeline queue non-empty", []), case lists:member(NextRequest#request.id, State#state.canceled) of true -> @@ -1218,7 +1240,7 @@ handle_pipeline(#state{status = pipeline, Session#session{queue_length = %% Queue + current queue:len(Pipeline) + 1}, - httpc_manager:insert_session(NewSession, ProfileName), + insert_session(NewSession, ProfileName), Relaxed = (NextRequest#request.settings)#http_options.relaxed, MFA = {httpc_response, @@ -1257,7 +1279,7 @@ handle_keep_alive_queue( case queue:out(State#state.keep_alive) of {empty, _} -> - ?hcrd("empty keep_alive queue", []), + ?hcrd("keep_alive queue empty", []), %% The server may choose too terminate an idle keep_alive session %% in this case we want to receive the close message %% at once and not when trying to send the next @@ -1266,8 +1288,7 @@ handle_keep_alive_queue( %% If a keep_alive session has been idle for some time is not %% closed by the server, the client may want to close it. NewState = activate_queue_timeout(TimeOut, State), - NewSession = Session#session{queue_length = 0}, - httpc_manager:insert_session(NewSession, ProfileName), + update_session(ProfileName, Session, #session.queue_length, 0), %% Note mfa will be initilized when a new request %% arrives. {noreply, @@ -1279,6 +1300,7 @@ handle_keep_alive_queue( } }; {{value, NextRequest}, KeepAlive} -> + ?hcrd("keep_alive queue non-empty", []), case lists:member(NextRequest#request.id, State#state.canceled) of true -> @@ -1388,10 +1410,10 @@ try_to_enable_pipeline_or_keep_alive( case (is_pipeline_enabled_client(Session) andalso httpc_request:is_idempotent(Method)) of true -> - httpc_manager:insert_session(Session, ProfileName), + insert_session(Session, ProfileName), State#state{status = pipeline}; false -> - httpc_manager:insert_session(Session, ProfileName), + insert_session(Session, ProfileName), %% Make sure type is keep_alive in session %% as it in this case might be pipeline NewSession = Session#session{type = keep_alive}, @@ -1403,7 +1425,9 @@ try_to_enable_pipeline_or_keep_alive( end. answer_request(#request{id = RequestId, from = From} = Request, Msg, - #state{timers = Timers, profile_name = ProfileName} = State) -> + #state{session = Session, + timers = Timers, + profile_name = ProfileName} = State) -> ?hcrt("answer request", [{request, Request}, {msg, Msg}]), httpc_response:send(From, Msg), RequestTimers = Timers#timers.request_timers, @@ -1412,12 +1436,20 @@ answer_request(#request{id = RequestId, from = From} = Request, Msg, Timer = {RequestId, TimerRef}, cancel_timer(TimerRef, {timeout, Request#request.id}), httpc_manager:request_done(RequestId, ProfileName), - + NewSession = maybe_make_session_available(ProfileName, Session), + Timers2 = Timers#timers{request_timers = lists:delete(Timer, + RequestTimers)}, State#state{request = Request#request{from = answer_sent}, - timers = - Timers#timers{request_timers = - lists:delete(Timer, RequestTimers)}}. - + session = NewSession, + timers = Timers2}. + +maybe_make_session_available(ProfileName, + #session{available = false} = Session) -> + update_session(ProfileName, Session, #session.available, true), + Session#session{available = true}; +maybe_make_session_available(_ProfileName, Session) -> + Session. + cancel_timers(#timers{request_timers = ReqTmrs, queue_timer = QTmr}) -> cancel_timer(QTmr, timeout_queue), CancelTimer = fun({_, Timer}) -> cancel_timer(Timer, timeout) end, @@ -1656,6 +1688,28 @@ send_raw(SocketType, Socket, ProcessBody, Acc) -> end. +%% --------------------------------------------------------------------- +%% Session wrappers +%% --------------------------------------------------------------------- + +insert_session(Session, ProfileName) -> + httpc_manager:insert_session(Session, ProfileName). + + +update_session(ProfileName, #session{id = SessionId} = Session, Pos, Value) -> + try + begin + httpc_manager:update_session(ProfileName, SessionId, Pos, Value) + end + catch + error:undef -> % This could happen during code upgrade + Session2 = erlang:setelement(Pos, Session, Value), + insert_session(Session2, ProfileName) + end. + + +%% --------------------------------------------------------------------- + call(Msg, Pid) -> Timeout = infinity, call(Msg, Pid, Timeout). diff --git a/lib/inets/src/http_client/httpc_internal.hrl b/lib/inets/src/http_client/httpc_internal.hrl index 1d8a5b6a92..3261061d61 100644 --- a/lib/inets/src/http_client/httpc_internal.hrl +++ b/lib/inets/src/http_client/httpc_internal.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2010. All Rights Reserved. +%% Copyright Ericsson AB 2005-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 @@ -112,17 +112,37 @@ } ). + -record(session, { - id, % {{Host, Port}, HandlerPid} - client_close, % true | false - scheme, % http (HTTP/TCP) | https (HTTP/SSL/TCP) - socket, % Open socket, used by connection - socket_type, % socket-type, used by connection - queue_length = 1, % Current length of pipeline or keep-alive queue - type % pipeline | keep_alive (wait for response before sending new request) + %% {{Host, Port}, HandlerPid} + id, + + %% true | false + client_close, + + %% http (HTTP/TCP) | https (HTTP/SSL/TCP) + scheme, + + %% Open socket, used by connection + socket, + + %% socket-type, used by connection + socket_type, + + %% Current length of pipeline or keep-alive queue + queue_length = 1, + + %% pipeline | keep_alive (wait for response before sending new request) + type, + + %% true | false + %% This will be true, when a response has been received for + %% the first request. See type above. + available = false }). + -record(http_cookie, { domain, diff --git a/lib/inets/src/http_client/httpc_manager.erl b/lib/inets/src/http_client/httpc_manager.erl index 9015bf1ce2..3d846c2bff 100644 --- a/lib/inets/src/http_client/httpc_manager.erl +++ b/lib/inets/src/http_client/httpc_manager.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2011. All Rights Reserved. +%% Copyright Ericsson AB 2002-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 @@ -34,6 +34,7 @@ retry_request/2, redirect_request/2, insert_session/2, + update_session/4, delete_session/2, set_options/2, store_cookies/3, @@ -193,6 +194,27 @@ insert_session(Session, ProfileName) -> %%-------------------------------------------------------------------- +%% Function: update_session(ProfileName, SessionId, Pos, Value) -> _ +%% Session - #session{} +%% ProfileName - atom() +%% +%% Description: Update, only one field (Pos) of the session record +%% identified by the SessionId, the session information +%% of the httpc manager table <ProfileName>_session_db. +%% Intended to be called by the httpc request handler process. +%%-------------------------------------------------------------------- + +update_session(ProfileName, SessionId, Pos, Value) -> + SessionDbName = session_db_name(ProfileName), + ?hcrt("update session", + [{id, SessionId}, + {pos, Pos}, + {value, Value}, + {profile, ProfileName}]), + ets:update_element(SessionDbName, SessionId, {Pos, Value}). + + +%%-------------------------------------------------------------------- %% Function: delete_session(SessionId, ProfileName) -> _ %% SessionId - {{Host, Port}, HandlerPid} %% ProfileName - atom() @@ -548,9 +570,70 @@ terminate(_, State) -> %% Func: code_change(_OldVsn, State, Extra) -> {ok, NewState} %% Purpose: Convert process state when code is changed %%-------------------------------------------------------------------- -code_change(_OldVsn, State, _Extra) -> +code_change(_, + #state{session_db = SessionDB} = State, + upgrade_from_pre_5_7_3) -> + Upgrade = + fun({session, + Id, ClientClose, Scheme, Socket, SocketType, QueueLen, Type}) -> + {ok, #session{id = Id, + client_close = ClientClose, + scheme = Scheme, + socket = Socket, + socket_type = SocketType, + queue_length = QueueLen, + type = Type}}; + (_) -> % Already upgraded (by handler) + ignore + end, + (catch update_session_table(SessionDB, Upgrade)), + {ok, State}; + +code_change(_, + #state{session_db = SessionDB} = State, + downgrade_to_pre_5_7_3) -> + Downgrade = + fun(#session{id = Id, + client_close = ClientClose, + scheme = Scheme, + socket = Socket, + socket_type = SocketType, + queue_length = QueueLen, + type = Type}) -> + {ok, {session, + Id, ClientClose, Scheme, Socket, SocketType, + QueueLen, Type}}; + (_) -> % Already downgraded (by handler) + ignore + end, + (catch update_session_table(SessionDB, Downgrade)), + {ok, State}; + +code_change(_, State, _) -> {ok, State}. +%% This function is to catch everything that calls through the cracks... +update_session_table(SessionDB, Transform) -> + ets:safe_fixtable(SessionDB, true), + update_session_table(SessionDB, ets:first(SessionDB), Transform), + ets:safe_fixtable(SessionDB, false). + +update_session_table(_SessionDB, '$end_of_table', _Transform) -> + ok; +update_session_table(SessionDB, Key, Transform) -> + case ets:lookup(SessionDB, Key) of + [OldSession] -> + case Transform(OldSession) of + {ok, NewSession} -> + ets:insert(SessionDB, NewSession); + ignore -> + ok + end; + _ -> + ok + end, + update_session_table(SessionDB, ets:next(SessionDB, Key), Transform). + %%-------------------------------------------------------------------- %% Internal functions @@ -679,6 +762,7 @@ select_session(Method, HostPort, Scheme, SessionType, scheme = Scheme, queue_length = '$2', type = SessionType, + available = true, _ = '_'}, %% {'_', {HostPort, '$1'}, false, Scheme, '_', '$2', SessionTyp}, Candidates = ets:match(SessionDb, Pattern), @@ -716,7 +800,7 @@ pipeline_or_keep_alive(Request, HandlerPid, State) -> ets:insert(State#state.handler_db, {Request#request.id, HandlerPid, Request#request.from}); - _ -> %timeout pipelining failed + _ -> % timeout pipelining failed start_handler(Request, State) end. diff --git a/lib/inets/src/http_lib/http_uri.erl b/lib/inets/src/http_lib/http_uri.erl index 44b9face0b..607475c359 100644 --- a/lib/inets/src/http_lib/http_uri.erl +++ b/lib/inets/src/http_lib/http_uri.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2010. All Rights Reserved. +%% Copyright Ericsson AB 2006-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 @@ -20,7 +20,9 @@ -module(http_uri). --export([parse/1, encode/1, decode/1]). +-export([parse/1]). +-export([encode/1, decode/1]). + %%%========================================================================= %%% API @@ -42,20 +44,24 @@ encode(URI) -> Reserved = sets:from_list([$;, $:, $@, $&, $=, $+, $,, $/, $?, $#, $[, $], $<, $>, $\", ${, $}, $|, $\\, $', $^, $%, $ ]), - lists:append(lists:map(fun(Char) -> - uri_encode(Char, Reserved) - end, URI)). - -decode([$%,Hex1,Hex2|Rest]) -> - [hex2dec(Hex1)*16+hex2dec(Hex2)|decode(Rest)]; -decode([First|Rest]) -> - [First|decode(Rest)]; -decode([]) -> + %% lists:append(lists:map(fun(Char) -> uri_encode(Char, Reserved) end, URI)). + lists:append([uri_encode(Char, Reserved) || Char <- URI]). + +decode(String) -> + do_decode(String). + +do_decode([$%,Hex1,Hex2|Rest]) -> + [hex2dec(Hex1)*16+hex2dec(Hex2)|do_decode(Rest)]; +do_decode([First|Rest]) -> + [First|do_decode(Rest)]; +do_decode([]) -> []. + %%%======================================================================== %%% Internal functions %%%======================================================================== + parse_scheme(AbsURI) -> case split_uri(AbsURI, ":", {error, no_scheme}, 1, 1) of {error, no_scheme} -> diff --git a/lib/inets/src/http_lib/http_util.erl b/lib/inets/src/http_lib/http_util.erl index 973600d7be..5b21170b78 100644 --- a/lib/inets/src/http_lib/http_util.erl +++ b/lib/inets/src/http_lib/http_util.erl @@ -206,9 +206,7 @@ timeout(Timeout, Started) -> html_encode(Chars) -> Reserved = sets:from_list([$&, $<, $>, $\", $', $/]), - lists:append(lists:map(fun(Char) -> - char_to_html_entity(Char, Reserved) - end, Chars)). + lists:append([char_to_html_entity(Char, Reserved) || Char <- Chars]). %%%======================================================================== diff --git a/lib/inets/src/http_server/httpd_file.erl b/lib/inets/src/http_server/httpd_file.erl index e8a8ab6411..f2ba33099e 100644 --- a/lib/inets/src/http_server/httpd_file.erl +++ b/lib/inets/src/http_server/httpd_file.erl @@ -36,9 +36,9 @@ handle_error(emfile, Op, _ModData, Path) -> handle_error(500, Op, none, Path, ": Too many open files"); handle_error({enfile,_}, Op, _ModData, Path) -> handle_error(500, Op, none, Path, ": File table overflow"); -handle_error(_Reason, Op, ModData, Path) -> - handle_error(404, Op, ModData, Path, ": File not found"). - +handle_error(_Reason, Op, _ModData, Path) -> + handle_error(500, Op, none, Path, ""). + handle_error(StatusCode, Op, none, Path, Reason) -> {StatusCode, none, ?NICE("Can't " ++ Op ++ " " ++ Path ++ Reason)}; handle_error(StatusCode, Op, ModData, Path, Reason) -> diff --git a/lib/inets/src/http_server/httpd_request.erl b/lib/inets/src/http_server/httpd_request.erl index a04bcc2778..5ba79b2706 100644 --- a/lib/inets/src/http_server/httpd_request.erl +++ b/lib/inets/src/http_server/httpd_request.erl @@ -309,12 +309,12 @@ validate_uri(RequestURI) -> (catch http_uri:decode(string:left(RequestURI, Ndx))) end, case UriNoQueryNoHex of - {'EXIT',_Reason} -> + {'EXIT', _Reason} -> {error, {bad_request, {malformed_syntax, RequestURI}}}; _ -> Path = format_request_uri(UriNoQueryNoHex), - Path2 = [X||X<-string:tokens(Path, "/\\"),X=/="."], - validate_path( Path2,0, RequestURI) + Path2 = [X||X<-string:tokens(Path, "/"),X=/="."], %% OTP-5938 + validate_path(Path2, 0, RequestURI) end. validate_path([], _, _) -> diff --git a/lib/inets/src/http_server/httpd_request_handler.erl b/lib/inets/src/http_server/httpd_request_handler.erl index c3b47ce390..d2f22fce93 100644 --- a/lib/inets/src/http_server/httpd_request_handler.erl +++ b/lib/inets/src/http_server/httpd_request_handler.erl @@ -1,8 +1,8 @@ %% %% %CopyrightBegin% -%% +%% %% Copyright Ericsson AB 1997-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 @@ -355,7 +355,7 @@ handle_http_msg({Method, Uri, Version, {RecordHeaders, Headers}, Body}, Reason = io_lib:format("Forbidden URI: ~p~n", [URI]), error_log(Reason, ModData), {stop, normal, State#state{response_sent = true}}; - {error,{bad_request, {malformed_syntax, URI}}} -> + {error, {bad_request, {malformed_syntax, URI}}} -> ?hdrd("validation failed: bad request - malformed syntax", [{uri, URI}]), httpd_response:send_status(ModData#mod{http_version = Version}, diff --git a/lib/inets/src/http_server/httpd_response.erl b/lib/inets/src/http_server/httpd_response.erl index ea9cfbf4f2..dd7223876e 100644 --- a/lib/inets/src/http_server/httpd_response.erl +++ b/lib/inets/src/http_server/httpd_response.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% Copyright Ericsson AB 1997-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 @@ -78,6 +78,7 @@ traverse_modules(ModData,[Module|Rest]) -> [Module, Reason])), report_error(mod_log, ModData#mod.config_db, String), report_error(mod_disk_log, ModData#mod.config_db, String), + send_status(ModData, 500, none), done; done -> ?hdrt("traverse modules - done", []), @@ -100,12 +101,19 @@ send_status(#mod{socket_type = SocketType, socket = Socket, config_db = ConfigDB} = ModData, StatusCode, PhraseArgs) -> + ?hdrd("send status", [{status_code, StatusCode}, + {phrase_args, PhraseArgs}]), + ReasonPhrase = httpd_util:reason_phrase(StatusCode), Message = httpd_util:message(StatusCode, PhraseArgs, ConfigDB), Body = get_body(ReasonPhrase, Message), - send_header(ModData, StatusCode, [{content_type, "text/html"}, - {content_length, integer_to_list(length(Body))}]), + ?hdrt("send status - header", [{reason_phrase, ReasonPhrase}, + {message, Message}]), + send_header(ModData, StatusCode, + [{content_type, "text/html"}, + {content_length, integer_to_list(length(Body))}]), + httpd_socket:deliver(SocketType, Socket, Body). @@ -345,8 +353,9 @@ transform({Field, Value}) when is_list(Field) -> %% Leave this method and go on to the newer form of response %% OTP-4408 %%---------------------------------------------------------------------- -send_response_old(#mod{method = "HEAD"} = ModData, +send_response_old(#mod{method = "HEAD"} = ModData, StatusCode, Response) -> + NewResponse = lists:flatten(Response), case httpd_util:split(NewResponse, [?CR, ?LF, ?CR, ?LF],2) of diff --git a/lib/inets/src/http_server/httpd_util.erl b/lib/inets/src/http_server/httpd_util.erl index c051422529..b0b18b9c3d 100644 --- a/lib/inets/src/http_server/httpd_util.erl +++ b/lib/inets/src/http_server/httpd_util.erl @@ -178,11 +178,12 @@ message(301,URL,_) -> "The document has moved <A HREF=\""++ maybe_encode(URL) ++"\">here</A>."; message(304, _URL,_) -> "The document has not been changed."; -message(400,none,_) -> - "Your browser sent a query that this server could not understand."; -message(400,Msg,_) -> - "Your browser sent a query that this server could not understand. "++ http_util:html_encode(Msg); -message(401,none,_) -> +message(400, none, _) -> + "Your browser sent a query that this server could not understand. "; +message(400, Msg, _) -> + "Your browser sent a query that this server could not understand. " ++ + html_encode(Msg); +message(401, none, _) -> "This server could not verify that you are authorized to access the document you requested. Either you supplied the wrong @@ -190,40 +191,49 @@ credentials (e.g., bad password), or your browser doesn't understand how to supply the credentials required."; message(403,RequestURI,_) -> - "You don't have permission to access "++ http_util:html_encode(RequestURI) ++" on this server."; + "You don't have permission to access " ++ + html_encode(RequestURI) ++ + " on this server."; message(404,RequestURI,_) -> - "The requested URL " ++ http_util:html_encode(RequestURI) ++ " was not found on this server."; + "The requested URL " ++ + html_encode(RequestURI) ++ + " was not found on this server."; message(408, Timeout, _) -> Timeout; message(412,none,_) -> "The requested preconditions were false"; message(413, Reason,_) -> - "Entity: " ++ http_util:html_encode(Reason); + "Entity: " ++ html_encode(Reason); message(414,ReasonPhrase,_) -> - "Message "++ http_util:html_encode(ReasonPhrase) ++"."; + "Message " ++ html_encode(ReasonPhrase) ++ "."; message(416,ReasonPhrase,_) -> - http_util:html_encode(ReasonPhrase); + html_encode(ReasonPhrase); message(500,_,ConfigDB) -> ServerAdmin=lookup(ConfigDB,server_admin,"unknown@unknown"), "The server encountered an internal error or " "misconfiguration and was unable to complete " "your request.<P>Please contact the server administrator " - ++ http_util:html_encode(ServerAdmin) ++ ", and inform them of the time the error occurred " + ++ html_encode(ServerAdmin) ++ + ", and inform them of the time the error occurred " "and anything you might have done that may have caused the error."; message(501,{Method, RequestURI, HTTPVersion}, _ConfigDB) -> if is_atom(Method) -> - http_util:html_encode(atom_to_list(Method))++ - " to "++ http_util:html_encode(RequestURI)++" ("++ http_util:html_encode(HTTPVersion)++") not supported."; + atom_to_list(Method) ++ + " to " ++ + html_encode(RequestURI) ++ + " (" ++ HTTPVersion ++ ") not supported."; is_list(Method) -> - http_util:html_encode(Method)++ - " to "++ http_util:html_encode(RequestURI)++" ("++ http_util:html_encode(HTTPVersion)++") not supported." + Method ++ + " to " ++ + html_encode(RequestURI) ++ + " (" ++ HTTPVersion ++ ") not supported." end; message(503, String, _ConfigDB) -> - "This service in unavailable due to: "++ http_util:html_encode(String). + "This service in unavailable due to: " ++ html_encode(String). maybe_encode(URI) -> Decoded = try http_uri:decode(URI) of @@ -233,6 +243,15 @@ maybe_encode(URI) -> end, http_uri:encode(Decoded). +html_encode(String) -> + try http_uri:decode(String) of + Decoded when is_list(Decoded) -> + http_util:html_encode(Decoded) + catch + _:_ -> + http_util:html_encode(String) + end. + %%convert_rfc_date(Date)->{{YYYY,MM,DD},{HH,MIN,SEC}} convert_request_date([D,A,Y,DateType| Rest])-> @@ -245,7 +264,7 @@ convert_request_date([D,A,Y,DateType| Rest])-> fun convert_rfc850_date/1 end, case catch Func([D,A,Y,DateType| Rest]) of - {ok,Date} -> + {ok, Date} -> Date; _Error-> bad_date diff --git a/lib/inets/src/http_server/mod_responsecontrol.erl b/lib/inets/src/http_server/mod_responsecontrol.erl index 5d5b60cdbd..989f45db20 100644 --- a/lib/inets/src/http_server/mod_responsecontrol.erl +++ b/lib/inets/src/http_server/mod_responsecontrol.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2010. All Rights Reserved. +%% Copyright Ericsson AB 2001-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 @@ -209,14 +209,14 @@ compare_etags(Tag,Etags) -> nomatch end. -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% %% -%%Control if the file is modificated %% -%% %% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% %% +%% Control if the file is modificated %% +%% %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%---------------------------------------------------------------------- -%%Control the If-Modified-Since and If-Not-Modified-Since header fields +%% Control the If-Modified-Since and If-Not-Modified-Since header fields %%---------------------------------------------------------------------- control_modification(Path,Info,FileInfo)-> ?DEBUG("control_modification() -> entry",[]), @@ -227,6 +227,8 @@ control_modification(Path,Info,FileInfo)-> continue; unmodified-> {304, Info, Path}; + {bad_date, _} = BadDate-> + {400, Info, BadDate}; undefined -> case control_modification_data(Info, FileInfo#file_info.mtime, @@ -253,21 +255,27 @@ control_modification_data(Info, ModificationTime, HeaderField)-> undefined-> undefined; LastModified0 -> - LastModified = calendar:universal_time_to_local_time( - httpd_util:convert_request_date(LastModified0)), - ?DEBUG("control_modification_data() -> " - "~n Request-Field: ~s" - "~n FileLastModified: ~p" - "~n FieldValue: ~p", - [HeaderField, ModificationTime, LastModified]), - FileTime = - calendar:datetime_to_gregorian_seconds(ModificationTime), - FieldTime = calendar:datetime_to_gregorian_seconds(LastModified), - if - FileTime =< FieldTime -> - ?DEBUG("File unmodified~n", []), unmodified; - FileTime >= FieldTime -> - ?DEBUG("File modified~n", []), modified + case httpd_util:convert_request_date(LastModified0) of + bad_date -> + {bad_date, LastModified0}; + ConvertedReqDate -> + LastModified = + calendar:universal_time_to_local_time(ConvertedReqDate), + ?DEBUG("control_modification_data() -> " + "~n Request-Field: ~s" + "~n FileLastModified: ~p" + "~n FieldValue: ~p", + [HeaderField, ModificationTime, LastModified]), + FileTime = + calendar:datetime_to_gregorian_seconds(ModificationTime), + FieldTime = + calendar:datetime_to_gregorian_seconds(LastModified), + if + FileTime =< FieldTime -> + ?DEBUG("File unmodified~n", []), unmodified; + FileTime >= FieldTime -> + ?DEBUG("File modified~n", []), modified + end end end. @@ -285,6 +293,9 @@ strip_date([C | Rest]) -> send_return_value({412,_,_}, _FileInfo)-> {status,{412,none,"Precondition Failed"}}; +send_return_value({400,_, {bad_date, BadDate}}, _FileInfo)-> + {status, {400, none, "Bad date: " ++ BadDate}}; + send_return_value({304,Info,Path}, FileInfo)-> Suffix = httpd_util:suffix(Path), MimeType = httpd_util:lookup_mime_default(Info#mod.config_db,Suffix, diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src index d5fdf86a60..84217eac78 100644 --- a/lib/inets/src/inets_app/inets.appup.src +++ b/lib/inets/src/inets_app/inets.appup.src @@ -1,7 +1,7 @@ %% This is an -*- erlang -*- file. %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2011. All Rights Reserved. +%% Copyright Ericsson AB 1999-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 @@ -18,85 +18,91 @@ {"%VSN%", [ - {"5.7", - [ - {load_module, httpd_request, soft_purge, soft_purge, []}, - {load_module, httpc_cookie, soft_purge, soft_purge, [http_util]}, - {load_module, http_util, soft_purge, soft_purge, []} - ] - }, - {"5.6", + {"5.7.2", [ - {load_module, httpd_request, soft_purge, soft_purge, []}, - {load_module, httpc, soft_purge, soft_purge, [httpc_manager]}, - {load_module, http_transport, soft_purge, soft_purge, [http_transport]}, - {load_module, httpc_cookie, soft_purge, soft_purge, [http_util]}, - {load_module, http_util, soft_purge, soft_purge, []}, - {update, httpc_handler, soft, soft_purge, soft_purge, []}, - {update, httpc_manager, soft, soft_purge, soft_purge, [httpc_handler]}, - {update, ftp, soft, soft_purge, soft_purge, []} + {load_module, ftp, soft_purge, soft_purge, []}, + {update, httpc_handler, {advanced, upgrade_from_pre_5_7_3}, + soft_purge, soft_purge, []}, + {update, httpc_manager, {advanced, upgrade_from_pre_5_7_3}, + soft_purge, soft_purge, [httpc_handler]} ] }, - {"5.5.2", + {"5.7.1", [ - {restart_application, inets} + {load_module, ftp, soft_purge, soft_purge, []}, + {load_module, http_uri, soft_purge, soft_purge, []}, + {load_module, http_util, soft_purge, soft_purge, []}, + {load_module, httpd_util, soft_purge, soft_purge, [http_util]}, + {load_module, httpd_file, soft_purge, soft_purge, []}, + {load_module, httpd_request, soft_purge, soft_purge, []}, + {load_module, mod_responsecontrol, soft_purge, soft_purge, []}, + {load_module, httpd_response, soft_purge, soft_purge, [mod_responsecontrol]}, + {update, httpc_handler, {advanced, upgrade_from_pre_5_7_3}, + soft_purge, soft_purge, []}, + {update, httpc_manager, {advanced, upgrade_from_pre_5_7_3}, + soft_purge, soft_purge, [httpc_handler]} ] }, - {"5.5.1", - [ - {restart_application, inets} - ] - }, - {"5.5", - [ - {restart_application, inets} - ] - }, - {"5.4", + {"5.7", [ - {restart_application, inets} + {load_module, ftp, soft_purge, soft_purge, []}, + {load_module, http_uri, soft_purge, soft_purge, []}, + {load_module, httpd_util, soft_purge, soft_purge, [http_util]}, + {load_module, httpd_file, soft_purge, soft_purge, []}, + {load_module, httpd_request, soft_purge, soft_purge, []}, + {load_module, httpc_cookie, soft_purge, soft_purge, [http_util]}, + {load_module, http_util, soft_purge, soft_purge, []}, + {load_module, mod_responsecontrol, soft_purge, soft_purge, []}, + {load_module, httpd_response, soft_purge, soft_purge, [mod_responsecontrol]}, + {update, httpc_handler, {advanced, upgrade_from_pre_5_7_3}, + soft_purge, soft_purge, []}, + {update, httpc_manager, {advanced, upgrade_from_pre_5_7_3}, + soft_purge, soft_purge, [httpc_handler]} ] - } + } ], [ - {"5.7", + {"5.7.2", [ - {load_module, httpd_request, soft_purge, soft_purge, []}, - {load_module, httpc_cookie, soft_purge, soft_purge, [http_util]}, - {load_module, http_util, soft_purge, soft_purge, []} + {load_module, ftp, soft_purge, soft_purge, []}, + {update, httpc_handler, {advanced, downgrade_to_pre_5_7_3}, + soft_purge, soft_purge, []}, + {update, httpc_manager, {advanced, downgrade_to_pre_5_7_3}, + soft_purge, soft_purge, [httpc_handler]} ] }, - {"5.6", - [ - {load_module, httpd_request, soft_purge, soft_purge, []}, - {load_module, httpc, soft_purge, soft_purge, [httpc_manager]}, - {load_module, http_transport, soft_purge, soft_purge, [http_transport]}, - {load_module, httpc_cookie, soft_purge, soft_purge, [http_util]}, - {load_module, http_util, soft_purge, soft_purge, []}, - {update, httpc_handler, soft, soft_purge, soft_purge, []}, - {update, httpc_manager, soft, soft_purge, soft_purge, [httpc_handler]}, - {update, ftp, soft, soft_purge, soft_purge, []} - ] - }, - {"5.5.2", - [ - {restart_application, inets} - ] - }, - {"5.5.1", + {"5.7.1", [ - {restart_application, inets} + {load_module, ftp, soft_purge, soft_purge, []}, + {load_module, http_uri, soft_purge, soft_purge, []}, + {load_module, http_util, soft_purge, soft_purge, []}, + {load_module, httpd_util, soft_purge, soft_purge, [http_util]}, + {load_module, httpd_file, soft_purge, soft_purge, []}, + {load_module, httpd_request, soft_purge, soft_purge, []}, + {load_module, mod_responsecontrol, soft_purge, soft_purge, []}, + {load_module, httpd_response, soft_purge, soft_purge, [mod_responsecontrol]}, + {update, httpc_handler, {advanced, downgrade_to_pre_5_7_3}, + soft_purge, soft_purge, []}, + {update, httpc_manager, {advanced, downgrade_to_pre_5_7_3}, + soft_purge, soft_purge, [httpc_handler]} ] }, - {"5.5", - [ - {restart_application, inets} - ] - }, - {"5.4", - [ - {restart_application, inets} + {"5.7", + [ + {load_module, ftp, soft_purge, soft_purge, []}, + {load_module, http_uri, soft_purge, soft_purge, []}, + {load_module, httpd_util, soft_purge, soft_purge, [http_util]}, + {load_module, httpd_file, soft_purge, soft_purge, []}, + {load_module, httpd_request, soft_purge, soft_purge, []}, + {load_module, httpc_cookie, soft_purge, soft_purge, [http_util]}, + {load_module, http_util, soft_purge, soft_purge, []}, + {load_module, mod_responsecontrol, soft_purge, soft_purge, []}, + {load_module, httpd_response, soft_purge, soft_purge, [mod_responsecontrol]}, + {update, httpc_handler, {advanced, downgrade_to_pre_5_7_3}, + soft_purge, soft_purge, []}, + {update, httpc_manager, {advanced, downgrade_to_pre_5_7_3}, + soft_purge, soft_purge, [httpc_handler]} ] - } + } ] }. diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl index 6edd5371af..63935a2352 100644 --- a/lib/inets/test/httpc_SUITE.erl +++ b/lib/inets/test/httpc_SUITE.erl @@ -90,6 +90,7 @@ all() -> parse_url, options, headers_as_is, + selecting_session, {group, proxy}, {group, ssl}, {group, stream}, @@ -253,10 +254,10 @@ init_per_testcase(Case, Config) -> init_per_testcase(Case, 2, Config). 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), - tsp("init_per_testcase -> stop inets"), + 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)), TmpConfig = lists:keydelete(watchdog, 1, Config), @@ -265,7 +266,7 @@ init_per_testcase(Case, Timeout, Config) -> %% inets:enable_trace(max, io, httpd), %% inets:enable_trace(max, io, httpc), - inets:enable_trace(max, io, all), + %% inets:enable_trace(max, io, all), NewConfig = case atom_to_list(Case) of @@ -296,12 +297,12 @@ init_per_testcase(Case, Timeout, Config) -> throw:{error, {failed_starting, App, _}} -> SkipString = "Could not start " ++ atom_to_list(App), - {skip, SkipString}; - _:X -> + skip(SkipString); + _:X -> SkipString = lists:flatten( io_lib:format("Failed starting apps: ~p", [X])), - {skip, SkipString} + skip(SkipString) end; _ -> @@ -330,14 +331,14 @@ init_per_testcase(Case, Timeout, Config) -> ], case lists:member(Rest, BadCases) of true -> - [{skip, "TC and server not compatible"}| + [skip("TC and server not compatible") | TmpConfig]; false -> inets:start(), [{watchdog, Dog} | TmpConfig] end; false -> - [{skip, "proxy not responding"} | TmpConfig] + [skip("proxy not responding") | TmpConfig] end end; @@ -367,20 +368,19 @@ init_per_testcase(Case, Timeout, Config) -> io_lib:format("Failed starting apps: ~p", [X])), {skip, SkipString} end; + _ -> TmpConfig2 = lists:keydelete(local_server, 1, TmpConfig), - Server = - %% Will start inets - inets_test_lib:start_http_server( - filename:join(PrivDir, IpConfFile)), + %% Will start inets + Server = start_http_server(PrivDir, IpConfFile), [{watchdog, Dog}, {local_server, Server} | TmpConfig2] end, %% This will fail for the ipv6_ - cases (but that is ok) - httpc:set_options([{proxy, {{?PROXY, ?PROXY_PORT}, - ["localhost", ?IPV6_LOCAL_HOST]}}, - {ipfamily, inet6fb4}]), - + ProxyExceptions = ["localhost", ?IPV6_LOCAL_HOST], + http:set_options([{proxy, {{?PROXY, ?PROXY_PORT}, ProxyExceptions}}]), + inets:enable_trace(max, io, httpc), + %% inets:enable_trace(max, io, all), %% snmp:set_trace([gen_tcp]), NewConfig. @@ -397,7 +397,10 @@ init_per_testcase_ssl(Tag, PrivDir, SslConfFile, Config) -> tsp("init_per_testcase(~w) -> Server: ~p", [Tag, Server]), [{local_ssl_server, Server} | Config2]. - +start_http_server(ConfDir, ConfFile) -> + inets_test_lib:start_http_server( filename:join(ConfDir, ConfFile) ). + + %%-------------------------------------------------------------------- %% Function: end_per_testcase(Case, Config) -> _ %% Case - atom() @@ -733,7 +736,7 @@ test_pipeline(URL) -> p("test_pipeline -> received reply for (async) request 2"), ok; {http, Msg1} -> - test_server:fail(Msg1) + tsf(Msg1) end; {http, {RequestId2, {{_, 200, _}, _, _}}} -> io:format("test_pipeline -> received reply for (async) request 2 - now wait for 1"), @@ -742,14 +745,14 @@ test_pipeline(URL) -> io:format("test_pipeline -> received reply for (async) request 1"), ok; {http, Msg2} -> - test_server:fail(Msg2) + tsf(Msg2) end; {http, Msg3} -> - test_server:fail(Msg3) + tsf(Msg3) after 60000 -> receive Any1 -> tsp("received crap after timeout: ~n ~p", [Any1]), - test_server:fail({error, {timeout, Any1}}) + tsf({error, {timeout, Any1}}) end end, @@ -774,7 +777,7 @@ test_pipeline(URL) -> p("test_pipeline -> expect *no* reply for cancelled (async) request 4 (for 3 secs)"), receive {http, {RequestId3, _}} -> - test_server:fail(http_cancel_request_failed) + tsf(http_cancel_request_failed) after 3000 -> ok end, @@ -787,11 +790,11 @@ test_pipeline(URL) -> tsp("Receive : ~p", [Res]), BinBody4; {http, Msg4} -> - test_server:fail(Msg4) + tsf(Msg4) after 60000 -> receive Any2 -> tsp("received crap after timeout: ~n ~p", [Any2]), - test_server:fail({error, {timeout, Any2}}) + tsf({error, {timeout, Any2}}) end end, @@ -801,7 +804,7 @@ test_pipeline(URL) -> p("test_pipeline -> ensure no unexpected incomming"), receive {http, Any} -> - test_server:fail({unexpected_message, Any}) + tsf({unexpected_message, Any}) after 500 -> ok end, @@ -823,11 +826,11 @@ http_trace(Config) when is_list(Config) -> {ok, {{_,200,_}, [_ | _], "TRACE /dummy.html" ++ _}} -> ok; {ok, {{_,200,_}, [_ | _], WrongBody}} -> - test_server:fail({wrong_body, WrongBody}); + tsf({wrong_body, WrongBody}); {ok, WrongReply} -> - test_server:fail({wrong_reply, WrongReply}); + tsf({wrong_reply, WrongReply}); Error -> - test_server:fail({failed, Error}) + tsf({failed, Error}) end; _ -> {skip, "Failed to start local http-server"} @@ -850,7 +853,7 @@ http_async(Config) when is_list(Config) -> {http, {RequestId, {{_, 200, _}, _, BinBody}}} -> BinBody; {http, Msg} -> - test_server:fail(Msg) + tsf(Msg) end, inets_test_lib:check_body(binary_to_list(Body)), @@ -860,7 +863,7 @@ http_async(Config) when is_list(Config) -> ok = httpc:cancel_request(NewRequestId), receive {http, {NewRequestId, _NewResult}} -> - test_server:fail(http_cancel_request_failed) + tsf(http_cancel_request_failed) after 3000 -> ok end; @@ -909,7 +912,7 @@ http_save_to_file_async(Config) when is_list(Config) -> {http, {RequestId, saved_to_file}} -> ok; {http, Msg} -> - test_server:fail(Msg) + tsf(Msg) end, {ok, Bin} = file:read_file(FilePath), @@ -1482,10 +1485,10 @@ proxy_options(Config) when is_list(Config) -> {value, {"allow", _}} -> ok; _ -> - test_server:fail(http_options_request_failed) + tsf(http_options_request_failed) end; Unexpected -> - test_server:fail({unexpected_result, Unexpected}) + tsf({unexpected_result, Unexpected}) end; Reason -> {skip, Reason} @@ -1506,7 +1509,7 @@ proxy_head(Config) when is_list(Config) -> {ok, {{_,200, _}, [_ | _], []}} -> ok; Unexpected -> - test_server:fail({unexpected_result, Unexpected}) + tsf({unexpected_result, Unexpected}) end; Reason -> {skip, Reason} @@ -1525,7 +1528,7 @@ proxy_get(Config) when is_list(Config) -> {ok, {{_,200,_}, [_ | _], Body = [_ | _]}} -> inets_test_lib:check_body(Body); Unexpected -> - test_server:fail({unexpected_result, Unexpected}) + tsf({unexpected_result, Unexpected}) end; Reason -> {skip, Reason} @@ -1604,7 +1607,7 @@ proxy_post(Config) when is_list(Config) -> {ok, {{_,405,_}, [_ | _], [_ | _]}} -> ok; Unexpected -> - test_server:fail({unexpected_result, Unexpected}) + tsf({unexpected_result, Unexpected}) end; Reason -> {skip, Reason} @@ -1629,7 +1632,7 @@ proxy_put(Config) when is_list(Config) -> {ok, {{_,405,_}, [_ | _], [_ | _]}} -> ok; Unexpected -> - test_server:fail({unexpected_result, Unexpected}) + tsf({unexpected_result, Unexpected}) end; Reason -> {skip, Reason} @@ -1654,7 +1657,7 @@ proxy_delete(Config) when is_list(Config) -> {ok, {{_,404,_}, [_ | _], [_ | _]}} -> ok; Unexpected -> - test_server:fail({unexpected_result, Unexpected}) + tsf({unexpected_result, Unexpected}) end; Reason -> {skip, Reason} @@ -1710,7 +1713,7 @@ proxy_auth(Config) when is_list(Config) -> {ok, {{_,200, _}, [_ | _], [_|_]}} -> ok; Unexpected -> - test_server:fail({unexpected_result, Unexpected}) + tsf({unexpected_result, Unexpected}) end; Reason -> {skip, Reason} @@ -1796,7 +1799,7 @@ http_stream(Config) when is_list(Config) -> {http, {RequestId, stream_start, _Headers}} -> ok; {http, Msg} -> - test_server:fail(Msg) + tsf(Msg) end, StreamedBody = receive_streamed_body(RequestId, <<>>), @@ -1805,6 +1808,7 @@ http_stream(Config) when is_list(Config) -> %%------------------------------------------------------------------------- + http_stream_once(doc) -> ["Test the option stream for asynchrony requests"]; http_stream_once(suite) -> @@ -1812,12 +1816,12 @@ http_stream_once(suite) -> http_stream_once(Config) when is_list(Config) -> p("http_stream_once -> entry with" "~n Config: ~p", [Config]), - + p("http_stream_once -> set ipfamily to inet", []), ok = httpc:set_options([{ipfamily, inet}]), p("http_stream_once -> start dummy server", []), {DummyServerPid, Port} = dummy_server(ipv4), - + PortStr = integer_to_list(Port), p("http_stream_once -> once", []), once(?URL_START ++ PortStr ++ "/once.html"), @@ -1825,14 +1829,14 @@ http_stream_once(Config) when is_list(Config) -> once(?URL_START ++ PortStr ++ "/once_chunked.html"), p("http_stream_once -> dummy", []), once(?URL_START ++ PortStr ++ "/dummy.html"), - + p("http_stream_once -> stop dummy server", []), DummyServerPid ! stop, p("http_stream_once -> set ipfamily to inet6fb4", []), ok = httpc:set_options([{ipfamily, inet6fb4}]), p("http_stream_once -> done", []), ok. - + once(URL) -> p("once -> issue sync request for ~p", [URL]), {ok, {{_,200,_}, [_ | _], Body}} = @@ -1851,7 +1855,7 @@ once(URL) -> [RequestId, Pid]), Pid; {http, Msg} -> - test_server:fail(Msg) + tsf(Msg) end, tsp("once -> request handler: ~p", [NewPid]), @@ -1894,7 +1898,7 @@ proxy_stream(Config) when is_list(Config) -> {http, {RequestId, stream_start, _Headers}} -> ok; {http, Msg} -> - test_server:fail(Msg) + tsf(Msg) end, StreamedBody = receive_streamed_body(RequestId, <<>>), @@ -2030,6 +2034,7 @@ ipv6(SocketType, Scheme, HTTPOptions, Extra, Config) -> %%------------------------------------------------------------------------- + headers_as_is(doc) -> ["Test the option headers_as_is"]; headers_as_is(suite) -> @@ -2047,6 +2052,321 @@ headers_as_is(Config) when is_list(Config) -> %%------------------------------------------------------------------------- + +selecting_session(doc) -> + ["Test selection of sessions - OTP-9847"]; +selecting_session(suite) -> + []; +selecting_session(Config) when is_list(Config) -> + tsp("selecting_session -> entry with" + "~n Config: ~p", [Config]), + + tsp("selecting_session -> set ipfamily to inet"), + ok = httpc:set_options([{ipfamily, inet}]), + + tsp("selecting_session -> start server"), + {ServerPid, Port} = otp_9847_server(), + + PortStr = integer_to_list(Port), + URL = ?URL_START ++ PortStr ++ "/index.html", + + tsp("selecting_session -> issue the first batch (three) requests"), + lists:foreach(fun(P) -> + tsp("selecting_session:fun1 -> " + "send stop request to ~p", [P]), + P ! stop + end, + reqs(URL, ServerPid, 3, 3, false)), + tsp("selecting_session -> sleep some (1) to make sure nothing lingers"), + ?SLEEP(5000), + tsp("selecting_session -> " + "instruct the server to reply to the first request"), + ServerPid ! {answer, true}, + receive + {answer, true} -> + tsp("selecting_session -> " + "received ack from server to reply to the first request"), + ok + end, + tsp("selecting_session -> issue the second batch (four) requests"), + lists:foreach(fun(P) -> + tsp("selecting_session:fun2 -> " + "send stop request to ~p", [P]), + P ! stop + end, + reqs(URL, ServerPid, 4, 1, true)), + tsp("selecting_session -> sleep some (2) to make sure nothing lingers"), + ?SLEEP(5000), + + tsp("selecting_session -> stop server"), + ServerPid ! stop, + tsp("selecting_session -> set ipfamily (back) to inet6fb4"), + ok = httpc:set_options([{ipfamily, inet6fb4}]), + tsp("selecting_session -> done"), + ok. + +reqs(URL, ServerPid, NumReqs, NumHandlers, InitialSync) -> + tsp("reqs -> entry with" + "~n URL: ~p" + "~n ServerPid: ~w" + "~n NumReqs: ~w" + "~n NumHandlers: ~w" + "~n InitialSync: ~w", + [URL, ServerPid, NumReqs, NumHandlers, InitialSync]), + Handlers = reqs2(URL, NumReqs, [], InitialSync), + tsp("reqs -> " + "~n Handlers: ~w", [Handlers]), + case length(Handlers) of + NumHandlers -> + tsp("reqs -> " + "~n NumHandlers: ~w", [NumHandlers]), + ServerPid ! num_handlers, + receive + {num_handlers, NumHandlers} -> + tsp("reqs -> received num_handlers with" + "~n NumHandlers: ~w", [NumHandlers]), + Handlers; + {num_handlers, WrongNumHandlers} -> + tsp("reqs -> received num_handlers with" + "~n WrongNumHandlers: ~w", [WrongNumHandlers]), + exit({wrong_num_handlers1, WrongNumHandlers, NumHandlers}) + end; + WrongNumHandlers -> + tsp("reqs -> " + "~n WrongNumHandlers: ~w", [WrongNumHandlers]), + exit({wrong_num_handlers2, WrongNumHandlers, NumHandlers}) + end. + + +reqs2(_URL, 0, Acc, _Sync) -> + lists:reverse(Acc); +reqs2(URL, Num, Acc, Sync) -> + tsp("reqs2 -> entry with" + "~n Num: ~w" + "~n Sync: ~w", [Num, Sync]), + case httpc:request(get, {URL, []}, [], [{sync, Sync}]) of + {ok, _Reply} -> + tsp("reqs2 -> successful request: ~p", [_Reply]), + receive + {handler, Handler, _Manager} -> + %% This is when a new handler is created + tsp("reqs2 -> received handler: ~p", [Handler]), + case lists:member(Handler, Acc) of + true -> + tsp("reqs2 -> duplicate handler"), + exit({duplicate_handler, Handler, Num, Acc}); + false -> + tsp("reqs2 -> wait for data ack"), + receive + {data_received, Handler} -> + tsp("reqs2 -> " + "received data ack from ~p", [Handler]), + case Sync of + true -> + reqs2(URL, Num-1, [Handler|Acc], + false); + false -> + reqs2(URL, Num-1, [Handler|Acc], + Sync) + end + end + end; + + {data_received, Handler} -> + tsp("reqs2 -> " + "received data ack from ~p", [Handler]), + reqs2(URL, Num-1, Acc, false) + + end; + + {error, Reason} -> + tsp("reqs2 -> request ~w failed: ~p", [Num, Reason]), + exit({request_failed, Reason, Num, Acc}) + end. + +otp_9847_server() -> + TC = self(), + Pid = spawn_link(fun() -> otp_9847_server_init(TC) end), + receive + {port, Port} -> + {Pid, Port} + end. + +otp_9847_server_init(TC) -> + tsp("otp_9847_server_init -> entry with" + "~n TC: ~p", [TC]), + {ok, ListenSocket} = + gen_tcp:listen(0, [binary, inet, {packet, 0}, + {reuseaddr,true}, + {active, false}]), + tsp("otp_9847_server_init -> listen socket created: " + "~n ListenSocket: ~p", [ListenSocket]), + {ok, Port} = inet:port(ListenSocket), + tsp("otp_9847_server_init -> Port: ~p", [Port]), + TC ! {port, Port}, + otp_9847_server_main(TC, ListenSocket, false, []). + +otp_9847_server_main(TC, ListenSocket, Answer, Handlers) -> + tsp("otp_9847_server_main -> entry with" + "~n TC: ~p" + "~n ListenSocket: ~p" + "~n Answer: ~p" + "~n Handlers: ~p", [TC, ListenSocket, Answer, Handlers]), + case gen_tcp:accept(ListenSocket, 1000) of + {ok, Sock} -> + tsp("otp_9847_server_main -> accepted" + "~n Sock: ~p", [Sock]), + {Handler, Mon, Port} = otp_9847_handler(TC, Sock, Answer), + tsp("otp_9847_server_main -> handler ~p created for ~w", + [Handler, Port]), + gen_tcp:controlling_process(Sock, Handler), + tsp("otp_9847_server_main -> control transfer"), + Handler ! owner, + tsp("otp_9847_server_main -> " + "handler ~p informed of owner transfer", [Handler]), + TC ! {handler, Handler, self()}, + tsp("otp_9847_server_main -> " + "TC ~p informed of handler ~p", [TC, Handler]), + otp_9847_server_main(TC, ListenSocket, Answer, + [{Handler, Mon, Sock, Port}|Handlers]); + + {error, timeout} -> + tsp("otp_9847_server_main -> timeout"), + receive + {answer, true} -> + tsp("otp_9847_server_main -> received answer request"), + TC ! {answer, true}, + otp_9847_server_main(TC, ListenSocket, true, Handlers); + + {'DOWN', _Mon, process, Pid, _Reason} -> + %% Could be one of the handlers + tsp("otp_9847_server_main -> received DOWN for ~p", [Pid]), + otp_9847_server_main(TC, ListenSocket, Answer, + lists:keydelete(Pid, 1, Handlers)); + + num_handlers -> + tsp("otp_9847_server_main -> " + "received request for number of handlers (~w)", + [length(Handlers)]), + TC ! {num_handlers, length(Handlers)}, + otp_9847_server_main(TC, ListenSocket, Answer, Handlers); + + stop -> + tsp("otp_9847_server_main -> received stop request"), + %% Stop all handlers (just in case) + Pids = [Handler || {Handler, _, _} <- Handlers], + lists:foreach(fun(Pid) -> Pid ! stop end, Pids), + exit(normal); + + Any -> + tsp("otp_9847_server_main -> received" + "~n Any: ~p", [Any]), + exit({crap, Any}) + + after 0 -> + tsp("otp_9847_server_main -> nothing in queue"), + otp_9847_server_main(TC, ListenSocket, Answer, Handlers) + end; + + Error -> + exit(Error) + end. + + +otp_9847_handler(TC, Sock, Answer) -> + tsp("otp_9847_handler -> entry with" + "~n TC: ~p" + "~n Sock: ~p" + "~n Answer: ~p", [TC, Sock, Answer]), + Self = self(), + {Pid, Mon} = + spawn_opt(fun() -> + otp_9847_handler_init(TC, Self, Sock, Answer) + end, + [monitor]), + receive + {port, Port} -> + tsp("otp_9847_handler -> received port message (from ~p)" + "~n Port: ~p", [Pid, Port]), + {Pid, Mon, Port} + end. + + +otp_9847_handler_init(TC, Server, Sock, Answer) -> + tsp("otp_9847_handler_init -> entry with" + "~n TC: ~p" + "~n Server: ~p" + "~n Sock: ~p" + "~n Answer: ~p", [TC, Server, Sock, Answer]), + {ok, Port} = inet:port(Sock), + Server ! {port, Port}, + receive + owner -> + tsp("otp_9847_handler_init -> " + "received owner message - activate socket"), + inet:setopts(Sock, [{active, true}]), + otp_9847_handler_main(TC, Server, Sock, Answer, [?HTTP_MAX_HEADER_SIZE]) + end. + +otp_9847_handler_main(TC, Server, Sock, Answer, ParseArgs) -> + tsp("otp_9847_handler_main -> entry with" + "~n TC: ~p" + "~n Server: ~p" + "~n Sock: ~p" + "~n Answer: ~p" + "~n ParseArgs: ~p", [TC, Server, Sock, Answer, ParseArgs]), + receive + stop -> + tsp("otp_9847_handler_main -> received stop request"), + exit(normal); + + {tcp, Sock, _Data} when Answer =:= false -> + tsp("otp_9847_handler_main -> received tcp data - no answer"), + TC ! {data_received, self()}, + inet:setopts(Sock, [{active, true}]), + %% Ignore all data + otp_9847_handler_main(TC, Server, Sock, Answer, ParseArgs); + + {tcp, Sock, Data} when Answer =:= true -> + tsp("otp_9847_handler_main -> received tcp data - answer"), + TC ! {data_received, self()}, + inet:setopts(Sock, [{active, true}]), + NewParseArgs = otp_9847_handler_request(Sock, [Data|ParseArgs]), + otp_9847_handler_main(TC, Server, Sock, Answer, NewParseArgs); + + {tcp_closed, Sock} -> + tsp("otp_9847_handler_main -> received tcp socket closed"), + exit(normal); + + {tcp_error, Sock, Reason} -> + tsp("otp_9847_handler_main -> socket error: ~p", [Reason]), + (catch gen_tcp:close(Sock)), + exit(normal) + + %% after 30000 -> + %% gen_tcp:close(Sock), + %% exit(normal) + end. + +otp_9847_handler_request(Sock, Args) -> + Msg = + case httpd_request:parse(Args) of + {ok, {_, "/index.html" = _RelUrl, _, _, _}} -> + B = + "<HTML><BODY>" ++ + "...some body part..." ++ + "</BODY></HTML>", + Len = integer_to_list(length(B)), + "HTTP/1.1 200 ok\r\n" ++ + "Content-Length:" ++ Len ++ "\r\n\r\n" ++ B + end, + gen_tcp:send(Sock, Msg), + [?HTTP_MAX_HEADER_SIZE]. + + + +%%------------------------------------------------------------------------- + options(doc) -> ["Test the option parameters."]; options(suite) -> @@ -2071,6 +2391,7 @@ options(Config) when is_list(Config) -> %%------------------------------------------------------------------------- + http_invalid_http(doc) -> ["Test parse error"]; http_invalid_http(suite) -> @@ -2861,6 +3182,7 @@ otp_8739_dummy_server_main(_Parent, ListenSocket) -> exit(Error) end. + %%------------------------------------------------------------------------- initial_server_connect(doc) -> @@ -2979,7 +3301,7 @@ receive_streamed_body(RequestId, Body) -> {http, {RequestId, stream_end, _Headers}} -> Body; {http, Msg} -> - test_server:fail(Msg) + tsf(Msg) end. receive_streamed_body(RequestId, Body, Pid) -> @@ -2993,7 +3315,7 @@ receive_streamed_body(RequestId, Body, Pid) -> {http, {RequestId, stream_end, _Headers}} -> Body; {http, Msg} -> - test_server:fail(Msg) + tsf(Msg) end. %% Perform a synchronous stop @@ -3455,7 +3777,7 @@ handle_auth("Basic " ++ UserInfo, Challange, DefaultResponse) -> end. check_cookie([]) -> - test_server:fail(no_cookie_header); + tsf(no_cookie_header); check_cookie(["cookie:" ++ _Value | _]) -> ok; check_cookie([_Head | Tail]) -> @@ -3513,9 +3835,9 @@ p(F, A) -> io:format("~p ~w:" ++ F ++ "~n", [self(), ?MODULE | A]). tsp(F) -> - tsp(F, []). + inets_test_lib:tsp(F). tsp(F, A) -> - test_server:format("~p ~p:" ++ F ++ "~n", [self(), ?MODULE | A]). + inets_test_lib:tsp(F, A). tsf(Reason) -> test_server:fail(Reason). @@ -3570,3 +3892,6 @@ ensure_started(App) when is_atom(App) -> throw({error, {failed_starting, App, Error}}) end. + +skip(Reason) -> + {skip, Reason}. diff --git a/lib/inets/test/httpd_1_1.erl b/lib/inets/test/httpd_1_1.erl index 2a6110e3ea..07d94ea97a 100644 --- a/lib/inets/test/httpd_1_1.erl +++ b/lib/inets/test/httpd_1_1.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2010. 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 @@ -19,7 +19,6 @@ %% -module(httpd_1_1). --author('[email protected]'). -include("test_server.hrl"). -include("test_server_line.hrl"). @@ -159,70 +158,79 @@ if_test(Type, Port, Host, Node, DocRoot)-> calendar:datetime_to_gregorian_seconds(FileInfo#file_info.mtime), Mod = httpd_util:rfc1123_date(calendar:gregorian_seconds_to_datetime( - CreatedSec-1)), - + CreatedSec-1)), + %% Test that we get the data when the file is modified ok = httpd_test_lib:verify_request(Type, Host, Port, Node, - "GET / HTTP/1.1\r\nHost:" ++ Host ++ - "\r\nIf-Modified-Since:" ++ - Mod ++ "\r\n\r\n", - [{statuscode, 200}]), - Mod1 = httpd_util:rfc1123_date(calendar:gregorian_seconds_to_datetime( - CreatedSec+100)), - ok = httpd_test_lib:verify_request(Type,Host,Port,Node, - "GET / HTTP/1.1\r\nHost:" - ++ Host ++"\r\nIf-Modified-Since:" - ++ Mod1 ++"\r\n\r\n", - [{statuscode, 304}]), + "GET / HTTP/1.1\r\nHost:" ++ Host ++ + "\r\nIf-Modified-Since:" ++ + Mod ++ "\r\n\r\n", + [{statuscode, 200}]), + Mod1 = httpd_util:rfc1123_date(calendar:gregorian_seconds_to_datetime( + CreatedSec+100)), + ok = httpd_test_lib:verify_request(Type,Host,Port,Node, + "GET / HTTP/1.1\r\nHost:" + ++ Host ++"\r\nIf-Modified-Since:" + ++ Mod1 ++"\r\n\r\n", + [{statuscode, 304}]), + + ok = httpd_test_lib:verify_request(Type, Host, Port, Node, + "GET / HTTP/1.1\r\nHost:" ++ Host ++ + "\r\nIf-Modified-Since:" ++ + "AAA[...]AAAA" ++ "\r\n\r\n", + [{statuscode, 400}]), + + Mod2 = httpd_util:rfc1123_date(calendar:gregorian_seconds_to_datetime( - CreatedSec+1)), + CreatedSec+1)), %% Control that the If-Unmodified-Header lmits the response ok = httpd_test_lib:verify_request(Type,Host,Port,Node, - "GET / HTTP/1.1\r\nHost:" - ++ Host ++ - "\r\nIf-Unmodified-Since:" ++ Mod2 - ++ "\r\n\r\n", - [{statuscode, 200}]), + "GET / HTTP/1.1\r\nHost:" + ++ Host ++ + "\r\nIf-Unmodified-Since:" ++ Mod2 + ++ "\r\n\r\n", + [{statuscode, 200}]), Mod3 = httpd_util:rfc1123_date(calendar:gregorian_seconds_to_datetime( - CreatedSec-1)), + CreatedSec-1)), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, - "GET / HTTP/1.1\r\nHost:" - ++ Host ++ - "\r\nIf-Unmodified-Since:"++ Mod3 - ++"\r\n\r\n", - [{statuscode, 412}]), - + "GET / HTTP/1.1\r\nHost:" + ++ Host ++ + "\r\nIf-Unmodified-Since:"++ Mod3 + ++"\r\n\r\n", + [{statuscode, 412}]), + %% Control that we get the body when the etag match ok = httpd_test_lib:verify_request(Type, Host, Port, Node, - "GET / HTTP/1.1\r\nHost:" ++ Host - ++"\r\n"++ - "If-Match:"++ - httpd_util:create_etag(FileInfo)++ - "\r\n\r\n", - [{statuscode, 200}]), + "GET / HTTP/1.1\r\nHost:" ++ Host + ++"\r\n"++ + "If-Match:"++ + httpd_util:create_etag(FileInfo)++ + "\r\n\r\n", + [{statuscode, 200}]), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, - "GET / HTTP/1.1\r\nHost:" ++ - Host ++ "\r\n"++ - "If-Match:NotEtag\r\n\r\n", - [{statuscode, 412}]), + "GET / HTTP/1.1\r\nHost:" ++ + Host ++ "\r\n"++ + "If-Match:NotEtag\r\n\r\n", + [{statuscode, 412}]), %% Control the response when the if-none-match header is there ok = httpd_test_lib:verify_request(Type, Host, Port, Node, - "GET / HTTP/1.1\r\nHost:" - ++ Host ++"\r\n"++ - "If-None-Match:NoTaag," ++ - httpd_util:create_etag(FileInfo) ++ - "\r\n\r\n", - [{statuscode, 304}]), - + "GET / HTTP/1.1\r\nHost:" + ++ Host ++"\r\n"++ + "If-None-Match:NoTaag," ++ + httpd_util:create_etag(FileInfo) ++ + "\r\n\r\n", + [{statuscode, 304}]), + ok = httpd_test_lib:verify_request(Type, Host, Port, Node, - "GET / HTTP/1.1\r\nHost:" - ++ Host ++ "\r\n"++ - "If-None-Match:NotEtag," - "NeihterEtag\r\n\r\n", - [{statuscode,200}]). + "GET / HTTP/1.1\r\nHost:" + ++ Host ++ "\r\n"++ + "If-None-Match:NotEtag," + "NeihterEtag\r\n\r\n", + [{statuscode,200}]), + ok. http_trace(Type, Port, Host, Node)-> ok = httpd_test_lib:verify_request(Type, Host, Port, Node, diff --git a/lib/inets/test/httpd_SUITE.erl b/lib/inets/test/httpd_SUITE.erl index 1112208295..ccc7aea2aa 100644 --- a/lib/inets/test/httpd_SUITE.erl +++ b/lib/inets/test/httpd_SUITE.erl @@ -740,6 +740,19 @@ end_per_testcase2(Case, Config) -> %%------------------------------------------------------------------------- +http_1_1_ip(doc) -> + ["HTTP/1.1"]; +http_1_1_ip(suite) -> + [ + ip_host, + ip_chunked, + ip_expect, + ip_range, + ip_if_test, + ip_http_trace, + ip_http1_1_head, + ip_mod_cgi_chunked_encoding_test + ]. %%------------------------------------------------------------------------- @@ -2571,24 +2584,24 @@ ticket_5913(doc) -> ["Tests that a header without last-modified is handled"]; ticket_5913(suite) -> []; ticket_5913(Config) -> - ok=httpd_test_lib:verify_request(ip_comm, ?config(host, Config), - ?IP_PORT, ?config(node, Config), + ok = httpd_test_lib:verify_request(ip_comm, ?config(host, Config), + ?IP_PORT, ?config(node, Config), "GET /cgi-bin/erl/httpd_example:get_bin " "HTTP/1.0\r\n\r\n", [{statuscode, 200}, - {version, "HTTP/1.0"}]), + {version, "HTTP/1.0"}]), ok. ticket_6003(doc) -> ["Tests that a URI with a bad hexadecimal code is handled"]; ticket_6003(suite) -> []; ticket_6003(Config) -> - ok=httpd_test_lib:verify_request(ip_comm, ?config(host, Config), - ?IP_PORT, ?config(node, Config), - "GET http://www.erlang.org/%skalle " - "HTTP/1.0\r\n\r\n", - [{statuscode, 400}, - {version, "HTTP/1.0"}]), + ok = httpd_test_lib:verify_request(ip_comm, ?config(host, Config), + ?IP_PORT, ?config(node, Config), + "GET http://www.erlang.org/%skalle " + "HTTP/1.0\r\n\r\n", + [{statuscode, 400}, + {version, "HTTP/1.0"}]), ok. ticket_7304(doc) -> diff --git a/lib/inets/test/httpd_basic_SUITE.erl b/lib/inets/test/httpd_basic_SUITE.erl index f23d0b4765..4cd38f2ec4 100644 --- a/lib/inets/test/httpd_basic_SUITE.erl +++ b/lib/inets/test/httpd_basic_SUITE.erl @@ -59,9 +59,28 @@ init_per_suite(Config) -> "~n Config: ~p", [Config]), ok = inets:start(), PrivDir = ?config(priv_dir, Config), - HttpdConf = [{port, 0}, {ipfamily, inet}, - {server_name, "httpd_test"}, {server_root, PrivDir}, - {document_root, PrivDir}, {bind_address, "localhost"}], + + Dummy = +"<HTML> +<HEAD> +<TITLE>/index.html</TITLE> +</HEAD> +<BODY> +DUMMY +</BODY> +</HTML>", + + DummyFile = filename:join([PrivDir,"dummy.html"]), + {ok, Fd} = file:open(DummyFile, [write]), + ok = file:write(Fd, Dummy), + ok = file:close(Fd), + HttpdConf = [{port, 0}, + {ipfamily, inet}, + {server_name, "httpd_test"}, + {server_root, PrivDir}, + {document_root, PrivDir}, + {bind_address, "localhost"}], + [{httpd_conf, HttpdConf} | Config]. %%-------------------------------------------------------------------- @@ -133,6 +152,10 @@ uri_too_long_414(Config) when is_list(Config) -> {version, "HTTP/0.9"}]), inets:stop(httpd, Pid). + +%%------------------------------------------------------------------------- +%%------------------------------------------------------------------------- + header_too_long_413(doc) -> ["Test that too long headers's get 413 HTTP code"]; header_too_long_413(suite) -> @@ -152,34 +175,92 @@ header_too_long_413(Config) when is_list(Config) -> {version, "HTTP/1.1"}]), inets:stop(httpd, Pid). + +%%------------------------------------------------------------------------- +%%------------------------------------------------------------------------- + escaped_url_in_error_body(doc) -> ["Test Url-encoding see OTP-8940"]; escaped_url_in_error_body(suite) -> []; escaped_url_in_error_body(Config) when is_list(Config) -> - tsp("escaped_url_in_error_body -> entry with" - "~n Config: ~p", [Config]), - HttpdConf = ?config(httpd_conf, Config), - {ok, Pid} = inets:start(httpd, [{port, 0} | HttpdConf]), - Info = httpd:info(Pid), - Port = proplists:get_value(port, Info), - _Address = proplists:get_value(bind_address, Info), - Path = "/<b>this_is_bold</b>", - URL = ?URL_START ++ integer_to_list(Port) ++ Path, - EscapedPath = http_uri:encode(Path), - {ok, {404, Body1}} = httpc:request(get, {URL, []}, - [{url_encode, true}, - {version, "HTTP/1.0"}], - [{full_result, false}]), - EscapedPath = find_URL_path(string:tokens(Body1, " ")), - {ok, {404, Body2}} = httpc:request(get, {URL, []}, - [{url_encode, false}, - {version, "HTTP/1.0"}], - [{full_result, false}]), + tsp("escaped_url_in_error_body -> entry"), + HttpdConf = ?config(httpd_conf, Config), + {ok, Pid} = inets:start(httpd, [{port, 0} | HttpdConf]), + Info = httpd:info(Pid), + Port = proplists:get_value(port, Info), + _Address = proplists:get_value(bind_address, Info), + + %% Request 1 + tsp("escaped_url_in_error_body -> request 1"), + URL1 = ?URL_START ++ integer_to_list(Port), + %% Make sure the server is ok, by making a request for a valid page + case httpc:request(get, {URL1 ++ "/dummy.html", []}, + [{url_encode, false}, + {version, "HTTP/1.0"}], + [{full_result, false}]) of + {ok, {200, _}} -> + %% Don't care about the the body, just that we get a ok response + ok; + {ok, UnexpectedOK1} -> + tsf({unexpected_ok_1, UnexpectedOK1}) + end, + + %% Request 2 + tsp("escaped_url_in_error_body -> request 2"), + %% Make sure the server is ok, by making a request for a valid page + case httpc:request(get, {URL1 ++ "/dummy.html", []}, + [{url_encode, true}, + {version, "HTTP/1.0"}], + [{full_result, false}]) of + {ok, {200, _}} -> + %% Don't care about the the body, just that we get a ok response + ok; + {ok, UnexpectedOK2} -> + tsf({unexpected_ok_2, UnexpectedOK2}) + end, + + %% Request 3 + tsp("escaped_url_in_error_body -> request 3"), + %% Ask for a non-existing page(1) + Path = "/<b>this_is_bold<b>", HTMLEncodedPath = http_util:html_encode(Path), - HTMLEncodedPath = find_URL_path(string:tokens(Body2, " ")), + URL2 = URL1 ++ Path, + case httpc:request(get, {URL2, []}, + [{url_encode, true}, + {version, "HTTP/1.0"}], + [{full_result, false}]) of + {ok, {404, Body3}} -> + case find_URL_path(string:tokens(Body3, " ")) of + HTMLEncodedPath -> + ok; + BadPath3 -> + tsf({unexpected_path_3, HTMLEncodedPath, BadPath3}) + end; + {ok, UnexpectedOK3} -> + tsf({unexpected_ok_1, UnexpectedOK3}) + end, + + %% Request 4 + tsp("escaped_url_in_error_body -> request 4"), + %% Ask for a non-existing page(2) + case httpc:request(get, {URL2, []}, + [{url_encode, false}, + {version, "HTTP/1.0"}], + [{full_result, false}]) of + {ok, {404, Body4}} -> + case find_URL_path(string:tokens(Body4, " ")) of + HTMLEncodedPath -> + ok; + BadPath4 -> + tsf({unexpected_path_2, HTMLEncodedPath, BadPath4}) + end; + {ok, UnexpectedOK4} -> + tsf({unexpected_ok_4, UnexpectedOK4}) + end, + tsp("escaped_url_in_error_body -> stop inets"), inets:stop(httpd, Pid), - tsp("escaped_url_in_error_body -> done"), + tsp("escaped_url_in_error_body -> done"), ok. find_URL_path([]) -> @@ -191,7 +272,14 @@ find_URL_path([_ | Rest]) -> tsp(F) -> - tsp(F, []). + inets_test_lib:tsp(F). tsp(F, A) -> - test_server:format("~p ~p:" ++ F ++ "~n", [self(), ?MODULE | A]). + inets_test_lib:tsp(F, A). + +tsf(Reason) -> + test_server:fail(Reason). + + +skip(Reason) -> + {skip, Reason}. diff --git a/lib/inets/test/httpd_mod.erl b/lib/inets/test/httpd_mod.erl index 1754cec7bc..5016cdb9e6 100644 --- a/lib/inets/test/httpd_mod.erl +++ b/lib/inets/test/httpd_mod.erl @@ -1,8 +1,8 @@ %% %% %CopyrightBegin% -%% +%% %% 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 %% compliance with the License. You should have received a copy of the @@ -88,13 +88,13 @@ actions(Type, Port, Host, Node) -> %%------------------------------------------------------------------------- security(ServerRoot, Type, Port, Host, Node) -> -%% io:format(user, "~w:security -> entry with" -%% "~n ServerRoot: ~p" -%% "~n Type: ~p" -%% "~n Port: ~p" -%% "~n Host: ~p" -%% "~n Node: ~p" -%% "~n", [?MODULE, ServerRoot, Type, Port, Host, Node]), + %% io:format(user, "~w:security -> entry with" + %% "~n ServerRoot: ~p" + %% "~n Type: ~p" + %% "~n Port: ~p" + %% "~n Host: ~p" + %% "~n Node: ~p" + %% "~n", [?MODULE, ServerRoot, Type, Port, Host, Node]), %% io:format(user, "~w:security -> register~n", [?MODULE]), global:register_name(mod_security_test, self()), % Receive events @@ -175,8 +175,8 @@ security(ServerRoot, Type, Port, Host, Node) -> [{"one",_, Port, OpenDir,_}] -> ok; Blocked -> - io:format(user, "~w:security -> Blocked: ~p" - "~n", [?MODULE, Blocked]), + %% io:format(user, "~w:security -> Blocked: ~p" + %% "~n", [?MODULE, Blocked]), exit({unexpected_blocked, Blocked}) end, @@ -917,11 +917,11 @@ list_users(Node, Root, _Host, Port, Dir) -> receive_security_event(Event, Node, Port) -> -%% io:format(user, "~w:receive_security_event -> entry with" -%% "~n Event: ~p" -%% "~n Node: ~p" -%% "~n Port: ~p" -%% "~n", [?MODULE, Event, Node, Port]), + %% io:format(user, "~w:receive_security_event -> entry with" + %% "~n Event: ~p" + %% "~n Node: ~p" + %% "~n Port: ~p" + %% "~n", [?MODULE, Event, Node, Port]), receive Event -> ok; diff --git a/lib/inets/test/httpd_test_lib.erl b/lib/inets/test/httpd_test_lib.erl index 581461fe03..1c7bb512cc 100644 --- a/lib/inets/test/httpd_test_lib.erl +++ b/lib/inets/test/httpd_test_lib.erl @@ -1,8 +1,8 @@ %% %% %CopyrightBegin% -%% +%% %% Copyright Ericsson AB 2001-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 @@ -140,6 +140,9 @@ request(#state{mfa = {Module, Function, Args}, HeadRequest = lists:sublist(RequestStr, 1, 4), receive {tcp, Socket, Data} -> + io:format("~p ~w[~w]request -> received (tcp) data" + "~n Data: ~p" + "~n", [self(), ?MODULE, ?LINE, Data]), print(tcp, Data, State), case Module:Function([Data | Args]) of {ok, Parsed} -> @@ -150,11 +153,19 @@ request(#state{mfa = {Module, Function, Args}, request(State#state{mfa = NewMFA}, TimeOut) end; {tcp_closed, Socket} when Function =:= whole_body -> + io:format("~p ~w[~w]request -> " + "received (tcp) closed when whole_body" + "~n", [self(), ?MODULE, ?LINE]), print(tcp, "closed", State), State#state{body = hd(Args)}; {tcp_closed, Socket} -> + io:format("~p ~w[~w]request -> received (tcp) closed" + "~n", [self(), ?MODULE, ?LINE]), test_server:fail(connection_closed); {tcp_error, Socket, Reason} -> + io:format("~p ~w[~w]request -> received (tcp) error" + "~n Reason: ~p" + "~n", [self(), ?MODULE, ?LINE, Reason]), test_server:fail({tcp_error, Reason}); {ssl, Socket, Data} -> print(ssl, Data, State), @@ -174,11 +185,21 @@ request(#state{mfa = {Module, Function, Args}, {ssl_error, Socket, Reason} -> test_server:fail({ssl_error, Reason}) after TimeOut -> + io:format("~p ~w[~w]request -> timeout" + "~n", [self(), ?MODULE, ?LINE]), test_server:fail(connection_timed_out) end. handle_http_msg({Version, StatusCode, ReasonPharse, Headers, Body}, State = #state{request = RequestStr}) -> + io:format("~p ~w[~w]handle_http_msg -> entry with" + "~n Version: ~p" + "~n StatusCode: ~p" + "~n ReasonPharse: ~p" + "~n Headers: ~p" + "~n Body: ~p" + "~n", [self(), ?MODULE, ?LINE, + Version, StatusCode, ReasonPharse, Headers, Body]), case is_expect(RequestStr) of true -> State#state{status_line = {Version, @@ -235,13 +256,14 @@ handle_http_body(Body, State = #state{headers = Headers, end. validate(RequestStr, #state{status_line = {Version, StatusCode, _}, - headers = Headers, - body = Body}, Options, N, P) -> + headers = Headers, + body = Body}, Options, N, P) -> %% tsp("validate -> entry with" %% "~n StatusCode: ~p" %% "~n Headers: ~p" %% "~n Body: ~p", [StatusCode, Headers, Body]), + check_version(Version, Options), case lists:keysearch(statuscode, 1, Options) of {value, _} -> @@ -255,6 +277,7 @@ validate(RequestStr, #state{status_line = {Version, StatusCode, _}, list_to_integer(Headers#http_response_h.'content-length'), Body). + %%-------------------------------------------------------------------- %% Internal functions %%------------------------------------------------------------------ @@ -263,21 +286,20 @@ check_version(Version, Options) -> {value, {version, Version}} -> ok; {value, {version, Ver}} -> - test_server:fail({wrong_version, [{got, Version}, - {expected, Ver}]}); + tsf({wrong_version, [{got, Version}, + {expected, Ver}]}); _ -> case Version of "HTTP/1.1" -> ok; _ -> - test_server:fail({wrong_version, [{got, Version}, - {expected, "HTTP/1.1"}]}) + tsf({wrong_version, [{got, Version}, + {expected, "HTTP/1.1"}]}) end end. check_status_code(StatusCode, [], Options) -> - test_server:fail({wrong_status_code, [{got, StatusCode}, - {expected, Options}]}); + tsf({wrong_status_code, [{got, StatusCode}, {expected, Options}]}); check_status_code(StatusCode, Current = [_ | Rest], Options) -> case lists:keysearch(statuscode, 1, Current) of {value, {statuscode, StatusCode}} -> @@ -285,8 +307,7 @@ check_status_code(StatusCode, Current = [_ | Rest], Options) -> {value, {statuscode, _OtherStatus}} -> check_status_code(StatusCode, Rest, Options); false -> - test_server:fail({wrong_status_code, [{got, StatusCode}, - {expected, Options}]}) + tsf({wrong_status_code, [{got, StatusCode}, {expected, Options}]}) end. do_validate(_, [], _, _) -> @@ -317,8 +338,7 @@ do_validate(Header, [{header, HeaderField, Value}|Rest],N,P) -> Header}) end, do_validate(Header, Rest, N, P); -do_validate(Header,[{no_last_modified,HeaderField}|Rest],N,P) -> -% io:format("Header: ~p~nHeaderField: ~p~n",[Header,HeaderField]), +do_validate(Header,[{no_last_modified, HeaderField}|Rest],N,P) -> case lists:keysearch(HeaderField,1,Header) of {value,_} -> test_server:fail({wrong_header_field_value, HeaderField, @@ -331,7 +351,6 @@ do_validate(Header, [_Unknown | Rest], N, P) -> do_validate(Header, Rest, N, P). is_expect(RequestStr) -> - case inets_regexp:match(RequestStr, "xpect:100-continue") of {match, _, _}-> true; @@ -340,15 +359,15 @@ is_expect(RequestStr) -> end. %% OTP-5775, content-length -check_body("GET /cgi-bin/erl/httpd_example:get_bin HTTP/1.0\r\n\r\n", 200, "text/html", Length, _Body) when Length /= 274-> - test_server:fail(content_length_error); +check_body("GET /cgi-bin/erl/httpd_example:get_bin HTTP/1.0\r\n\r\n", 200, "text/html", Length, _Body) when (Length =/= 274) -> + tsf(content_length_error); check_body("GET /cgi-bin/cgi_echo HTTP/1.0\r\n\r\n", 200, "text/plain", _, Body) -> case size(Body) of 100 -> ok; _ -> - test_server:fail(content_length_error) + tsf(content_length_error) end; check_body(RequestStr, 200, "text/html", _, Body) -> diff --git a/lib/inets/vsn.mk b/lib/inets/vsn.mk index 0e77bf913d..50c7915cb2 100644 --- a/lib/inets/vsn.mk +++ b/lib/inets/vsn.mk @@ -2,7 +2,7 @@ # %CopyrightBegin% # -# Copyright Ericsson AB 2001-2011. All Rights Reserved. +# Copyright Ericsson AB 2001-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 @@ -18,7 +18,7 @@ # %CopyrightEnd% APPLICATION = inets -INETS_VSN = 5.7.1 +INETS_VSN = 5.7.3 PRE_VSN = APP_VSN = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)" diff --git a/lib/mnesia/doc/src/notes.xml b/lib/mnesia/doc/src/notes.xml index 8ef573a948..1bb80f8fe3 100644 --- a/lib/mnesia/doc/src/notes.xml +++ b/lib/mnesia/doc/src/notes.xml @@ -38,7 +38,35 @@ thus constitutes one section in this document. The title of each section is the version number of Mnesia.</p> - <section><title>Mnesia 4.5</title> + <section><title>Mnesia 4.5.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fix deadlock in mnesia:del_table_copy/2.</p> + <p> + Own Id: OTP-9689 Aux Id: seq11927 </p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Allow schema operations when using different mnesia + versions.</p> + <p> + Own Id: OTP-9657 Aux Id: seq11926 </p> + </item> + </list> + </section> + +</section> + +<section><title>Mnesia 4.5</title> <section><title>Fixed Bugs and Malfunctions</title> <list> diff --git a/lib/mnesia/src/mnesia.appup.src b/lib/mnesia/src/mnesia.appup.src index fe4e5e2e7a..e0954ad206 100644 --- a/lib/mnesia/src/mnesia.appup.src +++ b/lib/mnesia/src/mnesia.appup.src @@ -1,12 +1,14 @@ %% -*- erlang -*- -{"%VSN%", +{"%VSN%", [ + {"4.5", [{restart_application, mnesia}]}, {"4.4.19", [{restart_application, mnesia}]}, {"4.4.18", [{restart_application, mnesia}]}, {"4.4.17", [{restart_application, mnesia}]}, {"4.4.16", [{restart_application, mnesia}]} ], [ + {"4.5", [{restart_application, mnesia}]}, {"4.4.19", [{restart_application, mnesia}]}, {"4.4.18", [{restart_application, mnesia}]}, {"4.4.17", [{restart_application, mnesia}]}, diff --git a/lib/mnesia/src/mnesia_bup.erl b/lib/mnesia/src/mnesia_bup.erl index 47dcdad7ac..14414537b9 100644 --- a/lib/mnesia/src/mnesia_bup.erl +++ b/lib/mnesia/src/mnesia_bup.erl @@ -372,7 +372,9 @@ mk_str() -> lists:concat([node()] ++ Now ++ ".TMP"). make_initial_backup(Ns, Opaque, Mod) -> - Schema = [{schema, schema, mnesia_schema:get_initial_schema(disc_copies, Ns)}], + Orig = mnesia_schema:get_initial_schema(disc_copies, Ns), + Modded = proplists:delete(storage_properties, proplists:delete(majority, Orig)), + Schema = [{schema, schema, Modded}], O2 = do_apply(Mod, open_write, [Opaque], Opaque), O3 = do_apply(Mod, write, [O2, [mnesia_log:backup_log_header()]], O2), O4 = do_apply(Mod, write, [O3, Schema], O3), diff --git a/lib/mnesia/src/mnesia_controller.erl b/lib/mnesia/src/mnesia_controller.erl index 1d3bd55b48..6a561394d5 100644 --- a/lib/mnesia/src/mnesia_controller.erl +++ b/lib/mnesia/src/mnesia_controller.erl @@ -289,40 +289,7 @@ get_remote_cstructs() -> get_cstructs() -> {cstructs, Cstructs, Running} = call(get_cstructs), Node = node(group_leader()), - {cstructs, normalize_cstructs(Cstructs, Node), Running}. - -normalize_cstructs(Cstructs, Node) -> - %% backward-compatibility hack; normalize before returning - case rpc:call(Node, mnesia_lib, val, [{schema,cstruct}]) of - {badrpc, _} -> - %% assume it's not a schema merge - Cstructs; - #cstruct{} -> - %% same format - Cstructs; - Cstruct -> - %% some other format - RemoteFields = [F || {F,_} <- rpc:call(Node, mnesia_schema, cs2list, [Cstruct])], - [convert_cs(Cs, RemoteFields) || Cs <- Cstructs] - end. - -convert_cs(Cs, Fields) -> - MyFields = record_info(fields, cstruct), - convert(tl(tuple_to_list(Cs)), MyFields, Fields, []). - -convert([H|T], [F|FsL], [F|FsR], Acc) -> - convert(T, FsL, FsR, [H|Acc]); -convert([H|T], [Fl|FsL] = L, [Fr|FsR] = R, Acc) -> - case {lists:member(Fl, FsR), lists:member(Fr, FsL)} of - {true, false} -> - convert(T, L, FsR, [H|Acc]); - {false, true} -> - %% Field Fl doesn't exist on receiver side; skip. - convert(T, FsL, R, Acc) - end; -convert([], _, _, Acc) -> - list_to_tuple([cstruct|lists:reverse(Acc)]). - + {cstructs, mnesia_schema:normalize_cs(Cstructs, Node), Running}. update(Fun) -> call({update,Fun}). diff --git a/lib/mnesia/src/mnesia_event.erl b/lib/mnesia/src/mnesia_event.erl index ec6b99ecaa..5a060a28ff 100644 --- a/lib/mnesia/src/mnesia_event.erl +++ b/lib/mnesia/src/mnesia_event.erl @@ -121,7 +121,7 @@ handle_system_event({mnesia_up, Node}, State) -> {ok, State#state{nodes = Nodes}}; handle_system_event({mnesia_down, Node}, State) -> - case mnesia:system_info(fallback_activated) of + case mnesia:system_info(fallback_activated) andalso Node =/= node() of true -> case mnesia_monitor:get_env(fallback_error_function) of {mnesia, lkill} -> @@ -129,8 +129,8 @@ handle_system_event({mnesia_down, Node}, State) -> "must be restarted. Forcing shutdown " "after mnesia_down from ~p...~n", report_fatal(Msg, [Node], nocore, State#state.dumped_core), - mnesia:lkill(), - exit(fatal); + catch exit(whereis(mnesia_monitor), fatal), + {ok, State}; {UserMod, UserFunc} -> Msg = "Warning: A fallback is installed and Mnesia got mnesia_down " "from ~p. ~n", diff --git a/lib/mnesia/src/mnesia_frag.erl b/lib/mnesia/src/mnesia_frag.erl index 9e77fe0b9f..4a1616e054 100644 --- a/lib/mnesia/src/mnesia_frag.erl +++ b/lib/mnesia/src/mnesia_frag.erl @@ -758,7 +758,7 @@ make_activate(Tab, Props) -> [] -> Cs2 = Cs#cstruct{frag_properties = Props}, [Cs3] = expand_cstruct(Cs2, activate), - TabDef = mnesia_schema:cs2list(Cs3), + TabDef = mnesia_schema:vsn_cs2list(Cs3), Op = {op, change_table_frag, activate, TabDef}, [[Op]]; BadProps -> @@ -783,7 +783,7 @@ make_deactivate(Tab) -> mnesia:abort({combine_error, Tab, "Too many fragments"}); true -> Cs2 = Cs#cstruct{frag_properties = []}, - TabDef = mnesia_schema:cs2list(Cs2), + TabDef = mnesia_schema:vsn_cs2list(Cs2), Op = {op, change_table_frag, deactivate, TabDef}, [[Op]] end. @@ -850,7 +850,7 @@ make_add_frag(Tab, SortedNs) -> SplitOps = split(Tab, FH2, FromIndecies, FragNames, []), Cs2 = replace_frag_hash(Cs, FH2), - TabDef = mnesia_schema:cs2list(Cs2), + TabDef = mnesia_schema:vsn_cs2list(Cs2), BaseOp = {op, change_table_frag, {add_frag, SortedNs}, TabDef}, [BaseOp, NewOp | SplitOps]. @@ -962,7 +962,7 @@ make_del_frag(Tab) -> LastFrag = element(N, FragNames), [LastOp] = mnesia_schema:make_delete_table(LastFrag, single_frag), Cs2 = replace_frag_hash(Cs, FH2), - TabDef = mnesia_schema:cs2list(Cs2), + TabDef = mnesia_schema:vsn_cs2list(Cs2), BaseOp = {op, change_table_frag, del_frag, TabDef}, [BaseOp, LastOp | MergeOps]; _ -> @@ -1075,7 +1075,7 @@ make_add_node(Tab, Node) when is_atom(Node) -> Props = Cs#cstruct.frag_properties, Props2 = lists:keyreplace(node_pool, 1, Props, {node_pool, Pool2}), Cs2 = Cs#cstruct{frag_properties = Props2}, - TabDef = mnesia_schema:cs2list(Cs2), + TabDef = mnesia_schema:vsn_cs2list(Cs2), Op = {op, change_table_frag, {add_node, Node}, TabDef}, [Op]; true -> @@ -1104,7 +1104,7 @@ make_del_node(Tab, Node) when is_atom(Node) -> Pool2 = Pool -- [Node], Props = lists:keyreplace(node_pool, 1, Cs#cstruct.frag_properties, {node_pool, Pool2}), Cs2 = Cs#cstruct{frag_properties = Props}, - TabDef = mnesia_schema:cs2list(Cs2), + TabDef = mnesia_schema:vsn_cs2list(Cs2), Op = {op, change_table_frag, {del_node, Node}, TabDef}, [Op]; false -> diff --git a/lib/mnesia/src/mnesia_monitor.erl b/lib/mnesia/src/mnesia_monitor.erl index e110ad3241..8cb2e92c08 100644 --- a/lib/mnesia/src/mnesia_monitor.erl +++ b/lib/mnesia/src/mnesia_monitor.erl @@ -536,7 +536,11 @@ handle_info({'EXIT', Pid, R}, State) when Pid == State#state.supervisor -> handle_info({'EXIT', Pid, fatal}, State) when node(Pid) == node() -> dbg_out("~p got FATAL ERROR from: ~p~n",[?MODULE, Pid]), - exit(State#state.supervisor, shutdown), + %% This may hang supervisor if a shutdown happens at the same time as an fatal + %% is in progress + %% exit(State#state.supervisor, shutdown), + %% It is better to kill an innocent process + catch exit(whereis(mnesia_locker), kill), {noreply, State}; handle_info(Msg = {'EXIT',Pid,_}, State) -> diff --git a/lib/mnesia/src/mnesia_schema.erl b/lib/mnesia/src/mnesia_schema.erl index 05be474aea..179e15197e 100644 --- a/lib/mnesia/src/mnesia_schema.erl +++ b/lib/mnesia/src/mnesia_schema.erl @@ -39,9 +39,10 @@ change_table_load_order/2, change_table_majority/2, change_table_frag/2, - clear_table/1, +%% clear_table/1, %% removed since it is not a schema op anymore create_table/1, cs2list/1, + vsn_cs2list/1, del_snmp/1, del_table_copy/2, del_table_index/2, @@ -65,6 +66,7 @@ merge_schema/0, merge_schema/1, move_table/3, + normalize_cs/2, opt_create_dir/2, prepare_commit/3, purge_dir/2, @@ -626,6 +628,17 @@ do_insert_schema_ops(Store, [Head | Tail]) -> do_insert_schema_ops(_Store, []) -> ok. +api_list2cs(List) when is_list(List) -> + Name = pick(unknown, name, List, must), + Keys = check_keys(Name, List, record_info(fields, cstruct)), + check_duplicates(Name, Keys), + list2cs(List); +api_list2cs(Other) -> + mnesia:abort({badarg, Other}). + +vsn_cs2list(Cs) -> + cs2list(need_old_cstructs(), Cs). + cs2list(Cs) when is_record(Cs, cstruct) -> Tags = record_info(fields, cstruct), rec2list(Tags, Tags, 2, Cs); @@ -648,7 +661,7 @@ cs2list(Cs) when element(1, Cs) == cstruct, tuple_size(Cs) == 17 -> cs2list(false, Cs) -> cs2list(Cs); -cs2list(ver4_4_18, Cs) -> +cs2list(ver4_4_18, Cs) -> %% Or earlier Orig = record_info(fields, cstruct), Tags = [name,type,ram_copies,disc_copies,disc_only_copies, load_order,access_mode,index,snmp,local_content, @@ -671,13 +684,19 @@ rec2list([], _, _Pos, _Rec) -> rec2list(Tags, [_|Orig], Pos, Rec) -> rec2list(Tags, Orig, Pos+1, Rec). -api_list2cs(List) when is_list(List) -> - Name = pick(unknown, name, List, must), - Keys = check_keys(Name, List, record_info(fields, cstruct)), - check_duplicates(Name, Keys), - list2cs(List); -api_list2cs(Other) -> - mnesia:abort({badarg, Other}). +normalize_cs(Cstructs, Node) -> + %% backward-compatibility hack; normalize before returning + case need_old_cstructs([Node]) of + false -> + Cstructs; + Version -> + %% some other format + [convert_cs(Version, Cs) || Cs <- Cstructs] + end. + +convert_cs(Version, Cs) -> + Fields = [Value || {_, Value} <- cs2list(Version, Cs)], + list_to_tuple([cstruct|Fields]). list2cs(List) when is_list(List) -> Name = pick(unknown, name, List, must), @@ -1048,7 +1067,7 @@ unsafe_make_create_table(Cs) -> Nodes = mnesia_lib:intersect(mnesia_lib:cs_to_nodes(Cs), RunningNodes), Store = Ts#tidstore.store, mnesia_locker:wlock_no_exist(Tid, Store, Tab, Nodes), - [{op, create_table, cs2list(Cs)}]. + [{op, create_table, vsn_cs2list(Cs)}]. check_if_exists(Tab) -> TidTs = get_tid_ts_and_lock(schema, write), @@ -1133,7 +1152,7 @@ make_delete_table2(Tab) -> Cs = val({Tab, cstruct}), ensure_active(Cs), ensure_writable(Tab), - {op, delete_table, cs2list(Cs)}. + {op, delete_table, vsn_cs2list(Cs)}. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Change fragmentation of a table @@ -1152,10 +1171,6 @@ do_change_table_frag(Tab, _Change) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Clear a table -%% No need for a schema transaction -clear_table(Tab) -> - schema_transaction(fun() -> do_clear_table(Tab) end). - do_clear_table(schema) -> mnesia:abort({bad_type, schema}); do_clear_table(Tab) -> @@ -1166,7 +1181,7 @@ do_clear_table(Tab) -> make_clear_table(Tab) -> Cs = val({Tab, cstruct}), ensure_writable(Tab), - [{op, clear_table, cs2list(Cs)}]. + [{op, clear_table, vsn_cs2list(Cs)}]. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1206,7 +1221,7 @@ make_add_table_copy(Tab, Node, Storage) -> IsRunning == false -> mnesia:abort({not_active, schema, Node}) end, - [{op, add_table_copy, Storage, Node, cs2list(Cs2)}]. + [{op, add_table_copy, Storage, Node, vsn_cs2list(Cs2)}]. del_table_copy(Tab, Node) -> schema_transaction(fun() -> do_del_table_copy(Tab, Node) end). @@ -1235,11 +1250,11 @@ make_del_table_copy(Tab, Node) -> ensure_not_active(Tab, Node), verify_cstruct(Cs2), Ops = remove_node_from_tabs(val({schema, tables}), Node), - [{op, del_table_copy, ram_copies, Node, cs2list(Cs2)} | Ops]; + [{op, del_table_copy, ram_copies, Node, vsn_cs2list(Cs2)} | Ops]; _ -> ensure_active(Cs), verify_cstruct(Cs2), - [{op, del_table_copy, Storage, Node, cs2list(Cs2)}] + [{op, del_table_copy, Storage, Node, vsn_cs2list(Cs2)}] end. remove_node_from_tabs([], _Node) -> @@ -1253,7 +1268,7 @@ remove_node_from_tabs([Tab|Rest], Node) -> unknown -> case IsFragModified of true -> - [{op, change_table_frag, {del_node, Node}, cs2list(Cs)} | + [{op, change_table_frag, {del_node, Node}, vsn_cs2list(Cs)} | remove_node_from_tabs(Rest, Node)]; false -> remove_node_from_tabs(Rest, Node) @@ -1262,11 +1277,11 @@ remove_node_from_tabs([Tab|Rest], Node) -> Cs2 = new_cs(Cs, Node, Storage, del), case mnesia_lib:cs_to_nodes(Cs2) of [] -> - [{op, delete_table, cs2list(Cs)} | + [{op, delete_table, vsn_cs2list(Cs)} | remove_node_from_tabs(Rest, Node)]; _Ns -> verify_cstruct(Cs2), - [{op, del_table_copy, ram_copies, Node, cs2list(Cs2)}| + [{op, del_table_copy, ram_copies, Node, vsn_cs2list(Cs2)}| remove_node_from_tabs(Rest, Node)] end end. @@ -1318,9 +1333,9 @@ make_move_table(Tab, FromNode, ToNode) -> Cs2 = new_cs(Cs, ToNode, Storage, add), Cs3 = new_cs(Cs2, FromNode, Storage, del), verify_cstruct(Cs3), - [{op, add_table_copy, Storage, ToNode, cs2list(Cs2)}, + [{op, add_table_copy, Storage, ToNode, vsn_cs2list(Cs2)}, {op, sync_trans}, - {op, del_table_copy, Storage, FromNode, cs2list(Cs3)}]. + {op, del_table_copy, Storage, FromNode, vsn_cs2list(Cs3)}]. %% end of functions to add and delete nodes to tables %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1357,7 +1372,7 @@ make_change_table_copy_type(Tab, Node, ToS) -> Cs3 = new_cs(Cs2, Node, ToS, add), verify_cstruct(Cs3), - [{op, change_table_copy_type, Node, FromS, ToS, cs2list(Cs3)}]. + [{op, change_table_copy_type, Node, FromS, ToS, vsn_cs2list(Cs3)}]. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% change index functions .... @@ -1383,7 +1398,7 @@ make_add_table_index(Tab, Pos) -> Ix2 = lists:sort([Pos | Ix]), Cs2 = Cs#cstruct{index = Ix2}, verify_cstruct(Cs2), - [{op, add_index, Pos, cs2list(Cs2)}]. + [{op, add_index, Pos, vsn_cs2list(Cs2)}]. del_table_index(Tab, Pos) -> schema_transaction(fun() -> do_del_table_index(Tab, Pos) end). @@ -1404,7 +1419,7 @@ make_del_table_index(Tab, Pos) -> verify(true, lists:member(Pos, Ix), {no_exists, Tab, Pos}), Cs2 = Cs#cstruct{index = lists:delete(Pos, Ix)}, verify_cstruct(Cs2), - [{op, del_index, Pos, cs2list(Cs2)}]. + [{op, del_index, Pos, vsn_cs2list(Cs2)}]. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1427,7 +1442,7 @@ make_add_snmp(Tab, Ustruct) -> verify(true, mnesia_snmp_hook:check_ustruct(Ustruct), Error), Cs2 = Cs#cstruct{snmp = Ustruct}, verify_cstruct(Cs2), - [{op, add_snmp, Ustruct, cs2list(Cs2)}]. + [{op, add_snmp, Ustruct, vsn_cs2list(Cs2)}]. del_snmp(Tab) -> schema_transaction(fun() -> do_del_snmp(Tab) end). @@ -1445,7 +1460,7 @@ make_del_snmp(Tab) -> ensure_active(Cs), Cs2 = Cs#cstruct{snmp = []}, verify_cstruct(Cs2), - [{op, del_snmp, cs2list(Cs2)}]. + [{op, del_snmp, vsn_cs2list(Cs2)}]. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% @@ -1477,26 +1492,26 @@ make_transform(Tab, Fun, NewAttrs, NewRecName) -> [] -> Cs2 = Cs#cstruct{attributes = NewAttrs, record_name = NewRecName}, verify_cstruct(Cs2), - [{op, transform, Fun, cs2list(Cs2)}]; + [{op, transform, Fun, vsn_cs2list(Cs2)}]; PosList -> DelIdx = fun(Pos, Ncs) -> Ix = Ncs#cstruct.index, Ncs1 = Ncs#cstruct{index = lists:delete(Pos, Ix)}, - Op = {op, del_index, Pos, cs2list(Ncs1)}, + Op = {op, del_index, Pos, vsn_cs2list(Ncs1)}, {Op, Ncs1} end, AddIdx = fun(Pos, Ncs) -> Ix = Ncs#cstruct.index, Ix2 = lists:sort([Pos | Ix]), Ncs1 = Ncs#cstruct{index = Ix2}, - Op = {op, add_index, Pos, cs2list(Ncs1)}, + Op = {op, add_index, Pos, vsn_cs2list(Ncs1)}, {Op, Ncs1} end, {DelOps, Cs1} = lists:mapfoldl(DelIdx, Cs, PosList), Cs2 = Cs1#cstruct{attributes = NewAttrs, record_name = NewRecName}, {AddOps, Cs3} = lists:mapfoldl(AddIdx, Cs2, PosList), verify_cstruct(Cs3), - lists:flatten([DelOps, {op, transform, Fun, cs2list(Cs2)}, AddOps]) + lists:flatten([DelOps, {op, transform, Fun, vsn_cs2list(Cs2)}, AddOps]) end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1520,7 +1535,7 @@ make_change_table_access_mode(Tab, Mode) -> verify(false, OldMode == Mode, {already_exists, Tab, Mode}), Cs2 = Cs#cstruct{access_mode = Mode}, verify_cstruct(Cs2), - [{op, change_table_access_mode, cs2list(Cs2), OldMode, Mode}]. + [{op, change_table_access_mode, vsn_cs2list(Cs2), OldMode, Mode}]. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1541,7 +1556,7 @@ make_change_table_load_order(Tab, LoadOrder) -> OldLoadOrder = Cs#cstruct.load_order, Cs2 = Cs#cstruct{load_order = LoadOrder}, verify_cstruct(Cs2), - [{op, change_table_load_order, cs2list(Cs2), OldLoadOrder, LoadOrder}]. + [{op, change_table_load_order, vsn_cs2list(Cs2), OldLoadOrder, LoadOrder}]. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1571,14 +1586,14 @@ make_change_table_majority(Tab, Majority) -> ensure_active(CsT), CsT2 = CsT#cstruct{majority = Majority}, verify_cstruct(CsT2), - {op, change_table_majority, cs2list(CsT2), + {op, change_table_majority, vsn_cs2list(CsT2), OldMajority, Majority} end, FragNames); false -> []; {_, _} -> mnesia:abort({bad_type, Tab}) end, verify_cstruct(Cs2), - [{op, change_table_majority, cs2list(Cs2), OldMajority, Majority} | FragOps]. + [{op, change_table_majority, vsn_cs2list(Cs2), OldMajority, Majority} | FragOps]. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1619,7 +1634,7 @@ make_write_table_properties(Tab, [Prop | Props], Cs) -> MergedProps = lists:merge(DelProps, [Prop]), Cs2 = Cs#cstruct{user_properties = MergedProps}, verify_cstruct(Cs2), - [{op, write_property, cs2list(Cs2), Prop} | + [{op, write_property, vsn_cs2list(Cs2), Prop} | make_write_table_properties(Tab, Props, Cs2)]; make_write_table_properties(_Tab, [], _Cs) -> []. @@ -1740,7 +1755,7 @@ make_delete_table_properties(Tab, [PropKey | PropKeys], Cs) -> Props = lists:keydelete(PropKey, 1, OldProps), Cs2 = Cs#cstruct{user_properties = Props}, verify_cstruct(Cs2), - [{op, delete_property, cs2list(Cs2), PropKey} | + [{op, delete_property, vsn_cs2list(Cs2), PropKey} | make_delete_table_properties(Tab, PropKeys, Cs2)]; make_delete_table_properties(_Tab, [], _Cs) -> []. @@ -2166,12 +2181,17 @@ receive_sync(Nodes, Pids) -> {abort, Else} end. -lock_del_table(Tab, Node, Cs, Father) -> +lock_del_table(Tab, NewNode, Cs0, Father) -> Ns = val({schema, active_replicas}), process_flag(trap_exit,true), Lock = fun() -> mnesia:write_lock_table(Tab), - {Res, []} = rpc:multicall(Ns, ?MODULE, set_where_to_read, [Tab, Node, Cs]), + %% Sigh using cs record + Set = fun(Node) -> + [Cs] = normalize_cs([Cs0], Node), + rpc:call(Node, ?MODULE, set_where_to_read, [Tab, NewNode, Cs]) + end, + Res = [Set(Node) || Node <- Ns], Filter = fun(ok) -> false; ({badrpc, {'EXIT', {undef, _}}}) -> @@ -2353,11 +2373,12 @@ undo_prepare_op(Tid, {op, add_table_copy, Storage, Node, TabDef}) -> undo_prepare_op(_Tid, {op, del_table_copy, _, Node, TabDef}) when Node == node() -> + WriteLocker = get(mnesia_lock), + WriteLocker =/= undefined andalso (WriteLocker ! die), Cs = list2cs(TabDef), Tab = Cs#cstruct.name, mnesia_lib:set({Tab, where_to_read}, Node); - undo_prepare_op(_Tid, {op, change_table_copy_type, N, FromS, ToS, TabDef}) when N == node() -> Cs = list2cs(TabDef), @@ -2829,6 +2850,9 @@ fetch_cstructs(Node) -> rpc:call(Node, mnesia_controller, get_remote_cstructs, []) end. +need_old_cstructs() -> + need_old_cstructs(val({schema, where_to_write})). + need_old_cstructs(Nodes) -> Filter = fun(Node) -> not mnesia_monitor:needs_protocol_conversion(Node) end, case lists:dropwhile(Filter, Nodes) of diff --git a/lib/mnesia/test/mnesia_evil_backup.erl b/lib/mnesia/test/mnesia_evil_backup.erl index 63f4146d98..9e0a8db1ae 100644 --- a/lib/mnesia/test/mnesia_evil_backup.erl +++ b/lib/mnesia/test/mnesia_evil_backup.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2010. All Rights Reserved. +%% Copyright Ericsson AB 1998-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 @@ -244,9 +244,9 @@ restore(Config, Op) -> [rpc:call(Node, ?MODULE, check_tab, [Res31, ?LINE]) || Node <- Nodes], %% Restore all tables on it's nodes - mnesia_schema:clear_table(Tab1), - mnesia_schema:clear_table(Tab2), - mnesia_schema:clear_table(Tab3), + mnesia:clear_table(Tab1), + mnesia:clear_table(Tab2), + mnesia:clear_table(Tab3), [mnesia:dirty_write({Tab1, N, N+1}) || N <- lists:seq(1, 11)], [mnesia:dirty_write({Tab2, N, N+1}) || N <- lists:seq(1, 11)], [mnesia:dirty_write({Tab3, N, N+1}) || N <- lists:seq(1, 11)], diff --git a/lib/mnesia/test/mnesia_evil_coverage_test.erl b/lib/mnesia/test/mnesia_evil_coverage_test.erl index 668eba176f..17d6c6c212 100644 --- a/lib/mnesia/test/mnesia_evil_coverage_test.erl +++ b/lib/mnesia/test/mnesia_evil_coverage_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% Copyright Ericsson AB 1996-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 @@ -1795,7 +1795,7 @@ subscribe_extended(Config) when is_list(Config) -> ?match({mnesia_table_event, {delete, schema, {schema, Tab1}, [{schema, Tab1, _}],_}}, recv_event()), ?match({mnesia_table_event, {write, schema, {schema, Tab1, _}, [], _}}, recv_event()), - ?match({atomic, ok}, mnesia_schema:clear_table(Tab2)), + ?match({atomic, ok}, mnesia:clear_table(Tab2)), ?match({mnesia_table_event, {delete, schema, {schema, Tab2}, [{schema, Tab2, _}],_}}, recv_event()), ?match({mnesia_table_event, {write, schema, {schema, Tab2, _}, [], _}}, recv_event()), diff --git a/lib/mnesia/test/mnesia_install_test.erl b/lib/mnesia/test/mnesia_install_test.erl index 5d55fcac0e..3a2d44aa95 100644 --- a/lib/mnesia/test/mnesia_install_test.erl +++ b/lib/mnesia/test/mnesia_install_test.erl @@ -205,7 +205,7 @@ silly_upgrade(Config) when is_list(Config) -> ?match(ok, mnesia:install_fallback(Bup2)), file:delete(Bup2), %% Will generate intentional crash, fatal error - ?match([], mnesia_test_lib:stop_mnesia([Node2])), + ?match([], mnesia_test_lib:stop_mnesia([Node2])), wait_till_dead([Node1, Node2]), ?match([], mnesia_test_lib:start_mnesia([Node1, Node2], [Tab1, Tab2])), ?match(match, verify_state(Tab1, Tab2, CpState)), @@ -213,22 +213,29 @@ silly_upgrade(Config) when is_list(Config) -> ?match(ok, mnesia:install_fallback(Bup)), file:delete(Bup), %% Will generate intentional crash, fatal error - ?match([], mnesia_test_lib:stop_mnesia([Node1, Node2])), + ?match([], mnesia_test_lib:stop_mnesia([Node1, Node2])), wait_till_dead([Node1, Node2]), ?match([], mnesia_test_lib:start_mnesia([Node1, Node2], [Tab1, Tab2])), CpState2 = [X || X <- CpState, element(1, X) /= Tab1], ?match(match, verify_state(Tab1, Tab2, CpState2)), ?verify_mnesia(Nodes, []). -wait_till_dead([]) -> ok; -wait_till_dead([N|Ns]) -> +wait_till_dead([]) -> + ok; %% timer:sleep(5); +wait_till_dead(Repeat = [N|Ns]) -> Apps = rpc:call(N, application, which_applications, []), case lists:keymember(mnesia, 1, Apps) of - true -> + true -> timer:sleep(10), - wait_till_dead([N|Ns]); - false -> - wait_till_dead(Ns) + wait_till_dead(Repeat); + false -> + case rpc:call(N, erlang, whereis, [mnesia_monitor]) of + undefined -> + wait_till_dead(Ns); + _ -> + timer:sleep(10), + wait_till_dead(Repeat) + end end. add_some_records(Tab1, Tab2, Old) -> diff --git a/lib/mnesia/vsn.mk b/lib/mnesia/vsn.mk index a21ab007ef..ebf79dd2ae 100644 --- a/lib/mnesia/vsn.mk +++ b/lib/mnesia/vsn.mk @@ -1 +1 @@ -MNESIA_VSN = 4.5 +MNESIA_VSN = 4.5.1 diff --git a/lib/snmp/Makefile b/lib/snmp/Makefile index 4264531112..ff6fad8ddc 100644 --- a/lib/snmp/Makefile +++ b/lib/snmp/Makefile @@ -54,6 +54,9 @@ else endif +DIA_PLT = ./priv/plt/$(APPLICATION).plt +DIA_ANALYSIS = $(basename $(DIA_PLT)).dialyzer_analysis + # ---------------------------------------------------- # Default Subdir Targets # ---------------------------------------------------- @@ -75,6 +78,11 @@ info: @echo "" @echo "SNMP_VSN: $(SNMP_VSN)" @echo "APP_VSN: $(APP_VSN)" + @echo "" + @echo "DIA_PLT: $(DIA_PLT)" + @echo "DIA_ANALYSIS: $(DIA_ANALYSIS)" + @echo "" + gclean: git clean -fXd @@ -120,3 +128,23 @@ tar: $(APP_TAR_FILE) $(APP_TAR_FILE): $(APP_DIR) (cd $(APP_RELEASE_DIR); gtar zcf $(APP_TAR_FILE) $(DIR_NAME)) + +dclean: + rm -f $(DIA_PLT) + rm -f $(DIA_ANALYSIS) + +dialyzer_plt: $(DIA_PLT) + +$(DIA_PLT): + @echo "Building $(APPLICATION) plt file" + @dialyzer --build_plt \ + --output_plt $@ \ + -r ../$(APPLICATION)/ebin \ + --output $(DIA_ANALYSIS) \ + --verbose + +dialyzer: $(DIA_PLT) + @echo "Running dialyzer on $(APPLICATION)" + @dialyzer --plt $< \ + ../$(APPLICATION)/ebin \ + --verbose
\ No newline at end of file diff --git a/lib/snmp/doc/src/notes.xml b/lib/snmp/doc/src/notes.xml index 9e1a060dee..3fb8784d6b 100644 --- a/lib/snmp/doc/src/notes.xml +++ b/lib/snmp/doc/src/notes.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>1996</year><year>2011</year> + <year>1996</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -33,6 +33,369 @@ </header> <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 + 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] Mib server cache gclimit update function incorrectly calls + age update function. + The gclimit update function, + <seealso marker="snmpa#update_mibs_cache_gclimit">update_mibs_cache_gclimit/1</seealso>, + <em>incorrectly</em> called the age update function, + <seealso marker="snmpa#update_mibs_cache_age">update_mibs_cache_age/2</seealso>. </p> + <p>Johan Claesson</p> + <p>Own Id: OTP-9868</p> + </item> + + </list> + + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + </section> + + </section> <!-- 4.21.6 --> + + + <section> + <title>SNMP Development Toolkit 4.21.5</title> + <p>Version 4.21.5 supports code replacement in runtime from/to + version 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] Removed (more) use of old style tuple funs. </p> + <p>Own Id: OTP-9783</p> + </item> + + </list> + + </section> + + <section> + <title>Fixed Bugs and Malfunctions</title> +<!-- + <p>-</p> +--> + + <list type="bulleted"> + <item> + <p>[agent] Repeated vacm table dumping fails due to file name + conflict. When dumping the vacm table to disk, a temoporary + file with a fixed name was used. If the table dumping + (snmpa_vacm:dump_table/0) was initiated from several different + processes in rapid succesion, the dumping could fail because the + different processes was simultaniously trying to write to the + same file. This problem has been eliminated by creating a unique + name for the temporary file. </p> + <p>Own Id: OTP-9851</p> + <p>Aux Id: Seq 11980</p> + </item> + + </list> + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + +<!-- + <list type="bulleted"> + <item> + <p>foo. </p> + <p>Own Id: OTP-9718</p> + </item> + + </list> +--> + + </section> + + </section> <!-- 4.21.5 --> + + + <section> + <title>SNMP Development Toolkit 4.21.4</title> + <p>This version has never been released for R14B.</p> + <p>Version 4.21.4 supports code replacement in runtime from/to + version 4.21.3, 4.21.2, 4.21.1, 4.21, 4.20.1, 4.20 and 4.19. </p> + + <section> + <title>Improvements and new features</title> + <p>-</p> + +<!-- + <list type="bulleted"> + <item> + <p>[compiler] Improved version info printout from the + <seealso marker="snmpc(command)#">MIB compiler frontend escript</seealso>. </p> + <p>Own Id: OTP-9618</p> + </item> + + </list> +--> + + </section> + + <section> + <title>Fixed Bugs and Malfunctions</title> +<!-- + <p>-</p> +--> + + <list type="bulleted"> + <item> + <p>[agent] Removed use of old style tuple funs. </p> + <p>Own Id: OTP-9779</p> + </item> + + </list> + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + +<!-- + <list type="bulleted"> + <item> + <p>foo. </p> + <p>Own Id: OTP-9718</p> + </item> + + </list> +--> + + </section> + + </section> <!-- 4.21.4 --> + + + <section> + <title>SNMP Development Toolkit 4.21.3</title> + <p>Version 4.21.3 supports code replacement in runtime from/to + version 4.21.2, 4.21.1, 4.21, 4.20.1, 4.20 and 4.19. </p> + + <section> + <title>Improvements and new features</title> +<!-- + <p>-</p> +--> + + <list type="bulleted"> + <item> + <p>[compiler] Improved version info printout from the + <seealso marker="snmpc(command)#">MIB compiler frontend escript</seealso>. </p> + <p>Own Id: OTP-9618</p> + </item> + + </list> + + </section> + + <section> + <title>Fixed Bugs and Malfunctions</title> +<!-- + <p>-</p> +--> + + <list type="bulleted"> + <item> + <p>[agent] Version 4.20 introduced a change that broke trap + sending from subagents. Due to a bug in the test code, + this was not discovered, until that bug was fixed. </p> + <p>Own Id: OTP-9745</p> + </item> + + <item> + <p>[agent] When sending an error message (reply) regarding + <c>snmpUnknownPDUHandlers</c>, the agent used the wrong OID. </p> + <p>Own Id: OTP-9747</p> + </item> + + <item> + <p>[compiler] Fix the <c>--warnings/--W</c> option parsing in the + <seealso marker="snmpc(command)#option_warnings">snmpc</seealso> + wrapper (e)script. + The short warning option was incorrectly <c>--w</c>, instead + of as documented <c>--W</c>. This has now been corrected. </p> + <p>*** POTENTIAL INCOMPATIBILITY ***</p> + <p>Tuncer Ayaz</p> + <p>Own Id: OTP-9718</p> + </item> + + </list> + </section> + + + <section> + <title>Incompatibilities</title> +<!-- + <p>-</p> +--> + + <list type="bulleted"> + <item> + <p>[compiler] The short warning option has been changed from + <c>--w</c> to <c>--W</c> to comply with the documentation. </p> + <p>Tuncer Ayaz</p> + <p>Own Id: OTP-9718</p> + </item> + + </list> + </section> + + </section> <!-- 4.21.3 --> + + + <section> + <title>SNMP Development Toolkit 4.21.2</title> + <p>Version 4.21.2 supports code replacement in runtime from/to + version 4.21.1, 4.21, 4.20.1, 4.20 and 4.19. </p> + + <section> + <title>Improvements and new features</title> + <p>-</p> + +<!-- + <list type="bulleted"> + <item> + <p>Bad note store GC timer deactivation. + Wrong field in the state record was set (timeout instead active). </p> + <p>Stefan Grundmann</p> + <p>Own Id: OTP-9690</p> + </item> + + </list> +--> + + </section> + + <section> + <title>Fixed Bugs and Malfunctions</title> +<!-- + <p>-</p> +--> + + <list type="bulleted"> + <item> + <p>Bad note store GC timer deactivation. + Wrong field in the state record was set (timeout instead active). </p> + <p>Stefan Grundmann</p> + <p>Own Id: OTP-9690</p> + </item> + + </list> + </section> + + + <section> + <title>Incompatibilities</title> + <p>-</p> + </section> + + </section> <!-- 4.21.2 --> + + + <section> <title>SNMP Development Toolkit 4.21.1</title> <p>Version 4.21.1 supports code replacement in runtime from/to version 4.20.1, 4.20 and 4.19. </p> @@ -457,1276 +820,6 @@ snmp_view_basec_acm_mib:vacmAccessTable(set, RowIndex, Cols). </section> <!-- 4.18 --> - <section> - <title>SNMP Development Toolkit 4.17.1</title> - <p>Version 4.17.1 supports code replacement in runtime from/to - version 4.17, 4.16.2, 4.16.1, 4.16, 4.15, 4.14 and 4.13.5.</p> - - <section> - <title>Improvements and new features</title> - <p>-</p> - </section> - - <section> - <title>Reported Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>When the function FilterMod:accept_recv/2 - returned false the SNMP agent stopped collecting - messages from UDP.</p> - <p>Own Id: OTP-8761</p> - </item> - </list> - </section> - - <section> - <title>Incompatibilities</title> - <p>-</p> - </section> - </section> <!-- 4.17.1 --> - - - <section> - <title>SNMP Development Toolkit 4.17</title> - <p>Version 4.17 supports code replacement in runtime from/to - version 4.16.2, 4.16.1, 4.16, 4.15, 4.14 and 4.13.5.</p> - - <section> - <title>Improvements and new features</title> - <!-- - <p>-</p> - --> - <list type="bulleted"> - <item> - <p>[agent] Added very basic support for multiple SNMPv3 - EngineIDs in a single agent. See - <seealso marker="snmpa#send_notification">send_notification/7</seealso>, - <seealso marker="snmpa_mpd#process_packet">process_packet/7</seealso>, - <seealso marker="snmpa_mpd#generate_response_msg">generate_response_msg/6</seealso> or - <seealso marker="snmpa_mpd#generate_msg">generate_msg/6</seealso> - for more info. </p> - - <p>Own Id: OTP-8478</p> - </item> - - </list> - - </section> - - <section> - <title>Reported Fixed Bugs and Malfunctions</title> - <p>-</p> - - <!-- - <list type="bulleted"> - <item> - <p>The config utility - (<seealso marker="snmp#config">snmp:config/0</seealso>) - generated a default notify.conf - with a bad name for the standard trap entry (was "stadard trap", - but should have been "standard trap"). This has been corrected. </p> - <p>Kenji Rikitake</p> - <p>Own Id: OTP-8433</p> - </item> - - </list> - --> - - </section> - - <section> - <title>Incompatibilities</title> - <p>-</p> - </section> - </section> <!-- 4.17 --> - - - <section> - <title>SNMP Development Toolkit 4.16.2</title> - <p>Version 4.16.2 supports code replacement in runtime from/to - version 4.16.1, 4.16, 4.15, 4.14 and 4.13.5.</p> - - <section> - <title>Improvements and new features</title> - <!-- - <p>-</p> - --> - <list type="bulleted"> - <item> - <p>[compiler] The SMI specifies that a table row OID should be - named: { <tableIdentifier> "1" }. </p> - <p>A new option has been introduced, - <seealso marker="snmpc#compiler_opts">relaxed_row_name_assign_check</seealso>, - that allows for a more liberal numbering scheme</p> - <p>Own Id: OTP-8574</p> - </item> - - <item> - <p>[agent|manager] Changes to make snmp (forward) compatible with - the new version of the crypto application (released in R14). - As of R14, crypto is implemented using NIFs. Also, - the API is more strict. </p> - <p>Own Id: OTP-8594</p> - </item> - - <item> - <p>Auto [agent] Changed default value for the MIB server cache. - GC is now on by default. </p> - <p>Own Id: OTP-8648</p> - </item> - - </list> - - </section> - - <section> - <title>Reported Fixed Bugs and Malfunctions</title> - <!-- - <p>-</p> - --> - - <list type="bulleted"> - <item> - <p>Encode/decode of Counter64 values larger than - 16#7fffffffffffffff (9223372036854775807) failed. </p> - <p>Own Id: OTP-8563</p> - </item> - - <item> - <p>[compiler] Fails to compile non-contiguous BITS. </p> - <p>Per Hedeland</p> - <p>Own Id: OTP-8595</p> - </item> - - <item> - <p>[manager] Raise condition causing the manager server process to - crash. Unregistering an agent while traffic (set/get-operations) - is ongoing could cause a crash in the manager server process - (raise condition). </p> - <p>Own Id: OTP-8646</p> - <p>Aux Id: Seq 11585</p> - </item> - - </list> - - </section> - - <section> - <title>Incompatibilities</title> - <p>-</p> - </section> - </section> <!-- 4.16.2 --> - - - <section> - <title>SNMP Development Toolkit 4.16.1</title> - <p>Version 4.16.1 supports code replacement in runtime from/to - version 4.16, 4.15, 4.14 and 4.13.5.</p> - - <section> - <title>Improvements and new features</title> - <p>-</p> - <!-- - <list type="bulleted"> - <item> - <p>[agent|manager] Entries in the audit trail log can now be - augmented by a sequence number. </p> - <p>This is enabled by the <c>seqno</c> option, which is part of the - <seealso marker="snmp_config#audit_trail_log">Audit Trail Log</seealso> - config option. </p> - <p>See the - <seealso marker="snmp_app#configuration_params">reference manual</seealso> - or the - <seealso marker="snmp_config#configuration_params">Configuring the application</seealso> - chapter of the User's Guide for further info. </p> - - <p>Own Id: OTP-8395</p> - </item> - - </list> - --> - - </section> - - <section> - <title>Reported Fixed Bugs and Malfunctions</title> - <!-- - <p>-</p> - --> - - <list type="bulleted"> - <item> - <p>[manager] Fixed an upgrade/downgrade problem. </p> - <p>Upgrade/downgrade from/to 4.13.5 did not work for the net-if - process. This has now been fixed. </p> - <p>Own Id: OTP-8481</p> - </item> - - <item> - <p>[agent] A minor mnesia related performance improvement. </p> - <p>Own Id: OTP-8480</p> - </item> - - </list> - - </section> - - <section> - <title>Incompatibilities</title> - <p>-</p> - </section> - </section> <!-- 4.16.1 --> - - - <section> - <title>SNMP Development Toolkit 4.16</title> - <p>Version 4.16 supports code replacement in runtime from/to - version 4.15, 4.14 and 4.13.5.</p> - - <section> - <title>Improvements and new features</title> - <!-- - <p>-</p> - --> - <list type="bulleted"> - <item> - <p>[agent|manager] Entries in the audit trail log can now be - augmented by a sequence number. </p> - <p>This is enabled by the <c>seqno</c> option, which is part of the - <seealso marker="snmp_config#audit_trail_log">Audit Trail Log</seealso> - config option. </p> - <p>See the - <seealso marker="snmp_app#configuration_params">reference manual</seealso> - or the - <seealso marker="snmp_config#configuration_params">Configuring the application</seealso> - chapter of the User's Guide for further info. </p> - - <p>Own Id: OTP-8395</p> - </item> - - </list> - - </section> - - <section> - <title>Reported Fixed Bugs and Malfunctions</title> - <!-- - <p>-</p> - --> - - <list type="bulleted"> - <item> - <p>[manager] Registration of agents using the config file, - <seealso marker="snmp_manager_config_files#agents">agents.conf</seealso>, - does not work. This has now been corrected. </p> - <p>Per Hedeland</p> - <p>Own Id: OTP-8442</p> - </item> - - <item> - <p>The config utility - (<seealso marker="snmp#config">snmp:config/0</seealso>) - generated a default notify.conf - with a bad name for the standard trap entry (was "stadard trap", - but should have been "standard trap"). This has been corrected. </p> - <p>Kenji Rikitake</p> - <p>Own Id: OTP-8433</p> - </item> - - </list> - - </section> - - <section> - <title>Incompatibilities</title> - <p>-</p> - </section> - </section> <!-- 4.16 --> - - - <section> - <title>SNMP Development Toolkit 4.15</title> - - <p>Version 4.15 supports code replacement in runtime from/to - version 4.14 and 4.13.5.</p> - - <section> - <title>Improvements and new features</title> - <!-- - <p>-</p> - --> - - <list type="bulleted"> - <item> - <p>The documentation is now built with open source tools - (<em>xsltproc</em> and <em>fop</em>) that exists on most - platforms. One visible change is that the frames are removed.</p> - <p>Own Id: OTP-8249</p> - </item> - - </list> - - </section> - - <section> - <title>Reported Fixed Bugs and Malfunctions</title> - <!-- - <p>-</p> - --> - <list type="bulleted"> - <item> - <p>[manager] When information from an unknown agent is received, - it was previously delivered to the default user via calls to all - the functions of the callback API depending on the info type - (<c>pdu</c>, <c>trap</c>, <c>report</c> or <c>inform</c>). - The problem was that the <c>TargetName</c> argument was useless - in this case (only an already known agent has a known/valid - <c>TargetName</c>, but the <c>TargetName</c> used in these calls - was generated "on the fly"). </p> - <p>This has now been changed so that when a message is received - from an unknown agent, then only - <seealso marker="snmpm_user#handle_agent">handle_agent</seealso> - (for the default user) is called, but now this call also has a - <c>Type</c> argument, which is - <c>pdu | trap | report | inform</c>, depending on what kind of - message was actually received, thus making it possible for the - user to properly analyze the data received. </p> - <p>To handle this, the - <seealso marker="snmpm_user">snmpm_user</seealso> behaviour has - been updated. </p> - <p>*** POTENTIAL INCOMPATIBILITY ***</p> - <p>Own Id: OTP-8229</p> - <!-- <p>Aux Id: Seq 11312</p> --> - </item> - - </list> - - </section> - - </section> <!-- 4.15 --> - - - <section> - <title>SNMP Development Toolkit 4.14</title> - - <p>Version 4.14 supports code replacement in runtime from/to - version 4.13.5, 4.13.4, 4.13.3, 4.13.2, 4.13.1 and 4.13.</p> - - <section> - <title>Improvements and new features</title> - <!-- - <p>-</p> - --> - - <list type="bulleted"> - <item> - <p>[compiler] Include object- and notification groups in the - compiled mib. - This will make it possible to import groups from other mibs. </p> - <p>Also the SNMPv2-MIB-file has been updated to a more - up-to-date version. </p> - <p>Own Id: OTP-8223</p> - <!-- <p>Aux Id: Seq 11383</p> --> - </item> - - <item> - <p>[manager] Added support for message filtering in the - network interface module provided with the application. - The component that actually make the filter decisions - is the network interface filter module. This module - must implement the - <seealso marker="snmpm_network_interface_filter">network interface filter behaviour</seealso> - for message filtering. - See also the Configuring chapter of - the User's Guide to see how to configure this feature. </p> - <p>See the - <seealso marker="snmp_app#configuration_params">configuration</seealso> - chapter for more info about the filter options.</p> - <p>Own Id: OTP-8228</p> - <p>Aux Id: Seq 11411</p> - </item> - - <item> - <p>The MIBs delivered as part of the application is now - also available as man pages, section 7. </p> - <p>Own Id: OTP-8237</p> - <!-- <p>Aux Id: Seq 11383</p> --> - </item> - - </list> - - </section> - - <section> - <title>Reported Fixed Bugs and Malfunctions</title> - <p>-</p> - - <!-- - <list type="bulleted"> - <item> - <p>[agent] The main agent type header file contained some miss-information - regarding the type of the entrytype field of the me-record, causing - unneccessary confusion.</p> - <p>Own Id: OTP-8116</p> - <p>Aux Id: Seq 11312</p> - </item> - - </list> - --> - - </section> - - <section> - <title>Incompatibilities</title> - <p>-</p> - </section> - </section> <!-- 4.14 --> - - - <section> - <title>SNMP Development Toolkit 4.13.5</title> - - <p>Version 4.13.5 supports code replacement in runtime from/to - version 4.13.4, 4.13.3, 4.13.2, 4.13.1 and 4.13.</p> - - <section> - <title>Improvements and new features</title> - <!-- - <p>-</p> - --> - - <list type="bulleted"> - <item> - <p>[agent] Improved the cache handling of the mib server. </p> - <p>A number of new functions and config options for the mib server - cache has been added. </p> - <p>See - <seealso marker="snmpa#invalidate_mibs_cache">invalidate_mibs_cache/0,1</seealso>, - <seealso marker="snmpa#enable_mibs_cache">enable_mibs_cache/0,1</seealso>, - <seealso marker="snmpa#disable_mibs_cache">disable_mibs_cache/0,1</seealso>, - <seealso marker="snmpa#gc_mibs_cache">gc_mibs_cache/0,1,2,3</seealso>, - <seealso marker="snmpa#enable_mibs_cache_autogc">enable_mibs_cache_autogc/0,1</seealso>, - <seealso marker="snmpa#disable_mibs_cache_autogc">disable_mibs_cache_autogc/0,1</seealso>, - <seealso marker="snmpa#update_mibs_cache_age">update_mibs_cache_age/1,2</seealso> and - <seealso marker="snmpa#update_mibs_cache_gclimit">update_mibs_cache_gclimit/1,2</seealso> for more info. </p> - <p>See also the - <seealso marker="snmp_app#configuration_params">configuration</seealso> - chapter for more info about the mib server cache options.</p> - <p>Own Id: OTP-8182</p> - <p>Aux Id: Seq 11383</p> - </item> - - <item> - <p>[agent] A manager could no longer use the SNMPv3 user "initial" - as this was interpretated as the first step of the discovery. </p> - <p>Introduced a new terminating option, <c>trigger_username</c> to - make it possible to configure the username the agent reacts to. - Default is <c>""</c>. </p> - <p>See the - <seealso marker="snmp_app#configuration_params">configuration</seealso> - chapter for more info about the discovery options.</p> - <p>Own Id: OTP-8120</p> - <p>Aux Id: Seq 11361</p> - </item> - - </list> - - </section> - - <section> - <title>Reported Fixed Bugs and Malfunctions</title> - <!-- - <p>-</p> - --> - <list type="bulleted"> - <item> - <p>[agent] The main agent type header file contained some miss-information - regarding the type of the entrytype field of the me-record, causing - unneccessary confusion.</p> - <p>Own Id: OTP-8116</p> - <p>Aux Id: Seq 11312</p> - </item> - - </list> - - </section> - - <section> - <title>Incompatibilities</title> - <p>-</p> - </section> - </section> <!-- 4.13.5 --> - - - <section> - <title>SNMP Development Toolkit 4.13.4</title> - - <p>Version 4.13.4 supports code replacement in runtime from/to - version 4.13.3, 4.13.2, 4.13.1 and 4.13.</p> - - <section> - <title>Improvements and new features</title> - <p>-</p> - - <!-- - <list type="bulleted"> - <item> - <p>[agent] Support for the discovery process. </p> - <p>The agent can both initiate discovery itself (see the - <seealso marker="snmp_agent_funct_descr#discovery">discovery</seealso> chapter - for more info) and respond to discovery initiated by a manager.</p> - <p>Own Id: OTP-7571</p> - <p>Aux Id: Seq 11053</p> - </item> - - </list> - --> - - </section> - - <section> - <title>Reported Fixed Bugs and Malfunctions</title> - <!-- - <p>-</p> - --> - <list type="bulleted"> - <item> - <p>[agent] Originating discovery problems. </p> - <p>Invalid state variable update during second stage of - discovery causes master agent crash. </p> - <p>Also the net_if process failed to activate socket - ({active, once}) after first discovery response was sent. </p> - <p>Own Id: OTP-8044</p> - <p>Aux Id: Seq 11295</p> - </item> - - <item> - <p>[agent] Terminating discovery problem. </p> - <p>The reply to the second stage request should include a - varbind with <c>usmStatsNotInTimeWindows</c>.</p> - <p>Own Id: OTP-8062</p> - <p>Aux Id: Seq 11318</p> - </item> - - <item> - <p>[agent] Originating discovery improvement. </p> - <p>Added the ExtraInfo argument to the - <seealso marker="snmpa#discovery">discovery</seealso> function. - This argument will be passed on to the stage1_finish callback - function. Also, the - <seealso marker="snmpa#discovery">discovery</seealso> function - will now always return <c>{ok, ManagerEngineID}</c> on successful - discovery. </p> - <p>The <seealso marker="snmpa_discovery_handler">discovery handler</seealso> - behaviour updated accordingly. </p> - <p>Own Id: OTP-8098</p> - <p>Aux Id: Seq 11346</p> - </item> - - </list> - - </section> - - <section> - <title>Incompatibilities</title> - <p>-</p> - </section> - </section> <!-- 4.13.4 --> - - - <section> - <title>SNMP Development Toolkit 4.13.3</title> - - <p>Version 4.13.3 supports code replacement in runtime from/to - version 4.13.2, 4.13.1 and 4.13.</p> - - <section> - <title>Improvements and new features</title> - <p>-</p> - - <!-- - <list type="bulleted"> - <item> - <p>[agent] Support for the discovery process. </p> - <p>The agent can both initiate discovery itself (see the - <seealso marker="snmp_agent_funct_descr#discovery">discovery</seealso> chapter - for more info) and respond to discovery initiated by a manager.</p> - <p>Own Id: OTP-7571</p> - <p>Aux Id: Seq 11053</p> - </item> - - </list> - --> - - </section> - - <section> - <title>Reported Fixed Bugs and Malfunctions</title> - <!-- - <p>-</p> - --> - <list type="bulleted"> - <item> - <p>[manager] A request for an oid of type BITS was actually - returned as OCTET STRING. </p> - <p>Values of type BITS are encoded as OCTET STRING, - which makes it impossible for the decoder to know that - they should really be of type BITS. - Instead, this has to be done higher up in the stack, where - there is knowledge of the MIB (assuming that the mib has - been loaded, there is info about the type of the mibentry). </p> - <p>This problem has now been fixed, but requires that the MIB - defining this mib-entry is loaded! </p> - <p>The utility function - <seealso marker="snmpm#oid_to_type">oid_to_type</seealso> - has been added, for debug purpose. </p> - <p>The utility function(s) - <seealso marker="snmp#octet_string_to_bits">octet_string_to_bits</seealso> - and - <seealso marker="snmp#bits_to_octet_string">bits_to_octet_string</seealso> - has also been added. These can be used if the user prefers to - handle the conversion on their own. </p> - <p>Own Id: OTP-8015</p> - <p>Aux Id: Seq 11285</p> - </item> - - <item> - <p>[agent] Fixed some issues with the discovery handling. </p> - <p>Changed the API of the - <seealso marker="snmpa#discovery">discovery</seealso> - function to solve some - of these problems. </p> - <p>Introduced various options for controlling the discovery - process. See the - <seealso marker="snmp_app#configuration_params">configuration</seealso> - chapter for more info about the discovery options.</p> - <p>Own Id: OTP-8020</p> - <p>Aux Id: Seq 11295</p> - </item> - - </list> - - </section> - - <section> - <title>Incompatibilities</title> - <p>-</p> - </section> - </section> <!-- 4.13.3 --> - - - <section> - <title>SNMP Development Toolkit 4.13.2</title> - - <p>Version 4.13.2 supports code replacement in runtime from/to - version 4.13.1 and 4.13.</p> - - <section> - <title>Improvements and new features</title> - <p>-</p> - - <!-- - <list type="bulleted"> - <item> - <p>[agent] Support for the discovery process. </p> - <p>The agent can both initiate discovery itself (see the - <seealso marker="snmp_agent_funct_descr#discovery">discovery</seealso> chapter - for more info) and respond to discovery initiated by a manager.</p> - <p>Own Id: OTP-7571</p> - <p>Aux Id: Seq 11053</p> - </item> - - </list> - --> - - </section> - - <section> - <title>Reported Fixed Bugs and Malfunctions</title> - <!-- - <p>-</p> - --> - <list type="bulleted"> - <item> - <p>[manager] Failure during downed user cleanup. - As part of the cleanup after a crashed user, - the manager attempts to unregister the agents - registered by this user. This however failed, - causing a server crash. </p> - <p>Own Id: OTP-7961</p> - <p>Aux Id: Seq 11275</p> - </item> - - <item> - <p>[manager] Incorrectly documented value type for - IpAddress (ip). The value type for IpAddress is - documented as ip but is actually ia. The value type - ip has been added. The old (not documented) value - type ia still works. </p> - <p>Own Id: OTP-7977</p> - <p>Aux Id: Seq 11279</p> - </item> - - <item> - <p>[manager] EngineId lookup fails when using version-3. </p> - <p>Own Id: OTP-7983</p> - <p>Aux Id: Seq 11275</p> - </item> - - <item> - <p>[agent] As of version 4.13 the possible return values - of the function - <seealso marker="snmpa_mpd#process_packet">snmpa_mpd:process_packet/4</seealso> - changed, but this was not documented. </p> - <p>Own Id: OTP-7989</p> - <p>Aux Id: Seq 11275</p> - </item> - - </list> - - </section> - - <section> - <title>Incompatibilities</title> - <p>-</p> - </section> - </section> <!-- 4.13.2 --> - - <section> - <title>SNMP Development Toolkit 4.13.1</title> - - <p>Version 4.13.1 supports code replacement in runtime from/to - version 4.13.</p> - - <section> - <title>Improvements and new features</title> - <p>-</p> - - <!-- - <list type="bulleted"> - <item> - <p>[agent] Support for the discovery process. </p> - <p>The agent can both initiate discovery itself (see the - <seealso marker="snmp_agent_funct_descr#discovery">discovery</seealso> chapter - for more info) and respond to discovery initiated by a manager.</p> - <p>Own Id: OTP-7571</p> - <p>Aux Id: Seq 11053</p> - </item> - - </list> - --> - - </section> - - <section> - <title>Reported Fixed Bugs and Malfunctions</title> - <!-- - <p>-</p> - --> - <list type="bulleted"> - <item> - <p>[manager] Registration of users had some issues. </p> - <p>Not all of the registration functions where actually exported - (<seealso marker="snmpm#register_user">register_user/4</seealso> - and - <seealso marker="snmpm#register_user_monitor">register_user_monitor/4</seealso>). - This has now been fixed. </p> - <p>Also, the registration did not succeed unless - user implemented the *new* behaviour. This has now - also been fixed (registration succeeds if the user - implements either the new (i.e. updated - <seealso marker="snmpm_user">snmpm_user</seealso>) - or the old user behaviour (<c>snmpm_user_old</c>)). </p> - <p>Own Id: OTP-7902</p> - <p>Aux Id: Seq 11240</p> - </item> - - </list> - - </section> - - <section> - <title>Incompatibilities</title> - <p>-</p> - </section> - </section> <!-- 4.13.1 --> - - <section> - <title>SNMP Development Toolkit 4.13</title> -<!-- - <p>Version 4.13 supports code replacement in runtime from/to - version 4.12.1.</p> ---> - - <section> - <title>Improvements and new features</title> - <!-- - <p>-</p> - --> - <list type="bulleted"> - <item> - <p>[agent] Support for the discovery process. </p> - <p>The agent can both initiate discovery itself (see the - <seealso marker="snmp_agent_funct_descr#discovery">discovery</seealso> chapter - for more info) and respond to discovery initiated by a manager.</p> - <p>Own Id: OTP-7571</p> - <p>Aux Id: Seq 11053</p> - </item> - - </list> - - </section> - - <section> - <title>Reported Fixed Bugs and Malfunctions</title> - <!-- - <p>-</p> - --> - <list type="bulleted"> - <item> - <p>[agent] Unnecessary use of math:pow/2 could cause problems - on systems without floating point support. </p> - <p>Per Hedeland</p> - <p>Own Id: OTP-7735</p> - <!-- <p>Aux Id: Seq 10966</p> --> - </item> - - <item> - <p>[manager] A major flaw was discovered with the agent handling. </p> - <p>First, <c>TargetName</c> was never used as intended, as a unique - identifier for the target (agent in this case). </p> - <p>Second, <c>TargetName</c> had a <em>default value</em>, which meant - that several agents could have the same <c>TargetName</c>, causing - unpredictable behaviour in the manager. </p> - <p>Third, <c>EngineID</c> was not a mandatory config option and had - furthermore also a <em>default value</em>. </p> - - <p>These problems has been solved in the following way: </p> - <p>First, a new set of api functions has been introduced (and documented): - <seealso marker="snmpm#register_user">register_user/4</seealso>, - <seealso marker="snmpm#register_user_monitor">register_user_monitor/4</seealso>, - <seealso marker="snmpm#register_agent">register_agent/3</seealso>, - <seealso marker="snmpm#unregister_agent">unregister_agent/2</seealso>, - <seealso marker="snmpm#agent_info">agent_info/2</seealso>, - <seealso marker="snmpm#update_agent_info">update_agent_info/4</seealso>, - <seealso marker="snmpm#sync_get">sync_get/3,4,5,6</seealso>, - <seealso marker="snmpm#async_get">async_get/3,4,5,6</seealso>, - <seealso marker="snmpm#sync_get_next">sync_get_next/3,4,5,6</seealso>, - <seealso marker="snmpm#async_get_next">async_get_next/3,4,5,6</seealso>, - <seealso marker="snmpm#sync_set">sync_set/3,4,5,6</seealso>, - <seealso marker="snmpm#async_set">async_set/3,4,5,6</seealso>, - <seealso marker="snmpm#sync_get_bulk">sync_get_bulk/5,6,7,8</seealso> and - <seealso marker="snmpm#async_get_bulk">async_get_bulk/5,6,7,8</seealso> - that all use <c>TargetName</c> (and not, as previously, <c>Addr</c> - and <c>Port</c>) to identify the agent (also the return value of - <seealso marker="snmpm#which_agents">which_agents</seealso> has - been changed). </p> - <p>Second, for backward compatibility, the old functions still - exist, but are no longer documented and are now wrappers for the - new functions, including erroneous default value for EngineID and - all. The TargetName is however generated from the provided - <c>Addr</c>, <c>Port</c> and <c>Version</c> config options. </p> - <p>Third, the behaviour of the - <seealso marker="snmpm_user">SNMP manager user</seealso> has - been changed to reflect this, i.e. - <seealso marker="snmpm_user#handle_pdu">handle_pdu/4</seealso>, - <seealso marker="snmpm_user#handle_trap">handle_trap/3</seealso>, - <seealso marker="snmpm_user#handle_inform">handle_inform/3</seealso>, - <seealso marker="snmpm_user#handle_report">handle_report/3</seealso> - and the return-value of - <seealso marker="snmpm_user#handle_agent">handle_agent/4</seealso>. - The old (non-documented) callback-functions (using Addr and Port) - will still be called if the agent was registered using the old - registration functions. </p> - - <p>Own Id: OTP-7836</p> - <!-- <p>Aux Id: Seq 10966</p> --> - </item> - - </list> - - </section> - - <section> - <title>Incompatibilities</title> - <p>-</p> - </section> - </section> <!-- 4.13 --> - - <section> - <title>SNMP Development Toolkit 4.12.2</title> - <p>Version 4.12.2 supports code replacement in runtime from/to - version 4.12.1, 4.12, 4.11.2, 4.11.1 and 4.11.</p> - - <section> - <title>Improvements and new features</title> - <p>-</p> - <!-- - <list type="bulleted"> - <item> - <item> - <p>[agent] Improvement of the inform reporting. - It was previously not certain how many acks an - application received, 0, 1 or 2. This has now been - fixed, so that only 1 (one) ack is issued. </p> - <p>Per Hedeland</p> - <p>Own Id: OTP-7525</p> - </item> - - </list> - --> - - </section> - - <section> - <title>Reported Fixed Bugs and Malfunctions</title> - <!-- - <p>-</p> - --> - <list type="bulleted"> - <item> - <p>[agent] Bad session cache (usm+camv-info) invalidation - could cause user crash, through call(s) to (a number of) - MIB API function(s) (undefined function). </p> - <p>Own Id: OTP-7868</p> - <!-- <p>Aux Id: Seq 11124</p> --> - </item> - - </list> - - </section> - - <section> - <title>Incompatibilities</title> - <p>-</p> - </section> - </section> <!-- 4.12.2 --> - - <section> - <title>SNMP Development Toolkit 4.12.1</title> - <p>Version 4.12.1 supports code replacement in runtime from/to - version 4.12, 4.11.2, 4.11.1 and 4.11.</p> - - <section> - <title>Improvements and new features</title> - <p>-</p> - <!-- - <list type="bulleted"> - <item> - <item> - <p>[agent] Improvement of the inform reporting. - It was previously not certain how many acks an - application received, 0, 1 or 2. This has now been - fixed, so that only 1 (one) ack is issued. </p> - <p>Per Hedeland</p> - <p>Own Id: OTP-7525</p> - </item> - - </list> - --> - - </section> - - <section> - <title>Reported Fixed Bugs and Malfunctions</title> - <!-- - <p>-</p> - --> - <list type="bulleted"> - <item> - <p>Logging of messages with the GetBulk-request PDU - incorrectly produced an erroneous entry in the - log: "An error occurred". </p> - <p>The reason for this was that the PDU-fields - error_status and error_index is re-used for - Non-repeaters and Max-repetitions for - GetBulk-request PDUs, but this was not handled - by the logging code. </p> - <p>Own Id: OTP-7695</p> - <p>Aux Id: Seq 11124</p> - </item> - - <item> - <p>[agent] An attempt to set the row status to active for an - notReady table row, could result in an "inconsistentValue" - error. </p> - <p>The same problem existed when attempting to set row status - to notInService for a row in notReady. </p> - <p>Serge Aleynikov</p> - <p>Own Id: OTP-7698</p> - <!-- <p>Aux Id: Seq 10966</p> --> - </item> - - </list> - - </section> - - <section> - <title>Incompatibilities</title> - <p>-</p> - </section> - </section> <!-- 4.12.1 --> - - <section> - <title>SNMP Development Toolkit 4.12</title> - <p>Version 4.12 supports code replacement in runtime from/to - version 4.11.2, 4.11.1 and 4.11.</p> - - <section> - <title>Improvements and new features</title> - <!-- - <p>-</p> - --> - <list type="bulleted"> - <item> - <p>[agent] A simple lookup cache has been added to improve - the mib server lookup performance. </p> - <p>This can be disabled with the mib_server - <seealso marker="snmp_app">cache</seealso> option. </p> - <p>Own Id: OTP-7346</p> - </item> - - <item> - <p>[agent] Improvement of the inform reporting. - It was previously not certain how many acks an - application received, 0, 1 or 2. This has now been - fixed, so that only 1 (one) ack is issued. </p> - <p>Per Hedeland</p> - <p>Own Id: OTP-7525</p> - </item> - - </list> - - </section> - - <section> - <title>Reported Fixed Bugs and Malfunctions</title> - <p>-</p> - <!-- - <list type="bulleted"> - <item> - <p>[manager] Encryption error when attempting to send - version 3 inform-requests. </p> - <p>Own Id: OTP-7432</p> - <p>Aux Id: Seq 10966</p> - </item> - - </list> - --> - - </section> - - <section> - <title>Incompatibilities</title> - <p>-</p> - </section> - </section> <!-- 4.12 --> - - <section> - <title>SNMP Development Toolkit 4.11.2</title> - <p>Version 4.11.2 supports code replacement in runtime from/to - version 4.11.1 and 4.11. </p> - - <section> - <title>Improvements and new features</title> - <p>-</p> - <!-- - <list type="bulleted"> - <item> - <p>Added utility functions for transforming DateAndTime - as [int()] to strings; - <seealso marker="snmp#dat2s">date_and_time_to_string/2</seealso> - and - <seealso marker="snmp#dat2s2">date_and_time_to_string2/1</seealso>. </p> - <p>Also added new validation function - <seealso marker="snmp#vdat">validate_date_and_time/2</seealso>. </p> - <p>Own Id: OTP-7412</p> - <p>Aux Id: Seq 10987</p> - </item> - </list> - --> - </section> - - <section> - <title>Reported Fixed Bugs and Malfunctions</title> - <!-- - <p>-</p> - --> - <list type="bulleted"> - <item> - <p>[manager] Erroneous engine-id check when receiving version 3 - informs. </p> - <p>Own Id: OTP-7570</p> - <p>Aux Id: Seq 11060</p> - </item> - - <item> - <p>Receiving an snmp message with a very large version - number could cause the erlang node to run out of - memory and consequently crash. </p> - <p>The standard specifies the snmp version as an - (unlimited) INTEGER, but today only - 0 (version 1), 1 (version 2) and 3 (version 3) is - actually used. So, when decoding a message, a limit - has been put on the snmp version integer in order - to not allow this kind of a problem. </p> - <p>Own Id: OTP-7575</p> - <p>Aux Id: Seq 11064</p> - </item> - - </list> - </section> - - <section> - <title>Incompatibilities</title> - <p>-</p> - </section> - </section> <!-- 4.11.2 --> - - - <section> - <title>SNMP Development Toolkit 4.11.1</title> - <p>Version 4.11.1 supports code replacement in runtime from/to - version 4.11.</p> - - <section> - <title>Improvements and new features</title> - <!-- - <p>-</p> - --> - <list type="bulleted"> - <item> - <p>[compiler] The MIB compiler did not retrieve the REFERENCE part - of a SNMP MIB definition. </p> - <p>This problem has been partly solved. For SNMP tables, - the assocList field of the tables mib-entry record now contains - this info (as <c>{reference, string()}</c>), <em>if</em> the - MIB was compiled with the compiler option <em>+reference</em>. </p> - <p>This solution is temporary, until such time as a permanent - solution (and probably not backward compatible) is devised, which - retrieves and stores all REFERENCE part(s) of a MIB. </p> - <p>See the - <seealso marker="snmpc#compiler_opts">compiler options</seealso> - for more info. </p> - - <p>Serge Aleynikov</p> - <p>Own Id: OTP-7426</p> - </item> - - <item> - <p>Added utility functions for transforming DateAndTime - as [int()] to strings; - <seealso marker="snmp#dat2s">date_and_time_to_string/2</seealso> - and - <seealso marker="snmp#dat2s2">date_and_time_to_string2/1</seealso>. </p> - <p>Also added new validation function - <seealso marker="snmp#vdat">validate_date_and_time/2</seealso>. </p> - <p>Own Id: OTP-7412</p> - <p>Aux Id: Seq 10987</p> - </item> - - </list> - - </section> - - <section> - <title>Reported Fixed Bugs and Malfunctions</title> - <!-- - <p>-</p> - --> - <list type="bulleted"> - <item> - <p>[manager] Encryption error when attempting to send - version 3 inform-requests. </p> - <p>Own Id: OTP-7432</p> - <p>Aux Id: Seq 10966</p> - </item> - - </list> - </section> - - <section> - <title>Incompatibilities</title> - <p>-</p> - </section> - </section> <!-- 4.11.1 --> - - <section> - <title>SNMP Development Toolkit 4.11</title> - <p>Version 4.11 supports code replacement in runtime from/to - version 4.10.3, 4.10.2, 4.10.1 and 4.10.</p> - - <section> - <title>Improvements and new features</title> - <!-- - <p>-</p> - --> - <list type="bulleted"> - <item> - <p>[agent] Performance improvements in the case when an SNMP - manager performs an snmpwalk. </p> - <p>Martin Björklund</p> - <p>Own Id: OTP-7201</p> - </item> - - <item> - <p>The API for sending inform(s) has been improved. Also - the documentation has been corrected and updated. See - <seealso marker="snmpa#send_notification">snmpa:send_notification</seealso> and - <seealso marker="snmpa_notification_delivery_info_receiver">snmpa_notification_delivery_info_receiver</seealso> - for more info.</p> - <p>Own Id: OTP-7287</p> - <p>Aux Id: Seq 10926</p> - </item> - - <item> - <p>[agent] Performance of the internal database (local-db) - has been improved.</p> - <p>Own Id: OTP-7319</p> - <p>Aux Id: Seq 10942</p> - </item> - - <item> - <p>[agent] Added utility functions, - <seealso marker="snmpa#restart_worker">snmpa:restart_worker/0,1</seealso> and - <seealso marker="snmpa#restart_set_worker">snmpa:restart_set_worker/0,1</seealso>, - for restarting the agent worker processes (in case the agent is - multi-threaded).</p> - <p>Own Id: OTP-7369</p> - </item> - - <item> - <p>Add utility function to - <seealso marker="snmp#read_mib">read</seealso> - a compiled mib. </p> - <p>Own Id: OTP-7371</p> - </item> - - </list> - </section> - - <section> - <title>Reported Fixed Bugs and Malfunctions</title> - <!-- - <p>-</p> - --> - <list type="bulleted"> - <item> - <p>[manager] Encryption error when attempting to send - version 3 inform-requests. </p> - <p>Own Id: OTP-7377</p> - <p>Aux Id: Seq 10966</p> - </item> - - </list> - </section> - - <section> - <title>Incompatibilities</title> - <p>-</p> - </section> - </section> <!-- 4.11 --> - <!-- section> <title>Release notes history</title> <p>For information about older versions see diff --git a/lib/snmp/doc/src/notes_history.xml b/lib/snmp/doc/src/notes_history.xml index 934df87866..023717cd7c 100644 --- a/lib/snmp/doc/src/notes_history.xml +++ b/lib/snmp/doc/src/notes_history.xml @@ -1,10 +1,10 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="iso-8859-1" ?> <!DOCTYPE chapter SYSTEM "chapter.dtd"> <chapter> <header> <copyright> - <year>2004</year><year>2010</year> + <year>2004</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -33,6 +33,1277 @@ </header> <section> + <title>SNMP Development Toolkit 4.17.1</title> + <p>Version 4.17.1 supports code replacement in runtime from/to + version 4.17, 4.16.2, 4.16.1, 4.16, 4.15, 4.14 and 4.13.5.</p> + + <section> + <title>Improvements and new features</title> + <p>-</p> + </section> + + <section> + <title>Reported Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>When the function FilterMod:accept_recv/2 + returned false the SNMP agent stopped collecting + messages from UDP.</p> + <p>Own Id: OTP-8761</p> + </item> + </list> + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + </section> + </section> <!-- 4.17.1 --> + + + <section> + <title>SNMP Development Toolkit 4.17</title> + <p>Version 4.17 supports code replacement in runtime from/to + version 4.16.2, 4.16.1, 4.16, 4.15, 4.14 and 4.13.5.</p> + + <section> + <title>Improvements and new features</title> + <!-- + <p>-</p> + --> + <list type="bulleted"> + <item> + <p>[agent] Added very basic support for multiple SNMPv3 + EngineIDs in a single agent. See + <seealso marker="snmpa#send_notification">send_notification/7</seealso>, + <seealso marker="snmpa_mpd#process_packet">process_packet/7</seealso>, + <seealso marker="snmpa_mpd#generate_response_msg">generate_response_msg/6</seealso> or + <seealso marker="snmpa_mpd#generate_msg">generate_msg/6</seealso> + for more info. </p> + + <p>Own Id: OTP-8478</p> + </item> + + </list> + + </section> + + <section> + <title>Reported Fixed Bugs and Malfunctions</title> + <p>-</p> + + <!-- + <list type="bulleted"> + <item> + <p>The config utility + (<seealso marker="snmp#config">snmp:config/0</seealso>) + generated a default notify.conf + with a bad name for the standard trap entry (was "stadard trap", + but should have been "standard trap"). This has been corrected. </p> + <p>Kenji Rikitake</p> + <p>Own Id: OTP-8433</p> + </item> + + </list> + --> + + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + </section> + </section> <!-- 4.17 --> + + + <section> + <title>SNMP Development Toolkit 4.16.2</title> + <p>Version 4.16.2 supports code replacement in runtime from/to + version 4.16.1, 4.16, 4.15, 4.14 and 4.13.5.</p> + + <section> + <title>Improvements and new features</title> + <!-- + <p>-</p> + --> + <list type="bulleted"> + <item> + <p>[compiler] The SMI specifies that a table row OID should be + named: { <tableIdentifier> "1" }. </p> + <p>A new option has been introduced, + <seealso marker="snmpc#compiler_opts">relaxed_row_name_assign_check</seealso>, + that allows for a more liberal numbering scheme</p> + <p>Own Id: OTP-8574</p> + </item> + + <item> + <p>[agent|manager] Changes to make snmp (forward) compatible with + the new version of the crypto application (released in R14). + As of R14, crypto is implemented using NIFs. Also, + the API is more strict. </p> + <p>Own Id: OTP-8594</p> + </item> + + <item> + <p>Auto [agent] Changed default value for the MIB server cache. + GC is now on by default. </p> + <p>Own Id: OTP-8648</p> + </item> + + </list> + + </section> + + <section> + <title>Reported Fixed Bugs and Malfunctions</title> + <!-- + <p>-</p> + --> + + <list type="bulleted"> + <item> + <p>Encode/decode of Counter64 values larger than + 16#7fffffffffffffff (9223372036854775807) failed. </p> + <p>Own Id: OTP-8563</p> + </item> + + <item> + <p>[compiler] Fails to compile non-contiguous BITS. </p> + <p>Per Hedeland</p> + <p>Own Id: OTP-8595</p> + </item> + + <item> + <p>[manager] Raise condition causing the manager server process to + crash. Unregistering an agent while traffic (set/get-operations) + is ongoing could cause a crash in the manager server process + (raise condition). </p> + <p>Own Id: OTP-8646</p> + <p>Aux Id: Seq 11585</p> + </item> + + </list> + + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + </section> + </section> <!-- 4.16.2 --> + + + <section> + <title>SNMP Development Toolkit 4.16.1</title> + <p>Version 4.16.1 supports code replacement in runtime from/to + version 4.16, 4.15, 4.14 and 4.13.5.</p> + + <section> + <title>Improvements and new features</title> + <p>-</p> + <!-- + <list type="bulleted"> + <item> + <p>[agent|manager] Entries in the audit trail log can now be + augmented by a sequence number. </p> + <p>This is enabled by the <c>seqno</c> option, which is part of the + <seealso marker="snmp_config#audit_trail_log">Audit Trail Log</seealso> + config option. </p> + <p>See the + <seealso marker="snmp_app#configuration_params">reference manual</seealso> + or the + <seealso marker="snmp_config#configuration_params">Configuring the application</seealso> + chapter of the User's Guide for further info. </p> + + <p>Own Id: OTP-8395</p> + </item> + + </list> + --> + + </section> + + <section> + <title>Reported Fixed Bugs and Malfunctions</title> + <!-- + <p>-</p> + --> + + <list type="bulleted"> + <item> + <p>[manager] Fixed an upgrade/downgrade problem. </p> + <p>Upgrade/downgrade from/to 4.13.5 did not work for the net-if + process. This has now been fixed. </p> + <p>Own Id: OTP-8481</p> + </item> + + <item> + <p>[agent] A minor mnesia related performance improvement. </p> + <p>Own Id: OTP-8480</p> + </item> + + </list> + + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + </section> + </section> <!-- 4.16.1 --> + + + <section> + <title>SNMP Development Toolkit 4.16</title> + <p>Version 4.16 supports code replacement in runtime from/to + version 4.15, 4.14 and 4.13.5.</p> + + <section> + <title>Improvements and new features</title> + <!-- + <p>-</p> + --> + <list type="bulleted"> + <item> + <p>[agent|manager] Entries in the audit trail log can now be + augmented by a sequence number. </p> + <p>This is enabled by the <c>seqno</c> option, which is part of the + <seealso marker="snmp_config#audit_trail_log">Audit Trail Log</seealso> + config option. </p> + <p>See the + <seealso marker="snmp_app#configuration_params">reference manual</seealso> + or the + <seealso marker="snmp_config#configuration_params">Configuring the application</seealso> + chapter of the User's Guide for further info. </p> + + <p>Own Id: OTP-8395</p> + </item> + + </list> + + </section> + + <section> + <title>Reported Fixed Bugs and Malfunctions</title> + <!-- + <p>-</p> + --> + + <list type="bulleted"> + <item> + <p>[manager] Registration of agents using the config file, + <seealso marker="snmp_manager_config_files#agents">agents.conf</seealso>, + does not work. This has now been corrected. </p> + <p>Per Hedeland</p> + <p>Own Id: OTP-8442</p> + </item> + + <item> + <p>The config utility + (<seealso marker="snmp#config">snmp:config/0</seealso>) + generated a default notify.conf + with a bad name for the standard trap entry (was "stadard trap", + but should have been "standard trap"). This has been corrected. </p> + <p>Kenji Rikitake</p> + <p>Own Id: OTP-8433</p> + </item> + + </list> + + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + </section> + </section> <!-- 4.16 --> + + + <section> + <title>SNMP Development Toolkit 4.15</title> + + <p>Version 4.15 supports code replacement in runtime from/to + version 4.14 and 4.13.5.</p> + + <section> + <title>Improvements and new features</title> + <!-- + <p>-</p> + --> + + <list type="bulleted"> + <item> + <p>The documentation is now built with open source tools + (<em>xsltproc</em> and <em>fop</em>) that exists on most + platforms. One visible change is that the frames are removed.</p> + <p>Own Id: OTP-8249</p> + </item> + + </list> + + </section> + + <section> + <title>Reported Fixed Bugs and Malfunctions</title> + <!-- + <p>-</p> + --> + <list type="bulleted"> + <item> + <p>[manager] When information from an unknown agent is received, + it was previously delivered to the default user via calls to all + the functions of the callback API depending on the info type + (<c>pdu</c>, <c>trap</c>, <c>report</c> or <c>inform</c>). + The problem was that the <c>TargetName</c> argument was useless + in this case (only an already known agent has a known/valid + <c>TargetName</c>, but the <c>TargetName</c> used in these calls + was generated "on the fly"). </p> + <p>This has now been changed so that when a message is received + from an unknown agent, then only + <seealso marker="snmpm_user#handle_agent">handle_agent</seealso> + (for the default user) is called, but now this call also has a + <c>Type</c> argument, which is + <c>pdu | trap | report | inform</c>, depending on what kind of + message was actually received, thus making it possible for the + user to properly analyze the data received. </p> + <p>To handle this, the + <seealso marker="snmpm_user">snmpm_user</seealso> behaviour has + been updated. </p> + <p>*** POTENTIAL INCOMPATIBILITY ***</p> + <p>Own Id: OTP-8229</p> + <!-- <p>Aux Id: Seq 11312</p> --> + </item> + + </list> + + </section> + + </section> <!-- 4.15 --> + + + <section> + <title>SNMP Development Toolkit 4.14</title> + + <p>Version 4.14 supports code replacement in runtime from/to + version 4.13.5, 4.13.4, 4.13.3, 4.13.2, 4.13.1 and 4.13.</p> + + <section> + <title>Improvements and new features</title> + <!-- + <p>-</p> + --> + + <list type="bulleted"> + <item> + <p>[compiler] Include object- and notification groups in the + compiled mib. + This will make it possible to import groups from other mibs. </p> + <p>Also the SNMPv2-MIB-file has been updated to a more + up-to-date version. </p> + <p>Own Id: OTP-8223</p> + <!-- <p>Aux Id: Seq 11383</p> --> + </item> + + <item> + <p>[manager] Added support for message filtering in the + network interface module provided with the application. + The component that actually make the filter decisions + is the network interface filter module. This module + must implement the + <seealso marker="snmpm_network_interface_filter">network interface filter behaviour</seealso> + for message filtering. + See also the Configuring chapter of + the User's Guide to see how to configure this feature. </p> + <p>See the + <seealso marker="snmp_app#configuration_params">configuration</seealso> + chapter for more info about the filter options.</p> + <p>Own Id: OTP-8228</p> + <p>Aux Id: Seq 11411</p> + </item> + + <item> + <p>The MIBs delivered as part of the application is now + also available as man pages, section 7. </p> + <p>Own Id: OTP-8237</p> + <!-- <p>Aux Id: Seq 11383</p> --> + </item> + + </list> + + </section> + + <section> + <title>Reported Fixed Bugs and Malfunctions</title> + <p>-</p> + + <!-- + <list type="bulleted"> + <item> + <p>[agent] The main agent type header file contained some miss-information + regarding the type of the entrytype field of the me-record, causing + unneccessary confusion.</p> + <p>Own Id: OTP-8116</p> + <p>Aux Id: Seq 11312</p> + </item> + + </list> + --> + + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + </section> + </section> <!-- 4.14 --> + + + <section> + <title>SNMP Development Toolkit 4.13.5</title> + + <p>Version 4.13.5 supports code replacement in runtime from/to + version 4.13.4, 4.13.3, 4.13.2, 4.13.1 and 4.13.</p> + + <section> + <title>Improvements and new features</title> + <!-- + <p>-</p> + --> + + <list type="bulleted"> + <item> + <p>[agent] Improved the cache handling of the mib server. </p> + <p>A number of new functions and config options for the mib server + cache has been added. </p> + <p>See + <seealso marker="snmpa#invalidate_mibs_cache">invalidate_mibs_cache/0,1</seealso>, + <seealso marker="snmpa#enable_mibs_cache">enable_mibs_cache/0,1</seealso>, + <seealso marker="snmpa#disable_mibs_cache">disable_mibs_cache/0,1</seealso>, + <seealso marker="snmpa#gc_mibs_cache">gc_mibs_cache/0,1,2,3</seealso>, + <seealso marker="snmpa#enable_mibs_cache_autogc">enable_mibs_cache_autogc/0,1</seealso>, + <seealso marker="snmpa#disable_mibs_cache_autogc">disable_mibs_cache_autogc/0,1</seealso>, + <seealso marker="snmpa#update_mibs_cache_age">update_mibs_cache_age/1,2</seealso> and + <seealso marker="snmpa#update_mibs_cache_gclimit">update_mibs_cache_gclimit/1,2</seealso> for more info. </p> + <p>See also the + <seealso marker="snmp_app#configuration_params">configuration</seealso> + chapter for more info about the mib server cache options.</p> + <p>Own Id: OTP-8182</p> + <p>Aux Id: Seq 11383</p> + </item> + + <item> + <p>[agent] A manager could no longer use the SNMPv3 user "initial" + as this was interpretated as the first step of the discovery. </p> + <p>Introduced a new terminating option, <c>trigger_username</c> to + make it possible to configure the username the agent reacts to. + Default is <c>""</c>. </p> + <p>See the + <seealso marker="snmp_app#configuration_params">configuration</seealso> + chapter for more info about the discovery options.</p> + <p>Own Id: OTP-8120</p> + <p>Aux Id: Seq 11361</p> + </item> + + </list> + + </section> + + <section> + <title>Reported Fixed Bugs and Malfunctions</title> + <!-- + <p>-</p> + --> + <list type="bulleted"> + <item> + <p>[agent] The main agent type header file contained some miss-information + regarding the type of the entrytype field of the me-record, causing + unneccessary confusion.</p> + <p>Own Id: OTP-8116</p> + <p>Aux Id: Seq 11312</p> + </item> + + </list> + + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + </section> + </section> <!-- 4.13.5 --> + + + <section> + <title>SNMP Development Toolkit 4.13.4</title> + + <p>Version 4.13.4 supports code replacement in runtime from/to + version 4.13.3, 4.13.2, 4.13.1 and 4.13.</p> + + <section> + <title>Improvements and new features</title> + <p>-</p> + + <!-- + <list type="bulleted"> + <item> + <p>[agent] Support for the discovery process. </p> + <p>The agent can both initiate discovery itself (see the + <seealso marker="snmp_agent_funct_descr#discovery">discovery</seealso> chapter + for more info) and respond to discovery initiated by a manager.</p> + <p>Own Id: OTP-7571</p> + <p>Aux Id: Seq 11053</p> + </item> + + </list> + --> + + </section> + + <section> + <title>Reported Fixed Bugs and Malfunctions</title> + <!-- + <p>-</p> + --> + <list type="bulleted"> + <item> + <p>[agent] Originating discovery problems. </p> + <p>Invalid state variable update during second stage of + discovery causes master agent crash. </p> + <p>Also the net_if process failed to activate socket + ({active, once}) after first discovery response was sent. </p> + <p>Own Id: OTP-8044</p> + <p>Aux Id: Seq 11295</p> + </item> + + <item> + <p>[agent] Terminating discovery problem. </p> + <p>The reply to the second stage request should include a + varbind with <c>usmStatsNotInTimeWindows</c>.</p> + <p>Own Id: OTP-8062</p> + <p>Aux Id: Seq 11318</p> + </item> + + <item> + <p>[agent] Originating discovery improvement. </p> + <p>Added the ExtraInfo argument to the + <seealso marker="snmpa#discovery">discovery</seealso> function. + This argument will be passed on to the stage1_finish callback + function. Also, the + <seealso marker="snmpa#discovery">discovery</seealso> function + will now always return <c>{ok, ManagerEngineID}</c> on successful + discovery. </p> + <p>The <seealso marker="snmpa_discovery_handler">discovery handler</seealso> + behaviour updated accordingly. </p> + <p>Own Id: OTP-8098</p> + <p>Aux Id: Seq 11346</p> + </item> + + </list> + + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + </section> + </section> <!-- 4.13.4 --> + + + <section> + <title>SNMP Development Toolkit 4.13.3</title> + + <p>Version 4.13.3 supports code replacement in runtime from/to + version 4.13.2, 4.13.1 and 4.13.</p> + + <section> + <title>Improvements and new features</title> + <p>-</p> + + <!-- + <list type="bulleted"> + <item> + <p>[agent] Support for the discovery process. </p> + <p>The agent can both initiate discovery itself (see the + <seealso marker="snmp_agent_funct_descr#discovery">discovery</seealso> chapter + for more info) and respond to discovery initiated by a manager.</p> + <p>Own Id: OTP-7571</p> + <p>Aux Id: Seq 11053</p> + </item> + + </list> + --> + + </section> + + <section> + <title>Reported Fixed Bugs and Malfunctions</title> + <!-- + <p>-</p> + --> + <list type="bulleted"> + <item> + <p>[manager] A request for an oid of type BITS was actually + returned as OCTET STRING. </p> + <p>Values of type BITS are encoded as OCTET STRING, + which makes it impossible for the decoder to know that + they should really be of type BITS. + Instead, this has to be done higher up in the stack, where + there is knowledge of the MIB (assuming that the mib has + been loaded, there is info about the type of the mibentry). </p> + <p>This problem has now been fixed, but requires that the MIB + defining this mib-entry is loaded! </p> + <p>The utility function + <seealso marker="snmpm#oid_to_type">oid_to_type</seealso> + has been added, for debug purpose. </p> + <p>The utility function(s) + <seealso marker="snmp#octet_string_to_bits">octet_string_to_bits</seealso> + and + <seealso marker="snmp#bits_to_octet_string">bits_to_octet_string</seealso> + has also been added. These can be used if the user prefers to + handle the conversion on their own. </p> + <p>Own Id: OTP-8015</p> + <p>Aux Id: Seq 11285</p> + </item> + + <item> + <p>[agent] Fixed some issues with the discovery handling. </p> + <p>Changed the API of the + <seealso marker="snmpa#discovery">discovery</seealso> + function to solve some + of these problems. </p> + <p>Introduced various options for controlling the discovery + process. See the + <seealso marker="snmp_app#configuration_params">configuration</seealso> + chapter for more info about the discovery options.</p> + <p>Own Id: OTP-8020</p> + <p>Aux Id: Seq 11295</p> + </item> + + </list> + + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + </section> + </section> <!-- 4.13.3 --> + + + <section> + <title>SNMP Development Toolkit 4.13.2</title> + + <p>Version 4.13.2 supports code replacement in runtime from/to + version 4.13.1 and 4.13.</p> + + <section> + <title>Improvements and new features</title> + <p>-</p> + + <!-- + <list type="bulleted"> + <item> + <p>[agent] Support for the discovery process. </p> + <p>The agent can both initiate discovery itself (see the + <seealso marker="snmp_agent_funct_descr#discovery">discovery</seealso> chapter + for more info) and respond to discovery initiated by a manager.</p> + <p>Own Id: OTP-7571</p> + <p>Aux Id: Seq 11053</p> + </item> + + </list> + --> + + </section> + + <section> + <title>Reported Fixed Bugs and Malfunctions</title> + <!-- + <p>-</p> + --> + <list type="bulleted"> + <item> + <p>[manager] Failure during downed user cleanup. + As part of the cleanup after a crashed user, + the manager attempts to unregister the agents + registered by this user. This however failed, + causing a server crash. </p> + <p>Own Id: OTP-7961</p> + <p>Aux Id: Seq 11275</p> + </item> + + <item> + <p>[manager] Incorrectly documented value type for + IpAddress (ip). The value type for IpAddress is + documented as ip but is actually ia. The value type + ip has been added. The old (not documented) value + type ia still works. </p> + <p>Own Id: OTP-7977</p> + <p>Aux Id: Seq 11279</p> + </item> + + <item> + <p>[manager] EngineId lookup fails when using version-3. </p> + <p>Own Id: OTP-7983</p> + <p>Aux Id: Seq 11275</p> + </item> + + <item> + <p>[agent] As of version 4.13 the possible return values + of the function + <seealso marker="snmpa_mpd#process_packet">snmpa_mpd:process_packet/4</seealso> + changed, but this was not documented. </p> + <p>Own Id: OTP-7989</p> + <p>Aux Id: Seq 11275</p> + </item> + + </list> + + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + </section> + </section> <!-- 4.13.2 --> + + <section> + <title>SNMP Development Toolkit 4.13.1</title> + + <p>Version 4.13.1 supports code replacement in runtime from/to + version 4.13.</p> + + <section> + <title>Improvements and new features</title> + <p>-</p> + + <!-- + <list type="bulleted"> + <item> + <p>[agent] Support for the discovery process. </p> + <p>The agent can both initiate discovery itself (see the + <seealso marker="snmp_agent_funct_descr#discovery">discovery</seealso> chapter + for more info) and respond to discovery initiated by a manager.</p> + <p>Own Id: OTP-7571</p> + <p>Aux Id: Seq 11053</p> + </item> + + </list> + --> + + </section> + + <section> + <title>Reported Fixed Bugs and Malfunctions</title> + <!-- + <p>-</p> + --> + <list type="bulleted"> + <item> + <p>[manager] Registration of users had some issues. </p> + <p>Not all of the registration functions where actually exported + (<seealso marker="snmpm#register_user">register_user/4</seealso> + and + <seealso marker="snmpm#register_user_monitor">register_user_monitor/4</seealso>). + This has now been fixed. </p> + <p>Also, the registration did not succeed unless + user implemented the *new* behaviour. This has now + also been fixed (registration succeeds if the user + implements either the new (i.e. updated + <seealso marker="snmpm_user">snmpm_user</seealso>) + or the old user behaviour (<c>snmpm_user_old</c>)). </p> + <p>Own Id: OTP-7902</p> + <p>Aux Id: Seq 11240</p> + </item> + + </list> + + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + </section> + </section> <!-- 4.13.1 --> + + <section> + <title>SNMP Development Toolkit 4.13</title> +<!-- + <p>Version 4.13 supports code replacement in runtime from/to + version 4.12.1.</p> +--> + + <section> + <title>Improvements and new features</title> + <!-- + <p>-</p> + --> + <list type="bulleted"> + <item> + <p>[agent] Support for the discovery process. </p> + <p>The agent can both initiate discovery itself (see the + <seealso marker="snmp_agent_funct_descr#discovery">discovery</seealso> chapter + for more info) and respond to discovery initiated by a manager.</p> + <p>Own Id: OTP-7571</p> + <p>Aux Id: Seq 11053</p> + </item> + + </list> + + </section> + + <section> + <title>Reported Fixed Bugs and Malfunctions</title> + <!-- + <p>-</p> + --> + <list type="bulleted"> + <item> + <p>[agent] Unnecessary use of math:pow/2 could cause problems + on systems without floating point support. </p> + <p>Per Hedeland</p> + <p>Own Id: OTP-7735</p> + <!-- <p>Aux Id: Seq 10966</p> --> + </item> + + <item> + <p>[manager] A major flaw was discovered with the agent handling. </p> + <p>First, <c>TargetName</c> was never used as intended, as a unique + identifier for the target (agent in this case). </p> + <p>Second, <c>TargetName</c> had a <em>default value</em>, which meant + that several agents could have the same <c>TargetName</c>, causing + unpredictable behaviour in the manager. </p> + <p>Third, <c>EngineID</c> was not a mandatory config option and had + furthermore also a <em>default value</em>. </p> + + <p>These problems has been solved in the following way: </p> + <p>First, a new set of api functions has been introduced (and documented): + <seealso marker="snmpm#register_user">register_user/4</seealso>, + <seealso marker="snmpm#register_user_monitor">register_user_monitor/4</seealso>, + <seealso marker="snmpm#register_agent">register_agent/3</seealso>, + <seealso marker="snmpm#unregister_agent">unregister_agent/2</seealso>, + <seealso marker="snmpm#agent_info">agent_info/2</seealso>, + <seealso marker="snmpm#update_agent_info">update_agent_info/4</seealso>, + <seealso marker="snmpm#sync_get">sync_get/3,4,5,6</seealso>, + <seealso marker="snmpm#async_get">async_get/3,4,5,6</seealso>, + <seealso marker="snmpm#sync_get_next">sync_get_next/3,4,5,6</seealso>, + <seealso marker="snmpm#async_get_next">async_get_next/3,4,5,6</seealso>, + <seealso marker="snmpm#sync_set">sync_set/3,4,5,6</seealso>, + <seealso marker="snmpm#async_set">async_set/3,4,5,6</seealso>, + <seealso marker="snmpm#sync_get_bulk">sync_get_bulk/5,6,7,8</seealso> and + <seealso marker="snmpm#async_get_bulk">async_get_bulk/5,6,7,8</seealso> + that all use <c>TargetName</c> (and not, as previously, <c>Addr</c> + and <c>Port</c>) to identify the agent (also the return value of + <seealso marker="snmpm#which_agents">which_agents</seealso> has + been changed). </p> + <p>Second, for backward compatibility, the old functions still + exist, but are no longer documented and are now wrappers for the + new functions, including erroneous default value for EngineID and + all. The TargetName is however generated from the provided + <c>Addr</c>, <c>Port</c> and <c>Version</c> config options. </p> + <p>Third, the behaviour of the + <seealso marker="snmpm_user">SNMP manager user</seealso> has + been changed to reflect this, i.e. + <seealso marker="snmpm_user#handle_pdu">handle_pdu/4</seealso>, + <seealso marker="snmpm_user#handle_trap">handle_trap/3</seealso>, + <seealso marker="snmpm_user#handle_inform">handle_inform/3</seealso>, + <seealso marker="snmpm_user#handle_report">handle_report/3</seealso> + and the return-value of + <seealso marker="snmpm_user#handle_agent">handle_agent/4</seealso>. + The old (non-documented) callback-functions (using Addr and Port) + will still be called if the agent was registered using the old + registration functions. </p> + + <p>Own Id: OTP-7836</p> + <!-- <p>Aux Id: Seq 10966</p> --> + </item> + + </list> + + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + </section> + </section> <!-- 4.13 --> + + <section> + <title>SNMP Development Toolkit 4.12.2</title> + <p>Version 4.12.2 supports code replacement in runtime from/to + version 4.12.1, 4.12, 4.11.2, 4.11.1 and 4.11.</p> + + <section> + <title>Improvements and new features</title> + <p>-</p> + <!-- + <list type="bulleted"> + <item> + <item> + <p>[agent] Improvement of the inform reporting. + It was previously not certain how many acks an + application received, 0, 1 or 2. This has now been + fixed, so that only 1 (one) ack is issued. </p> + <p>Per Hedeland</p> + <p>Own Id: OTP-7525</p> + </item> + + </list> + --> + + </section> + + <section> + <title>Reported Fixed Bugs and Malfunctions</title> + <!-- + <p>-</p> + --> + <list type="bulleted"> + <item> + <p>[agent] Bad session cache (usm+camv-info) invalidation + could cause user crash, through call(s) to (a number of) + MIB API function(s) (undefined function). </p> + <p>Own Id: OTP-7868</p> + <!-- <p>Aux Id: Seq 11124</p> --> + </item> + + </list> + + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + </section> + </section> <!-- 4.12.2 --> + + <section> + <title>SNMP Development Toolkit 4.12.1</title> + <p>Version 4.12.1 supports code replacement in runtime from/to + version 4.12, 4.11.2, 4.11.1 and 4.11.</p> + + <section> + <title>Improvements and new features</title> + <p>-</p> + <!-- + <list type="bulleted"> + <item> + <item> + <p>[agent] Improvement of the inform reporting. + It was previously not certain how many acks an + application received, 0, 1 or 2. This has now been + fixed, so that only 1 (one) ack is issued. </p> + <p>Per Hedeland</p> + <p>Own Id: OTP-7525</p> + </item> + + </list> + --> + + </section> + + <section> + <title>Reported Fixed Bugs and Malfunctions</title> + <!-- + <p>-</p> + --> + <list type="bulleted"> + <item> + <p>Logging of messages with the GetBulk-request PDU + incorrectly produced an erroneous entry in the + log: "An error occurred". </p> + <p>The reason for this was that the PDU-fields + error_status and error_index is re-used for + Non-repeaters and Max-repetitions for + GetBulk-request PDUs, but this was not handled + by the logging code. </p> + <p>Own Id: OTP-7695</p> + <p>Aux Id: Seq 11124</p> + </item> + + <item> + <p>[agent] An attempt to set the row status to active for an + notReady table row, could result in an "inconsistentValue" + error. </p> + <p>The same problem existed when attempting to set row status + to notInService for a row in notReady. </p> + <p>Serge Aleynikov</p> + <p>Own Id: OTP-7698</p> + <!-- <p>Aux Id: Seq 10966</p> --> + </item> + + </list> + + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + </section> + </section> <!-- 4.12.1 --> + + <section> + <title>SNMP Development Toolkit 4.12</title> + <p>Version 4.12 supports code replacement in runtime from/to + version 4.11.2, 4.11.1 and 4.11.</p> + + <section> + <title>Improvements and new features</title> + <!-- + <p>-</p> + --> + <list type="bulleted"> + <item> + <p>[agent] A simple lookup cache has been added to improve + the mib server lookup performance. </p> + <p>This can be disabled with the mib_server + <seealso marker="snmp_app">cache</seealso> option. </p> + <p>Own Id: OTP-7346</p> + </item> + + <item> + <p>[agent] Improvement of the inform reporting. + It was previously not certain how many acks an + application received, 0, 1 or 2. This has now been + fixed, so that only 1 (one) ack is issued. </p> + <p>Per Hedeland</p> + <p>Own Id: OTP-7525</p> + </item> + + </list> + + </section> + + <section> + <title>Reported Fixed Bugs and Malfunctions</title> + <p>-</p> + <!-- + <list type="bulleted"> + <item> + <p>[manager] Encryption error when attempting to send + version 3 inform-requests. </p> + <p>Own Id: OTP-7432</p> + <p>Aux Id: Seq 10966</p> + </item> + + </list> + --> + + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + </section> + </section> <!-- 4.12 --> + + <section> + <title>SNMP Development Toolkit 4.11.2</title> + <p>Version 4.11.2 supports code replacement in runtime from/to + version 4.11.1 and 4.11. </p> + + <section> + <title>Improvements and new features</title> + <p>-</p> + <!-- + <list type="bulleted"> + <item> + <p>Added utility functions for transforming DateAndTime + as [int()] to strings; + <seealso marker="snmp#dat2s">date_and_time_to_string/2</seealso> + and + <seealso marker="snmp#dat2s2">date_and_time_to_string2/1</seealso>. </p> + <p>Also added new validation function + <seealso marker="snmp#vdat">validate_date_and_time/2</seealso>. </p> + <p>Own Id: OTP-7412</p> + <p>Aux Id: Seq 10987</p> + </item> + </list> + --> + </section> + + <section> + <title>Reported Fixed Bugs and Malfunctions</title> + <!-- + <p>-</p> + --> + <list type="bulleted"> + <item> + <p>[manager] Erroneous engine-id check when receiving version 3 + informs. </p> + <p>Own Id: OTP-7570</p> + <p>Aux Id: Seq 11060</p> + </item> + + <item> + <p>Receiving an snmp message with a very large version + number could cause the erlang node to run out of + memory and consequently crash. </p> + <p>The standard specifies the snmp version as an + (unlimited) INTEGER, but today only + 0 (version 1), 1 (version 2) and 3 (version 3) is + actually used. So, when decoding a message, a limit + has been put on the snmp version integer in order + to not allow this kind of a problem. </p> + <p>Own Id: OTP-7575</p> + <p>Aux Id: Seq 11064</p> + </item> + + </list> + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + </section> + </section> <!-- 4.11.2 --> + + + <section> + <title>SNMP Development Toolkit 4.11.1</title> + <p>Version 4.11.1 supports code replacement in runtime from/to + version 4.11.</p> + + <section> + <title>Improvements and new features</title> + <!-- + <p>-</p> + --> + <list type="bulleted"> + <item> + <p>[compiler] The MIB compiler did not retrieve the REFERENCE part + of a SNMP MIB definition. </p> + <p>This problem has been partly solved. For SNMP tables, + the assocList field of the tables mib-entry record now contains + this info (as <c>{reference, string()}</c>), <em>if</em> the + MIB was compiled with the compiler option <em>+reference</em>. </p> + <p>This solution is temporary, until such time as a permanent + solution (and probably not backward compatible) is devised, which + retrieves and stores all REFERENCE part(s) of a MIB. </p> + <p>See the + <seealso marker="snmpc#compiler_opts">compiler options</seealso> + for more info. </p> + + <p>Serge Aleynikov</p> + <p>Own Id: OTP-7426</p> + </item> + + <item> + <p>Added utility functions for transforming DateAndTime + as [int()] to strings; + <seealso marker="snmp#dat2s">date_and_time_to_string/2</seealso> + and + <seealso marker="snmp#dat2s2">date_and_time_to_string2/1</seealso>. </p> + <p>Also added new validation function + <seealso marker="snmp#vdat">validate_date_and_time/2</seealso>. </p> + <p>Own Id: OTP-7412</p> + <p>Aux Id: Seq 10987</p> + </item> + + </list> + + </section> + + <section> + <title>Reported Fixed Bugs and Malfunctions</title> + <!-- + <p>-</p> + --> + <list type="bulleted"> + <item> + <p>[manager] Encryption error when attempting to send + version 3 inform-requests. </p> + <p>Own Id: OTP-7432</p> + <p>Aux Id: Seq 10966</p> + </item> + + </list> + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + </section> + </section> <!-- 4.11.1 --> + + <section> + <title>SNMP Development Toolkit 4.11</title> + <p>Version 4.11 supports code replacement in runtime from/to + version 4.10.3, 4.10.2, 4.10.1 and 4.10.</p> + + <section> + <title>Improvements and new features</title> + <!-- + <p>-</p> + --> + <list type="bulleted"> + <item> + <p>[agent] Performance improvements in the case when an SNMP + manager performs an snmpwalk. </p> + <p>Martin Björklund</p> + <p>Own Id: OTP-7201</p> + </item> + + <item> + <p>The API for sending inform(s) has been improved. Also + the documentation has been corrected and updated. See + <seealso marker="snmpa#send_notification">snmpa:send_notification</seealso> and + <seealso marker="snmpa_notification_delivery_info_receiver">snmpa_notification_delivery_info_receiver</seealso> + for more info.</p> + <p>Own Id: OTP-7287</p> + <p>Aux Id: Seq 10926</p> + </item> + + <item> + <p>[agent] Performance of the internal database (local-db) + has been improved.</p> + <p>Own Id: OTP-7319</p> + <p>Aux Id: Seq 10942</p> + </item> + + <item> + <p>[agent] Added utility functions, + <seealso marker="snmpa#restart_worker">snmpa:restart_worker/0,1</seealso> and + <seealso marker="snmpa#restart_set_worker">snmpa:restart_set_worker/0,1</seealso>, + for restarting the agent worker processes (in case the agent is + multi-threaded).</p> + <p>Own Id: OTP-7369</p> + </item> + + <item> + <p>Add utility function to + <seealso marker="snmp#read_mib">read</seealso> + a compiled mib. </p> + <p>Own Id: OTP-7371</p> + </item> + + </list> + </section> + + <section> + <title>Reported Fixed Bugs and Malfunctions</title> + <!-- + <p>-</p> + --> + <list type="bulleted"> + <item> + <p>[manager] Encryption error when attempting to send + version 3 inform-requests. </p> + <p>Own Id: OTP-7377</p> + <p>Aux Id: Seq 10966</p> + </item> + + </list> + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + </section> + </section> <!-- 4.11 --> + + + <section> <title>SNMP Development Toolkit 4.10.3</title> <p>Version 4.10.3 supports code replacement in runtime from/to version 4.10.2, 4.10.1 and 4.10.</p> diff --git a/lib/snmp/doc/src/snmp_app.xml b/lib/snmp/doc/src/snmp_app.xml index 694e619da1..f6abe783b3 100644 --- a/lib/snmp/doc/src/snmp_app.xml +++ b/lib/snmp/doc/src/snmp_app.xml @@ -1,10 +1,10 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="iso-8859-1" ?> <!DOCTYPE appref SYSTEM "appref.dtd"> <appref> <header> <copyright> - <year>1997</year><year>2010</year> + <year>1997</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -78,7 +78,15 @@ ]. </pre> - <!-- The info below is also found in the snmp_config.xml file --> + + <!-- + ******************************************************** + + The info below is also found in the snmp_config.xml file + + ******************************************************** + --> + <p>Each snmp component has its own set of configuration parameters, even though some of the types are common to both components. </p> @@ -92,6 +100,7 @@ {agent_verbosity, verbosity()} | {discovery, agent_discovery()} | {versions, versions()} | + {gb_max_vbs, gb_max_vbs()} | {priority, priority()} | {multi_threaded, multi_threaded()} | {db_dir, db_dir()} | @@ -122,8 +131,10 @@ {def_user_data, def_user_data()} </pre> + <marker id="agent_opts_and_types"></marker> <p>Agent specific config options and types:</p> <taglist> + <marker id="agent_type"></marker> <tag><c><![CDATA[agent_type() = master | sub <optional>]]></c></tag> <item> <p>If <c>master</c>, one master agent is @@ -131,6 +142,7 @@ <p>Default is <c>master</c>.</p> </item> + <marker id="agent_disco"></marker> <tag><c><![CDATA[agent_discovery() = [agent_discovery_opt()] <optional>]]></c></tag> <item> <p><c>agent_discovery_opt() = @@ -143,6 +155,7 @@ <p>For defaults see the options in <c>agent_discovery_opt()</c>.</p> </item> + <marker id="agent_term_disco_opts"></marker> <tag><c><![CDATA[agent_terminating_discovery_opts() = [agent_terminating_discovery_opt()] <optional>]]></c></tag> <item> <p><c>agent_terminating_discovery_opt() = @@ -160,6 +173,7 @@ </list> </item> + <marker id="agent_orig_disco_opts"></marker> <tag><c><![CDATA[agent_originating_discovery_opts() = [agent_originating_discovery_opt()] <optional>]]></c></tag> <item> <p><c>agent_originating_discovery_opt() = @@ -173,6 +187,7 @@ </list> </item> + <marker id="agent_mt"></marker> <tag><c><![CDATA[multi_threaded() = bool() <optional>]]></c></tag> <item> <p>If <c>true</c>, the agent is multi-threaded, with one @@ -180,11 +195,21 @@ <p>Default is <c>false</c>.</p> </item> + <marker id="agent_data_dir"></marker> <tag><c><![CDATA[db_dir() = string() <mandatory>]]></c></tag> <item> <p>Defines where the SNMP agent internal db files are stored.</p> </item> + <marker id="agent_gb_max_vbs"></marker> + <tag><c><![CDATA[gb_max_vbs() = pos_integer() | infinity <optional>]]></c></tag> + <item> + <p>Defines the maximum number of varbinds allowed + in a Get-BULK response.</p> + <p>Default is <c>1000</c>.</p> + </item> + + <marker id="agent_local_db"></marker> <tag><c><![CDATA[local_db() = [local_db_opt()] <optional>]]></c></tag> <item> <p><c>local_db_opt() = {repair, agent_repair()} | {auto_save, agent_auto_save()} | {verbosity, verbosity()}</c></p> @@ -192,6 +217,7 @@ <p>For defaults see the options in <c>local_db_opt()</c>.</p> </item> + <marker id="agent_ldb_repair"></marker> <tag><c><![CDATA[agent_repair() = false | true | force <optional>]]></c></tag> <item> <p>When starting snmpa_local_db it always tries to open an @@ -202,6 +228,7 @@ <p>Default is <c>true</c>.</p> </item> + <marker id="agent_ldb_auto_save"></marker> <tag><c><![CDATA[agent_auto_save() = integer() | infinity <optional>]]></c></tag> <item> <p>The auto save interval. The table is flushed to disk @@ -209,6 +236,7 @@ <p>Default is <c>5000</c>.</p> </item> + <marker id="agent_net_if"></marker> <tag><c><![CDATA[agent_net_if() = [agent_net_if_opt()] <optional>]]></c></tag> <item> <p><c>agent_net_if_opt() = {module, agent_net_if_module()} | {verbosity, verbosity()} | {options, agent_net_if_options()}</c></p> @@ -217,6 +245,7 @@ <p>For defaults see the options in <c>agent_net_if_opt()</c>.</p> </item> + <marker id="agent_ni_module"></marker> <tag><c><![CDATA[agent_net_if_module() = atom() <optional>]]></c></tag> <item> <p>Module which handles the network interface part for the @@ -225,6 +254,7 @@ <p>Default is <c>snmpa_net_if</c>.</p> </item> + <marker id="agent_ni_opts"></marker> <tag><c><![CDATA[agent_net_if_options() = [agent_net_if_option()] <optional>]]></c></tag> <item> <p><c>agent_net_if_option() = {bind_to, bind_to()} | @@ -239,12 +269,14 @@ <p>For defaults see the options in <c>agent_net_if_option()</c>.</p> </item> + <marker id="agent_ni_req_limit"></marker> <tag><c><![CDATA[req_limit() = integer() | infinity <optional>]]></c></tag> <item> <p>Max number of simultaneous requests handled by the agent.</p> <p>Default is <c>infinity</c>.</p> </item> + <marker id="agent_ni_filter_opts"></marker> <tag><c><![CDATA[agent_net_if_filter_options() = [agent_net_if_filter_option()] <optional>]]></c></tag> <item> <p><c>agent_net_if_filter_option() = {module, agent_net_if_filter_module()}</c></p> @@ -255,6 +287,7 @@ <c>agent_net_if_filter_option()</c>.</p> </item> + <marker id="agent_ni_filter_module"></marker> <tag><c><![CDATA[agent_net_if_filter_module() = atom() <optional>]]></c></tag> <item> <p>Module which handles the network interface filter part for the @@ -263,6 +296,7 @@ <p>Default is <c>snmpa_net_if_filter</c>.</p> </item> + <marker id="agent_mibs"></marker> <tag><c><![CDATA[agent_mibs() = [string()] <optional>]]></c></tag> <item> <p>Specifies a list of MIBs (including path) that defines which MIBs @@ -277,6 +311,7 @@ <p>Default is <c>[]</c>.</p> </item> + <marker id="agent_mib_storage"></marker> <tag><c><![CDATA[mib_storage() = ets | {ets, Dir} | {ets, Dir, Action} | dets | {dets, Dir} | {dets, Dir, Action} | mnesia | {mnesia, Nodes} | {mnesia, Nodes, Action} <optional>]]></c></tag> <item> <p>Specifies how info retrieved from the mibs will be stored.</p> @@ -302,6 +337,7 @@ mnesia/dets table already exist.</p> </item> + <marker id="agent_mib_server"></marker> <tag><c><![CDATA[mib_server() = [mib_server_opt()] <optional>]]></c></tag> <item> <p><c>mib_server_opt() = {mibentry_override, mibentry_override()} | {trapentry_override, trapentry_override()} | {verbosity, verbosity()} | {cache, mibs_cache()}</c></p> @@ -309,6 +345,7 @@ <p>For defaults see the options in <c>mib_server_opt()</c>.</p> </item> + <marker id="agent_ms_meo"></marker> <tag><c><![CDATA[mibentry_override() = bool() <optional>]]></c></tag> <item> <p>If this value is false, then when loading a mib each mib- @@ -318,6 +355,7 @@ <p>Default is <c>false</c>.</p> </item> + <marker id="agent_ms_teo"></marker> <tag><c><![CDATA[trapentry_override() = bool() <optional>]]></c></tag> <item> <p>If this value is false, then when loading a mib each trap @@ -327,6 +365,7 @@ <p>Default is <c>false</c>.</p> </item> + <marker id="agent_ms_cache"></marker> <tag><c><![CDATA[mibs_cache() = bool() | mibs_cache_opts() <optional>]]></c></tag> <item> <p>Shall the agent utilize the mib server lookup cache or not.</p> @@ -334,6 +373,7 @@ default values apply).</p> </item> + <marker id="agent_ms_cache_opts"></marker> <tag><c><![CDATA[mibs_cache_opts() = [mibs_cache_opt()] <optional>]]></c></tag> <item> <p><c>mibs_cache_opt() = {autogc, mibs_cache_autogc()} | {gclimit, mibs_cache_gclimit()} | {age, mibs_cache_age()}</c></p> @@ -341,6 +381,7 @@ <p>For defaults see the options in <c>mibs_cache_opt()</c>.</p> </item> + <marker id="agent_ms_cache_autogc"></marker> <tag><c><![CDATA[mibs_cache_autogc() = bool() <optional>]]></c></tag> <item> <p>Defines if the mib server shall perform cache gc automatically or @@ -349,6 +390,7 @@ <p>Default is <c>true</c>.</p> </item> + <marker id="agent_ms_cache_age"></marker> <tag><c><![CDATA[mibs_cache_age() = integer() > 0 <optional>]]></c></tag> <item> <p>Defines how old the entries in the cache will be allowed before @@ -358,6 +400,7 @@ <p>Default is <c>10 timutes</c>.</p> </item> + <marker id="agent_ms_cache_gclimit"></marker> <tag><c><![CDATA[mibs_cache_gclimit() = integer() > 0 | infinity <optional>]]></c></tag> <item> <p>When performing a GC, this is the max number of cache entries @@ -368,6 +411,7 @@ <p>Default is <c>100</c>.</p> </item> + <marker id="agent_error_report_mod"></marker> <tag><c><![CDATA[error_report_mod() = atom() <optional>]]></c></tag> <item> <p>Defines an error report module, implementing the @@ -377,6 +421,7 @@ <p>Default is <c>snmpa_error_logger</c>.</p> </item> + <marker id="agent_symbolic_store"></marker> <tag><c>symbolic_store() = [symbolic_store_opt()]</c></tag> <item> <p><c>symbolic_store_opt() = {verbosity, verbosity()}</c></p> @@ -384,23 +429,29 @@ <p>For defaults see the options in <c>symbolic_store_opt()</c>.</p> </item> + <marker id="agent_target_cache"></marker> <tag><c>target_cache() = [target_cache_opt()]</c></tag> <item> <p><c>target_cache_opt() = {verbosity, verbosity()}</c></p> <p>Defines options specific for the SNMP agent target cache. </p> <p>For defaults see the options in <c>target_cache_opt()</c>.</p> </item> + + <marker id="agent_config"></marker> <tag><c><![CDATA[agent_config() = [agent_config_opt()] <mandatory>]]></c></tag> <item> <p><c>agent_config_opt() = {dir, agent_config_dir()} | {force_load, force_load()} | {verbosity, verbosity()}</c></p> <p>Defines specific config related options for the SNMP agent. </p> <p>For defaults see the options in <c>agent_config_opt()</c>.</p> </item> + + <marker id="agent_config_dir"></marker> <tag><c><![CDATA[agent_config_dir = dir() <mandatory>]]></c></tag> <item> <p>Defines where the SNMP agent configuration files are stored.</p> </item> + <marker id="agent_force_load"></marker> <tag><c><![CDATA[force_load() = bool() <optional>]]></c></tag> <item> <p>If <c>true</c> the configuration files are re-read @@ -412,14 +463,18 @@ </item> </taglist> + <marker id="manager_opts_and_types"></marker> <p>Manager specific config options and types:</p> <taglist> + <marker id="manager_server"></marker> <tag><c><![CDATA[server() = [server_opt()] <optional>]]></c></tag> <item> <p><c>server_opt() = {timeout, server_timeout()} | {verbosity, verbosity()}</c></p> <p>Specifies the options for the manager server process.</p> <p>Default is <c>silence</c>.</p> </item> + + <marker id="manager_server_timeout"></marker> <tag><c><![CDATA[server_timeout() = integer() <optional>]]></c></tag> <item> <p>Asynchroneous request cleanup time. For every requests, @@ -440,6 +495,7 @@ <p>Default is <c>30000</c>.</p> </item> + <marker id="manager_config"></marker> <tag><c><![CDATA[manager_config() = [manager_config_opt()] <mandatory>]]></c></tag> <item> <p><c>manager_config_opt() = {dir, manager_config_dir()} | {db_dir, manager_db_dir()} | {db_init_error, db_init_error()} | {repair, manager_repair()} | {auto_save, manager_auto_save()} | {verbosity, verbosity()}</c></p> @@ -447,16 +503,19 @@ <p>For defaults see the options in <c>manager_config_opt()</c>.</p> </item> + <marker id="manager_config_dir"></marker> <tag><c><![CDATA[manager_config_dir = dir() <mandatory>]]></c></tag> <item> <p>Defines where the SNMP manager configuration files are stored.</p> </item> + <marker id="manager_config_db_dir"></marker> <tag><c><![CDATA[manager_db_dir = dir() <mandatory>]]></c></tag> <item> <p>Defines where the SNMP manager store persistent data.</p> </item> + <marker id="manager_config_repair"></marker> <tag><c><![CDATA[manager_repair() = false | true | force <optional>]]></c></tag> <item> <p>Defines the repair option for the persistent database (if @@ -464,6 +523,7 @@ <p>Default is <c>true</c>.</p> </item> + <marker id="manager_config_auto_save"></marker> <tag><c><![CDATA[manager_auto_save() = integer() | infinity <optional>]]></c></tag> <item> <p>The auto save interval. The table is flushed to disk @@ -471,6 +531,7 @@ <p>Default is <c>5000</c>.</p> </item> + <marker id="manager_irb"></marker> <tag><c><![CDATA[manager_irb() = auto | user | {user, integer()} <optional>]]></c></tag> <item> <p>This option defines how the manager will handle the sending of @@ -500,6 +561,7 @@ <p>Default is <c>auto</c>.</p> </item> + <marker id="manager_mibs"></marker> <tag><c><![CDATA[manager_mibs() = [string()] <optional>]]></c></tag> <item> <p>Specifies a list of MIBs (including path) and defines which MIBs @@ -507,6 +569,7 @@ <p>Default is <c>[]</c>.</p> </item> + <marker id="manager_net_if"></marker> <tag><c><![CDATA[manager_net_if() = [manager_net_if_opt()] <optional>]]></c></tag> <item> <p><c>manager_net_if_opt() = {module, manager_net_if_module()} | @@ -517,6 +580,7 @@ <p>For defaults see the options in <c>manager_net_if_opt()</c>.</p> </item> + <marker id="manager_ni_opts"></marker> <tag><c><![CDATA[manager_net_if_options() = [manager_net_if_option()] <optional>]]></c></tag> <item> <p><c>manager_net_if_option() = {bind_to, bind_to()} | @@ -530,6 +594,7 @@ <p>For defaults see the options in <c>manager_net_if_option()</c>.</p> </item> + <marker id="manager_ni_module"></marker> <tag><c><![CDATA[manager_net_if_module() = atom() <optional>]]></c></tag> <item> <p>Module which handles the network interface part for the @@ -538,6 +603,7 @@ <p>Default is <c>snmpm_net_if</c>.</p> </item> + <marker id="manager_ni_filter_opts"></marker> <tag><c><![CDATA[manager_net_if_filter_options() = [manager_net_if_filter_option()] <optional>]]></c></tag> <item> <p><c>manager_net_if_filter_option() = {module, manager_net_if_filter_module()}</c></p> @@ -548,6 +614,7 @@ <c>manager_net_if_filter_option()</c>.</p> </item> + <marker id="manager_ni_filter_module"></marker> <tag><c><![CDATA[manager_net_if_filter_module() = atom() <optional>]]></c></tag> <item> <p>Module which handles the network interface filter part for the @@ -556,6 +623,7 @@ <p>Default is <c>snmpm_net_if_filter</c>.</p> </item> + <marker id="manager_def_user_module"></marker> <tag><c><![CDATA[def_user_module() = atom() <optional>]]></c></tag> <item> <p>The module implementing the default user. See the @@ -563,6 +631,7 @@ <p>Default is <c>snmpm_user_default</c>.</p> </item> + <marker id="manager_def_user_data"></marker> <tag><c><![CDATA[def_user_data() = term() <optional>]]></c></tag> <item> <p>Data for the default user. Passed to the user module when @@ -571,8 +640,10 @@ </item> </taglist> + <marker id="common_types"></marker> <p>Common config types:</p> <taglist> + <marker id="restart_type"></marker> <tag><c>restart_type() = permanent | transient | temporary</c></tag> <item> <p>See <seealso marker="stdlib:supervisor#child_spec">supervisor</seealso> @@ -580,6 +651,8 @@ <p>Default is <c>permanent</c> for the agent and <c>transient</c> for the manager.</p> </item> + + <marker id="db_init_error"></marker> <tag><c>db_init_error() = terminate | create</c></tag> <item> <p>Defines what to do if the agent or manager is unable to open an @@ -588,23 +661,31 @@ agent/manager will remove the faulty file(s) and create new ones.</p> <p>Default is <c>terminate</c>.</p> </item> + + <marker id="prio"></marker> <tag><c><![CDATA[priority() = atom() <optional>]]></c></tag> <item> <p>Defines the Erlang priority for all SNMP processes.</p> <p>Default is <c>normal</c>.</p> </item> + + <marker id="versions"></marker> <tag><c><![CDATA[versions() = [version()] <optional>]]></c></tag> <item> <p><c>version() = v1 | v2 | v3</c></p> <p>Which SNMP versions shall be accepted/used.</p> <p>Default is <c>[v1,v2,v3]</c>.</p> </item> + + <marker id="verbosity"></marker> <tag><c><![CDATA[verbosity() = silence | info | log | debug | trace <optional>]]></c></tag> <item> <p>Verbosity for a SNMP process. This specifies now much debug info is printed.</p> <p>Default is <c>silence</c>.</p> </item> + + <marker id="bind_to"></marker> <tag><c><![CDATA[bind_to() = bool() <optional>]]></c></tag> <item> <p>If <c>true</c>, net_if binds to the IP address. @@ -612,6 +693,8 @@ where it is running. </p> <p>Default is <c>false</c>.</p> </item> + + <marker id="no_reuse"></marker> <tag><c><![CDATA[no_reuse() = bool() <optional>]]></c></tag> <item> <p>If <c>true</c>, net_if does not specify that the IP @@ -619,22 +702,30 @@ the address is set to reusable. </p> <p>Default is <c>false</c>.</p> </item> + + <marker id="recbuf"></marker> <tag><c><![CDATA[recbuf() = integer() <optional>]]></c></tag> <item> <p>Receive buffer size. </p> <p>Default value is defined by <c>gen_udp</c>.</p> </item> + + <marker id="sndbuf"></marker> <tag><c><![CDATA[sndbuf() = integer() <optional>]]></c></tag> <item> <p>Send buffer size. </p> <p>Default value is defined by <c>gen_udp</c>.</p> </item> + + <marker id="note_store"></marker> <tag><c><![CDATA[note_store() = [note_store_opt()] <optional>]]></c></tag> <item> <p><c>note_store_opt() = {timeout, note_store_timeout()} | {verbosity, verbosity()}</c></p> <p>Specifies the start-up verbosity for the SNMP note store.</p> <p>For defaults see the options in <c>note_store_opt()</c>.</p> </item> + + <marker id="ns_timeout"></marker> <tag><c><![CDATA[note_store_timeout() = integer() <optional>]]></c></tag> <item> <p>Note cleanup time. When storing a note in the note store, @@ -643,9 +734,9 @@ milli-seconds.</p> <p>Default is <c>30000</c>.</p> - <marker id="audit_trail_log"></marker> </item> + <marker id="audit_trail_log"></marker> <tag><c><![CDATA[audit_trail_log() = [audit_trail_log_opt()] <optional>]]></c></tag> <item> <p><c>audit_trail_log_opt() = {type, atl_type()} | {dir, atl_dir()} | {size, atl_size()} | {repair, atl_repair()} | {seqno, atl_seqno()}</c></p> @@ -655,6 +746,8 @@ <c>size</c> options are mandatory.</p> <p>If not present, audit trail logging is not used.</p> </item> + + <marker id="atl_type"></marker> <tag><c><![CDATA[atl_type() = read | write | read_write <optional>]]></c></tag> <item> <p>Specifies what type of an audit trail log should be used. @@ -675,12 +768,16 @@ </list> <p>Default is <c>read_write</c>.</p> </item> + + <marker id="atl_dir"></marker> <tag><c><![CDATA[atl_dir = dir() <mandatory>]]></c></tag> <item> <p>Specifies where the audit trail log should be stored.</p> <p>If <c>audit_trail_log</c> specifies that logging should take place, this parameter <em>must</em> be defined.</p> </item> + + <marker id="atl_size"></marker> <tag><c><![CDATA[atl_size() = {integer(), integer()} <mandatory>]]></c></tag> <item> <p>Specifies the size of the audit @@ -688,6 +785,8 @@ <p>If <c>audit_trail_log</c> specifies that logging should take place, this parameter <em>must</em> be defined.</p> </item> + + <marker id="atl_repair"></marker> <tag><c><![CDATA[atl_repair() = true | false | truncate | snmp_repair <optional>]]></c></tag> <item> <p>Specifies if and how the audit trail log shall be repaired @@ -699,6 +798,8 @@ analysis.</p> <p>Default is <c>true</c>.</p> </item> + + <marker id="atl_seqno"></marker> <tag><c><![CDATA[atl_seqno() = true | false <optional>]]></c></tag> <item> <p>Specifies if the audit trail log entries will be (sequence) diff --git a/lib/snmp/doc/src/snmp_config.xml b/lib/snmp/doc/src/snmp_config.xml index fc8562b638..0a49b7a62e 100644 --- a/lib/snmp/doc/src/snmp_config.xml +++ b/lib/snmp/doc/src/snmp_config.xml @@ -40,6 +40,7 @@ <item>starting the application (agent and/or manager)</item> <item>debugging the application (agent and/or manager)</item> </list> + <p>Refer also to the chapter(s) <seealso marker="snmp_agent_config_files">Definition of Agent Configuration Files</seealso> and <seealso marker="snmp_manager_config_files">Definition of Manager Configuration Files</seealso> which contains more detailed information @@ -73,7 +74,14 @@ </item> </list> - <!-- The info below is also found in the snmp_app.xml file --> + + <!-- + ***************************************************** + + The info below is also found in the snmp_app.xml file + + ***************************************************** + --> <p>The agent and manager uses (application) configuration parameters to find out where these directories are located. The parameters should be @@ -87,6 +95,7 @@ {agent_verbosity, verbosity()} | {versions, versions()} | {discovery, agent_discovery()} | + {gb_max_vbs, gb_max_vbs()} | {priority, priority()} | {multi_threaded, multi_threaded()} | {db_dir, db_dir()} | @@ -117,8 +126,10 @@ {def_user_data, def_user_data()} </pre> + <marker id="agent_opts_and_types"></marker> <p>Agent specific config options and types:</p> <taglist> + <marker id="agent_type"></marker> <tag><c><![CDATA[agent_type() = master | sub <optional>]]></c></tag> <item> <p>If <c>master</c>, one master agent is @@ -126,6 +137,7 @@ <p>Default is <c>master</c>.</p> </item> + <marker id="agent_disco"></marker> <tag><c><![CDATA[agent_discovery() = [agent_discovery_opt()] <optional>]]></c></tag> <item> <p><c>agent_discovery_opt() = @@ -138,6 +150,7 @@ <p>For defaults see the options in <c>agent_discovery_opt()</c>.</p> </item> + <marker id="agent_term_disco_opts"></marker> <tag><c><![CDATA[agent_terminating_discovery_opts() = [agent_terminating_discovery_opt()] <optional>]]></c></tag> <item> <p><c>agent_terminating_discovery_opt() = @@ -155,6 +168,7 @@ </list> </item> + <marker id="agent_orig_disco_opts"></marker> <tag><c><![CDATA[agent_originating_discovery_opts() = [agent_originating_discovery_opt()] <optional>]]></c></tag> <item> <p><c>agent_originating_discovery_opt() = @@ -168,6 +182,7 @@ </list> </item> + <marker id="agent_mt"></marker> <tag><c><![CDATA[multi_threaded() = bool() <optional>]]></c></tag> <item> <p>If <c>true</c>, the agent is multi-threaded, with one @@ -175,11 +190,21 @@ <p>Default is <c>false</c>.</p> </item> + <marker id="agent_data_dir"></marker> <tag><c><![CDATA[db_dir() = string() <mandatory>]]></c></tag> <item> <p>Defines where the SNMP agent internal db files are stored.</p> </item> + <marker id="agent_gb_max_vbs"></marker> + <tag><c><![CDATA[gb_max_vbs() = pos_integer() | infinity <optional>]]></c></tag> + <item> + <p>Defines the maximum number of varbinds allowed + in a Get-BULK response.</p> + <p>Default is <c>1000</c>.</p> + </item> + + <marker id="agent_local_db"></marker> <tag><c><![CDATA[local_db() = [local_db_opt()] <optional>]]></c></tag> <item> <p><c>local_db_opt() = {repair, agent_repair()} | {auto_save, agent_auto_save()} | {verbosity, verbosity()}</c></p> @@ -187,6 +212,7 @@ <p>For defaults see the options in <c>local_db_opt()</c>.</p> </item> + <marker id="agent_ldb_repair"></marker> <tag><c><![CDATA[agent_repair() = false | true | force <optional>]]></c></tag> <item> <p>When starting snmpa_local_db it always tries to open an @@ -197,6 +223,7 @@ <p>Default is <c>true</c>.</p> </item> + <marker id="agent_ldb_auto_save"></marker> <tag><c><![CDATA[agent_auto_save() = integer() | infinity <optional>]]></c></tag> <item> <p>The auto save interval. The table is flushed to disk @@ -204,6 +231,7 @@ <p>Default is <c>5000</c>.</p> </item> + <marker id="agent_net_if"></marker> <tag><c><![CDATA[agent_net_if() = [agent_net_if_opt()] <optional>]]></c></tag> <item> <p><c>agent_net_if_option() = {module, agent_net_if_module()} | @@ -214,6 +242,7 @@ <p>For defaults see the options in <c>agent_net_if_opt()</c>.</p> </item> + <marker id="agent_ni_module"></marker> <tag><c><![CDATA[agent_net_if_module() = atom() <optional>]]></c></tag> <item> <p>Module which handles the network interface part for the @@ -222,6 +251,7 @@ <p>Default is <c>snmpa_net_if</c>.</p> </item> + <marker id="agent_ni_opts"></marker> <tag><c><![CDATA[agent_net_if_options() = [agent_net_if_option()] <optional>]]></c></tag> <item> <p><c>agent_net_if_option() = {bind_to, bind_to()} | @@ -236,6 +266,14 @@ <p>For defaults see the options in <c>agent_net_if_option()</c>.</p> </item> + <marker id="agent_ni_req_limit"></marker> + <tag><c><![CDATA[req_limit() = integer() | infinity <optional>]]></c></tag> + <item> + <p>Max number of simultaneous requests handled by the agent.</p> + <p>Default is <c>infinity</c>.</p> + </item> + + <marker id="agent_ni_filter_opts"></marker> <tag><c><![CDATA[agent_net_if_filter_options() = [agent_net_if_filter_option()] <optional>]]></c></tag> <item> <p><c><![CDATA[agent_net_if_filter_option() = {module, agent_net_if_filter_module()}]]></c></p> @@ -245,6 +283,7 @@ <p>For defaults see the options in <c>agent_net_if_filter_option()</c>.</p> </item> + <marker id="agent_ni_filter_module"></marker> <tag><c><![CDATA[agent_net_if_filter_module() = atom() <optional>]]></c></tag> <item> <p>Module which handles the network interface filter part for the @@ -254,12 +293,7 @@ <p>Default is <c>snmpa_net_if_filter</c>.</p> </item> - <tag><c><![CDATA[req_limit() = integer() | infinity <optional>]]></c></tag> - <item> - <p>Max number of simultaneous requests handled by the agent.</p> - <p>Default is <c>infinity</c>.</p> - </item> - + <marker id="agent_mibs"></marker> <tag><c><![CDATA[agent_mibs() = [string()] <optional>]]></c></tag> <item> <p>Specifies a list of MIBs (including path) that defines which MIBs @@ -274,6 +308,7 @@ <p>Default is <c>[]</c>.</p> </item> + <marker id="agent_mib_storage"></marker> <tag><c><![CDATA[mib_storage() = ets | {ets, Dir} | {ets, Dir, Action} | dets | {dets, Dir} | {dets, Dir, Action} | mnesia | {mnesia, Nodes} | {mnesia, Nodes, Action} <optional>]]></c></tag> <item> <p>Specifies how info retrieved from the mibs will be stored.</p> @@ -299,6 +334,7 @@ mnesia/dets table already exist.</p> </item> + <marker id="agent_mib_server"></marker> <tag><c><![CDATA[mib_server() = [mib_server_opt()] <optional>]]></c></tag> <item> <p><c>mib_server_opt() = {mibentry_override, mibentry_override()} | {trapentry_override, trapentry_override()} | {verbosity, verbosity()} | {cache, mibs_cache()}</c></p> @@ -306,6 +342,7 @@ <p>For defaults see the options in <c>mib_server_opt()</c>.</p> </item> + <marker id="agent_ms_meo"></marker> <tag><c><![CDATA[mibentry_override() = bool() <optional>]]></c></tag> <item> <p>If this value is false, then when loading a mib each mib- @@ -315,6 +352,7 @@ <p>Default is <c>false</c>.</p> </item> + <marker id="agent_ms_teo"></marker> <tag><c><![CDATA[trapentry_override() = bool() <optional>]]></c></tag> <item> <p>If this value is false, then when loading a mib each trap @@ -324,6 +362,7 @@ <p>Default is <c>false</c>.</p> </item> + <marker id="agent_ms_cache"></marker> <tag><c><![CDATA[mibs_cache() = bool() | mibs_cache_opts() <optional>]]></c></tag> <item> <p>Shall the agent utilize the mib server lookup cache or not.</p> @@ -331,6 +370,7 @@ default values apply).</p> </item> + <marker id="agent_ms_cache_opts"></marker> <tag><c><![CDATA[mibs_cache_opts() = [mibs_cache_opt()] <optional>]]></c></tag> <item> <p><c>mibs_cache_opt() = {autogc, mibs_cache_autogc()} | {gclimit, mibs_cache_gclimit()} | {age, mibs_cache_age()}</c></p> @@ -338,6 +378,7 @@ <p>For defaults see the options in <c>mibs_cache_opt()</c>.</p> </item> + <marker id="agent_ms_cache_autogc"></marker> <tag><c><![CDATA[mibs_cache_autogc() = bool() <optional>]]></c></tag> <item> <p>Defines if the mib server shall perform cache gc automatically or @@ -346,6 +387,7 @@ <p>Default is <c>true</c>.</p> </item> + <marker id="agent_ms_cache_age"></marker> <tag><c><![CDATA[mibs_cache_age() = integer() > 0 <optional>]]></c></tag> <item> <p>Defines how old the entries in the cache will be allowed before @@ -355,6 +397,7 @@ <p>Default is <c>10 timutes</c>.</p> </item> + <marker id="agent_ms_cache_gclimit"></marker> <tag><c><![CDATA[mibs_cache_gclimit() = integer() > 0 | infinity <optional>]]></c></tag> <item> <p>When performing a GC, this is the max number of cache entries @@ -365,6 +408,7 @@ <p>Default is <c>100</c>.</p> </item> + <marker id="agent_error_report_mod"></marker> <tag><c><![CDATA[error_report_mod() = atom() <optional>]]></c></tag> <item> <p>Defines an error report module, implementing the @@ -374,6 +418,7 @@ <p>Default is <c>snmpa_error_logger</c>.</p> </item> + <marker id="agent_symbolic_store"></marker> <tag><c>symbolic_store() = [symbolic_store_opt()]</c></tag> <item> <p><c>symbolic_store_opt() = {verbosity, verbosity()}</c></p> @@ -381,12 +426,15 @@ <p>For defaults see the options in <c>symbolic_store_opt()</c>.</p> </item> + <marker id="agent_target_cache"></marker> <tag><c>target_cache() = [target_cache_opt()]</c></tag> <item> <p><c>target_cache_opt() = {verbosity, verbosity()}</c></p> <p>Defines options specific for the SNMP agent target cache. </p> <p>For defaults see the options in <c>target_cache_opt()</c>.</p> </item> + + <marker id="agent_config"></marker> <tag><c><![CDATA[agent_config() = [agent_config_opt()] <mandatory>]]></c></tag> <item> <p><c>agent_config_opt() = {dir, agent_config_dir()} | {force_load, force_load()} | {verbosity, verbosity()}</c></p> @@ -394,11 +442,13 @@ <p>For defaults see the options in <c>agent_config_opt()</c>.</p> </item> + <marker id="agent_config_dir"></marker> <tag><c><![CDATA[agent_config_dir = dir() <mandatory>]]></c></tag> <item> <p>Defines where the SNMP agent configuration files are stored.</p> </item> + <marker id="agent_force_load"></marker> <tag><c><![CDATA[force_load() = bool() <optional>]]></c></tag> <item> <p>If <c>true</c> the configuration files are re-read @@ -410,14 +460,18 @@ </item> </taglist> + <marker id="manager_opts_and_types"></marker> <p>Manager specific config options and types:</p> <taglist> + <marker id="manager_server"></marker> <tag><c><![CDATA[server() = [server_opt()] <optional>]]></c></tag> <item> <p><c>server_opt() = {timeout, server_timeout()} | {verbosity, verbosity()}</c></p> <p>Specifies the options for the manager server process.</p> <p>Default is <c>silence</c>.</p> </item> + + <marker id="manager_server_timeout"></marker> <tag><c><![CDATA[server_timeout() = integer() <optional>]]></c></tag> <item> <p>Asynchroneous request cleanup time. For every requests, @@ -438,6 +492,7 @@ <p>Default is <c>30000</c>.</p> </item> + <marker id="manager_config"></marker> <tag><c><![CDATA[manager_config() = [manager_config_opt()] <mandatory>]]></c></tag> <item> <p><c>manager_config_opt() = {dir, manager_config_dir()} | {db_dir, manager_db_dir()} | {db_init_error, db_init_error()} | {repair, manager_repair()} | {auto_save, manager_auto_save()} | {verbosity, verbosity()}</c></p> @@ -445,16 +500,19 @@ <p>For defaults see the options in <c>manager_config_opt()</c>.</p> </item> + <marker id="manager_config_dir"></marker> <tag><c><![CDATA[manager_config_dir = dir() <mandatory>]]></c></tag> <item> <p>Defines where the SNMP manager configuration files are stored.</p> </item> + <marker id="manager_config_db_dir"></marker> <tag><c><![CDATA[manager_db_dir = dir() <mandatory>]]></c></tag> <item> <p>Defines where the SNMP manager store persistent data.</p> </item> + <marker id="manager_config_repair"></marker> <tag><c><![CDATA[manager_repair() = false | true | force <optional>]]></c></tag> <item> <p>Defines the repair option for the persistent database (if @@ -462,6 +520,7 @@ <p>Default is <c>true</c>.</p> </item> + <marker id="manager_config_auto_save"></marker> <tag><c><![CDATA[manager_auto_save() = integer() | infinity <optional>]]></c></tag> <item> <p>The auto save interval. The table is flushed to disk @@ -469,6 +528,7 @@ <p>Default is <c>5000</c>.</p> </item> + <marker id="manager_irb"></marker> <tag><c><![CDATA[manager_irb() = auto | user | {user, integer()} <optional>]]></c></tag> <item> <p>This option defines how the manager will handle the sending of @@ -498,6 +558,7 @@ <p>Default is <c>auto</c>.</p> </item> + <marker id="manager_mibs"></marker> <tag><c><![CDATA[manager_mibs() = [string()] <optional>]]></c></tag> <item> <p>Specifies a list of MIBs (including path) and defines which MIBs @@ -505,6 +566,7 @@ <p>Default is <c>[]</c>.</p> </item> + <marker id="manager_net_if"></marker> <tag><c><![CDATA[manager_net_if() = [manager_net_if_opt()] <optional>]]></c></tag> <item> <p><c>manager_net_if_opt() = {module, manager_net_if_module()} | @@ -515,6 +577,7 @@ <p>For defaults see the options in <c>manager_net_if_opt()</c>.</p> </item> + <marker id="manager_ni_opts"></marker> <tag><c><![CDATA[manager_net_if_options() = [manager_net_if_option()] <optional>]]></c></tag> <item> <p><c>manager_net_if_option() = {bind_to, bind_to()} | @@ -528,6 +591,7 @@ <p>For defaults see the options in <c>manager_net_if_option()</c>.</p> </item> + <marker id="manager_ni_module"></marker> <tag><c><![CDATA[manager_net_if_module() = atom() <optional>]]></c></tag> <item> <p>Module which handles the network interface part for the @@ -536,6 +600,7 @@ <p>Default is <c>snmpm_net_if</c>.</p> </item> + <marker id="manager_ni_filter_opts"></marker> <tag><c><![CDATA[manager_net_if_filter_options() = [manager_net_if_filter_option()] <optional>]]></c></tag> <item> <p><c>manager_net_if_filter_option() = {module, manager_net_if_filter_module()}</c></p> @@ -546,6 +611,7 @@ <c>manager_net_if_filter_option()</c>.</p> </item> + <marker id="manager_ni_filter_module"></marker> <tag><c><![CDATA[manager_net_if_filter_module() = atom() <optional>]]></c></tag> <item> <p>Module which handles the network interface filter part for the @@ -554,6 +620,7 @@ <p>Default is <c>snmpm_net_if_filter</c>.</p> </item> + <marker id="manager_def_user_module"></marker> <tag><c><![CDATA[def_user_module() = atom() <optional>]]></c></tag> <item> <p>The module implementing the default user. See the @@ -561,6 +628,7 @@ <p>Default is <c>snmpm_user_default</c>.</p> </item> + <marker id="manager_def_user_data"></marker> <tag><c><![CDATA[def_user_data() = term() <optional>]]></c></tag> <item> <p>Data for the default user. Passed to the user when calling @@ -569,8 +637,10 @@ </item> </taglist> + <marker id="common_types"></marker> <p>Common config types:</p> <taglist> + <marker id="restart_type"></marker> <tag><c>restart_type() = permanent | transient | temporary</c></tag> <item> <p>See <seealso marker="stdlib:supervisor#child_spec">supervisor</seealso> @@ -579,6 +649,7 @@ for the manager.</p> </item> + <marker id="db_init_error"></marker> <tag><c>db_init_error() = terminate | create</c></tag> <item> <p>Defines what to do if the agent is unable to open an @@ -588,12 +659,14 @@ <p>Default is <c>terminate</c>.</p> </item> + <marker id="prio"></marker> <tag><c><![CDATA[priority() = atom() <optional>]]></c></tag> <item> <p>Defines the Erlang priority for all SNMP processes.</p> <p>Default is <c>normal</c>.</p> </item> + <marker id="versions"></marker> <tag><c><![CDATA[versions() = [version()] <optional>]]></c></tag> <item> <p><c>version() = v1 | v2 | v3</c></p> @@ -601,6 +674,7 @@ <p>Default is <c>[v1,v2,v3]</c>.</p> </item> + <marker id="verbosity"></marker> <tag><c><![CDATA[verbosity() = silence | info | log | debug | trace <optional>]]></c></tag> <item> <p>Verbosity for a SNMP process. This specifies now much debug info @@ -608,6 +682,7 @@ <p>Default is <c>silence</c>.</p> </item> + <marker id="bind_to"></marker> <tag><c><![CDATA[bind_to() = bool() <optional>]]></c></tag> <item> <p>If <c>true</c>, net_if binds to the IP address. @@ -616,6 +691,7 @@ <p>Default is <c>false</c>.</p> </item> + <marker id="no_reuse"></marker> <tag><c><![CDATA[no_reuse() = bool() <optional>]]></c></tag> <item> <p>If <c>true</c>, net_if does not specify that the IP @@ -624,17 +700,21 @@ <p>Default is <c>false</c>.</p> </item> + <marker id="recbuf"></marker> <tag><c><![CDATA[recbuf() = integer() <optional>]]></c></tag> <item> <p>Receive buffer size. </p> <p>Default value is defined by <c>gen_udp</c>.</p> </item> + + <marker id="sndbuf"></marker> <tag><c><![CDATA[sndbuf() = integer() <optional>]]></c></tag> <item> <p>Send buffer size. </p> <p>Default value is defined by <c>gen_udp</c>.</p> </item> + <marker id="note_store"></marker> <tag><c><![CDATA[note_store() = [note_store_opt()] <optional>]]></c></tag> <item> <p><c>note_store_opt() = {timeout, note_store_timeout()} | {verbosity, verbosity()}</c></p> @@ -642,6 +722,7 @@ <p>For defaults see the options in <c>note_store_opt()</c>.</p> </item> + <marker id="ns_timeout"></marker> <tag><c><![CDATA[note_store_timeout() = integer() <optional>]]></c></tag> <item> <p>Note cleanup time. When storing a note in the note store, @@ -649,10 +730,9 @@ process performs a GC to remove the expired note's. Time in milli-seconds.</p> <p>Default is <c>30000</c>.</p> - - <marker id="audit_trail_log"></marker> </item> + <marker id="audit_trail_log"></marker> <tag><c><![CDATA[audit_trail_log() [audit_trail_log_opt()] <optional>]]></c></tag> <item> <p><c>audit_trail_log_opt() = {type, atl_type()} | {dir, atl_dir()} | {size, atl_size()} | {repair, atl_repair()} | {seqno, atl_seqno()}</c></p> @@ -663,6 +743,7 @@ <p>If not present, audit trail logging is not used.</p> </item> + <marker id="atl_type"></marker> <tag><c><![CDATA[atl_type() = read | write | read_write <optional>]]></c></tag> <item> <p>Specifies what type of an audit trail log should be used. @@ -684,6 +765,7 @@ <p>Default is <c>read_write</c>.</p> </item> + <marker id="atl_dir"></marker> <tag><c><![CDATA[atl_dir = dir() <mandatory>]]></c></tag> <item> <p>Specifies where the audit trail log should be stored.</p> @@ -691,6 +773,7 @@ place, this parameter <em>must</em> be defined.</p> </item> + <marker id="atl_size"></marker> <tag><c><![CDATA[atl_size() = {integer(), integer()} <mandatory>]]></c></tag> <item> <p>Specifies the size of the audit @@ -699,6 +782,7 @@ take place, this parameter <em>must</em> be defined.</p> </item> + <marker id="atl_repair"></marker> <tag><c><![CDATA[atl_repair() = true | false | truncate | snmp_repair <optional>]]></c></tag> <item> <p>Specifies if and how the audit trail log shall be repaired @@ -710,6 +794,8 @@ analysis.</p> <p>Default is <c>true</c>.</p> </item> + + <marker id="atl_seqno"></marker> <tag><c><![CDATA[atl_seqno() = true | false <optional>]]></c></tag> <item> <p>Specifies if the audit trail log entries will be (sequence) 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/priv/plt/.gitignore b/lib/snmp/priv/plt/.gitignore new file mode 100644 index 0000000000..174481f561 --- /dev/null +++ b/lib/snmp/priv/plt/.gitignore @@ -0,0 +1,3 @@ +/*.plt +/*.dialyzer_analysis + diff --git a/lib/snmp/src/agent/depend.mk b/lib/snmp/src/agent/depend.mk index bc39e1fa35..078ef15821 100644 --- a/lib/snmp/src/agent/depend.mk +++ b/lib/snmp/src/agent/depend.mk @@ -52,6 +52,7 @@ $(EBIN)/snmpa_acm.$(EMULATOR): \ $(EBIN)/snmpa_agent.$(EMULATOR): \ snmpa_agent.erl \ + snmpa_internal.hrl \ ../misc/snmp_debug.hrl \ ../misc/snmp_verbosity.hrl \ ../../include/snmp_types.hrl @@ -136,6 +137,7 @@ $(EBIN)/snmpa_set_lib.$(EMULATOR): \ $(EBIN)/snmpa_supervisor.$(EMULATOR): \ snmpa_supervisor.erl \ + snmpa_internal.hrl \ ../misc/snmp_debug.hrl \ ../misc/snmp_verbosity.hrl diff --git a/lib/snmp/src/agent/snmp_generic_mnesia.erl b/lib/snmp/src/agent/snmp_generic_mnesia.erl index a73aad5b33..ce42af404b 100644 --- a/lib/snmp/src/agent/snmp_generic_mnesia.erl +++ b/lib/snmp/src/agent/snmp_generic_mnesia.erl @@ -121,7 +121,7 @@ table_func(set, RowIndex, Cols, Name) -> fun() -> snmp_generic:table_set_row( {Name, mnesia}, nofunc, - {snmp_generic_mnesia, table_try_make_consistent}, + fun table_try_make_consistent/2, RowIndex, Cols) end) of {atomic, Value} -> @@ -368,7 +368,8 @@ table_set_elements(Name, RowIndex, Cols) -> _ -> false end. table_set_elements(Name, RowIndex, Cols, ConsFunc) -> - #table_info{index_types = Indexes, first_own_index = FirstOwnIndex} = + #table_info{index_types = Indexes, + first_own_index = FirstOwnIndex} = snmp_generic:table_info(Name), AddCol = if FirstOwnIndex == 0 -> 2; diff --git a/lib/snmp/src/agent/snmp_target_mib.erl b/lib/snmp/src/agent/snmp_target_mib.erl index 60bd3e0912..a45db89c09 100644 --- a/lib/snmp/src/agent/snmp_target_mib.erl +++ b/lib/snmp/src/agent/snmp_target_mib.erl @@ -46,8 +46,14 @@ %% Column not accessible via SNMP - needed when the agent sends informs -define(snmpTargetAddrEngineId, 10). %% Extra comlumns for the augmented table snmpTargetAddrExtTable --define(snmpTargetAddrTMask, 11). --define(snmpTargetAddrMMS, 12). +-define(snmpTargetAddrTMask, 11). +-define(snmpTargetAddrMMS, 12). + +-ifdef(snmp_extended_verbosity). +-define(vt(F,A), ?vtrace(F, A)). +-else. +-define(vt(_F, _A), ok). +-endif. %%----------------------------------------------------------------- @@ -459,10 +465,16 @@ get_target_addrs() -> get_target_addrs(Key, {Tab, _} = TabDb, Acc) -> + ?vt("get_target_addrs -> entry with" + "~n Key: ~p", [Key]), case table_next(Tab, Key) of endOfTable -> + ?vt("get_target_addrs -> endOfTable when" + "~n Acc: ~p", [Acc]), Acc; NextKey -> + ?vt("get_target_addrs -> next ok: " + "~n NextKey: ~p", [NextKey]), case get_target_addr(TabDb, NextKey) of {ok, Targ} -> get_target_addrs(NextKey, TabDb, [Targ| Acc]); 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 37f6dd3f26..2cee91b081 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-2011. All Rights Reserved. +%% Copyright Ericsson AB 1999-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 @@ -203,18 +203,16 @@ init_sec2group_table([Row | T]) -> init_sec2group_table(T); init_sec2group_table([]) -> true. -init_access_table([{GN, Prefix, Model, Level, Row} | T]) -> -%% ?vtrace("init access table: " -%% "~n GN: ~p" -%% "~n Prefix: ~p" -%% "~n Model: ~p" -%% "~n Level: ~p" -%% "~n Row: ~p",[GN, Prefix, Model, Level, Row]), - Key = [length(GN) | GN] ++ [length(Prefix) | Prefix] ++ [Model, Level], - snmpa_vacm:insert([{Key, Row}], false), - init_access_table(T); -init_access_table([]) -> - snmpa_vacm:dump_table(). +make_access_key(GN, Prefix, Model, Level) -> + [length(GN) | GN] ++ [length(Prefix) | Prefix] ++ [Model, Level]. + +make_access_entry({GN, Prefix, Model, Level, Row}) -> + Key = make_access_key(GN, Prefix, Model, Level), + {Key, Row}. + +init_access_table(TableData) -> + TableData2 = [make_access_entry(E) || E <- TableData], + snmpa_vacm:insert(TableData2, true). init_view_table([Row | T]) -> %% ?vtrace("init view table: " @@ -276,10 +274,7 @@ add_access(GroupName, Prefix, SecModel, SecLevel, Match, RV, WV, NV) -> Match, RV, WV, NV}, case (catch check_vacm(Access)) of {ok, {vacmAccess, {GN, Pref, SM, SL, Row}}} -> - Key1 = [length(GN) | GN], - Key2 = [length(Pref) | Pref], - Key3 = [SM, SL], - Key = Key1 ++ Key2 ++ Key3, + Key = make_access_key(GN, Pref, SM, SL), snmpa_vacm:insert([{Key, Row}], false), snmpa_agent:invalidate_ca_cache(), {ok, Key}; diff --git a/lib/snmp/src/agent/snmpa.erl b/lib/snmp/src/agent/snmpa.erl index 50b169e4e7..c400aaddf7 100644 --- a/lib/snmp/src/agent/snmpa.erl +++ b/lib/snmp/src/agent/snmpa.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2011. All Rights Reserved. +%% Copyright Ericsson AB 2004-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 @@ -547,7 +547,7 @@ update_mibs_cache_age(Agent, Age) -> update_mibs_cache_gclimit(GcLimit) -> - update_mibs_cache_age(snmp_master_agent, GcLimit). + update_mibs_cache_gclimit(snmp_master_agent, GcLimit). update_mibs_cache_gclimit(Agent, GcLimit) -> snmpa_agent:update_mibs_cache_gclimit(Agent, GcLimit). diff --git a/lib/snmp/src/agent/snmpa_agent.erl b/lib/snmp/src/agent/snmpa_agent.erl index 6322f0f21d..9cc986cf47 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-2011. 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 @@ -68,8 +68,11 @@ %% Internal exports -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3, tr_var/2, tr_varbind/1, - handle_pdu/7, worker/2, worker_loop/1, + handle_pdu/8, worker/2, worker_loop/1, do_send_trap/7, do_send_trap/8]). +%% <BACKWARD-COMPAT> +-export([handle_pdu/7]). +%% </BACKWARD-COMPAT> -include("snmpa_internal.hrl"). @@ -87,7 +90,6 @@ -define(DISCO_TERMINATING_TRIGGER_USERNAME, ""). - -ifdef(snmp_debug). -define(GS_START_LINK3(Prio, Parent, Ref, Opts), gen_server:start_link(?MODULE, [Prio, Parent, Ref, Opts], @@ -103,13 +105,49 @@ gen_server:start_link({local, Name}, ?MODULE, [Prio, Parent, Ref, Opts],[])). -endif. - + +%% Increment this whenever a change is made to the worker interface +-define(WORKER_INTERFACE_VERSION, 1). + +%% -- Utility macros for creating worker commands -- +-define(mk_pdu_wreq(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra), + #wrequest{cmd = handle_pdu, + info = [{vsn, Vsn}, + {pdu, Pdu}, + {pdu_ms, PduMS}, + {acm_data, ACMData}, + {addr, Address}, + {gb_max_vbs, GbMaxVBs}, + {extra, Extra}]}). +-define(mk_send_trap_wreq(TrapRec, NotifyName, ContextName, + Recv, Vbs, LocalEngineID, Extra), + #wrequest{cmd = send_trap, + info = [{trap_rec, TrapRec}, + {notify_name, NotifyName}, + {context_name, ContextName}, + {receiver, Recv}, + {varbinds, Vbs}, + {local_engine_id, LocalEngineID}, + {extra, Extra}]}). +-define(mk_terminate_wreq(), #wrequest{cmd = terminate, info = []}). +-define(mk_verbosity_wreq(V), #wrequest{cmd = verbosity, + info = [{verbosity, V}]}). + -record(notification_filter, {id, mod, data}). -record(disco, {from, rec, sender, target, engine_id, sec_level, ctx, ivbs, stage, handler, extra}). +%% This record is used when sending requests to the worker processes +-record(wrequest, + { + version = ?WORKER_INTERFACE_VERSION, + cmd, + info + } + ). + %%----------------------------------------------------------------- %% The agent is multi-threaded, i.e. each request is handled @@ -142,7 +180,8 @@ net_if_mod, backup, disco, - mibs_cache_request}). + mibs_cache_request, + gb_max_vbs}). %%%----------------------------------------------------------------- @@ -330,6 +369,8 @@ do_init(Prio, Parent, Ref, Options) -> MultiT = get_multi_threaded(Options), Vsns = get_versions(Options), + GbMaxVbs = get_gb_max_vbs(Options), + NS = start_note_store(Prio, Ref, Options), {Type, NetIfPid, NetIfMod} = start_net_if(Parent, Prio, Ref, Vsns, NS, Options), @@ -348,7 +389,8 @@ do_init(Prio, Parent, Ref, Options) -> ref = Ref, vsns = Vsns, note_store = NS, - net_if_mod = NetIfMod}}. + net_if_mod = NetIfMod, + gb_max_vbs = GbMaxVbs}}. start_note_store(Prio, Ref, Options) -> @@ -410,7 +452,8 @@ start_net_if(Parent, _Prio, _Ref, _Vsns, _NoteStore, _Options) start_mib_server(Prio, Ref, Mibs, Options) -> ?vdebug("start_mib_server -> with Prio: ~p", [Prio]), MibStorage = get_mib_storage(Options), - MibsOpts = [{mib_storage, MibStorage}|get_option(mib_server, Options, [])], + MibsOpts = [{mib_storage, MibStorage} | + get_option(mib_server, Options, [])], ?vtrace("start_mib_server -> " "~n Mibs: ~p" @@ -558,25 +601,6 @@ send_trap(Agent, Trap, NotifyName, CtxName, Recv, Varbinds) -> ], send_notification(Agent, Trap, SendOpts). -%% send_trap(Agent, Trap, NotifyName, CtxName, Recv, Varbinds) -> -%% ?d("send_trap -> entry with" -%% "~n self(): ~p" -%% "~n Agent: ~p [~p]" -%% "~n Trap: ~p" -%% "~n NotifyName: ~p" -%% "~n CtxName: ~p" -%% "~n Recv: ~p" -%% "~n Varbinds: ~p", -%% [self(), Agent, wis(Agent), -%% Trap, NotifyName, CtxName, Recv, Varbinds]), -%% Msg = {send_trap, Trap, NotifyName, CtxName, Recv, Varbinds}, -%% case (wis(Agent) =:= self()) of -%% false -> -%% call(Agent, Msg); -%% true -> -%% Agent ! Msg -%% end. - send_trap(Agent, Trap, NotifyName, CtxName, Recv, Varbinds, LocalEngineID) -> ?d("send_trap -> entry with" "~n self(): ~p" @@ -599,27 +623,6 @@ send_trap(Agent, Trap, NotifyName, CtxName, Recv, Varbinds, LocalEngineID) -> ], send_notification(Agent, Trap, SendOpts). -%% send_trap(Agent, Trap, NotifyName, CtxName, Recv, Varbinds, LocalEngineID) -> -%% ?d("send_trap -> entry with" -%% "~n self(): ~p" -%% "~n Agent: ~p [~p]" -%% "~n Trap: ~p" -%% "~n NotifyName: ~p" -%% "~n CtxName: ~p" -%% "~n Recv: ~p" -%% "~n Varbinds: ~p" -%% "~n LocalEngineID: ~p", -%% [self(), Agent, wis(Agent), -%% Trap, NotifyName, CtxName, Recv, Varbinds, LocalEngineID]), -%% Msg = -%% {send_trap, Trap, NotifyName, CtxName, Recv, Varbinds, LocalEngineID}, -%% case (wis(Agent) =:= self()) of -%% false -> -%% call(Agent, Msg); -%% true -> -%% Agent ! Msg -%% end. - %% </BACKWARD-COMPAT> @@ -709,11 +712,6 @@ wis(Atom) when is_atom(Atom) -> whereis(Atom). -forward_trap(Agent, TrapRecord, NotifyName, CtxName, Recv, Varbinds) -> - ExtraInfo = ?DEFAULT_NOTIF_EXTRA_INFO, - forward_trap(Agent, TrapRecord, NotifyName, CtxName, Recv, Varbinds, - ExtraInfo). - forward_trap(Agent, TrapRecord, NotifyName, CtxName, Recv, Varbinds, ExtraInfo) -> Agent ! {forward_trap, TrapRecord, NotifyName, CtxName, Recv, Varbinds, @@ -796,7 +794,8 @@ handle_info({snmp_pdu, Vsn, Pdu, PduMS, ACMData, Address, Extra}, S) -> ?vdebug("handle_info(snmp_pdu) -> entry with" "~n Vsn: ~p" "~n Pdu: ~p" - "~n Address: ~p", [Vsn, Pdu, Address]), + "~n Address: ~p" + "~n Extra: ~p", [Vsn, Pdu, Address, Extra]), NewS = handle_snmp_pdu(is_valid_pdu_type(Pdu#pdu.type), Vsn, Pdu, PduMS, ACMData, Address, Extra, S), @@ -808,11 +807,11 @@ handle_info(worker_available, S) -> {noreply, S#state{worker_state = ready}}; handle_info({send_notif, Notification, SendOpts}, S) -> - ?vlog("[handle_info] send trap request:" + ?vlog("[handle_info] send notif request:" "~n Notification: ~p" "~n SendOpts: ~p", [Notification, SendOpts]), - case (catch handle_send_trap(cast, S, Notification, SendOpts)) of + case (catch handle_send_trap(S, Notification, SendOpts)) of {ok, NewS} -> {noreply, NewS}; {'EXIT', R} -> @@ -832,7 +831,7 @@ handle_info({send_trap, Trap, NotifyName, ContextName, Recv, Varbinds}, S) -> "~n Varbinds: ~p", [Trap, NotifyName, ContextName, Recv, Varbinds]), ExtraInfo = ?DEFAULT_NOTIF_EXTRA_INFO, - LocalEngineID = ?DEFAULT_LOCAL_ENGINE_ID, + LocalEngineID = local_engine_id(S), case (catch handle_send_trap(S, Trap, NotifyName, ContextName, Recv, Varbinds, LocalEngineID, ExtraInfo)) of {ok, NewS} -> @@ -979,6 +978,7 @@ handle_info({'EXIT', Pid, Reason}, S) -> end, {noreply, S} end; + handle_info({'DOWN', Ref, process, Pid, {mibs_cache_reply, Reply}}, #state{mibs_cache_request = {Pid, Ref, From}} = S) -> ?vlog("reply from the mibs cache request handler (~p): ~n~p", @@ -1014,11 +1014,11 @@ handle_call(restart_set_worker, _From, #state{set_worker = Pid} = S) -> {reply, ok, S}; handle_call({send_notif, Notification, SendOpts}, _From, S) -> - ?vlog("[handle_info] send trap request:" + ?vlog("[handle_call] send notif request:" "~n Notification: ~p" "~n SendOpts: ~p", [Notification, SendOpts]), - case (catch handle_send_trap(call, S, Notification, SendOpts)) of + case (catch handle_send_trap(S, Notification, SendOpts)) of {ok, NewS} -> {reply, ok, NewS}; {'EXIT', Reason} -> @@ -1039,18 +1039,8 @@ handle_call({send_trap, Trap, NotifyName, ContextName, Recv, Varbinds}, "~n Recv: ~p" "~n Varbinds: ~p", [Trap, NotifyName, ContextName, Recv, Varbinds]), - ExtraInfo = ?DEFAULT_NOTIF_EXTRA_INFO, - LocalEngineID = - case S#state.type of - master_agent -> - ?DEFAULT_LOCAL_ENGINE_ID; - _ -> - %% subagent - - %% we don't need this now, eventually the trap send - %% request will reach the master-agent and then it - %% will look up the proper engine id. - ignore - end, + ExtraInfo = ?DEFAULT_NOTIF_EXTRA_INFO, + LocalEngineID = local_engine_id(S), case (catch handle_send_trap(S, Trap, NotifyName, ContextName, Recv, Varbinds, LocalEngineID, ExtraInfo)) of {ok, NewS} -> @@ -1130,7 +1120,7 @@ handle_call({subagent_get_next, MibView, Varbinds, PduData}, _From, S) -> "~n PduData: ~p", [MibView,Varbinds,PduData]), put_pdu_data(PduData), - {reply, do_get_next(MibView, Varbinds), S}; + {reply, do_get_next(MibView, Varbinds, infinity), S}; handle_call({subagent_set, Arguments, PduData}, _From, S) -> ?vlog("[handle_call] subagent set:" "~n Arguments: ~p" @@ -1171,7 +1161,7 @@ handle_call({get_next, Vars, Context}, _From, S) -> ?vdebug("Varbinds: ~p",[Varbinds]), MibView = snmpa_acm:get_root_mib_view(), Reply = - case do_get_next(MibView, Varbinds) of + case do_get_next(MibView, Varbinds, infinity) of {noError, 0, NewVarbinds} -> Vbs = lists:keysort(#varbind.org_index, NewVarbinds), [{Oid,Val} || #varbind{oid = Oid, value = Val} <- Vbs]; @@ -1272,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), @@ -1289,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}; @@ -1338,27 +1333,27 @@ handle_call({me_of, Oid}, _From, S) -> {reply, Reply, S}; handle_call(get_log_type, _From, S) -> - ?vlog("get_log_type", []), + ?vlog("handle_call(get_log_type) -> entry with", []), Reply = handle_get_log_type(S), {reply, Reply, S}; handle_call({set_log_type, NewType}, _From, S) -> - ?vlog("set_log_type -> " + ?vlog("handle_call(set_log_type) -> entry with" "~n NewType: ~p", [NewType]), Reply = handle_set_log_type(S, NewType), {reply, Reply, S}; handle_call(get_request_limit, _From, S) -> - ?vlog("get_request_limit", []), + ?vlog("handle_call(get_request_limit) -> entry with", []), Reply = handle_get_request_limit(S), {reply, Reply, S}; handle_call({set_request_limit, NewLimit}, _From, S) -> - ?vlog("set_request_limit -> " + ?vlog("handle_call(set_request_limit) -> entry with" "~n NewLimit: ~p", [NewLimit]), Reply = handle_set_request_limit(S, NewLimit), {reply, Reply, S}; - + handle_call(stop, _From, S) -> {stop, normal, ok, S}; @@ -1367,15 +1362,15 @@ handle_call(Req, _From, S) -> Reply = {error, {unknown, Req}}, {reply, Reply, S}. -handle_cast({verbosity,Verbosity}, S) -> - ?vlog("verbosity: ~p -> ~p",[get(verbosity),Verbosity]), +handle_cast({verbosity, Verbosity}, S) -> + ?vlog("verbosity: ~p -> ~p",[get(verbosity), Verbosity]), put(verbosity,snmp_verbosity:validate(Verbosity)), case S#state.worker of - Pid when is_pid(Pid) -> Pid ! {verbosity,Verbosity}; + Pid when is_pid(Pid) -> Pid ! ?mk_verbosity_wreq(Verbosity); _ -> ok end, case S#state.set_worker of - Pid2 when is_pid(Pid2) -> Pid2 ! {verbosity,Verbosity}; + Pid2 when is_pid(Pid2) -> Pid2 ! ?mk_verbosity_wreq(Verbosity); _ -> ok end, {noreply, S}; @@ -1462,13 +1457,80 @@ handle_mibs_cache_request(MibServer, Req) -> %% Downgrade %% -%% code_change({down, _Vsn}, S, downgrade_to_pre_4_13) -> -%% {ok, S2}; +code_change({down, _Vsn}, S1, downgrade_to_pre_4_17_3) -> + #state{type = Type, + parent = Parent, + worker = Worker, + worker_state = WorkerState, + set_worker = SetWorker, + multi_threaded = MT, + ref = Ref, + vsns = Vsns, + nfilters = NF, + note_store = NoteStore, + mib_server = MS, + net_if = NetIf, + net_if_mod = NetIfMod, + backup = Backup, + disco = Disco, + mibs_cache_request = MCR} = S1, + S2 = {state, + type = Type, + parent = Parent, + worker = Worker, + worker_state = WorkerState, + set_worker = SetWorker, + multi_threaded = MT, + ref = Ref, + vsns = Vsns, + nfilters = NF, + note_store = NoteStore, + mib_server = MS, + net_if = NetIf, + net_if_mod = NetIfMod, + backup = Backup, + disco = Disco, + mibs_cache_request = MCR}, + {ok, S2}; %% Upgrade %% -%% code_change(_Vsn, S, upgrade_from_pre_4_13) -> -%% {ok, S2}; +code_change(_Vsn, S1, upgrade_from_pre_4_17_3) -> + {state, + type = Type, + parent = Parent, + worker = Worker, + worker_state = WorkerState, + set_worker = SetWorker, + multi_threaded = MT, + ref = Ref, + vsns = Vsns, + nfilters = NF, + note_store = NoteStore, + mib_server = MS, + net_if = NetIf, + net_if_mod = NetIfMod, + backup = Backup, + disco = Disco, + mibs_cache_request = MCR} = S1, + S2 = #state{type = Type, + parent = Parent, + worker = Worker, + worker_state = WorkerState, + set_worker = SetWorker, + multi_threaded = MT, + ref = Ref, + vsns = Vsns, + nfilters = NF, + note_store = NoteStore, + mib_server = MS, + net_if = NetIf, + net_if_mod = NetIfMod, + backup = Backup, + disco = Disco, + mibs_cache_request = MCR, + gb_max_vbs = ?DEFAULT_GB_MAX_VBS}, + {ok, S2}; code_change(_Vsn, S, _Extra) -> {ok, S}. @@ -1508,7 +1570,7 @@ worker_start(Dict) -> %% worker_stop(Pid, infinity). worker_stop(Pid, Timeout) when is_pid(Pid) -> - Pid ! terminate, + Pid ! ?mk_terminate_wreq(), receive {'EXIT', Pid, normal} -> ok @@ -1595,7 +1657,7 @@ handle_backup_res([{Who, Crap}|Results], Acc) -> %% because we (for some reason) support the function %% snmpa:current_community(). %%----------------------------------------------------------------- -cheat({community, SecModel, Community, _TAddress}, Address, ContextName) -> +cheat({community, _SecModel, Community, _TAddress}, Address, ContextName) -> {Community, Address, ContextName}; cheat({community, _SecModel, Community, _TDomain, _TAddress}, Address, ContextName) -> @@ -1645,9 +1707,11 @@ invalidate_ca_cache() -> %% %%----------------------------------------------------------------- -spawn_thread(Vsn, Pdu, PduMS, ACMData, Address, Extra) -> +%% This functions spawns a temporary worker process, +%% that evaluates one request and then silently exits. +spawn_thread(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra) -> Dict = get(), - Args = [Vsn, Pdu, PduMS, ACMData, Address, Extra, Dict], + Args = [Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra, Dict], proc_lib:spawn_link(?MODULE, handle_pdu, Args). spawn_trap_thread(TrapRec, NotifyName, ContextName, Recv, Vbs, @@ -1665,7 +1729,7 @@ do_send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs, do_send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs, LocalEngineID, ExtraInfo, Dict) -> lists:foreach(fun({Key, Val}) -> put(Key, Val) end, Dict), - put(sname,trap_sender_short_name(get(sname))), + put(sname, trap_sender_short_name(get(sname))), ?vlog("starting",[]), snmpa_trap:send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs, LocalEngineID, ExtraInfo, get(net_if)). @@ -1677,58 +1741,122 @@ worker(Master, Dict) -> worker_loop(Master). worker_loop(Master) -> - receive - {Vsn, Pdu, PduMS, ACMData, Address, Extra} -> - ?vtrace("worker_loop -> received request", []), - handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra), - Master ! worker_available; - - %% We don't trap EXITs! - {TrapRec, NotifyName, ContextName, Recv, Vbs} -> - ?vtrace("worker_loop -> send trap:" - "~n ~p", [TrapRec]), - snmpa_trap:send_trap(TrapRec, NotifyName, - ContextName, Recv, Vbs, - ?DEFAULT_NOTIF_EXTRA_INFO, - get(net_if)), - Master ! worker_available; - - %% We don't trap EXITs! - {send_trap, - TrapRec, NotifyName, ContextName, Recv, Vbs, LocalEngineID} -> - ?vtrace("worker_loop -> send trap:" - "~n ~p", [TrapRec]), - snmpa_trap:send_trap(TrapRec, NotifyName, - ContextName, Recv, Vbs, - LocalEngineID, ?DEFAULT_NOTIF_EXTRA_INFO, - get(net_if)), - Master ! worker_available; - - {send_trap, - TrapRec, NotifyName, ContextName, Recv, Vbs, LocalEngineID, ExtraInfo} -> - ?vtrace("worker_loop -> send trap:" - "~n ~p", [TrapRec]), - snmpa_trap:send_trap(TrapRec, NotifyName, - ContextName, Recv, Vbs, - LocalEngineID, ExtraInfo, - get(net_if)), - Master ! worker_available; - - {verbosity, Verbosity} -> - put(verbosity,snmp_verbosity:validate(Verbosity)); - - terminate -> - exit(normal); - - _X -> - %% ignore - ok - - after 30000 -> - %% This is to assure that the worker process leaves a - %% possibly old version of this module. - ok - end, + Res = + receive + #wrequest{cmd = handle_pdu, + info = Info} = Req -> + ?vtrace("worker_loop -> received handle_pdu request with" + "~n Info: ~p", [Info]), + Vsn = proplists:get_value(vsn, Info), + Pdu = proplists:get_value(pdu, Info), + PduMS = proplists:get_value(pdu_ms, Info), + ACMData = proplists:get_value(acm_data, Info), + Address = proplists:get_value(addr, Info), + GbMaxVBs = proplists:get_value(gb_max_vbs, Info), + Extra = proplists:get_value(extra, Info), + HandlePduRes = + try + begin + handle_pdu2(Vsn, Pdu, PduMS, ACMData, Address, + GbMaxVBs, Extra) + end + catch + T:E -> + exit({worker_crash, Req, T, E, + erlang:get_stacktrace()}) + end, + Master ! worker_available, + HandlePduRes; % For debugging... + + + #wrequest{cmd = send_trap, + info = Info} = Req -> + ?vtrace("worker_loop -> received send_trap request with" + "~n Info: ~p", [Info]), + TrapRec = proplists:get_value(trap_rec, Info), + NotifyName = proplists:get_value(notify_name, Info), + ContextName = proplists:get_value(context_name, Info), + Recv = proplists:get_value(receiver, Info), + Vbs = proplists:get_value(varbinds, Info), + LocalEngineID = proplists:get_value(local_engine_id, Info), + Extra = proplists:get_value(extra, Info), + SendTrapRes = + try + begin + snmpa_trap:send_trap(TrapRec, NotifyName, + ContextName, Recv, Vbs, + LocalEngineID, Extra, + get(net_if)) + end + catch + T:E -> + exit({worker_crash, Req, T, E, + erlang:get_stacktrace()}) + end, + Master ! worker_available, + SendTrapRes; % For debugging... + + + #wrequest{cmd = verbosity, + info = Info} -> + Verbosity = proplists:get_value(verbosity, Info), + put(verbosity, snmp_verbosity:validate(Verbosity)); + + + #wrequest{cmd = terminate} -> + ?vtrace("worker_loop -> received terminate request", []), + exit(normal); + + + %% ************************************************************* + %% + %% Kept for backward compatibillity reasons + %% + %% ************************************************************* + + {Vsn, Pdu, PduMS, ACMData, Address, Extra} -> + ?vtrace("worker_loop -> received request", []), + handle_pdu2(Vsn, Pdu, PduMS, ACMData, Address, + ?DEFAULT_GB_MAX_VBS, Extra), + Master ! worker_available; + + %% We don't trap exits! + {TrapRec, NotifyName, ContextName, Recv, Vbs} -> + ?vtrace("worker_loop -> send trap:" + "~n ~p", [TrapRec]), + snmpa_trap:send_trap(TrapRec, NotifyName, + ContextName, Recv, Vbs, get(net_if)), + Master ! worker_available; + + %% We don't trap exits! + {send_trap, + TrapRec, NotifyName, ContextName, Recv, Vbs, LocalEngineID, + ExtraInfo} -> + ?vtrace("worker_loop -> send trap:" + "~n ~p", [TrapRec]), + snmpa_trap:send_trap(TrapRec, NotifyName, + ContextName, Recv, Vbs, + LocalEngineID, ExtraInfo, + get(net_if)), + Master ! worker_available; + + {verbosity, Verbosity} -> + put(verbosity, snmp_verbosity:validate(Verbosity)); + + terminate -> + exit(normal); + + _X -> + %% ignore + ignore_unknown + + after 30000 -> + %% This is to assure that the worker process leaves a + %% possibly old version of this module. + ok + end, + ?vtrace("worker_loop -> wrap with" + "~n ~p", [Res]), ?MODULE:worker_loop(Master). @@ -1736,42 +1864,52 @@ worker_loop(Master) -> %%----------------------------------------------------------------- handle_snmp_pdu(true, Vsn, Pdu, PduMS, ACMData, Address, Extra, - #state{multi_threaded = false} = S) -> + #state{multi_threaded = false, + gb_max_vbs = GbMaxVBs} = S) -> ?vtrace("handle_snmp_pdu -> single-thread agent",[]), - handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra), + handle_pdu2(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra), S; handle_snmp_pdu(true, Vsn, #pdu{type = 'set-request'} = Pdu, PduMS, ACMData, Address, Extra, #state{set_worker = Worker} = S) -> ?vtrace("handle_snmp_pdu -> multi-thread agent: " "send set-request to main worker",[]), - Worker ! {Vsn, Pdu, PduMS, ACMData, Address, Extra}, + WRequest = ?mk_pdu_wreq(Vsn, Pdu, PduMS, ACMData, Address, infinity, Extra), + Worker ! WRequest, S#state{worker_state = busy}; handle_snmp_pdu(true, Vsn, Pdu, PduMS, ACMData, Address, Extra, - #state{worker_state = busy} = S) -> + #state{worker_state = busy, + gb_max_vbs = GbMaxVBs} = S) -> ?vtrace("handle_snmp_pdu -> multi-thread agent: " "main worker busy - create new worker",[]), - spawn_thread(Vsn, Pdu, PduMS, ACMData, Address, Extra), + spawn_thread(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra), S; handle_snmp_pdu(true, Vsn, Pdu, PduMS, ACMData, Address, Extra, - #state{worker = Worker} = S) -> + #state{worker = Worker, + gb_max_vbs = GbMaxVBs} = S) -> ?vtrace("handle_snmp_pdu -> multi-thread agent: " "send to main worker",[]), - Worker ! {Vsn, Pdu, PduMS, ACMData, Address, Extra}, + WRequest = ?mk_pdu_wreq(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra), + Worker ! WRequest, S#state{worker_state = busy}; handle_snmp_pdu(_, _Vsn, _Pdu, _PduMS, _ACMData, _Address, _Extra, S) -> S. %% Called via the spawn_thread function +%% <BACKWARD-COMPAT> handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra, Dict) -> + handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, ?DEFAULT_GB_MAX_VBS, Extra, + Dict). +%% </BACKWARD-COMPAT> +handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra, Dict) -> lists:foreach(fun({Key, Val}) -> put(Key, Val) end, Dict), put(sname, pdu_handler_short_name(get(sname))), ?vlog("new worker starting",[]), - handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra). + handle_pdu2(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra). -handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra) -> +handle_pdu2(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra) -> %% OTP-3324 AuthMod = get(auth_module), case AuthMod:init_check_access(Pdu, ACMData) of @@ -1780,7 +1918,8 @@ handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra) -> "~n MibView: ~p" "~n ContextName: ~p", [MibView, ContextName]), AgentData = cheat(ACMData, Address, ContextName), - do_handle_pdu(MibView, Vsn, Pdu, PduMS, ACMData, AgentData, Extra); + do_handle_pdu(MibView, Vsn, Pdu, PduMS, ACMData, AgentData, + GbMaxVBs, Extra); {error, Reason} -> ?vlog("handle_pdu -> error:" "~n Reason: ~p", [Reason]), @@ -1794,16 +1933,19 @@ handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra) -> end. do_handle_pdu(MibView, Vsn, Pdu, PduMS, - ACMData, {Community, Address, ContextName}, Extra) -> + ACMData, {Community, Address, ContextName}, + GbMaxVBs, Extra) -> put(net_if_data, Extra), + RePdu = process_msg(MibView, Vsn, Pdu, PduMS, Community, - Address, ContextName), + Address, ContextName, GbMaxVBs), ?vtrace("do_handle_pdu -> processed:" "~n RePdu: ~p", [RePdu]), - get(net_if) ! {snmp_response, Vsn, RePdu, - RePdu#pdu.type, ACMData, Address, Extra}. + NetIf = get(net_if), + NetIf ! {snmp_response, Vsn, RePdu, + RePdu#pdu.type, ACMData, Address, Extra}. handle_acm_error(Vsn, Reason, Pdu, ACMData, Address, Extra) -> @@ -1859,7 +2001,7 @@ handle_acm_error(Vsn, Reason, Pdu, ACMData, Address, Extra) -> ok end. -get_opt(Key, Default, SendOpts) -> +get_send_opt(Key, Default, SendOpts) -> case lists:keysearch(Key, 1, SendOpts) of {value, {Key, Value}} -> Value; @@ -1867,40 +2009,19 @@ get_opt(Key, Default, SendOpts) -> Default end. -handle_send_trap(call, #state{type = master_agent} = S, - Notification, SendOpts) -> - SendOpts2 = - case lists:keymember(local_engine_id, 1, SendOpts) of - true -> - SendOpts; - false -> - [{local_engine_id, ?DEFAULT_LOCAL_ENGINE_ID}|SendOpts] - end, - handle_send_trap(S, Notification, SendOpts2); -handle_send_trap(call, S, Notification, SendOpts) -> - SendOpts2 = - case lists:keymember(local_engine_id, 1, SendOpts) of - true -> - SendOpts; - false -> - %% subagent - - %% we don't need this now, eventually the trap send - %% request will reach the master-agent and then it - %% will look up the proper engine id. - [{local_engine_id, ignore}|SendOpts] - end, - handle_send_trap(S, Notification, SendOpts2); -handle_send_trap(_, S, Notification, SendOpts) -> - handle_send_trap(S, Notification, SendOpts). - handle_send_trap(S, Notification, SendOpts) -> - NotifyName = get_opt(name, "", SendOpts), - ContextName = get_opt(context, "", SendOpts), - Recv = get_opt(receiver, no_receiver, SendOpts), - Varbinds = get_opt(varbinds, [], SendOpts), - ExtraInfo = get_opt(extra, ?DEFAULT_NOTIF_EXTRA_INFO, SendOpts), + NotifyName = get_send_opt(name, "", SendOpts), + ContextName = get_send_opt(context, "", SendOpts), + Recv = get_send_opt(receiver, no_receiver, SendOpts), + Varbinds = get_send_opt(varbinds, [], SendOpts), + ExtraInfo = get_send_opt(extra, ?DEFAULT_NOTIF_EXTRA_INFO, SendOpts), LocalEngineID = - get_opt(local_engine_id, ?DEFAULT_LOCAL_ENGINE_ID, SendOpts), + case lists:keysearch(local_engine_id, 1, SendOpts) of + {value, {local_engine_id, Value}} -> + Value; + false -> + local_engine_id(S) + end, handle_send_trap(S, Notification, NotifyName, ContextName, Recv, Varbinds, LocalEngineID, ExtraInfo). @@ -1908,11 +2029,11 @@ handle_send_trap(#state{type = Type} = S, Notification, NotifyName, ContextName, Recv, Varbinds, LocalEngineID, ExtraInfo) -> ?vtrace("handle_send_trap -> entry with" - "~n Agent type: ~p" - "~n TrapName: ~p" - "~n NotifyName: ~p" - "~n ContextName: ~p" - "~n LocalEngineID: ~p", + "~n Agent type: ~p" + "~n TrapName: ~p" + "~n NotifyName: ~p" + "~n ContextName: ~p" + "~n LocalEngineID: ~p", [Type, Notification, NotifyName, ContextName, LocalEngineID]), case snmpa_trap:construct_trap(Notification, Varbinds) of {ok, TrapRecord, VarList} -> @@ -2025,9 +2146,9 @@ do_handle_send_trap(S, TrapRec, NotifyName, ContextName, Recv, Varbinds, master_agent -> %% Send to main worker ?vtrace("do_handle_send_trap -> send to main worker",[]), - S#state.worker ! {send_trap, - TrapRec, NotifyName, ContextName, Recv, Vbs, - LocalEngineID, ExtraInfo}, + S#state.worker ! ?mk_send_trap_wreq(TrapRec, NotifyName, + ContextName, Recv, Vbs, + LocalEngineID, ExtraInfo), {ok, S#state{worker_state = busy}} end. @@ -2367,17 +2488,18 @@ handle_mib_of(MibServer, Oid) -> %% Func: process_msg/7 %% Returns: RePdu %%----------------------------------------------------------------- -process_msg(MibView, Vsn, Pdu, PduMS, Community, {Ip, Udp}, ContextName) -> +process_msg(MibView, Vsn, Pdu, PduMS, Community, {Ip, Udp}, ContextName, + GbMaxVBs) -> #pdu{request_id = ReqId} = Pdu, put(snmp_address, {tuple_to_list(Ip), Udp}), put(snmp_request_id, ReqId), put(snmp_community, Community), put(snmp_context, ContextName), ?vtrace("process ~p",[Pdu#pdu.type]), - process_pdu(Pdu, PduMS, Vsn, MibView). + process_pdu(Pdu, PduMS, Vsn, MibView, GbMaxVBs). process_pdu(#pdu{type='get-request', request_id = ReqId, varbinds=Vbs}, - _PduMS, Vsn, MibView) -> + _PduMS, Vsn, MibView, _GbMaxVBs) -> ?vtrace("get ~p",[ReqId]), Res = get_err(do_get(MibView, Vbs, false)), ?vtrace("get result: " @@ -2398,12 +2520,12 @@ process_pdu(#pdu{type='get-request', request_id = ReqId, varbinds=Vbs}, make_response_pdu(ReqId, ErrStatus, ErrIndex, Vbs, ResponseVarbinds); process_pdu(#pdu{type = 'get-next-request', request_id = ReqId, varbinds = Vbs}, - _PduMS, Vsn, MibView) -> + _PduMS, Vsn, MibView, _GbMaxVBs) -> ?vtrace("process get-next-request -> entry with" "~n ReqId: ~p" "~n Vbs: ~p" "~n MibView: ~p",[ReqId, Vbs, MibView]), - Res = get_err(do_get_next(MibView, Vbs)), + Res = get_err(do_get_next(MibView, Vbs, infinity)), ?vtrace("get-next result: " "~n ~p",[Res]), {ErrStatus, ErrIndex, ResVarbinds} = @@ -2420,11 +2542,15 @@ process_pdu(#pdu{type = 'get-next-request', request_id = ReqId, varbinds = Vbs}, "~n ~p",[ResponseVarbinds]), make_response_pdu(ReqId, ErrStatus, ErrIndex, Vbs, ResponseVarbinds); -process_pdu(#pdu{type = 'get-bulk-request',request_id = ReqId,varbinds = Vbs, - error_status = NonRepeaters, error_index = MaxRepetitions}, - PduMS, _Vsn, MibView)-> +process_pdu(#pdu{type = 'get-bulk-request', + request_id = ReqId, + varbinds = Vbs, + error_status = NonRepeaters, + error_index = MaxRepetitions}, + PduMS, _Vsn, MibView, GbMaxVBs) -> {ErrStatus, ErrIndex, ResponseVarbinds} = - get_err(do_get_bulk(MibView,NonRepeaters,MaxRepetitions,PduMS,Vbs)), + get_err(do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Vbs, + GbMaxVBs)), ?vtrace("get-bulk final result: " "~n Error status: ~p" "~n Error index: ~p" @@ -2433,7 +2559,7 @@ process_pdu(#pdu{type = 'get-bulk-request',request_id = ReqId,varbinds = Vbs, make_response_pdu(ReqId, ErrStatus, ErrIndex, Vbs, ResponseVarbinds); process_pdu(#pdu{type = 'set-request', request_id = ReqId, varbinds = Vbs}, - _PduMS, Vsn, MibView)-> + _PduMS, Vsn, MibView, _GbMaxVbs)-> Res = do_set(MibView, Vbs), ?vtrace("set result: " "~n ~p",[Res]), @@ -2490,7 +2616,8 @@ validate_next_v1_2([Vb | _Vbs], _MibView, _Res) {noSuchName, Vb#varbind.org_index}; validate_next_v1_2([Vb | Vbs], MibView, Res) when Vb#varbind.variabletype =:= 'Counter64' -> - case validate_next_v1(do_get_next(MibView, [mk_next_oid(Vb)]), MibView) of + case validate_next_v1( + do_get_next(MibView, [mk_next_oid(Vb)], infinity), MibView) of {noError, 0, [NVb]} -> validate_next_v1_2(Vbs, MibView, [NVb | Res]); {Error, Index, _OrgVb} -> @@ -2963,59 +3090,97 @@ validate_tab_res(_TooMany, [], Mfa, _Res, I) -> %% that this really matters, since many nexts across the same %% subagent must be considered to be very rare. %%----------------------------------------------------------------- -do_get_next(MibView, UnsortedVarbinds) -> - SortedVarbinds = oid_sort_varbindlist(UnsortedVarbinds), - next_loop_varbinds([], SortedVarbinds, MibView, [], []). -oid_sort_varbindlist(Vbs) -> +%% It may be a bit agressive to check this already, +%% but since it is a security measure, it makes sense. +do_get_next(_MibView, UnsortedVarbinds, GbMaxVBs) + when (is_integer(GbMaxVBs) andalso (length(UnsortedVarbinds) > GbMaxVBs)) -> + {tooBig, 0, []}; % What is the correct index in this case? +do_get_next(MibView, UnsortedVBs, GbMaxVBs) -> + ?vt("do_get_next -> entry when" + "~n MibView: ~p" + "~n UnsortedVBs: ~p", [MibView, UnsortedVBs]), + SortedVBs = oid_sort_vbs(UnsortedVBs), + ?vt("do_get_next -> " + "~n SortedVBs: ~p", [SortedVBs]), + next_loop_varbinds([], SortedVBs, MibView, [], [], GbMaxVBs). + +oid_sort_vbs(Vbs) -> lists:keysort(#varbind.oid, Vbs). +next_loop_varbinds(_, Vbs, _MibView, Res, _LAVb, GbMaxVBs) + when (is_integer(GbMaxVBs) andalso + ((length(Vbs) + length(Res)) > GbMaxVBs)) -> + {tooBig, 0, []}; % What is the correct index in this case? + %% LAVb is Last Accessible Vb -next_loop_varbinds([], [Vb | Vbs], MibView, Res, LAVb) -> +next_loop_varbinds([], [Vb | Vbs], MibView, Res, LAVb, GbMaxVBs) -> ?vt("next_loop_varbinds -> entry when" "~n Vb: ~p" "~n MibView: ~p", [Vb, MibView]), case varbind_next(Vb, MibView) of endOfMibView -> + ?vt("next_loop_varbind -> endOfMibView", []), RVb = if LAVb =:= [] -> Vb; true -> LAVb end, NewVb = RVb#varbind{variabletype = 'NULL', value = endOfMibView}, - next_loop_varbinds([], Vbs, MibView, [NewVb | Res], []); + next_loop_varbinds([], Vbs, MibView, [NewVb | Res], [], GbMaxVBs); + {variable, ME, VarOid} when ((ME#me.access =/= 'not-accessible') andalso (ME#me.access =/= 'write-only') andalso (ME#me.access =/= 'accessible-for-notify')) -> + ?vt("next_loop_varbind -> variable: " + "~n ME: ~p" + "~n VarOid: ~p", [ME, VarOid]), case try_get_instance(Vb, ME) of {value, noValue, _NoSuchSomething} -> + ?vt("next_loop_varbind -> noValue", []), %% Try next one - NewVb = Vb#varbind{oid = VarOid, value = 'NULL'}, - next_loop_varbinds([], [NewVb | Vbs], MibView, Res, []); + NewVb = Vb#varbind{oid = VarOid, + value = 'NULL'}, + next_loop_varbinds([], [NewVb | Vbs], MibView, Res, [], + GbMaxVBs); {value, Type, Value} -> - NewVb = Vb#varbind{oid = VarOid, variabletype = Type, - value = Value}, - next_loop_varbinds([], Vbs, MibView, [NewVb | Res], []); + ?vt("next_loop_varbind -> value" + "~n Type: ~p" + "~n Value: ~p", [Type, Value]), + NewVb = Vb#varbind{oid = VarOid, + variabletype = Type, + value = Value}, + next_loop_varbinds([], Vbs, MibView, [NewVb | Res], [], + GbMaxVBs); {error, ErrorStatus} -> ?vdebug("next loop varbinds:" "~n ErrorStatus: ~p",[ErrorStatus]), {ErrorStatus, Vb#varbind.org_index, []} end; {variable, _ME, VarOid} -> + ?vt("next_loop_varbind -> variable: " + "~n VarOid: ~p", [VarOid]), RVb = if LAVb =:= [] -> Vb; true -> LAVb end, NewVb = Vb#varbind{oid = VarOid, value = 'NULL'}, - next_loop_varbinds([], [NewVb | Vbs], MibView, Res, RVb); + next_loop_varbinds([], [NewVb | Vbs], MibView, Res, RVb, GbMaxVBs); {table, TableOid, TableRestOid, ME} -> + ?vt("next_loop_varbind -> table: " + "~n TableOid: ~p" + "~n TableRestOid: ~p" + "~n ME: ~p", [TableOid, TableRestOid, ME]), next_loop_varbinds({table, TableOid, ME, [{tab_oid(TableRestOid), Vb}]}, - Vbs, MibView, Res, []); + Vbs, MibView, Res, [], GbMaxVBs); {subagent, SubAgentPid, SAOid} -> + ?vt("next_loop_varbind -> subagent: " + "~n SubAgentPid: ~p" + "~n SAOid: ~p", [SubAgentPid, SAOid]), NewVb = Vb#varbind{variabletype = 'NULL', value = 'NULL'}, next_loop_varbinds({subagent, SubAgentPid, SAOid, [NewVb]}, - Vbs, MibView, Res, []) + Vbs, MibView, Res, [], GbMaxVBs) end; next_loop_varbinds({table, TableOid, ME, TabOids}, - [Vb | Vbs], MibView, Res, _LAVb) -> + [Vb | Vbs], MibView, Res, _LAVb, GbMaxVBs) -> ?vt("next_loop_varbinds(table) -> entry with" "~n TableOid: ~p" "~n Vb: ~p", [TableOid, Vb]), @@ -3023,13 +3188,14 @@ next_loop_varbinds({table, TableOid, ME, TabOids}, {table, TableOid, TableRestOid, _ME} -> next_loop_varbinds({table, TableOid, ME, [{tab_oid(TableRestOid), Vb} | TabOids]}, - Vbs, MibView, Res, []); + Vbs, MibView, Res, [], GbMaxVBs); _ -> case get_next_table(ME, TableOid, TabOids, MibView) of {ok, TabRes, TabEndOfTabVbs} -> NewVbs = lists:append(TabEndOfTabVbs, [Vb | Vbs]), NewRes = lists:append(TabRes, Res), - next_loop_varbinds([], NewVbs, MibView, NewRes, []); + next_loop_varbinds([], NewVbs, MibView, NewRes, [], + GbMaxVBs); {ErrorStatus, OrgIndex} -> ?vdebug("next loop varbinds: next varbind" "~n ErrorStatus: ~p" @@ -3039,7 +3205,7 @@ next_loop_varbinds({table, TableOid, ME, TabOids}, end end; next_loop_varbinds({table, TableOid, ME, TabOids}, - [], MibView, Res, _LAVb) -> + [], MibView, Res, _LAVb, GbMaxVBs) -> ?vt("next_loop_varbinds(table) -> entry with" "~n TableOid: ~p", [TableOid]), case get_next_table(ME, TableOid, TabOids, MibView) of @@ -3048,7 +3214,8 @@ next_loop_varbinds({table, TableOid, ME, TabOids}, "~n TabRes: ~p" "~n TabEndOfTabVbs: ~p", [TabRes, TabEndOfTabVbs]), NewRes = lists:append(TabRes, Res), - next_loop_varbinds([], TabEndOfTabVbs, MibView, NewRes, []); + next_loop_varbinds([], TabEndOfTabVbs, MibView, NewRes, [], + GbMaxVBs); {ErrorStatus, OrgIndex} -> ?vdebug("next loop varbinds: next table" "~n ErrorStatus: ~p" @@ -3057,7 +3224,7 @@ next_loop_varbinds({table, TableOid, ME, TabOids}, {ErrorStatus, OrgIndex, []} end; next_loop_varbinds({subagent, SAPid, SAOid, SAVbs}, - [Vb | Vbs], MibView, Res, _LAVb) -> + [Vb | Vbs], MibView, Res, _LAVb, GbMaxVBs) -> ?vt("next_loop_varbinds(subagent) -> entry with" "~n SAPid: ~p" "~n SAOid: ~p" @@ -3066,13 +3233,14 @@ next_loop_varbinds({subagent, SAPid, SAOid, SAVbs}, {subagent, _SubAgentPid, SAOid} -> next_loop_varbinds({subagent, SAPid, SAOid, [Vb | SAVbs]}, - Vbs, MibView, Res, []); + Vbs, MibView, Res, [], GbMaxVBs); _ -> case get_next_sa(SAPid, SAOid, SAVbs, MibView) of {ok, SARes, SAEndOfMibViewVbs} -> NewVbs = lists:append(SAEndOfMibViewVbs, [Vb | Vbs]), NewRes = lists:append(SARes, Res), - next_loop_varbinds([], NewVbs, MibView, NewRes, []); + next_loop_varbinds([], NewVbs, MibView, NewRes, [], + GbMaxVBs); {noSuchName, OrgIndex} -> %% v1 reply, treat this Vb as endOfMibView, and try again %% for the others. @@ -3085,12 +3253,14 @@ next_loop_varbinds({subagent, SAPid, SAOid, SAVbs}, case lists:delete(EVb, SAVbs) of [] -> next_loop_varbinds([], [EndOfVb, Vb | Vbs], - MibView, Res, []); + MibView, Res, [], + GbMaxVBs); TryAgainVbs -> next_loop_varbinds({subagent, SAPid, SAOid, TryAgainVbs}, [EndOfVb, Vb | Vbs], - MibView, Res, []) + MibView, Res, [], + GbMaxVBs) end; false -> %% bad index from subagent @@ -3106,14 +3276,15 @@ next_loop_varbinds({subagent, SAPid, SAOid, SAVbs}, end end; next_loop_varbinds({subagent, SAPid, SAOid, SAVbs}, - [], MibView, Res, _LAVb) -> + [], MibView, Res, _LAVb, GbMaxVBs) -> ?vt("next_loop_varbinds(subagent) -> entry with" "~n SAPid: ~p" "~n SAOid: ~p", [SAPid, SAOid]), case get_next_sa(SAPid, SAOid, SAVbs, MibView) of {ok, SARes, SAEndOfMibViewVbs} -> NewRes = lists:append(SARes, Res), - next_loop_varbinds([], SAEndOfMibViewVbs, MibView, NewRes, []); + next_loop_varbinds([], SAEndOfMibViewVbs, MibView, NewRes, [], + GbMaxVBs); {noSuchName, OrgIndex} -> %% v1 reply, treat this Vb as endOfMibView, and try again for %% the others. @@ -3124,11 +3295,13 @@ next_loop_varbinds({subagent, SAPid, SAOid, SAVbs}, value = {endOfMibView, NextOid}}, case lists:delete(EVb, SAVbs) of [] -> - next_loop_varbinds([], [EndOfVb], MibView, Res, []); + next_loop_varbinds([], [EndOfVb], MibView, Res, [], + GbMaxVBs); TryAgainVbs -> next_loop_varbinds({subagent, SAPid, SAOid, TryAgainVbs}, - [EndOfVb], MibView, Res, []) + [EndOfVb], MibView, Res, [], + GbMaxVBs) end; false -> %% bad index from subagent @@ -3141,12 +3314,15 @@ next_loop_varbinds({subagent, SAPid, SAOid, SAVbs}, [ErrorStatus,OrgIndex]), {ErrorStatus, OrgIndex, []} end; -next_loop_varbinds([], [], _MibView, Res, _LAVb) -> +next_loop_varbinds([], [], _MibView, Res, _LAVb, _GbMaxVBs) -> ?vt("next_loop_varbinds -> entry when done", []), {noError, 0, Res}. try_get_instance(_Vb, #me{mfa = {M, F, A}, asn1_type = ASN1Type}) -> - ?vtrace("try get instance from <~p,~p,~p>",[M,F,A]), + ?vtrace("try_get_instance -> entry with" + "~n M: ~p" + "~n F: ~p" + "~n A: ~p", [M,F,A]), Result = (catch dbg_apply(M, F, [get | A])), % mib shall return {value, <a-nice-value-within-range>} | % {noValue, noSuchName} (v1) | @@ -3157,6 +3333,7 @@ try_get_instance(_Vb, #me{mfa = {M, F, A}, asn1_type = ASN1Type}) -> tab_oid([]) -> [0]; tab_oid(X) -> X. + %%----------------------------------------------------------------- %% Perform a next, using the varbinds Oid if value is simple %% value. If value is {endOf<something>, NextOid}, use NextOid. @@ -3403,22 +3580,30 @@ next_oid(Oid) -> %%%----------------------------------------------------------------- %%% 5. GET-BULK REQUEST +%%% +%%% In order to prevent excesses in reply sizes there are two +%%% preventive methods in place. One is to check that the encode +%%% size does not exceed Max PDU size (this is mentioned in the +%%% standard). The other is a simple VBs limit. That is, the +%%% resulting response cannot contain more then this number of VBs. %%%----------------------------------------------------------------- -do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds) -> - ?vtrace("do get bulk: start with" + +do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds, GbMaxVBs) -> + ?vtrace("do_get_bulk -> entry with" "~n MibView: ~p" "~n NonRepeaters: ~p" "~n MaxRepetitions: ~p" "~n PduMS: ~p" - "~n Varbinds: ~p", - [MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds]), + "~n Varbinds: ~p" + "~n GbMaxVBs: ~p", + [MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds, GbMaxVBs]), {NonRepVbs, RestVbs} = split_vbs(NonRepeaters, Varbinds, []), - ?vt("do get bulk -> split: " + ?vt("do_get_bulk -> split: " "~n NonRepVbs: ~p" "~n RestVbs: ~p", [NonRepVbs, RestVbs]), - case do_get_next(MibView, NonRepVbs) of - {noError, 0, UResNonRepVbs} -> - ?vt("do get bulk -> next: " + case do_get_next(MibView, NonRepVbs, GbMaxVBs) of + {noError, 0, UResNonRepVbs} -> + ?vt("do_get_bulk -> next noError: " "~n UResNonRepVbs: ~p", [UResNonRepVbs]), ResNonRepVbs = lists:keysort(#varbind.org_index, UResNonRepVbs), %% Decode the first varbinds, produce a reversed list of @@ -3428,11 +3613,12 @@ do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds) -> user_err("failed encoding varbind ~w:~n~p", [Idx, Reason]), {genErr, Idx, []}; {SizeLeft, Res} when is_integer(SizeLeft) and is_list(Res) -> - ?vtrace("do get bulk -> encoded: " + ?vtrace("do_get_bulk -> encoded: " "~n SizeLeft: ~p" "~n Res: ~w", [SizeLeft, Res]), case (catch do_get_rep(SizeLeft, MibView, MaxRepetitions, - RestVbs, Res)) of + RestVbs, Res, + length(UResNonRepVbs), GbMaxVBs)) of {error, Idx, Reason} -> user_err("failed encoding varbind ~w:~n~p", [Idx, Reason]), @@ -3441,6 +3627,10 @@ do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds) -> ?vtrace("do get bulk -> Res: " "~n ~w", [Res]), {noError, 0, conv_res(Res)}; + {noError, 0, Data} = OK -> + ?vtrace("do get bulk -> OK: " + "~n length(Data): ~w", [length(Data)]), + OK; Else -> ?vtrace("do get bulk -> Else: " "~n ~w", [Else]), @@ -3449,6 +3639,7 @@ do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds) -> Res when is_list(Res) -> {noError, 0, conv_res(Res)} end; + {ErrorStatus, Index, _} -> ?vdebug("do get bulk: " "~n ErrorStatus: ~p" @@ -3498,11 +3689,12 @@ enc_vbs(SizeLeft, Vbs) -> end, lists:foldl(Fun, {SizeLeft, []}, Vbs). -do_get_rep(Sz, MibView, MaxRepetitions, Varbinds, Res) +do_get_rep(Sz, MibView, MaxRepetitions, Varbinds, Res, GbNumVBs, GbMaxVBs) when MaxRepetitions >= 0 -> - do_get_rep(Sz, MibView, 0, MaxRepetitions, Varbinds, Res); -do_get_rep(Sz, MibView, _MaxRepetitions, Varbinds, Res) -> - do_get_rep(Sz, MibView, 0, 0, Varbinds, Res). + do_get_rep(Sz, MibView, 0, MaxRepetitions, Varbinds, Res, + GbNumVBs, GbMaxVBs); +do_get_rep(Sz, MibView, _MaxRepetitions, Varbinds, Res, GbNumVBs, GbMaxVBs) -> + do_get_rep(Sz, MibView, 0, 0, Varbinds, Res, GbNumVBs, GbMaxVBs). conv_res(ResVarbinds) -> conv_res(ResVarbinds, []). @@ -3511,22 +3703,30 @@ conv_res([VbListOfBytes | T], Bytes) -> conv_res([], Bytes) -> Bytes. -do_get_rep(_Sz, _MibView, Max, Max, _, Res) -> +%% The only other value, then a positive integer, is infinity. +do_get_rep(_Sz, _MibView, Count, Max, _, _Res, GbNumVBs, GbMaxVBs) + when (is_integer(GbMaxVBs) andalso (GbNumVBs > GbMaxVBs)) -> + ?vinfo("Max Get-BULK VBs limit (~w) exceeded (~w) when:" + "~n Count: ~p" + "~n Max: ~p", [GbMaxVBs, GbNumVBs, Count, Max]), + {tooBig, 0, []}; +do_get_rep(_Sz, _MibView, Max, Max, _, Res, _GbNumVBs, _GbMaxVBs) -> ?vt("do_get_rep -> done when: " "~n Res: ~p", [Res]), {noError, 0, conv_res(Res)}; -do_get_rep(Sz, MibView, Count, Max, Varbinds, Res) -> +do_get_rep(Sz, MibView, Count, Max, Varbinds, Res, GbNumVBs, GbMaxVBs) -> ?vt("do_get_rep -> entry when: " "~n Sz: ~p" "~n Count: ~p" "~n Res: ~w", [Sz, Count, Res]), - case try_get_bulk(Sz, MibView, Varbinds) of + case try_get_bulk(Sz, MibView, Varbinds, GbMaxVBs) of {noError, NextVarbinds, SizeLeft, Res2} -> ?vt("do_get_rep -> noError: " "~n SizeLeft: ~p" "~n Res2: ~p", [SizeLeft, Res2]), do_get_rep(SizeLeft, MibView, Count+1, Max, NextVarbinds, - Res2 ++ Res); + Res2 ++ Res, + GbNumVBs + length(Varbinds), GbMaxVBs); {endOfMibView, _NextVarbinds, _SizeLeft, Res2} -> ?vt("do_get_rep -> endOfMibView: " "~n Res2: ~p", [Res2]), @@ -3538,22 +3738,29 @@ do_get_rep(Sz, MibView, Count, Max, Varbinds, Res) -> {ErrorStatus, Index, []} end. -try_get_bulk(Sz, MibView, Varbinds) -> +org_index_sort_vbs(Vbs) -> + lists:keysort(#varbind.org_index, Vbs). + +try_get_bulk(Sz, MibView, Varbinds, GbMaxVBs) -> ?vt("try_get_bulk -> entry with" - "~n Sz: ~w", [Sz]), - case do_get_next(MibView, Varbinds) of + "~n Sz: ~w" + "~n MibView: ~w" + "~n Varbinds: ~w", [Sz, MibView, Varbinds]), + case do_get_next(MibView, Varbinds, GbMaxVBs) of {noError, 0, UNextVarbinds} -> - ?vt("try_get_bulk -> noError", []), - NextVarbinds = lists:keysort(#varbind.org_index, UNextVarbinds), + ?vt("try_get_bulk -> noError: " + "~n UNextVarbinds: ~p", [UNextVarbinds]), + NextVarbinds = org_index_sort_vbs(UNextVarbinds), case (catch enc_vbs(Sz, NextVarbinds)) of {error, Idx, Reason} -> user_err("failed encoding varbind ~w:~n~p", [Idx, Reason]), - ?vtrace("try_get_bulk -> error: " + ?vtrace("try_get_bulk -> encode error: " "~n Idx: ~p" "~n Reason: ~p", [Idx, Reason]), {genErr, Idx}; - {SizeLeft, Res} when is_integer(SizeLeft) andalso is_list(Res) -> - ?vt("try get bulk -> " + {SizeLeft, Res} when is_integer(SizeLeft) andalso + is_list(Res) -> + ?vt("try get bulk -> encode ok: " "~n SizeLeft: ~w" "~n Res: ~w", [SizeLeft, Res]), {check_end_of_mibview(NextVarbinds), @@ -3564,9 +3771,9 @@ try_get_bulk(Sz, MibView, Varbinds) -> {endOfMibView, [], 0, Res} end; {ErrorStatus, Index, _} -> - ?vt("try get bulk: " + ?vt("try_get_bulk -> error: " "~n ErrorStatus: ~p" - "~n Index: ~p",[ErrorStatus, Index]), + "~n Index: ~p", [ErrorStatus, Index]), {ErrorStatus, Index} end. @@ -3707,9 +3914,8 @@ get_err({ErrC, ErrI, Vbs}) -> {get_err_i(ErrC), ErrI, Vbs}. get_err_i(noError) -> noError; -get_err_i(S) -> - ?vtrace("convert '~p' to 'genErr'",[S]), - genErr. +get_err_i(tooBig) -> tooBig; % OTP-9700 +get_err_i(ES) -> ?vtrace("convert ErrorStatus '~p' to 'genErr'", [ES]), genErr. v2err_to_v1err(noError) -> noError; v2err_to_v1err(noAccess) -> noSuchName; @@ -3935,6 +4141,7 @@ mapfoldl(F, Eas, Accu0, [Hd|Tail]) -> {Accu2,[R|Rs]}; mapfoldl(_F, _Eas, Accu, []) -> {Accu,[]}. + %%----------------------------------------------------------------- %% Runtime debugging of the agent. %%----------------------------------------------------------------- @@ -4001,6 +4208,18 @@ subagents_verbosity(_,_V) -> %% --------------------------------------------------------------------- +local_engine_id(#state{type = master_agent}) -> + ?DEFAULT_LOCAL_ENGINE_ID; +local_engine_id(_) -> + %% subagent - + %% we don't need this now, eventually the trap send + %% request will reach the master-agent and then it + %% will look up the proper engine id. + ignore. + + +%% --------------------------------------------------------------------- + handle_get_log_type(#state{net_if_mod = Mod}) when Mod =/= undefined -> case (catch Mod:get_log_type(get(net_if))) of @@ -4047,7 +4266,7 @@ handle_set_request_limit(_, _) -> {error, not_supported}. -agent_info(#state{worker = W, set_worker = SW}) -> +agent_info(#state{worker = W, set_worker = SW}) -> case (catch get_agent_info(W, SW)) of Info when is_list(Info) -> Info; @@ -4206,6 +4425,9 @@ get_multi_threaded(Opts) -> get_versions(Opts) -> get_option(versions, Opts, [v1,v2,v3]). +get_gb_max_vbs(Opts) -> + get_option(gb_max_vbs, Opts, infinity). + get_note_store_opt(Opts) -> get_option(note_store, Opts, []). diff --git a/lib/snmp/src/agent/snmpa_internal.hrl b/lib/snmp/src/agent/snmpa_internal.hrl index a490a78f84..c435b519d9 100644 --- a/lib/snmp/src/agent/snmpa_internal.hrl +++ b/lib/snmp/src/agent/snmpa_internal.hrl @@ -22,9 +22,19 @@ -include_lib("snmp/src/app/snmp_internal.hrl"). --define(DEFAULT_LOCAL_ENGINE_ID, snmp_framework_mib:get_engine_id()). +%% The DEFAULT_LOCAL_ENGINE_ID macro can only be used by the master_agent!! +-define(DEFAULT_LOCAL_ENGINE_ID, snmp_framework_mib:get_engine_id()). -define(DEFAULT_NOTIF_EXTRA_INFO, {snmpa_default_notification_extra_info}). +%% -- Max number of VBs in a Get-BULK response -- +%% (( The default value, 1000, is *way* more )) +%% (( then there is room for in a normal pdu )) +%% (( (unless the max pdu size has been )) +%% (( cranked way up), so this value should )) +%% (( suffice as "infinity" without actually )) +%% (( causing memory issues for the VM ... )) +-define(DEFAULT_GB_MAX_VBS, 1000). + -define(snmpa_info(F, A), ?snmp_info("agent", F, A)). -define(snmpa_warning(F, A), ?snmp_warning("agent", F, A)). -define(snmpa_error(F, A), ?snmp_error("agent", F, A)). diff --git a/lib/snmp/src/agent/snmpa_local_db.erl b/lib/snmp/src/agent/snmpa_local_db.erl index d9d6e633de..ab277fc3e9 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), @@ -1110,7 +1118,7 @@ table_func(is_set_ok, RowIndex, Cols, NameDb) -> table_func(set, RowIndex, Cols, NameDb) -> snmp_generic:table_set_row(NameDb, nofunc, - {snmp_generic, table_try_make_consistent}, + fun snmp_generic:table_try_make_consistent/3, RowIndex, Cols); 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_mib_lib.erl b/lib/snmp/src/agent/snmpa_mib_lib.erl index 078e681945..3c94cc8095 100644 --- a/lib/snmp/src/agent/snmpa_mib_lib.erl +++ b/lib/snmp/src/agent/snmpa_mib_lib.erl @@ -61,23 +61,23 @@ table_del_row({Tab, Db} = TabDb, Key) -> get_table(NameDb, FOI) -> (catch get_table(NameDb, FOI, [], [])). -get_table(NameDb, FOI, Oid, Acc) -> - case table_next(NameDb, Oid) of +get_table(NameDb, FOI, Key, Acc) -> + case table_next(NameDb, Key) of endOfTable -> ?vdebug("end of table",[]), {ok, lists:reverse(Acc)}; - Oid -> + Key -> %% Crap, circular ref - ?vinfo("cyclic reference: ~w -> ~w", [Oid,Oid]), - throw({error, {cyclic_db_reference, Oid, Acc}}); - NextOid -> - ?vtrace("get row for oid ~w", [NextOid]), - case table_get_row(NameDb, NextOid, FOI) of + ?vinfo("cyclic reference: ~w -> ~w", [Key, Key]), + throw({error, {cyclic_db_reference, Key, Acc}}); + NextKey -> + ?vtrace("get row for key ~w", [NextKey]), + case table_get_row(NameDb, NextKey, FOI) of undefined -> - throw({error, {invalid_rowindex, NextOid, Acc}}); + throw({error, {invalid_rowindex, NextKey, Acc}}); Row -> ?vtrace("row: ~w", [Row]), - get_table(NameDb, FOI, NextOid, [{NextOid, Row}|Acc]) + get_table(NameDb, FOI, NextKey, [{NextKey, Row}|Acc]) end end. diff --git a/lib/snmp/src/agent/snmpa_mpd.erl b/lib/snmp/src/agent/snmpa_mpd.erl index 4f50b1a674..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 @@ -468,15 +468,10 @@ v3_proc(NoteStore, Packet, LocalEngineID, V3Hdr, Data, Log) -> _ -> %% 4.2.2.1.2 NIsReportable = snmp_misc:is_reportable_pdu(Type), - Val = inc(snmpUnknownPDUHandlers), ErrorInfo = - {#varbind{oid = ?snmpUnknownPDUHandlers, - variabletype = 'Counter32', - value = Val}, - SecName, - [{securityLevel, SecLevel}, - {contextEngineID, ContextEngineID}, - {contextName, ContextName}]}, + snmpUnknownPDUHandlers_ei(SecName, SecLevel, + ContextEngineID, + ContextName), case generate_v3_report_msg(MsgID, MsgSecurityModel, Data, LocalEngineID, @@ -507,6 +502,21 @@ v3_proc(NoteStore, Packet, LocalEngineID, V3Hdr, Data, Log) -> end end. +make_error_info(Variable, Oid, SecName, Opts) -> + Val = inc(Variable), + VB = #varbind{oid = Oid, + variabletype = 'Counter32', + value = Val}, + {VB, SecName, Opts}. + +snmpUnknownPDUHandlers_ei(SecName, SecLevel, + ContextEngineID, ContextName) -> + Opts = [{securityLevel, SecLevel}, + {contextEngineID, ContextEngineID}, + {contextName, ContextName}], + make_error_info(snmpUnknownPDUHandlers, + ?snmpUnknownPDUHandlers_instance, + SecName, Opts). get_security_module(?SEC_USM) -> snmpa_usm; diff --git a/lib/snmp/src/agent/snmpa_set_lib.erl b/lib/snmp/src/agent/snmpa_set_lib.erl index 191029f6db..9f355855b4 100644 --- a/lib/snmp/src/agent/snmpa_set_lib.erl +++ b/lib/snmp/src/agent/snmpa_set_lib.erl @@ -143,8 +143,8 @@ consistency_check(Varbinds) -> consistency_check(Varbinds, []). consistency_check([{TableOid, TableVbs} | Varbinds], Done) -> ?vtrace("consistency_check -> entry with" - "~n TableOid: ~p" - "~n TableVbs: ~p",[TableOid,TableVbs]), + "~n TableOid: ~p" + "~n TableVbs: ~p", [TableOid, TableVbs]), TableOpsWithShortOids = deletePrefixes(TableOid, TableVbs), [#ivarbind{mibentry = MibEntry}|_] = TableVbs, case is_set_ok_table(MibEntry, TableOpsWithShortOids) of @@ -158,7 +158,7 @@ consistency_check([{TableOid, TableVbs} | Varbinds], Done) -> end; consistency_check([IVarbind | Varbinds], Done) -> ?vtrace("consistency_check -> entry with" - "~n IVarbind: ~p",[IVarbind]), + "~n IVarbind: ~p", [IVarbind]), #ivarbind{varbind = Varbind, mibentry = MibEntry} = IVarbind, #varbind{value = Value, org_index = OrgIndex} = Varbind, case is_set_ok_variable(MibEntry, Value) of @@ -358,32 +358,39 @@ make_value_a_correct_value(Value, ASN1Type, Mfa) -> %% Runtime debug support %%----------------------------------------------------------------- -% XXX: This function match on the exakt return codes from EXIT -% messages. As of this writing it was not decided if this is -% the right way so don't blindly do things this way. -% -% We fake a real EXIT signal as the return value because the -% result is passed to the function snmpa_agent:validate_err() -% that expect it. +%% XYZ: This function match on the exakt return codes from EXIT +%% messages. As of this writing it was not decided if this is +%% the right way so don't blindly do things this way. +%% +%% We fake a real EXIT signal as the return value because the +%% result is passed to the function snmpa_agent:validate_err() +%% that expect it. dbg_apply(M,F,A) -> - Result = - case get(verbosity) of - false -> - (catch apply(M,F,A)); - _ -> - ?vlog("~n apply: ~w,~w,~p~n", [M,F,A]), - Res = (catch apply(M,F,A)), - ?vlog("~n returned: ~p", [Res]), - Res - end, - case Result of + case maybe_verbose_apply(M, F, A) of + %% <Future proofing> + %% As of R15 we get extra info containing, + %% among other things, line numbers. + {'EXIT', {undef, [{M, F, A, _} | _]}} -> + {'EXIT', {hook_undef, {M, F, A}}}; + {'EXIT', {function_clause, [{M, F, A, _} | _]}} -> + {'EXIT', {hook_function_clause, {M, F, A}}}; + + %% This is really overkill, but just to be on the safe side... + {'EXIT', {undef, {M, F, A, _}}} -> + {'EXIT', {hook_undef, {M, F, A}}}; + {'EXIT', {function_clause, {M, F, A, _}}} -> + {'EXIT', {hook_function_clause, {M, F, A}}}; + %% </Future proofing> + + + %% Old format format for compatibility {'EXIT', {undef, [{M, F, A} | _]}} -> {'EXIT', {hook_undef, {M, F, A}}}; {'EXIT', {function_clause, [{M, F, A} | _]}} -> {'EXIT', {hook_function_clause, {M, F, A}}}; - % XXX: Old format for compatibility + % XYZ: Older format for compatibility {'EXIT', {undef, {M, F, A}}} -> {'EXIT', {hook_undef, {M, F, A}}}; {'EXIT', {function_clause, {M, F, A}}} -> @@ -393,3 +400,15 @@ dbg_apply(M,F,A) -> Result end. + +maybe_verbose_apply(M, F, A) -> + case get(verbosity) of + false -> + (catch apply(M,F,A)); + _ -> + ?vlog("~n apply: ~w,~w,~p~n", [M,F,A]), + Res = (catch apply(M,F,A)), + ?vlog("~n returned: ~p", [Res]), + Res + end. + diff --git a/lib/snmp/src/agent/snmpa_supervisor.erl b/lib/snmp/src/agent/snmpa_supervisor.erl index 5ef5914e18..7a9c214e0d 100644 --- a/lib/snmp/src/agent/snmpa_supervisor.erl +++ b/lib/snmp/src/agent/snmpa_supervisor.erl @@ -176,8 +176,8 @@ init([AgentType, Opts]) -> "~n AgentType: ~p" "~n Opts: ~p", [AgentType, Opts]), - put(sname, asup), - put(verbosity,get_verbosity(Opts)), + put(sname, asup), + put(verbosity, get_verbosity(Opts)), ?vlog("starting",[]), @@ -203,7 +203,12 @@ init([AgentType, Opts]) -> Vsns = get_opt(versions, Opts, [v1,v2,v3]), ?vdebug("[agent table] store versions: ~p",[Vsns]), ets:insert(snmp_agent_table, {versions, Vsns}), - + + %% -- Max number of VBs in a Get-BULK response -- + GbMaxVBs = get_gb_max_vbs(Opts), + ?vdebug("[agent table] Get-BULK max VBs: ~p", [GbMaxVBs]), + ets:insert(snmp_agent_table, {gb_max_vbs, GbMaxVBs}), + %% -- DB-directory -- DbDir = get_opt(db_dir, Opts), ?vdebug("[agent table] store db_dir: ~n ~p",[DbDir]), @@ -377,7 +382,8 @@ init([AgentType, Opts]) -> {versions, Vsns}, {net_if, NiOpts}, {mib_server, MibsOpts}, - {note_store, NsOpts}| + {note_store, NsOpts}, + {gb_max_vbs, GbMaxVBs} | get_opt(master_agent_options, Opts, [])], AgentSpec = @@ -542,6 +548,32 @@ get_verbosity(Opts) -> get_agent_type(Opts) -> get_opt(agent_type, Opts, master). + +%% We validate this option! This should really be done for all +%% options, but it is beyond the scope of this ticket, OTP-9700. + +get_gb_max_vbs(Opts) -> + Validate = + fun(GbMaxVBs) + when ((is_integer(GbMaxVBs) andalso (GbMaxVBs > 0)) orelse + (GbMaxVBs =:= infinity)) -> + ok; + (_) -> + error + end, + get_option(gb_max_vbs, ?DEFAULT_GB_MAX_VBS, Validate, Opts). + +get_option(Key, Default, Validate, Opts) + when is_list(Opts) andalso is_function(Validate) -> + Value = get_opt(Key, Opts, Default), + case Validate(Value) of + ok -> + Value; + error -> + exit({bad_option, Key, Value}) + end. + + get_opt(Key, Opts) -> snmp_misc:get_option(Key, Opts). diff --git a/lib/snmp/src/agent/snmpa_trap.erl b/lib/snmp/src/agent/snmpa_trap.erl index 567de020c0..994d926224 100644 --- a/lib/snmp/src/agent/snmpa_trap.erl +++ b/lib/snmp/src/agent/snmpa_trap.erl @@ -352,11 +352,26 @@ send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs, ExtraInfo, NetIf) -> send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs, LocalEngineID, ExtraInfo, NetIf). +%% The agent normally does not care about the result, +%% but since it can be usefull when debugging, add +%% some info when we fail to send the trap(s). send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs, LocalEngineID, ExtraInfo, NetIf) -> - (catch do_send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs, - LocalEngineID, ExtraInfo, NetIf)). - + try + begin + do_send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs, + LocalEngineID, ExtraInfo, NetIf) + end + catch + T:E -> + Info = [{args, [TrapRec, NotifyName, ContextName, + Recv, Vbs, LocalEngineID, ExtraInfo, NetIf]}, + {tag, T}, + {err, E}, + {stacktrace, erlang:get_stacktrace()}], + {error, {failed_sending_trap, Info}} + end. + do_send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs, LocalEngineID, ExtraInfo, NetIf) -> VarbindList = make_varbind_list(Vbs), @@ -379,8 +394,13 @@ send_discovery(TargetName, Record, ContextName, Vbs, NetIf, ExtraInfo) -> get_values(VariablesWithType) -> {Order, Varbinds} = extract_order(VariablesWithType, 1), + ?vtrace("get_values -> " + "~n Order: ~p" + "~n Varbinds: ~p", [Order, Varbinds]), case snmpa_agent:do_get(snmpa_acm:get_root_mib_view(), Varbinds, true) of {noError, _, NewVarbinds} -> + ?vtrace("get_values -> values retrieved" + "~n NewVarbinds: ~p", [NewVarbinds]), %% NewVarbinds is the result of: %% first a reverse, then a sort on the oid field and finally %% a reverse during the get-processing so we need to re-sort diff --git a/lib/snmp/src/agent/snmpa_vacm.erl b/lib/snmp/src/agent/snmpa_vacm.erl index 892dc265f1..dadcf32543 100644 --- a/lib/snmp/src/agent/snmpa_vacm.erl +++ b/lib/snmp/src/agent/snmpa_vacm.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2010. All Rights Reserved. +%% Copyright Ericsson AB 1999-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 @@ -62,6 +62,13 @@ get_mib_view(ViewType, SecModel, SecName, SecLevel, ContextName) -> %% Follows the procedure in rfc2275 auth(ViewType, SecModel, SecName, SecLevel, ContextName) -> + ?vtrace("auth -> entry with" + "~n ViewType: ~p" + "~n SecModel: ~p" + "~n SecName: ~p" + "~n SecLevel: ~p" + "~n ContextName: ~p", + [ViewType, SecModel, SecName, SecLevel, ContextName]), % 3.2.1 - Check that the context is known to us ?vdebug("check that the context (~p) is known to us",[ContextName]), case snmp_view_based_acm_mib:vacmContextTable(get, ContextName, @@ -74,7 +81,7 @@ auth(ViewType, SecModel, SecName, SecLevel, ContextName) -> end, % 3.2.2 - Check that the SecModel and SecName is valid ?vdebug("check that SecModel (~p) and SecName (~p) is valid", - [SecModel,SecName]), + [SecModel, SecName]), GroupName = case snmp_view_based_acm_mib:get(vacmSecurityToGroupTable, [SecModel, length(SecName) | SecName], @@ -111,6 +118,8 @@ check_auth(Res) -> {ok, Res}. %% key in the table >= ViewIndex. %%----------------------------------------------------------------- get_mib_view(ViewName) -> + ?vtrace("get_mib_view -> entry with" + "~n ViewName: ~p", [ViewName]), ViewKey = [length(ViewName) | ViewName], case snmp_view_based_acm_mib:table_next(vacmViewTreeFamilyTable, ViewKey) of @@ -202,6 +211,13 @@ backup(BackupDir) -> %% Ret: {ok, ViewName} | {error, Reason} get_view_name(ViewType, GroupName, ContextName, SecModel, SecLevel) -> + ?vtrace("get_view_name -> entry with" + "~n ViewType: ~p" + "~n GroupName: ~p" + "~n ContextName: ~p" + "~n SecModel: ~p" + "~n SecLevel: ~p", + [ViewType, GroupName, ContextName, SecModel, SecLevel]), GroupKey = [length(GroupName) | GroupName], case get_access_row(GroupKey, ContextName, SecModel, SecLevel) of undefined -> @@ -266,9 +282,10 @@ dump_table(true) -> dump_table(_) -> ok. + dump_table() -> [{_, FName}] = ets:lookup(snmp_agent_table, snmpa_vacm_file), - TmpName = FName ++ ".tmp", + TmpName = unique_table_name(FName), case ets:tab2file(snmpa_vacm, TmpName) of ok -> case file:rename(TmpName, FName) of @@ -283,6 +300,35 @@ dump_table() -> [FName, Reason]) end. +%% This little thing is an attempt to create a "unique" filename +%% in order to minimize the risk of two processes at the same +%% time dumping the table. +unique_table_name(Pre) -> + %% We want something that is guaranteed to be unique, + %% therefor we use erlang:now() instead of os:timestamp() + unique_table_name(Pre, erlang:now()). + +unique_table_name(Pre, {_A, _B, C} = 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_~w", + [YYYY, MM, DD, Hour, Min, Sec, round(C/1000)]), + unique_table_name2(Pre, FormatDate). + +unique_table_name2(Pre, FormatedDate) -> + PidPart = unique_table_name_pid(), + lists:flatten(io_lib:format("~s.~s~s.tmp", [Pre, PidPart, FormatedDate])). + +unique_table_name_pid() -> + case string:tokens(pid_to_list(self()), [$<,$.,$>]) of + [A, B, C] -> + A ++ B ++ C ++ "."; + _ -> + "" + end. + %%----------------------------------------------------------------- %% Alg. diff --git a/lib/snmp/src/app/snmp.appup.src b/lib/snmp/src/app/snmp.appup.src index 0b6ea93231..c8e5eec6db 100644 --- a/lib/snmp/src/app/snmp.appup.src +++ b/lib/snmp/src/app/snmp.appup.src @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2011. All Rights Reserved. +%% Copyright Ericsson AB 1999-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 @@ -22,14 +22,124 @@ %% ----- 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, []}, + {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, []} + ] + }, + {"4.21.4", + [ + {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, []}, + {update, snmpa_supervisor, soft, soft_purge, soft_purge, []}, + + {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_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", + [ + {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, []}, + {update, snmpa_supervisor, soft, soft_purge, soft_purge, []}, + + {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_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.2", + [ + {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, []}, + {update, snmpa_supervisor, soft, soft_purge, soft_purge, []}, + + {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []}, + {load_module, snmpa_vacm, soft_purge, soft_purge, []}, + {load_module, snmpa_mpd, soft_purge, soft_purge, []}, + {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_mib, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []} + ] + }, + {"4.21.1", + [ + {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, []}, + {update, snmpa_supervisor, soft, soft_purge, soft_purge, []}, + + {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []}, + {load_module, snmpa_vacm, soft_purge, soft_purge, []}, + {load_module, snmpa_mpd, soft_purge, soft_purge, []}, + {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_mib, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []}, + {update, snmp_note_store, soft, soft_purge, soft_purge, []} + ] + }, {"4.21", [ - {load_module, snmp_target_mib, soft_purge, soft_purge, []} + {load_module, snmpa, soft_purge, soft_purge, []}, + {load_module, snmpa_mib_lib, soft_purge, soft_purge, []}, + {update, snmpa_supervisor, soft, soft_purge, soft_purge, []}, + + {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []}, + {load_module, snmpa_vacm, soft_purge, soft_purge, []}, + {load_module, snmpa_mpd, soft_purge, soft_purge, []}, + {load_module, snmpa_set_lib, soft_purge, soft_purge, []}, + {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_mib, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []}, + {update, snmp_note_store, soft, soft_purge, soft_purge, []} ] }, {"4.20.1", [ - {load_module, snmp_target_mib, soft_purge, soft_purge, []}, + {load_module, snmpa, soft_purge, soft_purge, []}, + {load_module, snmpa_mib_lib, soft_purge, soft_purge, []}, + {update, snmpa_supervisor, soft, soft_purge, soft_purge, []}, + + {load_module, snmpa_vacm, soft_purge, soft_purge, []}, + {load_module, snmpa_set_lib, soft_purge, soft_purge, []}, + {load_module, snmpa_trap, soft_purge, soft_purge, []}, + {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]}, {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []}, {load_module, snmpm, soft_purge, soft_purge, [snmpm_server, snmpm_config, snmp_config]}, @@ -40,18 +150,30 @@ {load_module, snmpa_mpd, soft_purge, soft_purge, [snmp_conf, snmp_config]}, {load_module, snmpa_conf, soft_purge, soft_purge, [snmp_config]}, - {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, + {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, [snmpm_net_if, snmpm_mpd, snmpm_config]}, - {update, snmpm_net_if, soft, soft_purge, soft_purge, + {update, snmpm_net_if, soft, soft_purge, soft_purge, [snmp_conf, snmpm_mpd, snmpm_config]} ] }, {"4.20", [ + {load_module, snmpa, soft_purge, soft_purge, []}, + {load_module, snmpa_mib_lib, soft_purge, soft_purge, []}, + {update, snmpa_supervisor, soft, soft_purge, soft_purge, []}, + + {load_module, snmpa_vacm, soft_purge, soft_purge, []}, + {load_module, snmpa_set_lib, soft_purge, soft_purge, []}, + {load_module, snmpa_trap, soft_purge, soft_purge, []}, {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []}, - {load_module, snmp_target_mib, soft_purge, soft_purge, [snmp_conf]}, + {load_module, snmp_target_mib, soft_purge, soft_purge, + [snmpa_mib_lib, snmp_conf]}, {load_module, snmpm, soft_purge, soft_purge, [snmpm_server, snmpm_config, snmp_config]}, {load_module, snmp_conf, soft_purge, soft_purge, []}, @@ -61,67 +183,140 @@ {load_module, snmpa_mpd, soft_purge, soft_purge, [snmp_conf, snmp_config]}, {load_module, snmpa_conf, soft_purge, soft_purge, [snmp_config]}, - {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, + {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, [snmpm_net_if, snmpm_mpd, snmpm_config]}, - {update, snmpm_net_if, soft, soft_purge, soft_purge, + {update, snmpm_net_if, soft, soft_purge, soft_purge, [snmp_conf, snmpm_mpd, snmpm_config]} ] + } + ], + +%% ------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, []}, + {update, snmpa_supervisor, 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", + [ + {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, []}, + {update, snmpa_supervisor, soft, soft_purge, soft_purge, []}, + + {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_local_db, soft, soft_purge, soft_purge, []}, + {update, snmpa_mib, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []} + ] }, - {"4.19", + {"4.21.3", [ {load_module, snmpa, soft_purge, soft_purge, []}, - {load_module, snmpm, soft_purge, soft_purge, - [snmpm_server, snmpm_config, snmp_config]}, - {load_module, snmpa_usm, soft_purge, soft_purge, []}, - {load_module, snmpm_usm, soft_purge, soft_purge, []}, - {load_module, snmp_log, soft_purge, soft_purge, []}, - {load_module, snmp_pdus, soft_purge, soft_purge, []}, - {load_module, snmp_conf, soft_purge, soft_purge, []}, - {load_module, snmpa_conf, soft_purge, soft_purge, - [snmp_conf, snmp_config]}, - {load_module, snmp_misc, soft_purge, soft_purge, []}, - {load_module, snmp_config, soft_purge, soft_purge, []}, - {load_module, snmpa_mpd, soft_purge, soft_purge, - [snmp_conf, snmp_config]}, - {load_module, snmpm_mpd, soft_purge, soft_purge, - [snmp_conf, snmp_config, snmpm_config]}, - {load_module, snmpa_trap, soft_purge, soft_purge, - [snmpa_mpd, snmp_notification_mib, snmp_target_mib, snmpa_net_if]}, - {load_module, snmpa_acm, soft_purge, soft_purge, - [snmp_conf, snmpa_mpd, snmp_target_mib]}, - {load_module, snmpa_conf, soft_purge, soft_purge, - [snmp_config, snmp_notification_mib]}, + {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, []}, + {update, snmpa_supervisor, soft, soft_purge, soft_purge, []}, + + {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []}, {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []}, - {load_module, snmp_notification_mib, soft_purge, soft_purge, - [snmp_conf, snmp_target_mib]}, - {load_module, snmp_community_mib, soft_purge, soft_purge, []}, - {load_module, snmp_target_mib, soft_purge, soft_purge, - [snmp_conf]}, - {update, snmpm_net_if, soft, soft_purge, soft_purge, - [snmp_conf, snmpm_mpd, snmpm_config]}, - {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]}, - {update, snmpa_net_if, soft, soft_purge, soft_purge, - [snmp_conf, snmpa_mpd]}, - {update, snmpa_agent, soft, soft_purge, soft_purge, - [snmpa_acm, snmpa_mpd, snmpa_trap]} + {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_agent, soft, soft_purge, soft_purge, []} ] - } - ], + }, + {"4.21.2", + [ + {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, []}, + {update, snmpa_supervisor, soft, soft_purge, soft_purge, []}, -%% ------D o w n g r a d e --------------------------------------------------- + {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []}, + {load_module, snmpa_vacm, soft_purge, soft_purge, []}, + {load_module, snmpa_mpd, soft_purge, soft_purge, []}, + {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_mib, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []} + ] + }, + {"4.21.1", + [ + {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, []}, + {update, snmpa_supervisor, soft, soft_purge, soft_purge, []}, - [ + {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []}, + {load_module, snmpa_vacm, soft_purge, soft_purge, []}, + {load_module, snmpa_mpd, soft_purge, soft_purge, []}, + {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_mib, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []}, + {update, snmp_note_store, soft, soft_purge, soft_purge, []} + ] + }, {"4.21", [ - {load_module, snmp_target_mib, soft_purge, soft_purge, []} + {load_module, snmpa, soft_purge, soft_purge, []}, + {load_module, snmpa_mib_lib, soft_purge, soft_purge, []}, + {update, snmpa_supervisor, soft, soft_purge, soft_purge, []}, + + {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []}, + {load_module, snmpa_vacm, soft_purge, soft_purge, []}, + {load_module, snmpa_mpd, soft_purge, soft_purge, []}, + {load_module, snmpa_set_lib, soft_purge, soft_purge, []}, + {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_mib, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []}, + {update, snmp_note_store, soft, soft_purge, soft_purge, []} ] }, {"4.20.1", [ + {load_module, snmpa, soft_purge, soft_purge, []}, + {load_module, snmpa_mib_lib, soft_purge, soft_purge, []}, + {update, snmpa_supervisor, soft, soft_purge, soft_purge, []}, + + {load_module, snmpa_vacm, soft_purge, soft_purge, []}, + {load_module, snmpa_set_lib, soft_purge, soft_purge, []}, + {load_module, snmpa_trap, soft_purge, soft_purge, []}, {load_module, snmp_target_mib, soft_purge, soft_purge, []}, {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []}, {load_module, snmpm, soft_purge, soft_purge, @@ -133,7 +328,11 @@ {load_module, snmpa_mpd, soft_purge, soft_purge, [snmp_conf, snmp_config]}, {load_module, snmpa_conf, soft_purge, soft_purge, [snmp_config]}, - {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]}, + {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, [snmpm_net_if, snmpm_mpd, snmpm_config]}, @@ -143,6 +342,13 @@ }, {"4.20", [ + {load_module, snmpa, soft_purge, soft_purge, []}, + {load_module, snmpa_mib_lib, soft_purge, soft_purge, []}, + {update, snmpa_supervisor, soft, soft_purge, soft_purge, []}, + + {load_module, snmpa_vacm, soft_purge, soft_purge, []}, + {load_module, snmpa_set_lib, soft_purge, soft_purge, []}, + {load_module, snmpa_trap, soft_purge, soft_purge, []}, {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []}, {load_module, snmp_target_mib, soft_purge, soft_purge, [snmp_conf]}, {load_module, snmpm, soft_purge, soft_purge, @@ -154,54 +360,17 @@ {load_module, snmpa_mpd, soft_purge, soft_purge, [snmp_conf, snmp_config]}, {load_module, snmpa_conf, soft_purge, soft_purge, [snmp_config]}, - {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]}, + {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, [snmpm_net_if, snmpm_mpd, snmpm_config]}, {update, snmpm_net_if, soft, soft_purge, soft_purge, [snmp_conf, snmpm_mpd, snmpm_config]} ] - }, - {"4.19", - [ - {load_module, snmpa, soft_purge, soft_purge, []}, - {load_module, snmpm, soft_purge, soft_purge, - [snmpm_server, snmpm_config, snmp_config]}, - {load_module, snmpa_usm, soft_purge, soft_purge, []}, - {load_module, snmpm_usm, soft_purge, soft_purge, []}, - {load_module, snmp_log, soft_purge, soft_purge, []}, - {load_module, snmp_pdus, soft_purge, soft_purge, []}, - {load_module, snmp_conf, soft_purge, soft_purge, []}, - {load_module, snmpa_conf, soft_purge, soft_purge, - [snmp_conf, snmp_config]}, - {load_module, snmp_misc, soft_purge, soft_purge, []}, - {load_module, snmp_config, soft_purge, soft_purge, []}, - {load_module, snmpa_mpd, soft_purge, soft_purge, - [snmp_conf, snmp_config]}, - {load_module, snmpm_mpd, soft_purge, soft_purge, - [snmp_conf, snmp_config, snmpm_config]}, - {load_module, snmpa_trap, soft_purge, soft_purge, - [snmpa_mpd, snmp_notification_mib, snmp_target_mib, snmpa_net_if]}, - {load_module, snmpa_acm, soft_purge, soft_purge, - [snmp_conf, snmpa_mpd, snmp_target_mib]}, - {load_module, snmpa_conf, soft_purge, soft_purge, - [snmp_config, snmp_notification_mib]}, - {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []}, - {load_module, snmp_notification_mib, soft_purge, soft_purge, - [snmp_conf, snmp_target_mib]}, - {load_module, snmp_community_mib, soft_purge, soft_purge, []}, - {load_module, snmp_target_mib, soft_purge, soft_purge, - [snmp_conf]}, - {update, snmpm_net_if, soft, soft_purge, soft_purge, - [snmp_conf, snmpm_mpd, snmpm_config]}, - {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]}, - {update, snmpa_net_if, soft, soft_purge, soft_purge, - [snmp_conf, snmpa_mpd]}, - {update, snmpa_agent, soft, soft_purge, soft_purge, - [snmpa_acm, snmpa_mpd, snmpa_trap]} - ] } ] }. diff --git a/lib/snmp/src/compile/depend.mk b/lib/snmp/src/compile/depend.mk index f7084f8bcd..3ee8dc4bec 100644 --- a/lib/snmp/src/compile/depend.mk +++ b/lib/snmp/src/compile/depend.mk @@ -44,6 +44,6 @@ $(EBIN)/snmpc_mib_gram.$(EMULATOR): \ ../../include/snmp_types.hrl \ snmpc_mib_gram.erl -$(BIN)/snmpc: snmpc.src +$(BIN)/snmpc: snmpc.src ../../vsn.mk $(PERL) -p -e 's?%VSN%?$(VSN)? ' < $< > $@ chmod 755 $@ diff --git a/lib/snmp/src/compile/snmpc.src b/lib/snmp/src/compile/snmpc.src index f993335b89..9d1af42764 100644 --- a/lib/snmp/src/compile/snmpc.src +++ b/lib/snmp/src/compile/snmpc.src @@ -74,7 +74,7 @@ %% --rrnac %% --version %% --verbosity V -%% --warnings +%% --warnings | --W %% --Werror | --wae | --warnings_as_errors main(Args) when is_list(Args) -> case (catch process_args(Args)) of @@ -221,7 +221,10 @@ process_args([], #state{verbosity = Verbosity0, file = MIB} = State) -> process_args(["--help"|_Args], _State) -> ok; process_args(["--version"|_Args], #state{version = Version, mfv = MFV} = _State) -> - {ok, lists:flatten(io_lib:format("snmpc ~s (~s)", [Version, MFV]))}; + OtpVersion = otp_release(), + {ok, lists:flatten( + io_lib:format("snmpc ~s [Mib format version ~s] (OTP ~s)", + [Version, MFV, OtpVersion]))}; process_args(["--verbosity", Verbosity0|Args], #state{verbosity = V} = State) when (V =:= undefined) -> Verbosity = list_to_atom(Verbosity0), @@ -234,7 +237,7 @@ process_args(["--verbosity", Verbosity0|Args], #state{verbosity = V} = State) process_args(["--verbosity"|_Args], #state{verbosity = V}) when (V =/= undefined) -> e(lists:flatten(io_lib:format("Verbosity already set to ~w", [V]))); -process_args(["--w"|Args], State) -> +process_args(["--W"|Args], State) -> process_args(Args, State#state{warnings = true}); process_args(["--warnings"|Args], State) -> process_args(Args, State#state{warnings = true}); @@ -398,3 +401,16 @@ usage() -> e(Reason) -> throw({error, Reason}). +otp_release() -> + system_info(otp_release, string). + + +system_info(Tag, Type) -> + case (catch erlang:system_info(Tag)) of + {'EXIT', _} -> + "-"; + Info when is_list(Info) andalso (Type =:= string) -> + Info; + Info -> + lists:flatten(io_lib:format("~w", [Info])) + end. diff --git a/lib/snmp/src/misc/snmp_note_store.erl b/lib/snmp/src/misc/snmp_note_store.erl index a21a6209f1..23fccf8a5f 100644 --- a/lib/snmp/src/misc/snmp_note_store.erl +++ b/lib/snmp/src/misc/snmp_note_store.erl @@ -258,10 +258,17 @@ code_change({down, _Vsn}, State, _Extra) -> {ok, NState}; % upgrade -code_change(_Vsn, State, _Extra) -> +code_change(_Vsn, State0, _Extra) -> process_flag(trap_exit, true), - NState = restart_timer(State), - {ok, NState}. + State1 = + case State0 of + #state{timeout = false} -> + State0#state{timeout = ?timeout}; + _ -> + State0 + end, + State2 = restart_timer(State1), + {ok, State2}. %%---------------------------------------------------------- @@ -282,7 +289,7 @@ deactivate_timer(#state{timer = Pid, active = true} = State) -> receive deactivated -> ok end, - State#state{timeout = false}; + State#state{active = false}; deactivate_timer(State) -> State. diff --git a/lib/snmp/test/snmp_agent_test.erl b/lib/snmp/test/snmp_agent_test.erl index 468280db02..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 @@ -92,7 +92,8 @@ all() -> Conf1 ++ Conf2. groups() -> - [{all_tcs, [], cases()}, + [ + {all_tcs, [], cases()}, {mib_storage, [], [ {group, mib_storage_ets}, @@ -221,7 +222,7 @@ groups() -> {group, otp_7157} ] }, - {tickets2, [], [otp8395]}, + {tickets2, [], [otp8395, otp9884]}, {otp_4394, [], [otp_4394_test]}, {otp_7157, [], [otp_7157_test] } @@ -321,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" @@ -348,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" @@ -1320,8 +1329,11 @@ finish_v3(Config) when is_list(Config) -> lists:keydelete(vsn, 1, C1). -mt_cases() -> -[multi_threaded, mt_trap]. +mt_cases() -> + [ + multi_threaded, + mt_trap + ]. init_mt(Config) when is_list(Config) -> SaNode = ?config(snmp_sa, Config), @@ -1498,7 +1510,8 @@ mt_trap(Config) when is_list(Config) -> ?line load_master("TestTrapv2"), try_test(mt_trap_test, [MA]), ?line unload_master("TestTrapv2"), - ?line unload_master("Test1"). + ?line unload_master("Test1"), + ok. v2_types(suite) -> []; v2_types(Config) when is_list(Config) -> @@ -3134,8 +3147,9 @@ mt_trap_test(MA) -> ?DBG("mt_trap_test(01) -> issue testTrapv22 (standard trap)", []), snmpa:send_trap(MA, testTrapv22, "standard trap"), ?DBG("mt_trap_test(02) -> await v2trap", []), - ?line expect(1, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}]), + ?line expect(mt_trap_test_1, v2trap, + [{[sysUpTime, 0], any}, + {[snmpTrapOID, 0], ?system ++ [0,1]}]), ?DBG("mt_trap_test(03) -> issue mtTrap (standard trap)", []), snmpa:send_trap(MA, mtTrap, "standard trap"), @@ -3143,28 +3157,22 @@ mt_trap_test(MA) -> ?DBG("mt_trap_test(04) -> multi pid: ~p. Now request sysUpTime...", [Pid]), g([[sysUpTime,0]]), - %% Previously (before OTP-6784) this was done at 09 below - %% when the test1:multiStr was actually executed by the - %% worker-process, but as of 4.9.4, this is now executed - %% my the master_agent-process... - ?DBG("mt_trap_test(05) -> send continue to multi-pid", []), - Pid ! continue, - ?DBG("mt_trap_test(06) -> await sysUpTime", []), - ?line expect(2, [{[sysUpTime,0], any}]), + ?line expect(mt_trap_test_2, [{[sysUpTime,0], any}]), ?DBG("mt_trap_test(07) -> issue testTrapv22 (standard trap)", []), snmpa:send_trap(MA, testTrapv22, "standard trap"), ?DBG("mt_trap_test(08) -> await v2trap", []), - ?line expect(3, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}]), + ?line expect(mt_trap_test_3, v2trap, + [{[sysUpTime, 0], any}, + {[snmpTrapOID, 0], ?system ++ [0,1]}]), - %% ?DBG("mt_trap_test(09) -> send continue to multi-pid", []), - %% Pid ! continue, + ?DBG("mt_trap_test(09) -> send continue to multi-pid", []), + Pid ! continue, ?DBG("mt_trap_test(10) -> await v2trap", []), - ?line expect(4, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?testTrap ++ [2]}, - {[multiStr,0], "ok"}]), + ?line expect(mt_trap_test_4, v2trap, [{[sysUpTime, 0], any}, + {[snmpTrapOID, 0], ?testTrap ++ [2]}, + {[multiStr,0], "ok"}]), ?DBG("mt_trap_test(11) -> done", []), ok. @@ -3563,53 +3571,82 @@ do_mul_set_err() -> %% Req. SA-MIB sa_mib() -> g([[sa, [2,0]]]), - ?line expect(1, [{[sa, [2,0]], 3}]), + ?line expect(sa_mib_1, [{[sa, [2,0]], 3}]), s([{[sa, [1,0]], s, "sa_test"}]), - ?line expect(2, [{[sa, [1,0]], "sa_test"}]). + ?line expect(sa_mib_2, [{[sa, [1,0]], "sa_test"}]), + ok. ma_trap1(MA) -> ok = snmpa:send_trap(MA, testTrap2, "standard trap"), - ?line expect(1, trap, [system], 6, 1, [{[system, [4,0]], - "{mbj,eklas}@erlang.ericsson.se"}]), + ?line expect(ma_trap1_1, + trap, [system], 6, 1, [{[system, [4,0]], + "{mbj,eklas}@erlang.ericsson.se"}]), ok = snmpa:send_trap(MA, testTrap1, "standard trap"), - ?line expect(2, trap, [1,2,3] , 1, 0, [{[system, [4,0]], - "{mbj,eklas}@erlang.ericsson.se"}]). + ?line expect(ma_trap1_2, + trap, [1,2,3] , 1, 0, [{[system, [4,0]], + "{mbj,eklas}@erlang.ericsson.se"}]), + ok. ma_trap2(MA) -> snmpa:send_trap(MA,testTrap2,"standard trap",[{sysContact,"pelle"}]), - ?line expect(3, trap, [system], 6, 1, [{[system, [4,0]], "pelle"}]). + ?line expect(ma_trap2_3, + trap, [system], 6, 1, [{[system, [4,0]], "pelle"}]), + ok. ma_v2_2_v1_trap(MA) -> snmpa:send_trap(MA,testTrapv22,"standard trap",[{sysContact,"pelle"}]), - ?line expect(3, trap, [system], 6, 1, [{[system, [4,0]], "pelle"}]). + ?line expect(ma_v2_2_v1_trap_3, + trap, [system], 6, 1, [{[system, [4,0]], "pelle"}]), + ok. ma_v2_2_v1_trap2(MA) -> snmpa:send_trap(MA,linkUp,"standard trap",[{ifIndex, [1], 1}, {ifAdminStatus, [1], 1}, {ifOperStatus, [1], 2}]), - ?line expect(3, trap, [1,2,3], 3, 0, [{[ifIndex, 1], 1}, - {[ifAdminStatus, 1], 1}, - {[ifOperStatus, 1], 2}]). + ?line expect(ma_v2_2_v1_trap2_3, + trap, [1,2,3], 3, 0, [{[ifIndex, 1], 1}, + {[ifAdminStatus, 1], 1}, + {[ifOperStatus, 1], 2}]), + ok. sa_trap1(SA) -> - snmpa:send_trap(SA, saTrap, "standard trap"), - ?line expect(4, trap, [ericsson], 6, 1, [{[system, [4,0]], - "{mbj,eklas}@erlang.ericsson.se"}, - {[sa, [1,0]], "sa_test"}]). + %% io:format("sa_trap1 -> entry with" + %% "~n SA: ~p" + %% "~n node(SA): ~p" + %% "~n self(): ~p" + %% "~n node(): ~p" + %% "~n", [SA, node(SA), self(), node()]), + _VRes = (catch snmpa:verbosity(SA, {subagents, trace})), + %% io:format("sa_trap1 -> SA verbosity set: " + %% "~n VRes: ~p" + %% "~n", [VRes]), + _TSRes = (catch snmpa:send_trap(SA, saTrap, "standard trap")), + %% io:format("sa_trap1 -> SA trap send: " + %% "~n TSRes: ~p" + %% "~n", [TSRes]), + ?line expect(sa_trap1_4, + trap, [ericsson], 6, 1, [{[system, [4,0]], + "{mbj,eklas}@erlang.ericsson.se"}, + {[sa, [1,0]], "sa_test"}]), + snmpa:verbosity(SA, {subagents, silence}), + ok. sa_trap2(SA) -> snmpa:send_trap(SA, saTrap, "standard trap",[{sysContact,"pelle"}]), - ?line expect(5, trap, [ericsson], 6, 1, [{[system, [4,0]], - "pelle"}, - {[sa, [1,0]], "sa_test"}]). + ?line expect(sa_trap2_5, + trap, [ericsson], 6, 1, [{[system, [4,0]], "pelle"}, + {[sa, [1,0]], "sa_test"}]), + ok. sa_trap3(SA) -> snmpa:send_trap(SA, saTrap2, "standard trap", [{intViewSubtree, [4], [1,2,3,4]}]), - ?line expect(6, trap, [ericsson], 6, 2, [{[system, [4,0]], - "{mbj,eklas}@erlang.ericsson.se"}, - {[sa, [1,0]], "sa_test"}, - {[intViewSubtree,4],[1,2,3,4]}]). + ?line expect(sa_trap3_6, + trap, [ericsson], 6, 2, [{[system, [4,0]], + "{mbj,eklas}@erlang.ericsson.se"}, + {[sa, [1,0]], "sa_test"}, + {[intViewSubtree,4],[1,2,3,4]}]), + ok. ma_v2_trap1(MA) -> ?DBG("ma_v2_traps -> entry with MA = ~p => " @@ -4029,33 +4066,42 @@ ma_v1_2_v2_trap2(MA) -> sa_v1_2_v2_trap1(SA) -> + snmpa:verbosity(SA, {subagents, trace}), snmpa:send_trap(SA, saTrap, "standard trap"), - ?line expect(4, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?ericsson ++ [0, 1]}, - {[system, [4,0]], - "{mbj,eklas}@erlang.ericsson.se"}, - {[sa, [1,0]], "sa_test"}, - {[snmpTrapEnterprise, 0], ?ericsson}]). + ?line expect(trap1_4, v2trap, [{[sysUpTime, 0], any}, + {[snmpTrapOID, 0], ?ericsson ++ [0, 1]}, + {[system, [4,0]], + "{mbj,eklas}@erlang.ericsson.se"}, + {[sa, [1,0]], "sa_test"}, + {[snmpTrapEnterprise, 0], ?ericsson}]), + snmpa:verbosity(SA, {subagents, silence}), + ok. sa_v1_2_v2_trap2(SA) -> + snmpa:verbosity(SA, {subagents, trace}), snmpa:send_trap(SA, saTrap, "standard trap",[{sysContact,"pelle"}]), - ?line expect(4, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?ericsson ++ [0, 1]}, - {[system, [4,0]], "pelle"}, - {[sa, [1,0]], "sa_test"}, - {[snmpTrapEnterprise, 0], ?ericsson}]). - + ?line expect(trap2_4, v2trap, [{[sysUpTime, 0], any}, + {[snmpTrapOID, 0], ?ericsson ++ [0, 1]}, + {[system, [4,0]], "pelle"}, + {[sa, [1,0]], "sa_test"}, + {[snmpTrapEnterprise, 0], ?ericsson}]), + snmpa:verbosity(SA, {subagents, silence}), + ok. + sa_v1_2_v2_trap3(SA) -> + snmpa:verbosity(SA, {subagents, trace}), snmpa:send_trap(SA, saTrap2, "standard trap", [{intViewSubtree, [4], [1,2,3,4]}]), - ?line expect(4, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?ericsson ++ [0, 2]}, - {[system, [4,0]], - "{mbj,eklas}@erlang.ericsson.se"}, - {[sa, [1,0]], "sa_test"}, - {[intViewSubtree,4],[1,2,3,4]}, - {[snmpTrapEnterprise, 0], ?ericsson}]). + ?line expect(trap3_4, v2trap, [{[sysUpTime, 0], any}, + {[snmpTrapOID, 0], ?ericsson ++ [0, 2]}, + {[system, [4,0]], + "{mbj,eklas}@erlang.ericsson.se"}, + {[sa, [1,0]], "sa_test"}, + {[intViewSubtree,4],[1,2,3,4]}, + {[snmpTrapEnterprise, 0], ?ericsson}]), + snmpa:verbosity(SA, {subagents, silence}), + ok. %% Req. SA-MIB, OLD-SNMPEA-MIB @@ -4195,9 +4241,9 @@ snmp_standard_mib(Config) when is_list(Config) -> %% Req. SNMP-STANDARD-MIB standard_mib_a() -> - ?line [OutPkts] = get_req(2, [[snmpOutPkts,0]]), + ?line [OutPkts] = get_req(2, [[snmpOutPkts,0]]), ?line [OutPkts2] = get_req(3, [[snmpOutPkts,0]]), - ?line OutPkts2 = OutPkts + 1, + ?line OutPkts2 = OutPkts + 1, %% There are some more counters we could test here, but it's not that %% important, since they are removed from SNMPv2-MIB. ok. @@ -4207,27 +4253,27 @@ std_mib_init() -> %% disable authentication failure traps. (otherwise w'd get many of %% them - this is also a test to see that it works). s([{[snmpEnableAuthenTraps,0], 2}]), - ?line expect(1, [{[snmpEnableAuthenTraps, 0], 2}]). + ?line expect(std_mib_init_1, [{[snmpEnableAuthenTraps, 0], 2}]). %% Req. SNMP-STANDARD-MIB | SNMPv2-MIB std_mib_finish() -> %% enable again s([{[snmpEnableAuthenTraps,0], 1}]), - ?line expect(1, [{[snmpEnableAuthenTraps, 0], 1}]). + ?line expect(std_mib_finish_1, [{[snmpEnableAuthenTraps, 0], 1}]). %% Req. SNMP-STANDARD-MIB standard_mib_test_finish() -> - %% force a authenticationFailure + %% force a authenticationFailure (should result in a trap) std_mib_write(), %% check that we got a trap - ?line expect(2, trap, [1,2,3], 4, 0, []). + ?line expect(standard_mib_test_finish_2, trap, [1,2,3], 4, 0, []). %% Req. SNMP-STANDARD-MIB | SNMPv2-MIB std_mib_read() -> ?DBG("std_mib_read -> entry", []), g([[sysUpTime,0]]), % try a bad <something>; msg dropped, no reply ?DBG("std_mib_read -> await timeout (i.e. no reply)", []), - ?line expect(1, timeout). % make sure we don't get a trap! + ?line expect(std_mib_read_1, timeout). % make sure we don't get a trap! %% Req. SNMP-STANDARD-MIB | SNMPv2-MIB @@ -4362,10 +4408,10 @@ std_mib_c({InBadCommunityNames, InBadCommunityUses, InASNErrs}) -> snmpv2_mib_a() -> ?line [SetSerial] = get_req(2, [[snmpSetSerialNo,0]]), s([{[snmpSetSerialNo,0], SetSerial}, {[sysLocation, 0], "val2"}]), - ?line expect(3, [{[snmpSetSerialNo,0], SetSerial}, - {[sysLocation, 0], "val2"}]), + ?line expect(snmpv2_mib_a_3, [{[snmpSetSerialNo,0], SetSerial}, + {[sysLocation, 0], "val2"}]), s([{[sysLocation, 0], "val3"}, {[snmpSetSerialNo,0], SetSerial}]), - ?line expect(4, inconsistentValue, 2, + ?line expect(snmpv2_mib_a_4, inconsistentValue, 2, [{[sysLocation, 0], "val3"}, {[snmpSetSerialNo,0], SetSerial}]), ?line ["val2"] = get_req(5, [[sysLocation,0]]). @@ -4688,46 +4734,46 @@ snmp_view_based_acm_mib() -> do_set(Row) -> s(Row), - expect(1, Row). + expect(do_set_1, Row). add_row(RowStatus) -> s([{RowStatus, ?createAndGo}]), - expect(1, [{RowStatus, ?createAndGo}]). + expect(add_row_1, [{RowStatus, ?createAndGo}]). del_row(RowStatus) -> s([{RowStatus, ?destroy}]), - expect(1, [{RowStatus, ?destroy}]). + expect(del_row_1, [{RowStatus, ?destroy}]). use_no_rights() -> g([[xDescr,0]]), - ?v1_2_3(expect(11, noSuchName, 1, any), - expect(12, [{[xDescr,0], noSuchObject}]), - expect(13, authorizationError, 1, any)), + ?v1_2_3(expect(use_no_rights_11, noSuchName, 1, any), + expect(use_no_rights_12, [{[xDescr,0], noSuchObject}]), + expect(use_no_rights_13, authorizationError, 1, any)), g([[xDescr2,0]]), - ?v1_2_3(expect(21, noSuchName, 1, any), - expect(22, [{[xDescr2,0], noSuchObject}]), - expect(23, authorizationError, 1, any)), + ?v1_2_3(expect(use_no_rights_21, noSuchName, 1, any), + expect(use_no_rights_22, [{[xDescr2,0], noSuchObject}]), + expect(use_no_rights_23, authorizationError, 1, any)), gn([[xDescr]]), - ?v1_2_3(expect(31, noSuchName, 1, any), - expect(32, [{[xDescr], endOfMibView}]), - expect(33, authorizationError, 1, any)), + ?v1_2_3(expect(use_no_rights_31, noSuchName, 1, any), + expect(use_no_rights_32, [{[xDescr], endOfMibView}]), + expect(use_no_rights_33, authorizationError, 1, any)), s([{[xDescr,0], "tryit"}]), - ?v1_2_3(expect(41, noSuchName, 1, any), - expect(42, noAccess, 1, any), - expect(43, authorizationError, 1, any)). + ?v1_2_3(expect(use_no_rights_41, noSuchName, 1, any), + expect(use_no_rights_42, noAccess, 1, any), + expect(use_no_rights_43, authorizationError, 1, any)). use_rights() -> g([[xDescr,0]]), - expect(1, [{[xDescr,0], any}]), + expect(use_rights_1, [{[xDescr,0], any}]), g([[xDescr2,0]]), - expect(2, [{[xDescr2,0], any}]), + expect(use_rights_2, [{[xDescr2,0], any}]), s([{[xDescr,0], "tryit"}]), - expect(3, noError, 0, any), + expect(use_rights_3, noError, 0, any), g([[xDescr,0]]), - expect(4, [{[xDescr,0], "tryit"}]). + expect(use_rights_4, [{[xDescr,0], "tryit"}]). mk_ln(X) -> [length(X) | X]. @@ -5200,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. @@ -5850,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 %% @@ -5858,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 %% @@ -5866,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]), @@ -5894,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), @@ -5923,7 +5959,7 @@ otp8395({init, Config}) when is_list(Config) -> {manager_node, ManagerNode}, {manager_host, ManagerHost}, {manager_ip, ManagerIP}|Config]), - + %% -- %% Create watchdog %% @@ -5935,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), @@ -5943,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 %% @@ -5963,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), %% - @@ -5984,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 @@ -6002,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 = @@ -6013,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/test/snmp_agent_test_lib.erl b/lib/snmp/test/snmp_agent_test_lib.erl index a18d9f3201..084b3ee8da 100644 --- a/lib/snmp/test/snmp_agent_test_lib.erl +++ b/lib/snmp/test/snmp_agent_test_lib.erl @@ -296,7 +296,12 @@ call(N,M,F,A) -> ?DBG("call -> done:" "~n Ret: ~p" "~n Zed: ~p", [Ret, Zed]), - Ret + case Ret of + {error, Reason} -> + exit(Reason); + OK -> + OK + end end. wait(From, Env, M, F, A) -> @@ -724,17 +729,13 @@ expect(Id, A, B, C, D, E) -> expect2(Id, Fun). expect2(Id, F) -> - io:format("~w:expect2 -> entry with" - "~n Id: ~w" - "~n", [?MODULE, Id]), + io:format("EXPECT for ~w~n", [Id]), case F() of {error, Reason} -> - {error, Id, Reason}; + io:format("EXPECT failed for ~w: ~n~p~n", [Id, Reason]), + throw({error, {expect, Id, Reason}}); Else -> - io:format("~w:expect2 -> " - "~n Id: ~w" - "~n Else: ~p" - "~n", [?MODULE, Id, Else]), + io:format("EXPECT result for ~w: ~n~p~n", [Id, Else]), Else end. @@ -769,21 +770,15 @@ do_expect(Expect) when is_atom(Expect) -> do_expect({any_pdu, To}) when is_integer(To) orelse (To =:= infinity) -> - io:format("~w:do_expect(any_pdu) -> entry with" - "~n To: ~w" - "~n", [?MODULE, To]), + io:format("EXPECT any PDU~n", []), receive_pdu(To); do_expect({any_trap, To}) -> - io:format("~w:do_expect(any_trap) -> entry with" - "~n To: ~w" - "~n", [?MODULE, To]), + io:format("EXPECT any TRAP within ~w~n", [To]), receive_trap(To); do_expect({timeout, To}) -> - io:format("~w:do_expect(timeout) -> entry with" - "~n To: ~w" - "~n", [?MODULE, To]), + io:format("EXPECT nothing within ~w~n", [To]), receive X -> {error, {unexpected, X}} @@ -794,13 +789,16 @@ do_expect({timeout, To}) -> do_expect({Err, To}) when is_atom(Err) andalso (is_integer(To) orelse (To =:= infinity)) -> + io:format("EXPECT error ~w within ~w~n", [Err, To]), do_expect({{error, Err}, To}); do_expect({error, Err}) when is_atom(Err) -> Check = fun(_, R) -> R end, + io:format("EXPECT error ~w~n", [Err]), do_expect2(Check, any, Err, any, any, get_timeout()); do_expect({{error, Err}, To}) -> Check = fun(_, R) -> R end, + io:format("EXPECT error ~w within ~w~n", [Err, To]), do_expect2(Check, any, Err, any, any, To); %% exp_varbinds() -> [exp_varbind()] @@ -810,16 +808,25 @@ do_expect({{error, Err}, To}) -> %% ExpVBs -> exp_varbinds() | {VbsCondition, exp_varbinds()} do_expect(ExpVBs) -> Check = fun(_, R) -> R end, + io:format("EXPECT 'get-response'" + "~n with" + "~n Varbinds: ~p~n", [ExpVBs]), do_expect2(Check, 'get-response', noError, 0, ExpVBs, get_timeout()). do_expect(v2trap, ExpVBs) -> Check = fun(_, R) -> R end, + io:format("EXPECT 'snmpv2-trap'" + "~n with" + "~n Varbinds: ~p~n", [ExpVBs]), do_expect2(Check, 'snmpv2-trap', noError, 0, ExpVBs, get_timeout()); do_expect(report, ExpVBs) -> Check = fun(_, R) -> R end, + io:format("EXPECT 'report'" + "~n with" + "~n Varbinds: ~p~n", [ExpVBs]), do_expect2(Check, 'report', noError, 0, ExpVBs, get_timeout()); @@ -827,16 +834,13 @@ do_expect(inform, ExpVBs) -> do_expect({inform, true}, ExpVBs); do_expect({inform, false}, ExpVBs) -> - io:format("~w:do_expect(inform, false) -> entry with" - "~n ExpVBs: ~p" - "~n", [?MODULE, ExpVBs]), Check = fun(_, R) -> R end, + io:format("EXPECT 'inform-request' (false)" + "~n with" + "~n Varbinds: ~p~n", [ExpVBs]), do_expect2(Check, 'inform-request', noError, 0, ExpVBs, get_timeout()); do_expect({inform, true}, ExpVBs) -> - io:format("~w:do_expect(inform, true) -> entry with" - "~n ExpVBs: ~p" - "~n", [?MODULE, ExpVBs]), Check = fun(PDU, ok) -> RespPDU = PDU#pdu{type = 'get-response', @@ -847,6 +851,9 @@ do_expect({inform, true}, ExpVBs) -> (_, Err) -> Err end, + io:format("EXPECT 'inform-request' (true)" + "~n with" + "~n Varbinds: ~p~n", [ExpVBs]), do_expect2(Check, 'inform-request', noError, 0, ExpVBs, get_timeout()); do_expect({inform, {error, EStat, EIdx}}, ExpVBs) @@ -861,6 +868,11 @@ do_expect({inform, {error, EStat, EIdx}}, ExpVBs) (_, Err) -> Err end, + io:format("EXPECT 'inform-request' (error)" + "~n with" + "~n Error Status: ~p" + "~n Error Index: ~p" + "~n Varbinds: ~p~n", [EStat, EIdx, ExpVBs]), do_expect2(Check, 'inform-request', noError, 0, ExpVBs, get_timeout()). @@ -871,6 +883,12 @@ do_expect(Err, Idx, ExpVBs, To) when is_atom(Err) andalso (is_integer(Idx) orelse is_list(Idx) orelse (Idx == any)) -> Check = fun(_, R) -> R end, + io:format("EXPECT 'get-response'" + "~n with" + "~n Error: ~p" + "~n Index: ~p" + "~n Varbinds: ~p" + "~n within ~w~n", [Err, Idx, ExpVBs, To]), do_expect2(Check, 'get-response', Err, Idx, ExpVBs, To). @@ -878,15 +896,13 @@ do_expect(Type, Enterp, Generic, Specific, ExpVBs) -> do_expect(Type, Enterp, Generic, Specific, ExpVBs, 3500). do_expect(trap, Enterp, Generic, Specific, ExpVBs, To) -> - io:format("~w:do_expect(trap) -> entry with" - "~n Enterp: ~w" - "~n Generic: ~w" - "~n Specific: ~w" - "~n ExpVBs: ~w" - "~n To: ~w" - "~nwhen" - "~n Time: ~w" - "~n", [?MODULE, Enterp, Generic, Specific, ExpVBs, To, t()]), + io:format("EXPECT trap" + "~n with" + "~n Enterp: ~w" + "~n Generic: ~w" + "~n Specific: ~w" + "~n Varbinds: ~w" + "~n within ~w~n", [Enterp, Generic, Specific, ExpVBs, To]), PureE = purify_oid(Enterp), case receive_trap(To) of #trappdu{enterprise = PureE, @@ -916,49 +932,51 @@ do_expect2(Check, Type, Err, Idx, ExpVBs, To) (is_list(ExpVBs) orelse (ExpVBs =:= any)) andalso (is_integer(To) orelse (To =:= infinity)) -> - io:format("~w:do_expect2 -> entry with" - "~n Type: ~w" - "~n Err: ~w" - "~n Idx: ~w" - "~n ExpVBs: ~w" - "~n To: ~w" - "~nwhen" - "~n Time: ~w" - "~n", [?MODULE, Type, Err, Idx, ExpVBs, To, t()]), - case receive_pdu(To) of #pdu{type = Type, error_status = Err, error_index = Idx} when ExpVBs =:= any -> + io:format("EXPECT received expected pdu (1)~n", []), ok; #pdu{type = Type, request_id = ReqId, error_status = Err2, error_index = Idx} when ExpVBs =:= any -> + io:format("EXPECT received expected pdu with " + "unexpected error status (2): " + "~n Error Status: ~p~n", [Err2]), {error, {unexpected_error_status, Err, Err2, ReqId}}; #pdu{error_status = Err} when (Type =:= any) andalso (Idx =:= any) andalso (ExpVBs =:= any) -> + io:format("EXPECT received expected pdu (3)~n", []), ok; #pdu{request_id = ReqId, error_status = Err2} when (Type =:= any) andalso (Idx =:= any) andalso (ExpVBs =:= any) -> + io:format("EXPECT received expected pdu with " + "unexpected error status (4): " + "~n Error Status: ~p~n", [Err2]), {error, {unexpected_error_status, Err, Err2, ReqId}}; #pdu{type = Type, error_status = Err} when (Idx =:= any) andalso (ExpVBs =:= any) -> + io:format("EXPECT received expected pdu (5)~n", []), ok; #pdu{type = Type, request_id = ReqId, error_status = Err2} when (Idx =:= any) andalso (ExpVBs =:= any) -> + io:format("EXPECT received expected pdu with " + "unexpected error status (6): " + "~n Error Status: ~p~n", [Err2]), {error, {unexpected_error_status, Err, Err2, ReqId}}; #pdu{type = Type, @@ -967,8 +985,13 @@ do_expect2(Check, Type, Err, Idx, ExpVBs, To) error_index = EI} when is_list(Idx) andalso (ExpVBs =:= any) -> case lists:member(EI, Idx) of true -> + io:format("EXPECT received expected pdu with " + "expected error index (7)~n", []), ok; false -> + io:format("EXPECT received expected pdu with " + "unexpected error index (8): " + "~n Error Index: ~p~n", [EI]), {error, {unexpected_error_index, EI, Idx, ReqId}} end; @@ -978,8 +1001,15 @@ do_expect2(Check, Type, Err, Idx, ExpVBs, To) error_index = EI} when is_list(Idx) andalso (ExpVBs =:= any) -> case lists:member(EI, Idx) of true -> + io:format("EXPECT received expected pdu with " + "unexpected error status (9): " + "~n Error Status: ~p~n", [Err2]), {error, {unexpected_error_status, Err, Err2, ReqId}}; false -> + io:format("EXPECT received expected pdu with " + "unexpected error (10): " + "~n Error Status: ~p" + "~n Error index: ~p~n", [Err2, EI]), {error, {unexpected_error, {Err, Idx}, {Err2, EI}, ReqId}} end; @@ -987,6 +1017,12 @@ do_expect2(Check, Type, Err, Idx, ExpVBs, To) request_id = ReqId, error_status = Err2, error_index = Idx2} when ExpVBs =:= any -> + io:format("EXPECT received unexpected pdu with (11) " + "~n Type: ~p" + "~n ReqId: ~p" + "~n Errot status: ~p" + "~n Error index: ~p" + "~n", [Type2, ReqId, Err2, Idx2]), {error, {unexpected_pdu, {Type, Err, Idx}, {Type2, Err2, Idx2}, ReqId}}; @@ -995,11 +1031,26 @@ do_expect2(Check, Type, Err, Idx, ExpVBs, To) error_status = Err, error_index = Idx, varbinds = VBs} = PDU -> + io:format("EXPECT received pdu (12): " + "~n [exp] Type: ~p" + "~n [exp] Error Status: ~p" + "~n [exp] Error Index: ~p" + "~n VBs: ~p" + "~nwhen" + "~n ExpVBs: ~p" + "~n", [Type, Err, Idx, VBs, ExpVBs]), Check(PDU, check_vbs(purify_oids(ExpVBs), VBs)); #pdu{type = Type, error_status = Err, varbinds = VBs} = PDU when Idx =:= any -> + io:format("EXPECT received pdu (13): " + "~n [exp] Type: ~p" + "~n [exp] Error Status: ~p" + "~n VBs: ~p" + "~nwhen" + "~n ExpVBs: ~p" + "~n", [Type, Err, VBs, ExpVBs]), Check(PDU, check_vbs(purify_oids(ExpVBs), VBs)); #pdu{type = Type, @@ -1007,6 +1058,15 @@ do_expect2(Check, Type, Err, Idx, ExpVBs, To) error_status = Err, error_index = EI, varbinds = VBs} = PDU when is_list(Idx) -> + io:format("EXPECT received pdu (14): " + "~n [exp] Type: ~p" + "~n ReqId: ~p" + "~n [exp] Error Status: ~p" + "~n [exp] Error Index: ~p" + "~n VBs: ~p" + "~nwhen" + "~n ExpVBs: ~p" + "~n", [Type, ReqId, Err, EI, VBs, ExpVBs]), PureVBs = purify_oids(ExpVBs), case lists:member(EI, Idx) of true -> @@ -1020,6 +1080,13 @@ do_expect2(Check, Type, Err, Idx, ExpVBs, To) error_status = Err2, error_index = Idx2, varbinds = VBs2} -> + io:format("EXPECT received unexpected pdu with (15) " + "~n Type: ~p" + "~n ReqId: ~p" + "~n Errot status: ~p" + "~n Error index: ~p" + "~n Varbinds: ~p" + "~n", [Type2, ReqId, Err2, Idx2, VBs2]), {error, {unexpected_pdu, {Type, Err, Idx, purify_oids(ExpVBs)}, @@ -1027,6 +1094,9 @@ do_expect2(Check, Type, Err, Idx, ExpVBs, To) ReqId}}; Error -> + io:format("EXPECT received error (16): " + "~n Error: ~p" + "~n", [Error]), Error end. @@ -1466,7 +1536,7 @@ rpc(Node, F, A) -> %% %% %% t() -> -%% {A,B,C} = erlang:now(), +%% {A,B,C} = os:timestamp(), %% A*1000000000+B*1000+(C div 1000). %% %% @@ -1478,6 +1548,6 @@ rpc(Node, F, A) -> %% Time in milli seconds -t() -> - {A,B,C} = erlang:now(), - A*1000000000+B*1000+(C div 1000). +%% t() -> +%% {A,B,C} = os:timestamp(), +%% A*1000000000+B*1000+(C div 1000). diff --git a/lib/snmp/test/snmp_compiler_test.erl b/lib/snmp/test/snmp_compiler_test.erl index c964b08168..0a147130b0 100644 --- a/lib/snmp/test/snmp_compiler_test.erl +++ b/lib/snmp/test/snmp_compiler_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 @@ -566,14 +566,7 @@ p(F, A) -> p(TName, F, A) -> io:format("*** [~w][~s] ***" - "~n" ++ F ++ "~n", [TName,format_timestamp(now())|A]). - -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). + "~n" ++ F ++ "~n", [TName, formated_timestamp()|A]). +formated_timestamp() -> + snmp_test_lib:formated_timestamp(). diff --git a/lib/snmp/test/snmp_manager_config_test.erl b/lib/snmp/test/snmp_manager_config_test.erl index 4498d506f3..3192fe1b40 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-2011. All Rights Reserved. +%% Copyright Ericsson AB 2004-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 @@ -2726,14 +2726,7 @@ p(F, A) -> p(TName, F, A) -> io:format("*** [~s] ***" - " ~w -> " ++ F ++ "~n", [format_timestamp(now()),TName|A]). - -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). + " ~w -> " ++ F ++ "~n", [formated_timestamp(),TName|A]). +formated_timestamp() -> + snmp_test_lib:formated_timestamp(). diff --git a/lib/snmp/test/snmp_manager_test.erl b/lib/snmp/test/snmp_manager_test.erl index d18f20d359..75c9f7b277 100644 --- a/lib/snmp/test/snmp_manager_test.erl +++ b/lib/snmp/test/snmp_manager_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 @@ -6064,7 +6064,7 @@ rcall(Node, Mod, Func, Args) -> %% Time in milli sec %% t() -> -%% {A,B,C} = erlang:now(), +%% {A,B,C} = os:timestamp(), %% A*1000000000+B*1000+(C div 1000). @@ -6078,16 +6078,10 @@ p(F, A) -> p(TName, F, A) -> io:format("*** [~w][~s] ***" - "~n" ++ F ++ "~n", [TName,format_timestamp(now())|A]). - -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). + "~n" ++ F ++ "~n", [TName, formated_timestamp()|A]). + +formated_timestamp() -> + snmp_test_lib:formated_timestamp(). %% p(TName, F, A) -> %% io:format("~w -> " ++ F ++ "~n", [TName|A]). diff --git a/lib/snmp/test/snmp_test_lib.erl b/lib/snmp/test/snmp_test_lib.erl index 54839d989b..e4d58a1253 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-2010. All Rights Reserved. +%% Copyright Ericsson AB 2002-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 @@ -37,7 +37,7 @@ -export([watchdog/3, watchdog_start/1, watchdog_start/2, watchdog_stop/1]). -export([del_dir/1]). -export([cover/1]). --export([p/2, print/5]). +-export([p/2, print/5, formated_timestamp/0]). %% ---------------------------------------------------------------------- @@ -521,15 +521,18 @@ p(F, A) when is_list(F) andalso is_list(A) -> print(Prefix, Module, Line, Format, Args) -> io:format("*** [~s] ~s ~p ~p ~p:~p *** " ++ Format ++ "~n", - [format_timestamp(now()), + [formated_timestamp(), Prefix, node(), self(), Module, Line|Args]). +formated_timestamp() -> + format_timestamp(os:timestamp()). + 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", + io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w ~w", [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]), lists:flatten(FormatDate). diff --git a/lib/snmp/test/snmp_test_mgr.erl b/lib/snmp/test/snmp_test_mgr.erl index 84bdc6b04f..499cf7abcf 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-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 @@ -1124,16 +1124,11 @@ d(F,A) -> d(get(debug),F,A). d(true,F,A) -> io:format("*** [~s] MGR_DBG *** " ++ F ++ "~n", - [format_timestamp(now())|A]); + [formated_timestamp()|A]); d(_,_F,_A) -> ok. -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). + +formated_timestamp() -> + snmp_test_lib:formated_timestamp(). diff --git a/lib/snmp/test/snmp_test_mgr_misc.erl b/lib/snmp/test/snmp_test_mgr_misc.erl index fc6dedd96d..5525c5c3ec 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-2011. 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 @@ -779,16 +779,9 @@ d(F,A) -> d(get(debug),F,A). d(true,F,A) -> io:format("*** [~s] MGR_PS_DBG *** " ++ F ++ "~n", - [format_timestamp(now())|A]); + [formated_timestamp()|A]); d(_,_F,_A) -> ok. -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). - +formated_timestamp() -> + snmp_test_lib:formated_timestamp(). diff --git a/lib/snmp/vsn.mk b/lib/snmp/vsn.mk index c95e0a22d1..fb1dcb6c41 100644 --- a/lib/snmp/vsn.mk +++ b/lib/snmp/vsn.mk @@ -2,7 +2,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 @@ -17,6 +17,7 @@ # # %CopyrightEnd% -SNMP_VSN = 4.21.1 -PRE_VSN = -APP_VSN = "snmp-$(SNMP_VSN)$(PRE_VSN)" +APPLICATION = snmp +SNMP_VSN = 4.21.7 +PRE_VSN = +APP_VSN = "$(APPLICATION)-$(SNMP_VSN)$(PRE_VSN)" |