diff options
Diffstat (limited to 'lib')
46 files changed, 2074 insertions, 727 deletions
diff --git a/lib/compiler/test/compilation_SUITE.erl b/lib/compiler/test/compilation_SUITE.erl index 8e7b7292cc..d517029b1b 100644 --- a/lib/compiler/test/compilation_SUITE.erl +++ b/lib/compiler/test/compilation_SUITE.erl @@ -50,7 +50,7 @@ groups() -> trycatch_4,opt_crash,otp_5404,otp_5436,otp_5481, otp_5553,otp_5632,otp_5714,otp_5872,otp_6121, otp_6121a,otp_6121b,otp_7202,otp_7345,on_load, - string_table,otp_8949_a,otp_8949_a,split_cases, + string_table,otp_8949_a,otp_8949_b,split_cases, beam_utils_liveopt]}]. init_per_suite(Config) -> @@ -630,13 +630,13 @@ string_table(Config) when is_list(Config) -> ok. otp_8949_a(Config) when is_list(Config) -> - value = otp_8949_a(), + value = do_otp_8949_a(), ok. -record(cs, {exs,keys = [],flags = 1}). -record(exs, {children = []}). -otp_8949_a() -> +do_otp_8949_a() -> case id([#cs{}]) of [#cs{}=Cs] -> SomeVar = id(value), diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml index fd62f778a2..bc4c68230e 100644 --- a/lib/kernel/doc/src/inet.xml +++ b/lib/kernel/doc/src/inet.xml @@ -430,8 +430,56 @@ fe80::204:acff:fe17:bf38 <name name="peername" arity="1"/> <fsummary>Return the address and port for the other end of a connection</fsummary> <desc> - <p>Returns the address and port for the other end of a - connection.</p> + <p> + Returns the address and port for the other end of a + connection. + </p> + <p> + Note that for SCTP sockets this function only returns + one of the socket's peer addresses. The function + <seealso marker="#peernames/1">peernames/1,2</seealso> + returns all. + </p> + </desc> + </func> + <func> + <name name="peernames" arity="1"/> + <fsummary> + Return all address/port numbers for the other end of a connection + </fsummary> + <desc> + <p> + Equivalent to + <seealso marker="#peernames/2"><c>peernames(<anno>Socket</anno>, 0)</c></seealso>. + Note that this function's behaviour for an SCTP + one-to-many style socket is not defined by the + <url href="http://tools.ietf.org/html/draft-ietf-tsvwg-sctpsocket-13">SCTP Sockets API Extensions</url>. + </p> + </desc> + </func> + <func> + <name name="peernames" arity="2"/> + <fsummary> + Return all address/port numbers for the other end of a connection + </fsummary> + <desc> + <p> + Returns a list of all address/port number pairs for the other end + of a socket's association <c><anno>Assoc</anno></c>. + </p> + <p> + This function can return multiple addresses for multihomed + sockets such as SCTP sockets. For other sockets it + returns a one element list. + </p> + <p> + Note that the <c><anno>Assoc</anno></c> parameter is by the + <url href="http://tools.ietf.org/html/draft-ietf-tsvwg-sctpsocket-13">SCTP Sockets API Extensions</url> + defined to be ignored for + one-to-one style sockets. What the special value <c>0</c> + means hence its behaviour for one-to-many style sockets + is unfortunately not defined. + </p> </desc> </func> <func> @@ -446,6 +494,46 @@ fe80::204:acff:fe17:bf38 <fsummary>Return the local address and port number for a socket</fsummary> <desc> <p>Returns the local address and port number for a socket.</p> + <p> + Note that for SCTP sockets this function only returns + one of the socket addresses. The function + <seealso marker="#socknames/1">socknames/1,2</seealso> + returns all. + </p> + </desc> + </func> + <func> + <name name="socknames" arity="1"/> + <fsummary>Return all local address/port numbers for a socket</fsummary> + <desc> + <p> + Equivalent to + <seealso marker="#socknames/2"><c>socknames(<anno>Socket</anno>, 0)</c></seealso>. + </p> + </desc> + </func> + <func> + <name name="socknames" arity="2"/> + <fsummary>Return all local address/port numbers for a socket</fsummary> + <desc> + <p> + Returns a list of all local address/port number pairs for a socket + for the given association <c><anno>Assoc</anno></c>. + </p> + <p> + This function can return multiple addresses for multihomed + sockets such as SCTP sockets. For other sockets it + returns a one element list. + </p> + <p> + Note that the <c><anno>Assoc</anno></c> parameter is by the + <url href="http://tools.ietf.org/html/draft-ietf-tsvwg-sctpsocket-13">SCTP Sockets API Extensions</url> + defined to be ignored for one-to-one style sockets. + For one-to-many style sockets the special value <c>0</c> + is defined to mean that the returned addresses shall be + without regard to any particular association. + How different SCTP implementations interprets this varies somewhat. + </p> </desc> </func> <func> diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl index d4c78505da..b1c9d56c2d 100644 --- a/lib/kernel/src/inet.erl +++ b/lib/kernel/src/inet.erl @@ -24,6 +24,7 @@ %% socket -export([peername/1, sockname/1, port/1, send/2, + peernames/1, peernames/2, socknames/1, socknames/2, setopts/2, getopts/2, getifaddrs/0, getifaddrs/1, getif/1, getif/0, getiflist/0, getiflist/1, @@ -157,6 +158,7 @@ close(Socket) -> ok end. + -spec peername(Socket) -> {ok, {Address, Port}} | {error, posix()} when Socket :: socket(), Address :: ip_address(), @@ -173,6 +175,24 @@ setpeername(Socket, {IP,Port}) -> setpeername(Socket, undefined) -> prim_inet:setpeername(Socket, undefined). +-spec peernames(Socket) -> {ok, [{Address, Port}]} | {error, posix()} when + Socket :: socket(), + Address :: ip_address(), + Port :: non_neg_integer(). + +peernames(Socket) -> + prim_inet:peernames(Socket). + +-spec peernames(Socket, Assoc) -> + {ok, [{Address, Port}]} | {error, posix()} when + Socket :: socket(), + Assoc :: #sctp_assoc_change{} | gen_sctp:assoc_id(), + Address :: ip_address(), + Port :: non_neg_integer(). + +peernames(Socket, Assoc) -> + prim_inet:peernames(Socket, Assoc). + -spec sockname(Socket) -> {ok, {Address, Port}} | {error, posix()} when Socket :: socket(), @@ -190,6 +210,25 @@ setsockname(Socket, {IP,Port}) -> setsockname(Socket, undefined) -> prim_inet:setsockname(Socket, undefined). +-spec socknames(Socket) -> {ok, [{Address, Port}]} | {error, posix()} when + Socket :: socket(), + Address :: ip_address(), + Port :: non_neg_integer(). + +socknames(Socket) -> + prim_inet:socknames(Socket). + +-spec socknames(Socket, Assoc) -> + {ok, [{Address, Port}]} | {error, posix()} when + Socket :: socket(), + Assoc :: #sctp_assoc_change{} | gen_sctp:assoc_id(), + Address :: ip_address(), + Port :: non_neg_integer(). + +socknames(Socket, Assoc) -> + prim_inet:socknames(Socket, Assoc). + + -spec port(Socket) -> {'ok', Port} | {'error', any()} when Socket :: socket(), Port :: port_number(). diff --git a/lib/kernel/src/inet_int.hrl b/lib/kernel/src/inet_int.hrl index 18a4a61b2f..641a8dc0ca 100644 --- a/lib/kernel/src/inet_int.hrl +++ b/lib/kernel/src/inet_int.hrl @@ -86,6 +86,8 @@ -define(INET_REQ_ACCEPT, 26). -define(INET_REQ_LISTEN, 27). -define(INET_REQ_IGNOREFD, 28). +-define(INET_REQ_GETLADDRS, 29). +-define(INET_REQ_GETPADDRS, 30). %% TCP requests %%-define(TCP_REQ_ACCEPT, 40). MOVED diff --git a/lib/kernel/test/gen_sctp_SUITE.erl b/lib/kernel/test/gen_sctp_SUITE.erl index e89cb44797..d2de96b269 100644 --- a/lib/kernel/test/gen_sctp_SUITE.erl +++ b/lib/kernel/test/gen_sctp_SUITE.erl @@ -1,4 +1,4 @@ -%% +%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2007-2013. All Rights Reserved. @@ -36,7 +36,9 @@ open_multihoming_ipv6_socket/1, open_multihoming_ipv4_and_ipv6_socket/1, basic_stream/1, xfer_stream_min/1, peeloff_active_once/1, - peeloff_active_true/1, buffers/1]). + peeloff_active_true/1, buffers/1, + names_unihoming_ipv4/1, names_unihoming_ipv6/1, + names_multihoming_ipv4/1, names_multihoming_ipv6/1]). suite() -> [{ct_hooks,[ts_install_cth]}]. @@ -48,7 +50,9 @@ all() -> open_multihoming_ipv6_socket, open_multihoming_ipv4_and_ipv6_socket, basic_stream, xfer_stream_min, peeloff_active_once, - peeloff_active_true, buffers]. + peeloff_active_true, buffers, + names_unihoming_ipv4, names_unihoming_ipv6, + names_multihoming_ipv4, names_multihoming_ipv6]. groups() -> []. @@ -107,7 +111,7 @@ xfer_min(Config) when is_list(Config) -> ?line {ok,Sb} = gen_sctp:open([{type,seqpacket}]), ?line {ok,Pb} = inet:port(Sb), ?line ok = gen_sctp:listen(Sb, true), - + ?line {ok,Sa} = gen_sctp:open(), ?line {ok,Pa} = inet:port(Sa), ?line {ok,#sctp_assoc_change{state=comm_up, @@ -118,18 +122,18 @@ xfer_min(Config) when is_list(Config) -> gen_sctp:connect(Sa, Loopback, Pb, []), ?line {SbAssocId,SaOutboundStreams,SaInboundStreams} = case recv_event(log_ok(gen_sctp:recv(Sb, infinity))) of - {Loopback,Pa, - #sctp_assoc_change{state=comm_up, - error=0, - outbound_streams=SbOutboundStreams, - inbound_streams=SbInboundStreams, - assoc_id=AssocId}} -> - {AssocId,SbInboundStreams,SbOutboundStreams}; - {Loopback,Pa, - #sctp_paddr_change{state=addr_confirmed, - addr={Loopback,Pa}, - error=0, - assoc_id=AssocId}} -> + {Loopback,Pa, + #sctp_assoc_change{state=comm_up, + error=0, + outbound_streams=SbOutboundStreams, + inbound_streams=SbInboundStreams, + assoc_id=AssocId}} -> + {AssocId,SbInboundStreams,SbOutboundStreams}; + {Loopback,Pa, + #sctp_paddr_change{state=addr_confirmed, + addr={Loopback,Pa}, + error=0, + assoc_id=AssocId}} -> {Loopback,Pa, #sctp_assoc_change{state=comm_up, error=0, @@ -148,17 +152,20 @@ xfer_min(Config) when is_list(Config) -> assoc_id=SbAssocId}], Data} -> ok; Event1 -> - {Loopback,Pa, - #sctp_paddr_change{addr = {Loopback,_}, - state = addr_available, - error = 0, - assoc_id = SbAssocId}} = - recv_event(Event1), - {ok,{Loopback, - Pa, - [#sctp_sndrcvinfo{stream=Stream, - assoc_id=SbAssocId}], - Data}} = gen_sctp:recv(Sb, infinity) + case recv_event(Event1) of + {Loopback,Pa, + #sctp_paddr_change{addr = {Loopback,_}, + state = State, + error = 0, + assoc_id = SbAssocId}} + when State =:= addr_available; + State =:= addr_confirmed -> + {Loopback, + Pa, + [#sctp_sndrcvinfo{stream=Stream, + assoc_id=SbAssocId}], + Data} = log_ok(gen_sctp:recv(Sb, infinity)) + end end, ?line ok = gen_sctp:send(Sb, SbAssocId, 0, Data), ?line case log_ok(gen_sctp:recv(Sa, infinity)) of @@ -197,7 +204,7 @@ xfer_min(Config) when is_list(Config) -> recv_event(log_ok(gen_sctp:recv(Sb, infinity))), ?line ok = gen_sctp:close(Sa), ?line ok = gen_sctp:close(Sb), - + ?line receive Msg -> test_server:fail({received,Msg}) after 17 -> ok @@ -216,7 +223,7 @@ xfer_active(Config) when is_list(Config) -> ?line {ok,Sb} = gen_sctp:open([{active,true}]), ?line {ok,Pb} = inet:port(Sb), ?line ok = gen_sctp:listen(Sb, true), - + ?line {ok,Sa} = gen_sctp:open([{active,true}]), ?line {ok,Pa} = inet:port(Sa), ?line ok = gen_sctp:connect_init(Sa, Loopback, Pb, []), @@ -348,7 +355,7 @@ def_sndrcvinfo(Config) when is_list(Config) -> %% ?line S1 = log_ok(gen_sctp:open( - 0, [{sctp_default_send_param,#sctp_sndrcvinfo{ppid=17}}])), + 0, [{sctp_default_send_param,#sctp_sndrcvinfo{ppid=17}}])), ?LOGVAR(S1), ?line P1 = log_ok(inet:port(S1)), @@ -455,18 +462,22 @@ def_sndrcvinfo(Config) when is_list(Config) -> stream=1, ppid=0, context=0, assoc_id=S1AssocId}], <<"3: ",Data/binary>>} -> ok; Event2 -> - {Loopback,P2, - #sctp_paddr_change{ - addr={Loopback,_}, state=addr_available, - error=0, assoc_id=S1AssocId}} = - recv_event(Event2), - ?line case log_ok(gen_sctp:recv(S1)) of - {Loopback,P2, - [#sctp_sndrcvinfo{ - stream=1, ppid=0, context=0, - assoc_id=S1AssocId}], - <<"3: ",Data/binary>>} -> ok - end + case recv_event(Event2) of + {Loopback,P2, + #sctp_paddr_change{ + addr={Loopback,_}, + state=State, + error=0, assoc_id=S1AssocId}} + when State =:= addr_available; + State =:= addr_confirmed -> + ?line case log_ok(gen_sctp:recv(S1)) of + {Loopback,P2, + [#sctp_sndrcvinfo{ + stream=1, ppid=0, context=0, + assoc_id=S1AssocId}], + <<"3: ",Data/binary>>} -> ok + end + end end, ?line ok = do_from_other_process( @@ -509,6 +520,13 @@ log_ok(X) -> log(ok(X)). ok({ok,X}) -> X. +err([], Result) -> + erlang:error(Result); +err([Reason|_], {error,Reason}) -> + ok; +err([_|Reasons], Result) -> + err(Reasons, Result). + log(X) -> io:format("LOG[~w]: ~p~n", [self(),X]), X. @@ -529,57 +547,57 @@ api_open_close(Config) when is_list(Config) -> ?line {ok,S1} = gen_sctp:open(0), ?line {ok,P} = inet:port(S1), ?line ok = gen_sctp:close(S1), - + ?line {ok,S2} = gen_sctp:open(P), ?line {ok,P} = inet:port(S2), ?line ok = gen_sctp:close(S2), - + ?line {ok,S3} = gen_sctp:open([{port,P}]), ?line {ok,P} = inet:port(S3), ?line ok = gen_sctp:close(S3), - + ?line {ok,S4} = gen_sctp:open(P, []), ?line {ok,P} = inet:port(S4), ?line ok = gen_sctp:close(S4), - + ?line {ok,S5} = gen_sctp:open(P, [{ifaddr,any}]), ?line {ok,P} = inet:port(S5), ?line ok = gen_sctp:close(S5), ?line ok = gen_sctp:close(S5), - + ?line try gen_sctp:close(0) catch error:badarg -> ok end, - + ?line try gen_sctp:open({}) catch error:badarg -> ok end, - + ?line try gen_sctp:open(-1) catch error:badarg -> ok end, - + ?line try gen_sctp:open(65536) catch error:badarg -> ok end, - + ?line try gen_sctp:open(make_ref(), []) catch error:badarg -> ok end, - + ?line try gen_sctp:open(0, {}) catch error:badarg -> ok end, - + ?line try gen_sctp:open(0, [make_ref()]) catch error:badarg -> ok end, - + ?line try gen_sctp:open([{invalid_option,0}]) catch error:badarg -> ok end, - + ?line try gen_sctp:open(0, [{mode,invalid_mode}]) catch error:badarg -> ok end, @@ -591,11 +609,11 @@ api_listen(suite) -> []; api_listen(Config) when is_list(Config) -> ?line Localhost = {127,0,0,1}, - + ?line try gen_sctp:listen(0, true) catch error:badarg -> ok end, - + ?line {ok,S} = gen_sctp:open(), ?line {ok,Pb} = inet:port(S), ?line try gen_sctp:listen(S, not_allowed_for_listen) @@ -603,7 +621,7 @@ api_listen(Config) when is_list(Config) -> end, ?line ok = gen_sctp:close(S), ?line {error,closed} = gen_sctp:listen(S, true), - + ?line {ok,Sb} = gen_sctp:open(Pb), ?line {ok,Sa} = gen_sctp:open(), ?line case gen_sctp:connect(Sa, localhost, Pb, []) of @@ -615,8 +633,8 @@ api_listen(Config) when is_list(Config) -> gen_sctp:recv(Sa, infinity); {error,#sctp_assoc_change{state=cant_assoc}} -> ok%; - %% {error,{Localhost,Pb,_,#sctp_assoc_change{state=cant_assoc}}} -> - %% ok + %% {error,{Localhost,Pb,_,#sctp_assoc_change{state=cant_assoc}}} -> + %% ok end, ?line ok = gen_sctp:listen(Sb, true), ?line {ok,#sctp_assoc_change{state=comm_up, @@ -840,23 +858,36 @@ xfer_stream_min(Config) when is_list(Config) -> ?line SbOutboundStreams = SaInboundStreams, ?line ?LOGVAR(SbOutboundStreams), ?line ok = gen_sctp:send(Sa, SaAssocId, 0, Data), - ?line case gen_sctp:recv(Sb, infinity) of - {ok,{Loopback, + ?line case log_ok(gen_sctp:recv(Sb, infinity)) of + {Loopback, + Pa, + [#sctp_sndrcvinfo{stream=Stream, + assoc_id=SbAssocId}], + Data} -> ok; + {Loopback, + Pa,[], + #sctp_paddr_change{addr = {Loopback,_}, + state = addr_available, + error = 0, + assoc_id = SbAssocId}} -> + {Loopback, + Pa, + [#sctp_sndrcvinfo{stream=Stream, + assoc_id=SbAssocId}], + Data} = log_ok(gen_sctp:recv(Sb, infinity)); + {Loopback, + Pa, + [#sctp_sndrcvinfo{stream=Stream, + assoc_id=SbAssocId}], + #sctp_paddr_change{addr = {Loopback,_}, + state = addr_confirmed, + error = 0, + assoc_id = SbAssocId}} -> + {Loopback, Pa, [#sctp_sndrcvinfo{stream=Stream, assoc_id=SbAssocId}], - Data}} -> ok; - {ok,{Loopback, - Pa,[], - #sctp_paddr_change{addr = {Loopback,_}, - state = addr_available, - error = 0, - assoc_id = SbAssocId}}} -> - {ok,{Loopback, - Pa, - [#sctp_sndrcvinfo{stream=Stream, - assoc_id=SbAssocId}], - Data}} = gen_sctp:recv(Sb, infinity) + Data} = log_ok(gen_sctp:recv(Sb, infinity)) end, ?line ok = do_from_other_process( @@ -972,10 +1003,10 @@ peeloff(Config, SockOpts) when is_list(Config) -> ?line ?LOGVAR(S2Ai), ?line S1Ai = receive - {S1,{Addr,P2, - #sctp_assoc_change{ - state=comm_up, - assoc_id=AssocId1}}} -> AssocId1 + {S1,{Addr,P2, + #sctp_assoc_change{ + state=comm_up, + assoc_id=AssocId1}}} -> AssocId1 after Timeout -> socket_bailout([S1,S2]) end, @@ -1003,8 +1034,8 @@ peeloff(Config, SockOpts) when is_list(Config) -> ?line P3 = case P3_X of 0 -> P1; _ -> P3_X end, ?line [{_,#sctp_paddrinfo{assoc_id=S3Ai,state=active}}] = socket_call(S3, - {getopts,[{sctp_get_peer_addr_info, - #sctp_paddrinfo{address={Addr,P2}}}]}), + {getopts,[{sctp_get_peer_addr_info, + #sctp_paddrinfo{address={Addr,P2}}}]}), %%?line S3Ai = S1Ai, ?line ?LOGVAR(S3Ai), %% @@ -1087,9 +1118,9 @@ buffers(Config) when is_list(Config) -> %% ?line socket_call(S1, {setopts,[{recbuf,Limit}]}), ?line Recbuf = - case socket_call(S1, {getopts,[recbuf]}) of - [{recbuf,RB1}] when RB1 >= Limit -> RB1 - end, + case socket_call(S1, {getopts,[recbuf]}) of + [{recbuf,RB1}] when RB1 >= Limit -> RB1 + end, ?line Data = mk_data(Recbuf+Limit), ?line socket_call(S2, {setopts,[{sndbuf,Recbuf+Limit}]}), ?line socket_call(S2, {send,S2Ai,Stream,Data}), @@ -1190,6 +1221,93 @@ open_multihoming_ipv4_and_ipv6_socket(Config) when is_list(Config) -> {skip, Reason} end. +names_unihoming_ipv4(doc) -> + "Test inet:socknames/peernames on unihoming IPv4 sockets"; +names_unihoming_ipv4(suite) -> + []; +names_unihoming_ipv4(Config) when is_list(Config) -> + ?line do_names(Config, inet, 1). + +names_unihoming_ipv6(doc) -> + "Test inet:socknames/peernames on unihoming IPv6 sockets"; +names_unihoming_ipv6(suite) -> + []; +names_unihoming_ipv6(Config) when is_list(Config) -> + ?line do_names(Config, inet6, 1). + +names_multihoming_ipv4(doc) -> + "Test inet:socknames/peernames on multihoming IPv4 sockets"; +names_multihoming_ipv4(suite) -> + []; +names_multihoming_ipv4(Config) when is_list(Config) -> + ?line do_names(Config, inet, 2). + +names_multihoming_ipv6(doc) -> + "Test inet:socknames/peernames on multihoming IPv6 sockets"; +names_multihoming_ipv6(suite) -> + []; +names_multihoming_ipv6(Config) when is_list(Config) -> + ?line do_names(Config, inet6, 2). + + + +do_names(_, FamilySpec, AddressCount) -> + Fun = + fun (ServerSocket, _, ServerAssoc, ClientSocket, _, ClientAssoc) -> + ?line ServerSocknamesNoassoc = + lists:sort(ok(inet:socknames(ServerSocket))), + ?line ?LOGVAR(ServerSocknamesNoassoc), + ?line ServerSocknames = + lists:sort(ok(inet:socknames(ServerSocket, ServerAssoc))), + ?line ?LOGVAR(ServerSocknames), + ?line [_|_] = + ordsets:intersection + (ServerSocknamesNoassoc, ServerSocknames), + ?line ClientSocknamesNoassoc = + lists:sort(ok(inet:socknames(ClientSocket))), + ?line ?LOGVAR(ClientSocknamesNoassoc), + ?line ClientSocknames = + lists:sort(ok(inet:socknames(ClientSocket, ClientAssoc))), + ?line ?LOGVAR(ClientSocknames), + ?line [_|_] = + ordsets:intersection + (ClientSocknamesNoassoc, ClientSocknames), + ?line err([einval,enotconn], inet:peernames(ServerSocket)), + ?line ServerPeernames = + lists:sort(ok(inet:peernames(ServerSocket, ServerAssoc))), + ?line ?LOGVAR(ServerPeernames), + ?line err([einval,enotconn], inet:peernames(ClientSocket)), + ?line ClientPeernames = + lists:sort(ok(inet:peernames(ClientSocket, ClientAssoc))), + ?line ?LOGVAR(ClientPeernames), + ?line ServerSocknames = ClientPeernames, + ?line ClientSocknames = ServerPeernames, + ?line {ok,Socket} = + gen_sctp:peeloff(ServerSocket, ServerAssoc), + ?line SocknamesNoassoc = + lists:sort(ok(inet:socknames(Socket))), + ?line ?LOGVAR(SocknamesNoassoc), + ?line Socknames = + lists:sort(ok(inet:socknames(Socket, ServerAssoc))), + ?line ?LOGVAR(Socknames), + ?line true = + ordsets:is_subset(SocknamesNoassoc, Socknames), + ?line Peernames = + lists:sort(ok(inet:peernames(Socket, ServerAssoc))), + ?line ?LOGVAR(Peernames), + ?line ok = gen_sctp:close(Socket), + ?line Socknames = ClientPeernames, + ?line ClientSocknames = Peernames, + ok + end, + ?line case get_addrs_by_family(FamilySpec, AddressCount) of + {ok, Addresses} when length(Addresses) =:= AddressCount -> + ?line do_open_and_connect(Addresses, hd(Addresses), Fun); + {error, Reason} -> + {skip, Reason} + end. + + get_addrs_by_family(Family, NumAddrs) -> case os:type() of @@ -1274,6 +1392,10 @@ f(F, A) -> lists:flatten(io_lib:format(F, A)). do_open_and_connect(ServerAddresses, AddressToConnectTo) -> + ?line Fun = fun (_, _, _, _, _, _) -> ok end, + ?line do_open_and_connect(ServerAddresses, AddressToConnectTo, Fun). +%% +do_open_and_connect(ServerAddresses, AddressToConnectTo, Fun) -> ?line ServerFamily = get_family_by_addrs(ServerAddresses), ?line io:format("Serving ~p addresses: ~p~n", [ServerFamily, ServerAddresses]), @@ -1284,14 +1406,26 @@ do_open_and_connect(ServerAddresses, AddressToConnectTo) -> ?line ClientFamily = get_family_by_addr(AddressToConnectTo), ?line io:format("Connecting to ~p ~p~n", [ClientFamily, AddressToConnectTo]), - ?line S2 = ok(gen_sctp:open(0, [ClientFamily])), + ?line ClientOpts = + [ClientFamily | + case ClientFamily of + inet6 -> + [{ipv6_v6only,true}]; + _ -> + [] + end], + ?line S2 = ok(gen_sctp:open(0, ClientOpts)), + log(open), %% Verify client can connect - ?line #sctp_assoc_change{state=comm_up} = + ?line #sctp_assoc_change{state=comm_up} = S2Assoc = ok(gen_sctp:connect(S2, AddressToConnectTo, P1, [])), + log(comm_up), %% verify server side also receives comm_up from client - ?line recv_comm_up_eventually(S1), + ?line S1Assoc = recv_comm_up_eventually(S1), + ?line Result = Fun(S1, ServerFamily, S1Assoc, S2, ClientFamily, S2Assoc), ?line ok = gen_sctp:close(S2), - ?line ok = gen_sctp:close(S1). + ?line ok = gen_sctp:close(S1), + Result. %% If at least one of the addresses is an ipv6 address, return inet6, else inet. get_family_by_addrs(Addresses) -> @@ -1306,9 +1440,11 @@ get_family_by_addr(Addr) when tuple_size(Addr) =:= 8 -> inet6. recv_comm_up_eventually(S) -> ?line case ok(gen_sctp:recv(S)) of - {_Addr, _Port, _Info, #sctp_assoc_change{state=comm_up}} -> - ok; - {_Addr, _Port, _Info, _OtherSctpMsg} -> + {_Addr, _Port, _Info, + #sctp_assoc_change{state=comm_up} = Assoc} -> + Assoc; + {_Addr, _Port, _Info, _OtherSctpMsg} = Msg -> + ?line log({unexpected,Msg}), ?line recv_comm_up_eventually(S) end. @@ -1367,10 +1503,10 @@ socket_bailout([]) -> socket_history({State,Flush}) -> {lists:keysort( - 2, - lists:flatten( - [[{Key,Val} || Val <- Vals] - || {Key,Vals} <- gb_trees:to_list(State)])), + 2, + lists:flatten( + [[{Key,Val} || Val <- Vals] + || {Key,Vals} <- gb_trees:to_list(State)])), Flush}. s_handler(Socket) -> @@ -1453,7 +1589,7 @@ s_loop(Socket, Timeout, Parent, Handler, State) -> #sctp_assoc_change{ state=comm_up, inbound_streams=Is}}}|_] - when 0 =< Stream, Stream < Is-> ok; + when 0 =< Stream, Stream < Is-> ok; [] -> ok end, Key = {msg,AssocId,Stream}, @@ -1473,7 +1609,7 @@ s_loop(Socket, Timeout, Parent, Handler, State) -> case {gb_get(Key, State),St} of {[],_} -> ok; {[{_,{Addr,Port,#sctp_assoc_change{state=comm_up}}}|_],_} - when St =:= comm_lost; St =:= shutdown_comp -> ok + when St =:= comm_lost; St =:= shutdown_comp -> ok end, NewState = gb_push(Key, Val, State), Parent ! {self(),{Addr,Port,SAC}}, @@ -1489,8 +1625,9 @@ s_loop(Socket, Timeout, Parent, Handler, State) -> [] -> ok end, case {gb_get({assoc_change,AssocId}, State),St} of - {[{_,{Addr,Port,#sctp_assoc_change{state=comm_up}}}|_], - addr_available} -> ok; + {[{_,{Addr,Port,#sctp_assoc_change{state=comm_up}}}|_],_} + when St =:= addr_available; + St =:= addr_confirmed -> ok; {[],addr_confirmed} -> ok end, Key = {paddr_change,AssocId}, diff --git a/lib/runtime_tools/src/observer_backend.erl b/lib/runtime_tools/src/observer_backend.erl index 670e216d97..202129c61a 100644 --- a/lib/runtime_tools/src/observer_backend.erl +++ b/lib/runtime_tools/src/observer_backend.erl @@ -77,8 +77,8 @@ sys_info() -> | MemInfo]. alloc_info() -> - {_,_,AllocTypes,_} = erlang:system_info(allocator), - try erlang:system_info({allocator_sizes,AllocTypes}) of + AlcuAllocs = erlang:system_info(alloc_util_allocators), + try erlang:system_info({allocator_sizes, AlcuAllocs}) of Allocators -> Allocators catch _:_ -> [] end. diff --git a/lib/snmp/doc/src/notes.xml b/lib/snmp/doc/src/notes.xml index 7514c52dda..d213b67052 100644 --- a/lib/snmp/doc/src/notes.xml +++ b/lib/snmp/doc/src/notes.xml @@ -34,6 +34,125 @@ <section> + <title>SNMP Development Toolkit 4.25</title> + <p>Version 4.25 supports code replacement in runtime from/to + version 4.24.2, 4.24.1, 4.24, 4.23.1 and 4.23. </p> + + <section> + <title>Improvements and new features</title> +<!-- + <p>-</p> +--> + + <list type="bulleted"> + <item> + <p>[agent] Enable SNMP to create missing database directories. </p> + <p>Add + <seealso marker="snmp_app#db_init_error"> + {db_init_error, create_db_and_dir}</seealso> option to SNMP + <seealso marker="snmp_app#manager_opts_and_types">manager</seealso> + and + <seealso marker="snmp_app#agent_opts_and_types">agent</seealso>. + This allows them to create any missing parent directories for + <c>db_dir</c>, rather than treating any missing directories + as a fatal error. + The default for <c>db_init_error</c>, which is <c>terminate</c>, + is unchanged. </p> + <p>Steve Vinoski</p> + <p>Own Id: OTP-11352</p> + </item> + + <item> + <p>[manager] Improved handling of unexpected return values from + <seealso marker="snmpm_user">snmpm_user</seealso> + callback functions. </p> + <p>Violations of the documented API (crashes or invalid return + values) will now result in an error message. </p> + <p>Own Id: OTP-11307</p> + </item> + + <item> + <p>Add (atl) log conversion block option. </p> + <p>It is now possible to request that the Audit Trail Log should + be blocked during conversion (<c>log_to_txt</c> or <c>log_to_io</c>). + This could be usefull when coverting an entire large log (when + there is a chance it may otherwise wrap during conversion). </p> + <p>See + agent + <seealso marker="snmpa#log_to_txt">log_to_txt</seealso> and + <seealso marker="snmpa#log_to_io">log_to_io</seealso> and also + manager + <seealso marker="snmpm#log_to_txt">log_to_txt</seealso> and + <seealso marker="snmpm#log_to_io">log_to_io</seealso> + for details. </p> + <p>Own Id: OTP-11396</p> + <p>Own Id: seq12433</p> + </item> + + <item> + <p>When converting an Audit Trail Log to text, a corrupt + log entry could cause the entire conversion to fail. </p> + <p>Also, for a log with sequence numbers, failing to + decode a log entry would cause the conversion to fail + (not because of the failed decode, but because of the + failure to write the error message). </p> + <p>Own Id: OTP-111453</p> + <p>Aux Id: Seq 12459</p> + </item> + + </list> + + </section> + + <section> + <title>Fixed Bugs and Malfunctions</title> +<!-- + <p>-</p> +--> + + <list type="bulleted"> + <item> + <p>Wrong block cypher type used for AES ('aes_cbf128' + instead of 'aes_cfb128') when performing AES block + encrypt/decrypt which breaks SNMP usmAesCfb128Protocol + in agent and manager. </p> + <p>Own Id: OTP-11412</p> + </item> + + <item> + <p>[manager] When performing the AES encryption, invalid values for + the EngineBoots and EngineTime was used. </p> + <p>The values of the local agent was used, which would have produced + "some" values if an agent was actually running. + If not it would have caused a crash. </p> + <p>Own Id: OTP-11413</p> + </item> + + </list> + + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + +<!-- + <list type="bulleted"> + <item> + <p>[manager] The old Addr-and-Port based API functions, previously + long deprecated and marked for deletion in R16B, has now been + removed. </p> + <p>Own Id: OTP-10027</p> + </item> + + </list> +--> + </section> + + </section> <!-- 4.25 --> + + + <section> <title>SNMP Development Toolkit 4.24.2</title> <p>Version 4.24.2 supports code replacement in runtime from/to version 4.24.1, 4.24, 4.23.1 and 4.23. </p> @@ -96,7 +215,7 @@ </list> --> </section> - + </section> <!-- 4.24.2 --> diff --git a/lib/snmp/doc/src/snmp.xml b/lib/snmp/doc/src/snmp.xml index 3e6610891f..97b479385c 100644 --- a/lib/snmp/doc/src/snmp.xml +++ b/lib/snmp/doc/src/snmp.xml @@ -341,8 +341,9 @@ <func> <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile) -> ok | {error, Reason}</name> - <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start) -> ok | {error, Reason}</name> - <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop) -> ok | {error, Reason}</name> + <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block | Start) -> ok | {error, Reason}</name> + <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Block | Stop) -> ok | {error, Reason}</name> + <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop, Block) -> ok | {error, Reason}</name> <fsummary>Convert an Audit Trail Log to text format</fsummary> <type> <v>LogDir = string()</v> @@ -352,53 +353,56 @@ <v>LogName = string()</v> <v>LogFile = string()</v> <v>Start = Stop = null | datetime() | {local_time,datetime()} | {universal_time,datetime()} </v> + <v>Block = boolean()</v> <v>Reason = term()</v> </type> <desc> - <p>Converts an Audit Trail Log to a readable text file, where - each item has a trailing TAB character, and any TAB - character in the body of an item has been replaced by ESC - TAB. - </p> + <p>Converts an Audit Trail Log to a readable text file, where + each item has a trailing TAB character, and any TAB + character in the body of an item has been replaced by ESC + TAB. </p> <p>The function can be used on a running system, or by copying - the entire log directory and calling this function. SNMP - must be running in order to provide MIB information. - </p> + the entire log directory and calling this function. SNMP + must be running in order to provide MIB information. </p> <p><c>LogDir</c> is the name of the directory where the audit - trail log is stored. - <c>Mibs</c> is a list of Mibs to be used. The function uses - the information in the Mibs to convert for example object - identifiers to their symbolic name. - <c>OutFile</c> is the name of the generated text-file. - <c>LogName</c> is the name of the log, - <c>LogFile</c> is the name of the log file. - <c>Start</c> is the start (first) date and time from which - log events will be converted and - <c>Stop</c> is the stop (last) date and time to which log - events will be converted. - </p> - <p>The format of an audit trail log text item is as follows: - </p> - <p><c>Tag Addr - Community [TimeStamp] Vsn</c><br></br> - <c>PDU</c></p> - <p>where <c>Tag</c> is <c>request</c>, <c>response</c>, - <c>report</c>, <c>trap</c> or <c>inform</c>; Addr is - <c>IP:Port</c> (or comma space separated list of such); - <c>Community</c> is the community parameter (SNMP version - v1 and v2), or <c>SecLevel:"AuthEngineID":"UserName"</c> - (SNMP v3); <c>TimeStamp</c> is a date and time stamp, - and <c>Vsn</c> is the SNMP version. <c>PDU</c> is a textual - version of the protocol data unit. There is a new line - between <c>Vsn</c> and <c>PDU</c>.</p> - + trail log is stored. + <c>Mibs</c> is a list of Mibs to be used. The function uses + the information in the Mibs to convert for example object + identifiers to their symbolic name. + <c>OutFile</c> is the name of the generated text-file. + <c>LogName</c> is the name of the log, + <c>LogFile</c> is the name of the log file. + <c>Start</c> is the start (first) date and time from which + log events will be converted and + <c>Stop</c> is the stop (last) date and time to which log + events will be converted. + The <c>Block</c> argument indicates if the log should be blocked + during conversion. This could be usefull when converting large + logs (when otherwise the log could wrap during conversion). + Defaults to <c>true</c>. + </p> + <p>The format of an audit trail log text item is as follows: </p> + <p><c>Tag Addr - Community [TimeStamp] Vsn</c><br></br> + <c>PDU</c></p> + <p>where <c>Tag</c> is <c>request</c>, <c>response</c>, + <c>report</c>, <c>trap</c> or <c>inform</c>; Addr is + <c>IP:Port</c> (or comma space separated list of such); + <c>Community</c> is the community parameter (SNMP version + v1 and v2), or <c>SecLevel:"AuthEngineID":"UserName"</c> + (SNMP v3); <c>TimeStamp</c> is a date and time stamp, + and <c>Vsn</c> is the SNMP version. <c>PDU</c> is a textual + version of the protocol data unit. There is a new line + between <c>Vsn</c> and <c>PDU</c>.</p> + <marker id="log_to_io"></marker> </desc> </func> <func> <name>log_to_io(LogDir, Mibs, LogName, LogFile) -> ok | {error, Reason}</name> - <name>log_to_io(LogDir, Mibs, LogName, LogFile, Start) -> ok | {error, Reason}</name> - <name>log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop) -> ok | {error, Reason}</name> + <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block | Start) -> ok | {error, Reason}</name> + <name>log_to_io(LogDir, Mibs, LogName, LogFile, Start, Block | Stop) -> ok | {error, Reason}</name> + <name>log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop, Block) -> ok | {error, Reason}</name> <fsummary>Convert an Audit Trail Log to text format</fsummary> <type> <v>LogDir = string()</v> diff --git a/lib/snmp/doc/src/snmp_app.xml b/lib/snmp/doc/src/snmp_app.xml index e5a05342c1..9ede75b943 100644 --- a/lib/snmp/doc/src/snmp_app.xml +++ b/lib/snmp/doc/src/snmp_app.xml @@ -763,12 +763,15 @@ </item> <marker id="db_init_error"></marker> - <tag><c>db_init_error() = terminate | create</c></tag> + <tag><c>db_init_error() = terminate | create | create_db_and_dir</c></tag> <item> <p>Defines what to do if the agent or manager is unable to open an existing database file. <c>terminate</c> means that the agent/manager will terminate and <c>create</c> means that the - agent/manager will remove the faulty file(s) and create new ones.</p> + agent/manager will remove the faulty file(s) and create new ones, + and <c>create_db_and_dir</c> means that the agent/manager will + create the database file along with any missing parent directories + for the database file.</p> <p>Default is <c>terminate</c>.</p> </item> diff --git a/lib/snmp/doc/src/snmp_config.xml b/lib/snmp/doc/src/snmp_config.xml index 61ee7f00ee..30b46e6aa8 100644 --- a/lib/snmp/doc/src/snmp_config.xml +++ b/lib/snmp/doc/src/snmp_config.xml @@ -792,12 +792,15 @@ in so far as it will be converted to the new format if found. </item> <marker id="db_init_error"></marker> - <tag><c>db_init_error() = terminate | create</c></tag> + <tag><c>db_init_error() = terminate | create | create_db_and_dir</c></tag> <item> <p>Defines what to do if the agent is unable to open an existing database file. <c>terminate</c> means that the - agent/manager will terminate and <c>create</c> means that the - agent/manager will remove the faulty file(s) and create new ones.</p> + agent/manager will terminate, <c>create</c> means that the + agent/manager will remove the faulty file(s) and create new ones, + and <c>create_db_and_dir</c> means that the agent/manager will + create the database file along with any missing parent directories + for the database file.</p> <p>Default is <c>terminate</c>.</p> </item> diff --git a/lib/snmp/doc/src/snmpa.xml b/lib/snmp/doc/src/snmpa.xml index 77146f3a89..cc8681e5c8 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>2012</year> + <year>2004</year><year>2013</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -557,32 +557,39 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} <func> <name>log_to_txt(LogDir)</name> - <name>log_to_txt(LogDir, Mibs)</name> - <name>log_to_txt(LogDir, Mibs, OutFile) -> ok | {error, Reason}</name> - <name>log_to_txt(LogDir, Mibs, OutFile, LogName) -> ok | {error, Reason}</name> - <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile) -> ok | {error, Reason}</name> - <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start) -> ok | {error, Reason}</name> + <name>log_to_txt(LogDir, Block | Mibs)</name> + <name>log_to_txt(LogDir, Mibs, Block | OutFile) -> ok | {error, Reason}</name> + <name>log_to_txt(LogDir, Mibs, OutFile, Block | LogName) -> ok | {error, Reason}</name> + <name>log_to_txt(LogDir, Mibs, OutFile, LogName, Block | LogFile) -> ok | {error, Reason}</name> + <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block | Start) -> ok | {error, Reason}</name> + <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start) -> ok | {error, Reason}</name> <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop) -> ok | {error, Reason}</name> + <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop) -> ok | {error, Reason}</name> <fsummary>Convert an Audit Trail Log to text format</fsummary> <type> <v>LogDir = string()</v> <v>Mibs = [MibName]</v> <v>MibName = string()</v> + <v>Block = boolean()</v> <v>OutFile = string()</v> <v>LogName = string()</v> <v>LogFile = string()</v> - <v>Start = Stop = null | datetime() | {local_time,datetime()} | {universal_time,datetime()} </v> + <v>Start = Stop = null | calendar:datetime() | {local_time, calendar:datetime()} | {universal_time, calendar:datetime()} </v> <v>Reason = disk_log_open_error() | file_open_error() | term()</v> <v>disk_log_open_error() = {LogName, term()}</v> <v>file_open_error() = {OutFile, term()}</v> </type> <desc> <p>Converts an Audit Trail Log to a readable text file. - <c>OutFile</c> defaults to "./snmpa_log.txt". - <c>LogName</c> defaults to "snmpa_log". - <c>LogFile</c> defaults to "snmpa.log". - See <seealso marker="snmp#log_to_txt">snmp:log_to_txt</seealso> - for more info.</p> + <c>OutFile</c> defaults to "./snmpa_log.txt". + <c>LogName</c> defaults to "snmpa_log". + <c>LogFile</c> defaults to "snmpa.log". </p> + <p>The <c>Block</c> option indicates if the log should be blocked + during conversion. This could be usefull when converting large + logs (when otherwise the log could wrap during conversion). + Defaults to <c>true</c>. </p> + <p>See <seealso marker="snmp#log_to_txt">snmp:log_to_txt</seealso> + for more info.</p> <marker id="log_to_io"></marker> </desc> @@ -590,19 +597,22 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} <func> <name>log_to_io(LogDir) -> ok | {error, Reason}</name> - <name>log_to_io(LogDir, Mibs) -> ok | {error, Reason}</name> - <name>log_to_io(LogDir, Mibs, LogName) -> ok | {error, Reason}</name> - <name>log_to_io(LogDir, Mibs, LogName, LogFile) -> ok | {error, Reason}</name> - <name>log_to_io(LogDir, Mibs, LogName, LogFile, Start) -> ok | {error, Reason}</name> + <name>log_to_io(LogDir, Block | Mibs) -> ok | {error, Reason}</name> + <name>log_to_io(LogDir, Mibs, Block | LogName) -> ok | {error, Reason}</name> + <name>log_to_io(LogDir, Mibs, LogName, Block | LogFile) -> ok | {error, Reason}</name> + <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block | Start) -> ok | {error, Reason}</name> + <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start) -> ok | {error, Reason}</name> <name>log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop) -> ok | {error, Reason}</name> + <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop) -> ok | {error, Reason}</name> <fsummary>Convert an Audit Trail Log to text format</fsummary> <type> <v>LogDir = string()</v> <v>Mibs = [MibName]</v> <v>MibName = string()</v> + <v>Block = boolean()</v> <v>LogName = string()</v> <v>LogFile = string()</v> - <v>Start = Stop = null | datetime() | {local_time,datetime()} | {universal_time,datetime()} </v> + <v>Start = Stop = null | calendar:datetime() | {local_time, calendar:datetime()} | {universal_time, calendar:datetime()} </v> <v>Reason = disk_log_open_error() | file_open_error() | term()</v> <v>disk_log_open_error() = {LogName, term()}</v> <v>file_open_error() = {OutFile, term()}</v> @@ -612,6 +622,10 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} prints it on stdio. <c>LogName</c> defaults to "snmpa_log". <c>LogFile</c> defaults to "snmpa.log". + <p>The <c>Block</c> option indicates if the log should be blocked + during conversion. This could be usefull when converting large + logs (when otherwise the log could wrap during conversion). + Defaults to <c>true</c>. </p> See <seealso marker="snmp#log_to_io">snmp:log_to_io</seealso> for more info.</p> diff --git a/lib/snmp/doc/src/snmpm.xml b/lib/snmp/doc/src/snmpm.xml index 07fdd208ff..a0a1b5716d 100644 --- a/lib/snmp/doc/src/snmpm.xml +++ b/lib/snmp/doc/src/snmpm.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>2004</year><year>2012</year> + <year>2004</year><year>2013</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -1209,32 +1209,40 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 </func> <func> - <name>log_to_txt(LogDir, Mibs)</name> - <name>log_to_txt(LogDir, Mibs, OutFile) -> ok | {error, Reason}</name> - <name>log_to_txt(LogDir, Mibs, OutFile, LogName) -> ok | {error, Reason}</name> - <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile) -> ok | {error, Reason}</name> - <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start) -> ok | {error, Reason}</name> + <name>log_to_txt(LogDir)</name> + <name>log_to_txt(LogDir, Block | Mibs)</name> + <name>log_to_txt(LogDir, Mibs, Block | OutFile) -> ok | {error, Reason}</name> + <name>log_to_txt(LogDir, Mibs, OutFile, Block | LogName) -> ok | {error, Reason}</name> + <name>log_to_txt(LogDir, Mibs, OutFile, LogName, Block | LogFile) -> ok | {error, Reason}</name> + <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block | Start) -> ok | {error, Reason}</name> + <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start) -> ok | {error, Reason}</name> <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop) -> ok | {error, Reason}</name> + <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop) -> ok | {error, Reason}</name> <fsummary>Convert an Audit Trail Log to text format</fsummary> <type> <v>LogDir = string()</v> <v>Mibs = [MibName]</v> <v>MibName = string()</v> + <v>Block = boolean()</v> <v>OutFile = string()</v> <v>LogName = string()</v> <v>LogFile = string()</v> - <v>Start = Stop = null | datetime() | {local_time,datetime()} | {universal_time,datetime()} </v> + <v>Start = Stop = null | calendar:datetime() | {local_time, calendar:datetime()} | {universal_time, calendar:datetime()} </v> <v>Reason = disk_log_open_error() | file_open_error() | term()</v> <v>disk_log_open_error() = {LogName, term()}</v> <v>file_open_error() = {OutFile, term()}</v> </type> <desc> <p>Converts an Audit Trail Log to a readable text file. - <c>OutFile</c> defaults to "./snmpm_log.txt". - <c>LogName</c> defaults to "snmpm_log". - <c>LogFile</c> defaults to "snmpm.log". - See <seealso marker="snmp#log_to_txt">snmp:log_to_txt</seealso> - for more info.</p> + <c>OutFile</c> defaults to "./snmpm_log.txt". + <c>LogName</c> defaults to "snmpm_log". + <c>LogFile</c> defaults to "snmpm.log". + <p>The <c>Block</c> argument indicates if the log should be blocked + during conversion. This could be usefull when converting large + logs (when otherwise the log could wrap during conversion). + Defaults to <c>true</c>. </p> + See <seealso marker="snmp#log_to_txt">snmp:log_to_txt</seealso> + for more info.</p> <marker id="log_to_io"></marker> </desc> @@ -1242,20 +1250,23 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 <func> <name>log_to_io(LogDir) -> ok | {error, Reason}</name> + <name>log_to_io(LogDir, Block | Mibs) -> ok | {error, Reason}</name> <name>log_to_io(LogDir, Mibs) -> ok | {error, Reason}</name> - <name>log_to_io(LogDir, Mibs) -> ok | {error, Reason}</name> - <name>log_to_io(LogDir, Mibs, LogName) -> ok | {error, Reason}</name> - <name>log_to_io(LogDir, Mibs, LogName, LogFile) -> ok | {error, Reason}</name> - <name>log_to_io(LogDir, Mibs, LogName, LogFile, Start) -> ok | {error, Reason}</name> + <name>log_to_io(LogDir, Mibs, Block | LogName) -> ok | {error, Reason}</name> + <name>log_to_io(LogDir, Mibs, LogName, Block | LogFile) -> ok | {error, Reason}</name> + <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block | Start) -> ok | {error, Reason}</name> + <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start) -> ok | {error, Reason}</name> <name>log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop) -> ok | {error, Reason}</name> + <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop) -> ok | {error, Reason}</name> <fsummary>Convert an Audit Trail Log to text format</fsummary> <type> <v>LogDir = string()</v> <v>Mibs = [MibName]</v> <v>MibName = string()</v> + <v>Block = boolean()</v> <v>LogName = string()</v> <v>LogFile = string()</v> - <v>Start = Stop = null | datetime() | {local_time,datetime()} | {universal_time,datetime()} </v> + <v>Start = Stop = null | calendar:datetime() | {local_time, calendar:datetime()} | {universal_time, calendar:datetime()} </v> <v>Reason = disk_log_open_error() | file_open_error() | term()</v> <v>disk_log_open_error() = {LogName, term()}</v> <v>file_open_error() = {OutFile, term()}</v> @@ -1265,6 +1276,10 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 prints it on stdio. <c>LogName</c> defaults to "snmpm_log". <c>LogFile</c> defaults to "snmpm.log". + <p>The <c>Block</c> argument indicates if the log should be blocked + during conversion. This could be usefull when converting large + logs (when otherwise the log could wrap during conversion). + Defaults to <c>true</c>. </p> See <seealso marker="snmp#log_to_io">snmp:log_to_io</seealso> for more info.</p> diff --git a/lib/snmp/doc/src/snmpm_user.xml b/lib/snmp/doc/src/snmpm_user.xml index 1823e0c815..cb2deab976 100644 --- a/lib/snmp/doc/src/snmpm_user.xml +++ b/lib/snmp/doc/src/snmpm_user.xml @@ -1,10 +1,10 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="iso-8859-1" ?> <!DOCTYPE erlref SYSTEM "erlref.dtd"> <erlref> <header> <copyright> - <year>2004</year><year>2009</year> + <year>2004</year><year>2013</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -56,40 +56,59 @@ <item> <p>handle_report/3</p> </item> + <item> + <p>handle_invalid_result/2</p> + </item> </list> <p>The semantics of them and their exact signatures are explained - below. </p> - <p>Note that if an agent is registered using the old, no longer - documented, functions (using Addr and Port), the old variant of the - callback functions, handle_pdu, handle_trap, handle_inform and - handle_report, will be called. </p> + below. </p> + <p>Some of the function has no defined return value (<c>void()</c>), + they can ofcourse return anythyng. But the functions that do have + specified return value(s) <em>must</em> adhere to this. None of the + functions can use exit of throw to return. </p> - <marker id="handle_error"></marker> + <marker id="types"></marker> </description> + + <section> + <title>DATA TYPES</title> + <code type="none"><![CDATA[ +snmp_gen_info() = {ErrorStatus :: atom(), + ErrorIndex :: pos_integer(), + Varbinds :: [snmp:varbind()]} +snmp_v1_trap_info() :: {Enteprise :: snmp:oid(), + Generic :: integer(), + Spec :: integer(), + Timestamp :: integer(), + Varbinds :: [snmp:varbind()]} + ]]></code> + <marker id="handle_error"></marker> + </section> + <funcs> <func> - <name>handle_error(ReqId, Reason, UserData) -> Reply</name> + <name>handle_error(ReqId, Reason, UserData) -> void()</name> <fsummary>Handle error</fsummary> <type> <v>ReqId = integer()</v> <v>Reason = {unexpected_pdu, SnmpInfo} | {invalid_sec_info, SecInfo, SnmpInfo} | {empty_message, Addr, Port} | term()</v> + <v>SnmpInfo = snmp_gen_info()</v> + <v>SecInfo = term()</v> <v>Addr = ip_address()</v> <v>Port = integer()</v> <v>UserData = term()</v> - <v>Reply = ignore</v> </type> <desc> <p>This function is called when the manager needs to - communicate an "asynchronous" error, to the user: - e.g. failure to send an asynchronous message (i.e. encoding - error), a received message was discarded due to security - error, the manager failed to generate a response message to - a received inform-request, or when receiving an unexpected - PDU from an agent (could be an expired async request). </p> - <p>If <c>ReqId</c> is less then 0, it means that this - information was not available to the manager (that info was - never retrieved before the message was discarded). - </p> + communicate an "asynchronous" error to the user: + e.g. failure to send an asynchronous message (i.e. encoding + error), a received message was discarded due to security + error, the manager failed to generate a response message to + a received inform-request, or when receiving an unexpected + PDU from an agent (could be an expired async request). </p> + <p>If <c>ReqId</c> is less then 0, it means that this + information was not available to the manager (that info was + never retrieved before the message was discarded). </p> <p>For <c>SnmpInfo</c> see handle_agent below.</p> <marker id="handle_agent"></marker> @@ -104,22 +123,22 @@ <v>Port = integer()</v> <v>Type = pdu | trap | report | inform</v> <v>SnmpInfo = SnmpPduInfo | SnmpTrapInfo | SnmpReportInfo | SnmpInformInfo</v> - <v>ErrorStatus = atom()</v> - <v>ErrorIndex = integer()</v> - <v>Varbinds = [varbind()]</v> - <v>varbind() = #varbind</v> + <v>SnmpPduInfo = snmp_gen_info()</v> + <v>SnmpTrapInfo = snmp_v1_trap_info()</v> + <v>SnmpReportInfo = snmp_gen_info()</v> + <v>SnmpInformInfo = snmp_gen_info()</v> <v>UserData = term()</v> - <v>Reply = ignore | {register, UserId, TargetName, agent_info()}</v> + <v>Reply = ignore | {register, UserId, TargetName, AgentConfig}</v> <v>UserId = term()</v> <v>TargetName = target_name()</v> - <v>agent_info() = [{agent_info_item(), agent_info_value()}]</v> + <v>AgentConfig = [agent_config()]</v> </type> <desc> - <p>This function is called when a message is received from an - unknown agent.</p> + <p>This function is called when a message is received from an + unknown agent.</p> <p>Note that this will always be the default user that is called.</p> - <p>For more info about the <c>agent_info()</c>, see - <seealso marker="snmpm#register_agent">register_agent</seealso>.</p> + <p>For more info about the <c>agent_config()</c>, see + <seealso marker="snmpm#register_agent">register_agent</seealso>.</p> <p>The arguments <c>Type</c> and <c>SnmpInfo</c> relates in the following way: </p> @@ -148,7 +167,7 @@ </list> <p>The only user which would return - <c>{register, UserId, TargetName, agent_info()}</c> is the + <c>{register, UserId, TargetName, AgentConfig}</c> is the <em>default user</em>.</p> <marker id="handle_pdu"></marker> @@ -156,18 +175,13 @@ </func> <func> - <name>handle_pdu(TargetName, ReqId, SnmpPduInfo, UserData) -> Reply</name> + <name>handle_pdu(TargetName, ReqId, SnmpPduInfo, UserData) -> void()</name> <fsummary>Handle the reply to an asynchronous request</fsummary> <type> <v>TargetName = target_name()</v> <v>ReqId = term()</v> - <v>SnmpPduInfo = {ErrorStatus, ErrorIndex, Varbinds}</v> - <v>ErrorStatus = atom()</v> - <v>ErrorIndex = integer()</v> - <v>Varbinds = [varbind()]</v> - <v>varbind() = #varbind</v> + <v>SnmpPduInfo = snmp_gen_info()</v> <v>UserData = term()</v> - <v>Reply = ignore</v> </type> <desc> <p>Handle the reply to an asynchronous request, such as @@ -186,27 +200,19 @@ <fsummary>Handle a trap/notification message</fsummary> <type> <v>TargetName = TargetName2 = target_name()</v> - <v>SnmpTrapInfo = {Enteprise, Generic, Spec, Timestamp, Varbinds} | {ErrorStatus, ErrorIndex, Varbinds}</v> - <v>Enterprise = oid()</v> - <v>Generic = integer()</v> - <v>Spec = integer()</v> - <v>Timestamp = integer()</v> - <v>ErrorStatus = atom()</v> - <v>ErrorIndex = integer()</v> - <v>Varbinds = [varbind()]</v> - <v>varbind() = #varbind</v> + <v>SnmpTrapInfo = snmp_v1_trap_info() | snmp_gen_info()</v> <v>UserData = term()</v> - <v>Reply = ignore | unregister | {register, UserId, TargetName2, agent_info()}</v> + <v>Reply = ignore | unregister | {register, UserId, TargetName2, AgentConfig}</v> <v>UserId = term()</v> - <v>agent_info() = [{agent_info_item(), agent_info_value()}]</v> + <v>AgentConfig = [agent_config()]</v> </type> <desc> <p>Handle a trap/notification message from an agent.</p> - <p>For more info about the <c>agent_info()</c>, see - <seealso marker="snmpm#register_agent">register_agent</seealso></p> + <p>For more info about the <c>agent_config()</c>, see + <seealso marker="snmpm#register_agent">register_agent</seealso></p> <p>The only user which would return - <c>{register, UserId, TargetName2, agent_info()}</c> is the - <em>default user</em>.</p> + <c>{register, UserId, TargetName2, agent_info()}</c> is the + <em>default user</em>.</p> <marker id="handle_inform"></marker> </desc> @@ -217,29 +223,25 @@ <fsummary>Handle a inform message</fsummary> <type> <v>TargetName = TargetName2 = target_name()</v> - <v>SnmpInformInfo = {ErrorStatus, ErrorIndex, Varbinds}</v> - <v>ErrorStatus = atom()</v> - <v>ErrorIndex = integer()</v> - <v>Varbinds = [varbind()]</v> - <v>varbind() = #varbind</v> + <v>SnmpInformInfo = snmp_gen_info()</v> <v>UserData = term()</v> - <v>Reply = ignore | unregister | {register, UserId, TargetName2, agent_info()}</v> + <v>Reply = ignore | no_reply | unregister | {register, UserId, TargetName2, AgentConfig}</v> <v>UserId = term()</v> - <v>agent_info() = [{agent_info_item(), agent_info_value()}]</v> + <v>AgentConfig = [agent_config()]</v> </type> <desc> <p>Handle a inform message.</p> - <p>For more info about the <c>agent_info()</c>, see - <seealso marker="snmpm#register_agent">register_agent</seealso></p> + <p>For more info about the <c>agent_config()</c>, see + <seealso marker="snmpm#register_agent">register_agent</seealso></p> <p>The only user which would return - <c>{register, UserId, TargetName2, agent_info()}</c> is the - <em>default user</em>.</p> - <p>If the - <seealso marker="snmp_app">inform request behaviour</seealso> - configuration option is set to <c>user</c> or - <c>{user, integer()}</c>, the response (acknowledgment) to this - inform-request will be sent when this function returns.</p> - + <c>{register, UserId, TargetName2, AgentConfig}</c> is the + <em>default user</em>.</p> + <p>If the + <seealso marker="snmp_app">inform request behaviour</seealso> + configuration option is set to <c>user</c> or + <c>{user, integer()}</c>, the response (acknowledgment) to this + inform-request will be sent when this function returns.</p> + <marker id="handle_report"></marker> </desc> </func> @@ -251,23 +253,46 @@ <v>TargetName = TargetName2 = target_name()</v> <v>Addr = ip_address()</v> <v>Port = integer()</v> - <v>SnmpReportInfo = {ErrorStatus, ErrorIndex, Varbinds}</v> - <v>ErrorStatus = atom()</v> - <v>ErrorIndex = integer()</v> - <v>Varbinds = [varbind()]</v> - <v>varbind() = #varbind</v> + <v>SnmpReportInfo = snmp_gen_info()</v> <v>UserData = term()</v> - <v>Reply = ignore | unregister | {register, UserId, TargetName2, agent_info()}</v> + <v>Reply = ignore | unregister | {register, UserId, TargetName2, AgentConfig}</v> <v>UserId = term()</v> - <v>agent_info() = [{agent_info_item(), agent_info_value()}]</v> + <v>AgentConfig = [agent_config()]</v> </type> <desc> <p>Handle a report message.</p> - <p>For more info about the <c>agent_info()</c>, see - <seealso marker="snmpm#register_agent">register_agent</seealso></p> + <p>For more info about the <c>agent_config()</c>, see + <seealso marker="snmpm#register_agent">register_agent</seealso></p> <p>The only user which would return - <c>{register, UserId, TargetName2, agent_info()}</c> is the - <em>default user</em>.</p> + <c>{register, UserId, TargetName2, AgentConfig}</c> is the + <em>default user</em>.</p> + + <marker id="handle_invalid_result"></marker> + </desc> + </func> + + <func> + <name>handle_invalid_result(IN, OUT) -> void()</name> + <fsummary>Handle a report message</fsummary> + <type> + <v>IN = {Func, Args}</v> + <v>Func = atom()</v> + <v>Args = list()</v> + <v>OUT = {crash, CrashInfo} | {result, InvalidResult}</v> + <v>CrashInfo = {ErrorType, Error, Stacktrace}</v> + <v>ErrorType = atom()</v> + <v>Error = term()</v> + <v>Stacktrace = list()</v> + <v>InvalidResult = term()</v> + </type> + <desc> + <p>If <em>any</em> of the <em>other</em> callback functions crashes + (exit, throw or a plain crash) or return an invalid result (if a valid + return has been specified), this function is called. + The purpose is to allow the user handle this + error (for instance to issue an error report).</p> + <p><c>IN</c> reprecents the function called (and its arguments). + <c>OUT</c> represents the unexpected/invalid result. </p> </desc> </func> </funcs> diff --git a/lib/snmp/examples/ex2/snmp_ex2_manager.erl b/lib/snmp/examples/ex2/snmp_ex2_manager.erl index 1b247d713d..a9dcc09b77 100644 --- a/lib/snmp/examples/ex2/snmp_ex2_manager.erl +++ b/lib/snmp/examples/ex2/snmp_ex2_manager.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2012. All Rights Reserved. +%% Copyright Ericsson AB 2006-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -43,7 +43,8 @@ handle_pdu/4, handle_trap/3, handle_inform/3, - handle_report/3]). + handle_report/3, + handle_invalid_result/3]). %% gen_server callbacks -export([init/1, handle_call/3, handle_cast/2, handle_info/2, @@ -406,5 +407,9 @@ handle_report(TargetName, SnmpReport, Server) when is_pid(Server) -> report_callback(Server, handle_inform, {TargetName, SnmpReport}), ok. +handle_invalid_result(In, Out, Server) when is_pid(Server) -> + report_callback(Server, handle_invalid_result, {In, Out}), + ok. + report_callback(Pid, Tag, Info) -> Pid ! {snmp_callback, Tag, Info}. diff --git a/lib/snmp/src/agent/snmpa.erl b/lib/snmp/src/agent/snmpa.erl index a95e41ea42..aea63effe6 100644 --- a/lib/snmp/src/agent/snmpa.erl +++ b/lib/snmp/src/agent/snmpa.erl @@ -85,11 +85,10 @@ -export([add_agent_caps/2, del_agent_caps/1, get_agent_caps/0]). %% Audit Trail Log functions --export([log_to_txt/1, - log_to_txt/2, log_to_txt/3, log_to_txt/4, - log_to_txt/5, log_to_txt/6, log_to_txt/7, - log_to_io/1, log_to_io/2, log_to_io/3, - log_to_io/4, log_to_io/5, log_to_io/6, +-export([log_to_txt/1, log_to_txt/2, log_to_txt/3, log_to_txt/4, + log_to_txt/5, log_to_txt/6, log_to_txt/7, log_to_txt/8, + log_to_io/1, log_to_io/2, log_to_io/3, log_to_io/4, + log_to_io/5, log_to_io/6, log_to_io/7, log_info/0, change_log_size/1, get_log_type/0, get_log_type/1, @@ -130,7 +129,8 @@ -include("snmpa_internal.hrl"). -include_lib("snmp/include/snmp_types.hrl"). % type of me needed. --define(DISCO_EXTRA_INFO, undefined). +-define(DISCO_EXTRA_INFO, undefined). +-define(ATL_BLOCK_DEFAULT, true). %%----------------------------------------------------------------- @@ -872,43 +872,207 @@ get_agent_caps() -> %%% Audit Trail Log functions %%%----------------------------------------------------------------- +-spec log_to_txt(LogDir :: snmp:dir()) -> + snmp:void(). + log_to_txt(LogDir) -> log_to_txt(LogDir, []). + +-spec log_to_txt(LogDir :: snmp:dir(), + Block :: boolean()) -> + snmp:void(); + (LogDir :: snmp:dir(), + Mibs :: [snmp:mib_name()]) -> + snmp:void(). + +log_to_txt(LogDir, Block) + when ((Block =:= true) orelse (Block =:= false)) -> + Mibs = [], + OutFile = "snmpa_log.txt", + LogName = ?audit_trail_log_name, + LogFile = ?audit_trail_log_file, + snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block); + log_to_txt(LogDir, Mibs) -> + Block = ?ATL_BLOCK_DEFAULT, OutFile = "snmpa_log.txt", LogName = ?audit_trail_log_name, LogFile = ?audit_trail_log_file, - snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile). + snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block). + +-spec log_to_txt(LogDir :: snmp:dir(), + Mibs :: [snmp:mib_name()], + Block :: boolean()) -> + snmp:void(); + (LogDir :: snmp:dir(), + Mibs :: [snmp:mib_name()], + OutFile :: file:filename()) -> + snmp:void(). + +log_to_txt(LogDir, Mibs, Block) + when ((Block =:= true) orelse (Block =:= false)) -> + OutFile = "snmpa_log.txt", + LogName = ?audit_trail_log_name, + LogFile = ?audit_trail_log_file, + snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block); log_to_txt(LogDir, Mibs, OutFile) -> + Block = ?ATL_BLOCK_DEFAULT, + LogName = ?audit_trail_log_name, + LogFile = ?audit_trail_log_file, + snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block). + +-spec log_to_txt(LogDir :: snmp:dir(), + Mibs :: [snmp:mib_name()], + OutFile :: file:filename(), + Block :: boolean()) -> + snmp:void(); + (LogDir :: snmp:dir(), + Mibs :: [snmp:mib_name()], + OutFile :: file:filename(), + LogName :: string()) -> + snmp:void(). + +log_to_txt(LogDir, Mibs, OutFile, Block) + when ((Block =:= true) orelse (Block =:= false)) -> LogName = ?audit_trail_log_name, LogFile = ?audit_trail_log_file, - snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile). + snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block); log_to_txt(LogDir, Mibs, OutFile, LogName) -> + Block = ?ATL_BLOCK_DEFAULT, + LogFile = ?audit_trail_log_file, + snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block). + +-spec log_to_txt(LogDir :: snmp:dir(), + Mibs :: [snmp:mib_name()], + OutFile :: file:filename(), + LogName :: string(), + Block :: boolean()) -> + snmp:void(); + (LogDir :: snmp:dir(), + Mibs :: [snmp:mib_name()], + OutFile :: file:filename(), + LogName :: string(), + LogFile :: string()) -> + snmp:void(). + +log_to_txt(LogDir, Mibs, OutFile, LogName, Block) + when ((Block =:= true) orelse (Block =:= false)) -> LogFile = ?audit_trail_log_file, - snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile). + snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block); log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile) -> - snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile). + Block = ?ATL_BLOCK_DEFAULT, + snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block). + +-spec log_to_txt(LogDir :: snmp:dir(), + Mibs :: [snmp:mib_name()], + OutFile :: file:filename(), + LogName :: string(), + LogFile :: string(), + Block :: boolean()) -> + snmp:void(); + (LogDir :: snmp:dir(), + Mibs :: [snmp:mib_name()], + OutFile :: file:filename(), + LogName :: string(), + LogFile :: string(), + Start :: snmp_log:log_time()) -> + snmp:void(). + +log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block) + when ((Block =:= true) orelse (Block =:= false)) -> + snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block); log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start) -> - snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start). + Block = ?ATL_BLOCK_DEFAULT, + snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start). + +-spec log_to_txt(LogDir :: snmp:dir(), + Mibs :: [snmp:mib_name()], + OutFile :: file:filename(), + LogName :: string(), + LogFile :: string(), + Block :: boolean(), + Start :: snmp_log:log_time()) -> + snmp:void(); + (LogDir :: snmp:dir(), + Mibs :: [snmp:mib_name()], + OutFile :: file:filename(), + LogName :: string(), + LogFile :: string(), + Start :: snmp_log:log_time(), + Stop :: snmp_log:log_time()) -> + snmp:void(). + +log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start) + when ((Block =:= true) orelse (Block =:= false)) -> + snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start); + log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop) -> - snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop). + Block = ?ATL_BLOCK_DEFAULT, + snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop). + +-spec log_to_txt(LogDir :: snmp:dir(), + Mibs :: [snmp:mib_name()], + OutFile :: file:filename(), + LogName :: string(), + LogFile :: string(), + Block :: boolean(), + Start :: snmp_log:log_time(), + Stop :: snmp_log:log_time()) -> + snmp:void(). + +log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop) -> + snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop). log_to_io(LogDir) -> log_to_io(LogDir, []). + +log_to_io(LogDir, Block) + when ((Block =:= true) orelse (Block =:= false)) -> + Mibs = [], + LogName = ?audit_trail_log_name, + LogFile = ?audit_trail_log_file, + snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block); log_to_io(LogDir, Mibs) -> + Block = ?ATL_BLOCK_DEFAULT, LogName = ?audit_trail_log_name, LogFile = ?audit_trail_log_file, - snmp:log_to_io(LogDir, Mibs, LogName, LogFile). + snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block). + +log_to_io(LogDir, Mibs, Block) + when ((Block =:= true) orelse (Block =:= false)) -> + LogName = ?audit_trail_log_name, + LogFile = ?audit_trail_log_file, + snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block); log_to_io(LogDir, Mibs, LogName) -> + Block = ?ATL_BLOCK_DEFAULT, + LogFile = ?audit_trail_log_file, + snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block). + +log_to_io(LogDir, Mibs, LogName, Block) + when ((Block =:= true) orelse (Block =:= false)) -> LogFile = ?audit_trail_log_file, - snmp:log_to_io(LogDir, Mibs, LogName, LogFile). + snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block); log_to_io(LogDir, Mibs, LogName, LogFile) -> - snmp:log_to_io(LogDir, Mibs, LogName, LogFile). + Block = ?ATL_BLOCK_DEFAULT, + snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block). + +log_to_io(LogDir, Mibs, LogName, LogFile, Block) + when ((Block =:= true) orelse (Block =:= false)) -> + snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block); log_to_io(LogDir, Mibs, LogName, LogFile, Start) -> - snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Start). + Block = ?ATL_BLOCK_DEFAULT, + snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start). + +log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start) + when ((Block =:= true) orelse (Block =:= false)) -> + snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start); log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop) -> - snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop). + Block = ?ATL_BLOCK_DEFAULT, + snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop). + +log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop) -> + snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop). log_info() -> diff --git a/lib/snmp/src/agent/snmpa_local_db.erl b/lib/snmp/src/agent/snmpa_local_db.erl index 5198c6ec4e..f991244287 100644 --- a/lib/snmp/src/agent/snmpa_local_db.erl +++ b/lib/snmp/src/agent/snmpa_local_db.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2012. All Rights Reserved. +%% Copyright Ericsson AB 1996-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -191,6 +191,12 @@ dets_open(DbDir, DbInitError, Opts) -> end end; _ -> + case DbInitError of + create_db_and_dir -> + ok = filelib:ensure_dir(Filename); + _ -> + ok + end, case do_dets_open(Name, Filename, Opts) of {ok, Dets} -> ?vdebug("dets open done",[]), diff --git a/lib/snmp/src/agent/snmpa_mpd.erl b/lib/snmp/src/agent/snmpa_mpd.erl index 2d37ea56f0..11ae806866 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-2012. All Rights Reserved. +%% Copyright Ericsson AB 1997-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -657,7 +657,7 @@ generate_response_msg(Vsn, RePdu, Type, ?SEC_USM -> snmpa_usm end, - SecEngineID = LocalEngineID, + SecEngineID = LocalEngineID, % 3.1.1a ?vtrace("generate_response_msg -> SecEngineID: ~w", [SecEngineID]), case (catch SecModule:generate_outgoing_msg(Message, SecEngineID, diff --git a/lib/snmp/src/agent/snmpa_supervisor.erl b/lib/snmp/src/agent/snmpa_supervisor.erl index aebcdbaa84..77ed54bee4 100644 --- a/lib/snmp/src/agent/snmpa_supervisor.erl +++ b/lib/snmp/src/agent/snmpa_supervisor.erl @@ -356,7 +356,7 @@ init([AgentType, Opts]) -> SymStoreSpec = worker_spec(snmpa_symbolic_store, SymStoreArgs, Restart, 2000), - LdbArgs = [Prio, DbDir, LdbOpts], + LdbArgs = [Prio, DbDir, DbInitError, LdbOpts], LocalDbSpec = worker_spec(snmpa_local_db, LdbArgs, Restart, 5000), diff --git a/lib/snmp/src/agent/snmpa_symbolic_store.erl b/lib/snmp/src/agent/snmpa_symbolic_store.erl index 00178f4bcd..a922d62ba8 100644 --- a/lib/snmp/src/agent/snmpa_symbolic_store.erl +++ b/lib/snmp/src/agent/snmpa_symbolic_store.erl @@ -642,10 +642,10 @@ code_change(_Vsn, S, _Extra) -> {ok, S}. -stop_backup_server(undefined) -> - ok; -stop_backup_server({Pid, _}) when is_pid(Pid) -> - exit(Pid, kill). +%% stop_backup_server(undefined) -> +%% ok; +%% stop_backup_server({Pid, _}) when is_pid(Pid) -> +%% exit(Pid, kill). diff --git a/lib/snmp/src/agent/snmpa_usm.erl b/lib/snmp/src/agent/snmpa_usm.erl index 6f54307f9f..719ea4e356 100644 --- a/lib/snmp/src/agent/snmpa_usm.erl +++ b/lib/snmp/src/agent/snmpa_usm.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2011. All Rights Reserved. +%% Copyright Ericsson AB 1999-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -16,6 +16,9 @@ %% %% %CopyrightEnd% %% +%% AES: RFC 3826 +%% + -module(snmpa_usm). %% Avoid warning for local function error/1 clashing with autoimported BIF. @@ -652,7 +655,10 @@ get_des_salt() -> [?i32(EngineBoots), ?i32(SaltInt)]. aes_encrypt(PrivKey, Data) -> - snmp_usm:aes_encrypt(PrivKey, Data, fun get_aes_salt/0). + EngineBoots = snmp_framework_mib:get_engine_boots(), + EngineTime = snmp_framework_mib:get_engine_time(), + snmp_usm:aes_encrypt(PrivKey, Data, fun get_aes_salt/0, + EngineBoots, EngineTime). aes_decrypt(PrivKey, UsmSecParams, EncData) -> #usmSecurityParameters{msgPrivacyParameters = PrivParams, diff --git a/lib/snmp/src/app/Makefile b/lib/snmp/src/app/Makefile index 716add8b9e..b8cc4b8754 100644 --- a/lib/snmp/src/app/Makefile +++ b/lib/snmp/src/app/Makefile @@ -2,7 +2,7 @@ # %CopyrightBegin% # -# Copyright Ericsson AB 2003-2012. All Rights Reserved. +# Copyright Ericsson AB 2003-2013. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -79,6 +79,8 @@ endif # FLAGS # ---------------------------------------------------- +ERL_COMPILE_FLAGS += -pa $(ERL_TOP)/lib/snmp/ebin + ifeq ($(WARN_UNUSED_VARS),true) ERL_COMPILE_FLAGS += +warn_unused_vars endif diff --git a/lib/snmp/src/app/snmp.appup.src b/lib/snmp/src/app/snmp.appup.src index 6edcf7e833..fa4b72ab68 100644 --- a/lib/snmp/src/app/snmp.appup.src +++ b/lib/snmp/src/app/snmp.appup.src @@ -27,26 +27,10 @@ %% {load_module, snmp_pdus, soft_purge, soft_purge, []} %% {update, snmpa_local_db, soft, soft_purge, soft_purge, []} %% {add_module, snmpm_net_if_mt} - [ - {"4.24.1", - [ - {load_module, snmpa, soft_purge, soft_purge, [snmpa_agent]}, - {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_agent]}, - {update, snmpa_mib, soft, soft_purge, soft_purge, []} - ] - }, - {"4.24", - [ - {load_module, snmp_conf, soft_purge, soft_purge, []}, - {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, - [snmp_conf]}, - {load_module, snmpa, soft_purge, soft_purge, [snmpa_agent]}, - {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, - {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_agent]}, - {update, snmpa_mib, soft, soft_purge, soft_purge, []} - ] - }, + {"4.24.2", [{restart_application, snmp}]}, + {"4.24.1", [{restart_application, snmp}]}, + {"4.24", [{restart_application, snmp}]}, {"4.23.1", [{restart_application, snmp}]}, {"4.23", [{restart_application, snmp}]} ], @@ -57,24 +41,9 @@ %% {remove, {snmpm_net_if_mt, soft_purge, soft_purge}} [ - {"4.24.1", - [ - {load_module, snmpa, soft_purge, soft_purge, [snmpa_agent]}, - {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_agent]}, - {update, snmpa_mib, soft, soft_purge, soft_purge, []} - ] - }, - {"4.24", - [ - {load_module, snmp_conf, soft_purge, soft_purge, []}, - {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, - [snmp_conf]}, - {load_module, snmpa, soft_purge, soft_purge, [snmpa_agent]}, - {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, - {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_agent]}, - {update, snmpa_mib, soft, soft_purge, soft_purge, []} - ] - }, + {"4.24.2", [{restart_application, snmp}]}, + {"4.24.1", [{restart_application, snmp}]}, + {"4.24", [{restart_application, snmp}]}, {"4.23.1", [{restart_application, snmp}]}, {"4.23", [{restart_application, snmp}]} ] diff --git a/lib/snmp/src/app/snmp.erl b/lib/snmp/src/app/snmp.erl index 1bb562654a..8b3a8af77d 100644 --- a/lib/snmp/src/app/snmp.erl +++ b/lib/snmp/src/app/snmp.erl @@ -49,8 +49,8 @@ read_mib/1, - log_to_txt/5, log_to_txt/6, log_to_txt/7, - log_to_io/4, log_to_io/5, log_to_io/6, + log_to_txt/5, log_to_txt/6, log_to_txt/7, log_to_txt/8, + log_to_io/4, log_to_io/5, log_to_io/6, log_to_io/7, change_log_size/2, octet_string_to_bits/1, bits_to_octet_string/1, @@ -91,7 +91,31 @@ ]). -export_type([ + dir/0, + snmp_timer/0, + + engine_id/0, + tdomain/0, + community/0, + mms/0, + version/0, + sec_model/0, + sec_name/0, + sec_level/0, + oid/0, + varbind/0, + ivarbind/0, + asn1_type/0, + table_info/0, + variable_info/0, + me/0, + trap/0, + notification/0, + pdu/0, + trappdu/0, + mib/0, + mib_name/0, void/0 ]). @@ -148,15 +172,42 @@ -define(APPLICATION, snmp). +-define(ATL_BLOCK_DEFAULT, true). +-include_lib("snmp/include/snmp_types.hrl"). %%----------------------------------------------------------------- %% Types %%----------------------------------------------------------------- --type oid() :: [non_neg_integer()]. --type void() :: term(). +-type dir() :: string(). +-type snmp_timer() :: #snmp_incr_timer{}. + +-type engine_id() :: string(). +-type tdomain() :: transportDomainUdpIpv4 | transportDomainUdpIpv6. +-type community() :: string(). +-type mms() :: non_neg_integer(). +-type version() :: v1 | v2 | v3. +-type sec_model() :: any | v1 | v2c | usm. +-type sec_name() :: string(). +-type sec_level() :: noAuthNoPriv | authNoPriv | authPriv. + +-type oid() :: [non_neg_integer()]. +-type varbind() :: #varbind{}. +-type ivarbind() :: #ivarbind{}. +-type asn1_type() :: #asn1_type{}. +-type table_info() :: #table_info{}. +-type variable_info() :: #variable_info{}. +-type me() :: #me{}. +-type trap() :: #trap{}. +-type notification() :: #notification{}. +-type mib() :: #mib{}. +-type mib_name() :: string(). +-type pdu() :: #pdu{}. +-type trappdu() :: #trappdu{}. + +-type void() :: term(). %%----------------------------------------------------------------- @@ -854,18 +905,60 @@ read_mib(FileName) -> %%%----------------------------------------------------------------- log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile) -> - snmp_log:log_to_txt(LogName, LogFile, LogDir, Mibs, OutFile). + Block = ?ATL_BLOCK_DEFAULT, + Start = null, + Stop = null, + log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop). + +log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block) + when ((Block =:= true) orelse (Block =:= false)) -> + Start = null, + Stop = null, + log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop); log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start) -> - snmp_log:log_to_txt(LogName, LogFile, LogDir, Mibs, OutFile, Start). + Block = ?ATL_BLOCK_DEFAULT, + Stop = null, + log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop). + +log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start) + when ((Block =:= true) orelse (Block =:= false)) -> + Stop = null, + log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop); log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop) -> - snmp_log:log_to_txt(LogName, LogFile, LogDir, Mibs, OutFile, Start, Stop). + Block = ?ATL_BLOCK_DEFAULT, + log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop). + +log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop) -> + snmp_log:log_to_txt(LogName, Block, LogFile, LogDir, Mibs, OutFile, + Start, Stop). + log_to_io(LogDir, Mibs, LogName, LogFile) -> - snmp_log:log_to_io(LogName, LogFile, LogDir, Mibs). + Block = ?ATL_BLOCK_DEFAULT, + Start = null, + Stop = null, + log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop). + +log_to_io(LogDir, Mibs, LogName, LogFile, Block) + when ((Block =:= true) orelse (Block =:= false)) -> + Start = null, + Stop = null, + log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop); log_to_io(LogDir, Mibs, LogName, LogFile, Start) -> - snmp_log:log_to_io(LogName, LogFile, LogDir, Mibs, Start). + Block = ?ATL_BLOCK_DEFAULT, + Stop = null, + log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop). + +log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start) + when ((Block =:= true) orelse (Block =:= false)) -> + Stop = null, + log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop); log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop) -> - snmp_log:log_to_io(LogName, LogFile, LogDir, Mibs, Start, Stop). + Block = ?ATL_BLOCK_DEFAULT, + log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop). + +log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop) -> + snmp_log:log_to_io(LogName, Block, LogFile, LogDir, Mibs, Start, Stop). change_log_size(LogName, NewSize) -> snmp_log:change_size(LogName, NewSize). @@ -878,12 +971,12 @@ change_log_size(LogName, NewSize) -> %% Usage: erl -s snmp str_apply '{Mod,Func,ArgList}' str_apply([Atom]) -> Str = atom_to_list(Atom), - {Mod,Func,Args} = to_erlang_term(Str), - apply(Mod,Func,Args). + {Mod, Func, Args} = to_erlang_term(Str), + apply(Mod, Func, Args). to_erlang_term(String) -> {ok, Tokens, _} = erl_scan:string(lists:append([String, ". "])), - {ok,Term} = erl_parse:parse_term(Tokens), + {ok, Term} = erl_parse:parse_term(Tokens), Term. diff --git a/lib/snmp/src/app/snmp_internal.hrl b/lib/snmp/src/app/snmp_internal.hrl index 5ff715e0b7..f04fa4dd53 100644 --- a/lib/snmp/src/app/snmp_internal.hrl +++ b/lib/snmp/src/app/snmp_internal.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2009. All Rights Reserved. +%% Copyright Ericsson AB 2006-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -24,6 +24,8 @@ -define(APPLICATION, snmp). -endif. +-define(STACK(), erlang:get_stacktrace()). + -define(snmp_info(C, F, A), ?snmp_msg(info_msg, C, F, A)). -define(snmp_warning(C, F, A), ?snmp_msg(warning_msg, C, F, A)). -define(snmp_error(C, F, A), ?snmp_msg(error_msg, C, F, A)). diff --git a/lib/snmp/src/manager/snmpm.erl b/lib/snmp/src/manager/snmpm.erl index 6ac0115dad..c97b635fc6 100644 --- a/lib/snmp/src/manager/snmpm.erl +++ b/lib/snmp/src/manager/snmpm.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2012. All Rights Reserved. +%% Copyright Ericsson AB 2004-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -75,11 +75,10 @@ %% %% Logging - log_to_txt/1, - log_to_txt/2, log_to_txt/3, log_to_txt/4, - log_to_txt/5, log_to_txt/6, log_to_txt/7, - log_to_io/1, log_to_io/2, log_to_io/3, - log_to_io/4, log_to_io/5, log_to_io/6, + log_to_txt/1, log_to_txt/2, log_to_txt/3, log_to_txt/4, + log_to_txt/5, log_to_txt/6, log_to_txt/7, log_to_txt/8, + log_to_io/1, log_to_io/2, log_to_io/3, log_to_io/4, + log_to_io/5, log_to_io/6, log_to_io/7, change_log_size/1, get_log_type/0, set_log_type/1, @@ -111,6 +110,12 @@ -export([start_link/3, snmpm_start_verify/2, snmpm_start_verify/3]). -export([target_name/1, target_name/2]). +-export_type([ + register_timeout/0, + agent_config/0, + target_name/0 + ]). + -include_lib("snmp/src/misc/snmp_debug.hrl"). -include_lib("snmp/include/snmp_types.hrl"). @@ -119,6 +124,26 @@ -include("snmp_verbosity.hrl"). -define(DEFAULT_AGENT_PORT, 161). +-define(ATL_BLOCK_DEFAULT, true). + + +%%----------------------------------------------------------------- +%% Types +%%----------------------------------------------------------------- + +-type register_timeout() :: pos_integer() | snmp:snmp_timer(). +-type agent_config() :: {engine_id, snmp:engine_id()} | % Mandatory + {address, inet:ip_address()} | % Mandatory + {port, inet:port_number()} | % Optional + {tdomain, snmp:tdomain()} | % Optional + {community, snmp:community()} | % Optional + {timeout, register_timeout()} | % Optional + {max_message_size, snmp:mms()} | % Optional + {version, snmp:version()} | % Optional + {sec_moduel, snmp:sec_model()} | % Optional + {sec_name, snmp:sec_name()} | % Optional + {sec_level, snmp:sec_level()}. % Optional +-type target_name() :: string(). %% This function is called when the snmp application @@ -762,43 +787,204 @@ cancel_async_request(UserId, ReqId) -> %%% Audit Trail Log functions (for backward compatibility) %%%----------------------------------------------------------------- +-spec log_to_txt(LogDir :: snmp:dir()) -> + snmp:void(). + log_to_txt(LogDir) -> log_to_txt(LogDir, []). + +-spec log_to_txt(LogDir :: snmp:dir(), + Block :: boolean()) -> + snmp:void(); + (LogDir :: snmp:dir(), + Mibs :: [snmp:mib_name()]) -> + snmp:void(). + +log_to_txt(LogDir, Block) + when ((Block =:= true) orelse (Block =:= false)) -> + Mibs = [], + OutFile = "snmpm_log.txt", + LogName = ?audit_trail_log_name, + LogFile = ?audit_trail_log_file, + snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block); log_to_txt(LogDir, Mibs) -> + Block = ?ATL_BLOCK_DEFAULT, + OutFile = "snmpm_log.txt", + LogName = ?audit_trail_log_name, + LogFile = ?audit_trail_log_file, + snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block). + +-spec log_to_txt(LogDir :: snmp:dir(), + Mibs :: [snmp:mib_name()], + Block :: boolean()) -> + snmp:void(); + (LogDir :: snmp:dir(), + Mibs :: [snmp:mib_name()], + OutFile :: file:filename()) -> + snmp:void(). + +log_to_txt(LogDir, Mibs, Block) + when ((Block =:= true) orelse (Block =:= false)) -> OutFile = "snmpm_log.txt", LogName = ?audit_trail_log_name, LogFile = ?audit_trail_log_file, - snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile). + snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block); log_to_txt(LogDir, Mibs, OutFile) -> + Block = ?ATL_BLOCK_DEFAULT, + LogName = ?audit_trail_log_name, + LogFile = ?audit_trail_log_file, + snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block). + +-spec log_to_txt(LogDir :: snmp:dir(), + Mibs :: [snmp:mib_name()], + OutFile :: file:filename(), + Block :: boolean()) -> + snmp:void(); + (LogDir :: snmp:dir(), + Mibs :: [snmp:mib_name()], + OutFile :: file:filename(), + LogName :: string()) -> + snmp:void(). + +log_to_txt(LogDir, Mibs, OutFile, Block) + when ((Block =:= true) orelse (Block =:= false)) -> LogName = ?audit_trail_log_name, LogFile = ?audit_trail_log_file, - snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile). + snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block); log_to_txt(LogDir, Mibs, OutFile, LogName) -> + Block = ?ATL_BLOCK_DEFAULT, + LogFile = ?audit_trail_log_file, + snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block). + +-spec log_to_txt(LogDir :: snmp:dir(), + Mibs :: [snmp:mib_name()], + OutFile :: file:filename(), + LogName :: string(), + Block :: boolean()) -> + snmp:void(); + (LogDir :: snmp:dir(), + Mibs :: [snmp:mib_name()], + OutFile :: file:filename(), + LogName :: string(), + LogFile :: string()) -> + snmp:void(). + +log_to_txt(LogDir, Mibs, OutFile, LogName, Block) + when ((Block =:= true) orelse (Block =:= false)) -> LogFile = ?audit_trail_log_file, - snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile). + snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block); log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile) -> - snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile). + Block = ?ATL_BLOCK_DEFAULT, + snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block). + +-spec log_to_txt(LogDir :: snmp:dir(), + Mibs :: [snmp:mib_name()], + OutFile :: file:filename(), + LogName :: string(), + LogFile :: string(), + Block :: boolean()) -> + snmp:void(); + (LogDir :: snmp:dir(), + Mibs :: [snmp:mib_name()], + OutFile :: file:filename(), + LogName :: string(), + LogFile :: string(), + Start :: snmp_log:log_time()) -> + snmp:void(). + +log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block) + when ((Block =:= true) orelse (Block =:= false)) -> + snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block); log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start) -> - snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start). + Block = ?ATL_BLOCK_DEFAULT, + snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start). + +-spec log_to_txt(LogDir :: snmp:dir(), + Mibs :: [snmp:mib_name()], + OutFile :: file:filename(), + LogName :: string(), + LogFile :: string(), + Block :: boolean(), + Start :: snmp_log:log_time()) -> + snmp:void(); + (LogDir :: snmp:dir(), + Mibs :: [snmp:mib_name()], + OutFile :: file:filename(), + LogName :: string(), + LogFile :: string(), + Start :: snmp_log:log_time(), + Stop :: snmp_log:log_time()) -> + snmp:void(). + +log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start) + when ((Block =:= true) orelse (Block =:= false)) -> + snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start); log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop) -> - snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop). + Block = ?ATL_BLOCK_DEFAULT, + snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop). + +-spec log_to_txt(LogDir :: snmp:dir(), + Mibs :: [snmp:mib_name()], + OutFile :: file:filename(), + LogName :: string(), + LogFile :: string(), + Block :: boolean(), + Start :: snmp_log:log_time(), + Stop :: snmp_log:log_time()) -> + snmp:void(). + +log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop) -> + snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop). log_to_io(LogDir) -> log_to_io(LogDir, []). + +log_to_io(LogDir, Block) + when ((Block =:= true) orelse (Block =:= false)) -> + Mibs = [], + LogName = ?audit_trail_log_name, + LogFile = ?audit_trail_log_file, + snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block); log_to_io(LogDir, Mibs) -> LogName = ?audit_trail_log_name, LogFile = ?audit_trail_log_file, snmp:log_to_io(LogDir, Mibs, LogName, LogFile). + +log_to_io(LogDir, Mibs, Block) + when ((Block =:= true) orelse (Block =:= false)) -> + LogName = ?audit_trail_log_name, + LogFile = ?audit_trail_log_file, + snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block); log_to_io(LogDir, Mibs, LogName) -> + Block = ?ATL_BLOCK_DEFAULT, LogFile = ?audit_trail_log_file, - snmp:log_to_io(LogDir, Mibs, LogName, LogFile). + snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block). + +log_to_io(LogDir, Mibs, LogName, Block) + when ((Block =:= true) orelse (Block =:= false)) -> + LogFile = ?audit_trail_log_file, + snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block); log_to_io(LogDir, Mibs, LogName, LogFile) -> - snmp:log_to_io(LogDir, Mibs, LogName, LogFile). + Block = ?ATL_BLOCK_DEFAULT, + snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block). + +log_to_io(LogDir, Mibs, LogName, LogFile, Block) + when ((Block =:= true) orelse (Block =:= false)) -> + snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block); log_to_io(LogDir, Mibs, LogName, LogFile, Start) -> - snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Start). + Block = ?ATL_BLOCK_DEFAULT, + snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start). + +log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start) + when ((Block =:= true) orelse (Block =:= false)) -> + snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start); log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop) -> - snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop). + Block = ?ATL_BLOCK_DEFAULT, + snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop). + +log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop) -> + snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop). change_log_size(NewSize) -> diff --git a/lib/snmp/src/manager/snmpm_config.erl b/lib/snmp/src/manager/snmpm_config.erl index 736debe544..2101ad46e1 100644 --- a/lib/snmp/src/manager/snmpm_config.erl +++ b/lib/snmp/src/manager/snmpm_config.erl @@ -1215,6 +1215,12 @@ dets_open(Dir, DbInitError, Repair, AutoSave) -> end end; _ -> + case DbInitError of + create_db_and_dir -> + ok = filelib:ensure_dir(Filename); + _ -> + ok + end, case do_dets_open(Name, Filename, Repair, AutoSave) of {ok, _Dets} -> ok; @@ -1316,7 +1322,14 @@ verify_option({server, ServerOpts}) -> verify_server_opts(ServerOpts); verify_option({note_store, NoteStoreOpts}) -> verify_note_store_opts(NoteStoreOpts); -verify_option({config, ConfOpts}) -> +verify_option({config, ConfOpts0}) -> + %% Make sure any db_dir option is first in the options list to make it + %% easier to check if the db_init_error option specifies that a missing + %% db_dir should be created. + ConfOpts = case lists:keytake(db_dir, 1, ConfOpts0) of + false -> ConfOpts0; + {value, Result, OtherOpts} -> [Result|OtherOpts] + end, verify_config_opts(ConfOpts); verify_option({versions, Vsns}) -> verify_versions(Vsns); @@ -1365,7 +1378,12 @@ verify_config_opts([{dir, Dir}|Opts]) -> verify_conf_dir(Dir), verify_config_opts(Opts); verify_config_opts([{db_dir, Dir}|Opts]) -> - verify_conf_db_dir(Dir), + case lists:keyfind(db_init_error, 1, Opts) of + {db_init_error, create_db_and_dir} -> + verify_conf_db_dir(Dir, false); + _ -> + verify_conf_db_dir(Dir, true) + end, verify_config_opts(Opts); verify_config_opts([{db_init_error, DbInitErr}|Opts]) -> verify_conf_db_init_error(DbInitErr), @@ -1443,7 +1461,7 @@ verify_conf_dir(Dir) -> error({invalid_conf_dir, Dir}) end. -verify_conf_db_dir(Dir) -> +verify_conf_db_dir(Dir, true) -> case (catch verify_dir(Dir)) of ok -> ok; @@ -1451,13 +1469,16 @@ verify_conf_db_dir(Dir) -> error({invalid_conf_db_dir, Dir, Reason}); _ -> error({invalid_conf_db_dir, Dir}) - end. - + end; +verify_conf_db_dir(_Dir, false) -> + ok. verify_conf_db_init_error(terminate) -> ok; verify_conf_db_init_error(create) -> ok; +verify_conf_db_init_error(create_db_and_dir) -> + ok; verify_conf_db_init_error(InvalidDbInitError) -> error({invalid_conf_db_init_error, InvalidDbInitError}). diff --git a/lib/snmp/src/manager/snmpm_server.erl b/lib/snmp/src/manager/snmpm_server.erl index 61d22362cc..9c79df2748 100644 --- a/lib/snmp/src/manager/snmpm_server.erl +++ b/lib/snmp/src/manager/snmpm_server.erl @@ -488,7 +488,7 @@ cancel_async_request(UserId, ReqId) -> %% discovery(UserId, BAddr, Port, Config, Expire, ExtraInfo) -> %% call({discovery, self(), UserId, BAddr, Port, Config, Expire, ExtraInfo}). - + verbosity(Verbosity) -> case ?vvalidate(Verbosity) of Verbosity -> @@ -1851,7 +1851,17 @@ handle_snmp_error(Addr, Port, ReqId, Reason, State) -> handle_error(_UserId, Mod, Reason, ReqId, Data, _State) -> ?vtrace("handle_error -> entry when" "~n Mod: ~p", [Mod]), - F = fun() -> (catch Mod:handle_error(ReqId, Reason, Data)) end, + F = fun() -> + try + begin + Mod:handle_error(ReqId, Reason, Data) + end + catch + T:E -> + CallbackArgs = [ReqId, Reason, Data], + handle_invalid_result(handle_error, CallbackArgs, T, E) + end + end, handle_callback(F), ok. @@ -2031,7 +2041,15 @@ handle_pdu(_UserId, Mod, target_name = _RegType, TargetName, _Addr, _Port, ?vtrace("handle_pdu(target_name) -> entry when" "~n Mod: ~p", [Mod]), F = fun() -> - (catch Mod:handle_pdu(TargetName, ReqId, SnmpResponse, Data)) + try + begin + Mod:handle_pdu(TargetName, ReqId, SnmpResponse, Data) + end + catch + T:E -> + CallbackArgs = [TargetName, ReqId, SnmpResponse, Data], + handle_invalid_result(handle_pdu, CallbackArgs, T, E) + end end, handle_callback(F), ok; @@ -2064,8 +2082,37 @@ do_handle_agent(DefUserId, DefMod, SnmpInfo, DefData, State) -> ?vdebug("do_handle_agent -> entry when" "~n DefUserId: ~p", [DefUserId]), - case (catch DefMod:handle_agent(Addr, Port, Type, SnmpInfo, DefData)) of - {'EXIT', {undef, _}} when Type =:= pdu -> + try DefMod:handle_agent(Addr, Port, Type, SnmpInfo, DefData) of + {register, UserId2, TargetName, Config} -> + ?vtrace("do_handle_agent -> register: " + "~n UserId2: ~p" + "~n TargetName: ~p" + "~n Config: ~p", + [UserId2, TargetName, Config]), + Config2 = ensure_present([{address, Addr}, {port, Port}], Config), + Config3 = [{reg_type, target_name} | Config2], + case snmpm_config:register_agent(UserId2, + TargetName, Config3) of + ok -> + ok; + {error, Reason} -> + error_msg("failed registering agent - " + "handling agent " + "~p <~p,~p>: ~n~w", + [TargetName, Addr, Port, Reason]), + ok + end; + + ignore -> + ?vdebug("do_handle_agent -> ignore", []), + ok; + + InvalidResult -> + CallbackArgs = [Addr, Port, Type, SnmpInfo, DefData], + handle_invalid_result(handle_agent, CallbackArgs, InvalidResult) + + catch + error:{undef, _} when Type =:= pdu -> %% Maybe, still on the old API ?vdebug("do_handle_agent -> maybe still on the old api", []), case (catch DefMod:handle_agent(Addr, Port, SnmpInfo, DefData)) of @@ -2113,10 +2160,10 @@ do_handle_agent(DefUserId, DefMod, ok end; - {'EXIT', {undef, _}} -> + error:{undef, _} -> %% If the user does not implement the new API (but the %% old), then this clause catches all non-pdu handle_agent - %% calls. These calls was previously never made,so we make + %% calls. These calls was previously never made, so we make %% a best-effert call (using reg-type target_name) to the %% various callback functions, and leave it to the user to %% figure out @@ -2148,31 +2195,11 @@ do_handle_agent(DefUserId, DefMod, "regarding agent " "<~p,~p>: ~n~w", [Type, Addr, Port, SnmpInfo]) end; - - {register, UserId2, TargetName, Config} -> - ?vtrace("do_handle_agent -> register: " - "~n UserId2: ~p" - "~n TargetName: ~p" - "~n Config: ~p", - [UserId2, TargetName, Config]), - Config2 = ensure_present([{address, Addr}, {port, Port}], Config), - Config3 = [{reg_type, target_name} | Config2], - case snmpm_config:register_agent(UserId2, - TargetName, Config3) of - ok -> - ok; - {error, Reason} -> - error_msg("failed registering agent - " - "handling agent " - "~p <~p,~p>: ~n~w", - [TargetName, Addr, Port, Reason]), - ok - end; - _Ignore -> - ?vdebug("do_handle_agent -> ignore", []), - ok - + T:E -> + CallbackArgs = [Addr, Port, Type, SnmpInfo, DefData], + handle_invalid_result(handle_agent, CallbackArgs, T, E) + end. ensure_present([], Config) -> @@ -2305,15 +2332,17 @@ do_handle_trap(UserId, Mod, RegType, Target, Addr, Port, SnmpTrapInfo, Data, _State) -> ?vdebug("do_handle_trap -> entry with" "~n UserId: ~p", [UserId]), - HandleTrap = + {HandleTrap, CallbackArgs} = case RegType of target_name -> - fun() -> Mod:handle_trap(Target, SnmpTrapInfo, Data) end; + {fun() -> Mod:handle_trap(Target, SnmpTrapInfo, Data) end, + [Target, SnmpTrapInfo, Data]}; addr_port -> - fun() -> Mod:handle_trap(Addr, Port, SnmpTrapInfo, Data) end + {fun() -> Mod:handle_trap(Addr, Port, SnmpTrapInfo, Data) end, + [Addr, Port, SnmpTrapInfo, Data]} end, - case (catch HandleTrap()) of + try HandleTrap() of {register, UserId2, Config} -> ?vtrace("do_handle_trap -> register: " "~n UserId2: ~p" @@ -2362,9 +2391,17 @@ do_handle_trap(UserId, Mod, [Addr, Port, Reason]), ok end; - _Ignore -> + ignore -> ?vtrace("do_handle_trap -> ignore", []), - ok + ok; + + InvalidResult -> + handle_invalid_result(handle_trap, CallbackArgs, InvalidResult) + + catch + T:E -> + handle_invalid_result(handle_trap, CallbackArgs, T, E) + end. @@ -2465,16 +2502,18 @@ do_handle_inform(UserId, Mod, Ref, RegType, Target, Addr, Port, SnmpInform, Data, State) -> ?vdebug("do_handle_inform -> entry with" "~n UserId: ~p", [UserId]), - HandleInform = + {HandleInform, CallbackArgs} = case RegType of target_name -> - fun() -> Mod:handle_inform(Target, SnmpInform, Data) end; + {fun() -> Mod:handle_inform(Target, SnmpInform, Data) end, + [Target, SnmpInform, Data]}; addr_port -> - fun() -> Mod:handle_inform(Addr, Port, SnmpInform, Data) end + {fun() -> Mod:handle_inform(Addr, Port, SnmpInform, Data) end, + [Addr, Port, SnmpInform, Data]} end, Rep = - case (catch HandleInform()) of + try HandleInform() of {register, UserId2, Config} -> ?vtrace("do_handle_inform -> register: " "~n UserId2: ~p" @@ -2494,6 +2533,7 @@ do_handle_inform(UserId, Mod, Ref, [Target2, Addr, Port, Reason]), reply end; + {register, UserId2, Target2, Config} -> ?vtrace("do_handle_inform -> register: " "~n UserId2: ~p" @@ -2512,6 +2552,7 @@ do_handle_inform(UserId, Mod, Ref, [Target2, Addr, Port, Reason]), reply end; + unregister -> ?vtrace("do_handle_inform -> unregister", []), case snmpm_config:unregister_agent(UserId, @@ -2525,12 +2566,25 @@ do_handle_inform(UserId, Mod, Ref, [Addr, Port, Reason]), reply end; + no_reply -> ?vtrace("do_handle_inform -> no_reply", []), no_reply; - _Ignore -> + + ignore -> ?vtrace("do_handle_inform -> ignore", []), + reply; + + InvalidResult -> + handle_invalid_result(handle_inform, CallbackArgs, + InvalidResult), reply + + catch + T:E -> + handle_invalid_result(handle_inform, CallbackArgs, T, E), + reply + end, handle_inform_response(Rep, Ref, Addr, Port, State), ok. @@ -2760,15 +2814,17 @@ do_handle_report(UserId, Mod, RegType, Target, Addr, Port, SnmpReport, Data, _State) -> ?vdebug("do_handle_report -> entry with" "~n UserId: ~p", [UserId]), - HandleReport = + {HandleReport, CallbackArgs} = case RegType of target_name -> - fun() -> Mod:handle_report(Target, SnmpReport, Data) end; + {fun() -> Mod:handle_report(Target, SnmpReport, Data) end, + [Target, SnmpReport, Data]}; addr_port -> - fun() -> Mod:handle_report(Addr, Port, SnmpReport, Data) end + {fun() -> Mod:handle_report(Addr, Port, SnmpReport, Data) end, + [Addr, Port, SnmpReport, Data]} end, - case (catch HandleReport()) of + try HandleReport() of {register, UserId2, Config} -> ?vtrace("do_handle_report -> register: " "~n UserId2: ~p" @@ -2788,6 +2844,7 @@ do_handle_report(UserId, Mod, [Addr, Port, Reason]), ok end; + {register, UserId2, Target2, Config} -> ?vtrace("do_handle_report -> register: " "~n UserId2: ~p" @@ -2806,6 +2863,7 @@ do_handle_report(UserId, Mod, [Target2, Addr, Port, Reason]), reply end; + unregister -> ?vtrace("do_handle_trap -> unregister", []), case snmpm_config:unregister_agent(UserId, @@ -2819,9 +2877,20 @@ do_handle_report(UserId, Mod, [Addr, Port, Reason]), ok end; - _Ignore -> + + ignore -> ?vtrace("do_handle_report -> ignore", []), - ok + ok; + + InvalidResult -> + handle_invalid_result(handle_report, CallbackArgs, InvalidResult), + reply + + catch + T:E -> + handle_invalid_result(handle_report, CallbackArgs, T, E), + reply + end. @@ -2835,6 +2904,25 @@ handle_callback(F) -> end). + +handle_invalid_result(Func, Args, T, E) -> + Stacktrace = ?STACK(), + error_msg("Callback function failed: " + "~n Function: ~p" + "~n Args: ~p" + "~n Error Type: ~p" + "~n Error: ~p" + "~n Stacktrace: ~p", + [Func, Args, T, E, Stacktrace]). + +handle_invalid_result(Func, Args, InvalidResult) -> + error_msg("Callback function returned invalid result: " + "~n Function: ~p" + "~n Args: ~p" + "~n Invalid result: ~p", + [Func, Args, InvalidResult]). + + handle_down(MonRef) -> (catch do_handle_down(MonRef)). diff --git a/lib/snmp/src/manager/snmpm_user.erl b/lib/snmp/src/manager/snmpm_user.erl index 78aa560b2e..e6b0b6943e 100644 --- a/lib/snmp/src/manager/snmpm_user.erl +++ b/lib/snmp/src/manager/snmpm_user.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2009. All Rights Reserved. +%% Copyright Ericsson AB 2004-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -19,79 +19,100 @@ -module(snmpm_user). --export([behaviour_info/1]). - -behaviour_info(callbacks) -> - [{handle_error, 3}, - {handle_agent, 5}, - {handle_pdu, 4}, - {handle_trap, 3}, - {handle_inform, 3}, - {handle_report, 3}]; -behaviour_info(_) -> - undefined. - - -%% handle_error(ReqId, Reason, UserData) -> Reply -%% ReqId -> integer() -%% Reason -> term() -%% UserData -> term() (supplied when the user register) -%% Reply -> ignore - -%% handle_agent(Addr, Port, Type, SnmpInfo, UserData) -> Reply -%% Addr -> term() -%% Port -> integer() -%% Type -> pdu | trap | inform | report -%% SnmpInfo -> {ErrorStatus, ErrorIndex, Varbinds} -%% UserId -> term() -%% ErrorStatus -> atom() -%% ErrorIndex -> integer() -%% Varbinds -> [varbind()] -%% UserData -> term() (supplied when the user register) -%% Reply -> ignore | {register, UserId, agent_info()} -%% agent_info() -> [{agent_info_item(), agent_info_value()}] -%% This is the same info as in update_agent_info/4 - -%% handle_pdu(TargetName, ReqId, SnmpResponse, UserData) -> Reply -%% TargetName -> target_name() -%% ReqId -> term() (returned when calling ag(...), ...) -%% SnmpResponse -> {ErrorStatus, ErrorIndex, Varbinds} -%% ErrorStatus -> atom() -%% ErrorIndex -> integer() -%% Varbinds -> [varbind()] -%% UserData -> term() (supplied when the user register) -%% Reply -> ignore - -%% handle_trap(TargetName, SnmpTrapInfo, UserData) -> Reply -%% TargetName -> target_name() -%% SnmpTrapInfo -> {Enteprise, Generic, Spec, Timestamp, Varbinds} | -%% {ErrorStatus, ErrorIndex, Varbinds} -%% Enteprise -> oid() -%% Generic -> integer() -%% Spec -> integer() -%% Timestamp -> integer() -%% ErrorStatus -> atom() -%% ErrorIndex -> integer() -%% Varbinds -> [varbind()] -%% UserData -> term() (supplied when the user register) -%% Reply -> ignore | unregister | {register, UserId, agent_info()} - -%% handle_inform(TargetName, SnmpInform, UserData) -> Reply -%% TargetName -> target_name() -%% SnmpInform -> {ErrorStatus, ErrorIndex, Varbinds} -%% ErrorStatus -> atom() -%% ErrorIndex -> integer() -%% Varbinds -> [varbind()] -%% UserData -> term() (supplied when the user register) -%% Reply -> ignore | unregister | {register, UserId, agent_info()} -%% - -%% handle_report(TargetName, SnmpReport, UserData) -> Reply -%% TargetName -> target_name() -%% SnmpReport -> {ErrorStatus, ErrorIndex, Varbinds} -%% ErrorStatus -> integer() -%% ErrorIndex -> integer() -%% Varbinds -> [varbind()] -%% UserData -> term() (supplied when the user register) -%% Reply -> ignore | unregister | {register, UserId, agent_info()} +-export_type([ + snmp_gen_info/0, + snmp_v1_trap_info/0 + ]). + +-type snmp_gen_info() :: {ErrorStatus :: atom(), + ErrorIndex :: pos_integer(), + Varbinds :: [snmp:varbind()]}. +-type snmp_v1_trap_info() :: {Enteprise :: snmp:oid(), + Generic :: integer(), + Spec :: integer(), + Timestamp :: integer(), + Varbinds :: [snmp:varbind()]}. +-type ip_address() :: inet:ip_address(). +-type port_number() :: inet:port_number(). + + +%% *** handle_error *** +%% An "asynchronous" error has been detected + +-callback handle_error(ReqId :: integer(), + Reason :: {unexpected_pdu, SnmpInfo :: snmp_gen_info()} | + {invalid_sec_info, SecInfo :: term(), SnmpInfo :: snmp_gen_info()} | + {empty_message, Addr :: ip_address(), Port :: port_number()} | + term(), + UserData :: term()) -> + snmp:void(). + + +%% *** handle_agent *** +%% A message was received from an unknown agent + +-callback handle_agent(Addr :: term(), + Port :: pos_integer(), + Type :: pdu | trap | inform | report, + SnmpInfo :: snmp_gen_info() | snmp_v1_trap_info(), + UserData :: term()) -> + Reply :: ignore | + {register, + UserId :: term(), + RTargetName :: snmpm:target_name(), + AgentConfig :: [snmpm:agent_config()]}. + + +%% *** handle_pdu *** +%% Handle the reply to an async request (such as get, get-next and set). + +-callback handle_pdu(TargetName :: snmpm:target_name(), + ReqId :: term(), + SnmpResponse :: snmp_gen_info(), + UserData :: term()) -> + snmp:void(). + + +%% *** handle_trap *** +%% Handle a trap/notification message received from an agent + +-callback handle_trap(TargetName :: snmpm:target_name(), + SnmpTrapInfo :: snmp_gen_info() | snmp_v1_trap_info(), + UserData :: term()) -> + Reply :: ignore | + unregister | + {register, + UserId :: term(), + RTargetName :: snmpm:target_name(), + AgentConfig :: [snmpm:agent_config()]}. + + +%% *** handle_inform *** +%% Handle a inform message received from an agent + +-callback handle_inform(TargetName :: snmpm:target_name(), + SnmpInform :: snmp_gen_info(), + UserData :: term()) -> + Reply :: ignore | no_reply | + unregister | + {register, + UserId :: term(), + RTargetName :: snmpm:target_name(), + AgentConfig :: [snmpm:agent_config()]}. + + +%% *** handle_report *** +%% Handle a report message received from an agent + +-callback handle_report(TargetName :: snmpm:target_name(), + SnmpReport :: snmp_gen_info(), + UserData :: term()) -> + Reply :: ignore | + unregister | + {register, + UserId :: term(), + RTargetName :: snmpm:target_name(), + AgentConfig :: [snmpm:agent_config()]}. + + diff --git a/lib/snmp/src/manager/snmpm_usm.erl b/lib/snmp/src/manager/snmpm_usm.erl index 497d6d6102..0a8a6436a3 100644 --- a/lib/snmp/src/manager/snmpm_usm.erl +++ b/lib/snmp/src/manager/snmpm_usm.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2011. All Rights Reserved. +%% Copyright Ericsson AB 2004-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -19,6 +19,9 @@ %%----------------------------------------------------------------- %% This module implements the User Based Security Model for SNMP, %% as defined in rfc2274. +%% +%% AES: RFC 3826 +%% %%----------------------------------------------------------------- -module(snmpm_usm). @@ -416,11 +419,14 @@ get_des_salt() -> [?i32(EngineBoots), ?i32(SaltInt)]. aes_encrypt(PrivKey, Data) -> - snmp_usm:aes_encrypt(PrivKey, Data, fun get_aes_salt/0). + EngineBoots = get_engine_boots(), + EngineTime = get_engine_time(), + snmp_usm:aes_encrypt(PrivKey, Data, fun get_aes_salt/0, + EngineBoots, EngineTime). aes_decrypt(PrivKey, UsmSecParams, EncData) -> - #usmSecurityParameters{msgPrivacyParameters = MsgPrivParams, - msgAuthoritativeEngineTime = EngineTime, + #usmSecurityParameters{msgPrivacyParameters = MsgPrivParams, + msgAuthoritativeEngineTime = EngineTime, msgAuthoritativeEngineBoots = EngineBoots} = UsmSecParams, snmp_usm:aes_decrypt(PrivKey, MsgPrivParams, EncData, diff --git a/lib/snmp/src/misc/snmp_config.erl b/lib/snmp/src/misc/snmp_config.erl index 945b8719fc..a222f842e5 100644 --- a/lib/snmp/src/misc/snmp_config.erl +++ b/lib/snmp/src/misc/snmp_config.erl @@ -233,16 +233,18 @@ config_agent_sys() -> fun verify_verbosity/1), DbDir = ask("5. Database directory (absolute path)?", DefDir, fun verify_dir/1), - MibStorageType = ask("6. Mib storage type (ets/dets/mnesia)?", "ets", + DbInitError = ask("6. How to handle DB init error?", + "terminate", fun verify_db_init_error/1), + MibStorageType = ask("7. Mib storage type (ets/dets/mnesia)?", "ets", fun verify_mib_storage_type/1), MibStorage = case MibStorageType of ets -> [{module, snmpa_mib_storage_ets}]; dets -> - DetsDir = ask("6b. Mib storage directory (absolute path)?", + DetsDir = ask("7b. Mib storage directory (absolute path)?", DbDir, fun verify_dir/1), - DetsAction = ask("6c. Mib storage [dets] database start " + DetsAction = ask("7c. Mib storage [dets] database start " "action " "(default/clear/keep)?", "default", fun verify_mib_storage_action/1), @@ -257,7 +259,7 @@ config_agent_sys() -> end; mnesia -> Nodes = [], - MnesiaAction = ask("6b. Mib storage [mnesia] database start " + MnesiaAction = ask("7b. Mib storage [mnesia] database start " "action " "(default/clear/keep)?", "default", fun verify_mib_storage_action/1), @@ -275,80 +277,80 @@ config_agent_sys() -> %% Here we should ask about mib-server data module, %% but as we only have one at the moment... - TargetCacheVerb = ask("7. Target cache verbosity " + TargetCacheVerb = ask("8. Target cache verbosity " "(silence/info/log/debug/trace)?", "silence", fun verify_verbosity/1), - SymStoreVerb = ask("8. Symbolic store verbosity " + SymStoreVerb = ask("9. Symbolic store verbosity " "(silence/info/log/debug/trace)?", "silence", fun verify_verbosity/1), - LocalDbVerb = ask("9. Local DB verbosity " + LocalDbVerb = ask("10. Local DB verbosity " "(silence/info/log/debug/trace)?", "silence", fun verify_verbosity/1), - LocalDbRepair = ask("10. Local DB repair (true/false/force)?", "true", + LocalDbRepair = ask("11. Local DB repair (true/false/force)?", "true", fun verify_dets_repair/1), - LocalDbAutoSave = ask("11. Local DB auto save (infinity/milli seconds)?", + LocalDbAutoSave = ask("12. Local DB auto save (infinity/milli seconds)?", "5000", fun verify_dets_auto_save/1), - ErrorMod = ask("12. Error report module?", "snmpa_error_logger", fun verify_module/1), - Type = ask("13. Agent type (master/sub)?", "master", + ErrorMod = ask("13. Error report module?", "snmpa_error_logger", fun verify_module/1), + Type = ask("14. Agent type (master/sub)?", "master", fun verify_agent_type/1), AgentConfig = case Type of master -> - MasterAgentVerb = ask("14. Master-agent verbosity " + MasterAgentVerb = ask("15. Master-agent verbosity " "(silence/info/log/debug/trace)?", "silence", fun verify_verbosity/1), - ForceLoad = ask("15. Shall the agent re-read the " + ForceLoad = ask("16. Shall the agent re-read the " "configuration files during startup ~n" " (and ignore the configuration " "database) (true/false)?", "true", fun verify_bool/1), - MultiThreaded = ask("16. Multi threaded agent (true/false)?", + MultiThreaded = ask("17. Multi threaded agent (true/false)?", "false", fun verify_bool/1), - MeOverride = ask("17. Check for duplicate mib entries when " + MeOverride = ask("18. Check for duplicate mib entries when " "installing a mib (true/false)?", "false", fun verify_bool/1), - TrapOverride = ask("18. Check for duplicate trap names when " + TrapOverride = ask("19. Check for duplicate trap names when " "installing a mib (true/false)?", "false", fun verify_bool/1), - MibServerVerb = ask("19. Mib server verbosity " + MibServerVerb = ask("20. Mib server verbosity " "(silence/info/log/debug/trace)?", "silence", fun verify_verbosity/1), - MibServerCache = ask("20. Mib server cache " + MibServerCache = ask("21. Mib server cache " "(true/false)?", "true", fun verify_bool/1), - NoteStoreVerb = ask("21. Note store verbosity " + NoteStoreVerb = ask("22. Note store verbosity " "(silence/info/log/debug/trace)?", "silence", fun verify_verbosity/1), - NoteStoreTimeout = ask("22. Note store GC timeout?", "30000", + NoteStoreTimeout = ask("23. Note store GC timeout?", "30000", fun verify_timeout/1), ATL = - case ask("23. Shall the agent use an audit trail log " + case ask("24. Shall the agent use an audit trail log " "(y/n)?", "n", fun verify_yes_or_no/1) of yes -> - ATLType = ask("23b. Audit trail log type " + ATLType = ask("24b. Audit trail log type " "(write/read_write)?", "read_write", fun verify_atl_type/1), - ATLDir = ask("23c. Where to store the " + ATLDir = ask("24c. Where to store the " "audit trail log?", DefDir, fun verify_dir/1), - ATLMaxFiles = ask("23d. Max number of files?", + ATLMaxFiles = ask("24d. Max number of files?", "10", fun verify_pos_integer/1), - ATLMaxBytes = ask("23e. Max size (in bytes) " + ATLMaxBytes = ask("24e. Max size (in bytes) " "of each file?", "10240", fun verify_pos_integer/1), ATLSize = {ATLMaxBytes, ATLMaxFiles}, - ATLRepair = ask("23f. Audit trail log repair " + ATLRepair = ask("24f. Audit trail log repair " "(true/false/truncate/snmp_repair)?", "true", fun verify_atl_repair/1), - ATLSeqNo = ask("23g. Audit trail log " + ATLSeqNo = ask("24g. Audit trail log " "sequence-numbering (true/false)?", "false", fun verify_atl_seqno/1), @@ -360,33 +362,33 @@ config_agent_sys() -> no -> [] end, - NetIfVerb = ask("24. Network interface verbosity " + NetIfVerb = ask("25. Network interface verbosity " "(silence/info/log/debug/trace)?", "silence", fun verify_verbosity/1), - NetIfMod = ask("25. Which network interface module shall be used?", + NetIfMod = ask("26. Which network interface module shall be used?", "snmpa_net_if", fun verify_module/1), NetIfOpts = case NetIfMod of snmpa_net_if -> NetIfBindTo = - ask("25a. Bind the agent IP address " + ask("26a. Bind the agent IP address " "(true/false)?", "false", fun verify_bool/1), NetIfNoReuse = - ask("25b. Shall the agents " + ask("26b. Shall the agents " "IP address " "and port be not reusable " "(true/false)?", "false", fun verify_bool/1), NetIfReqLimit = - ask("25c. Agent request limit " + ask("26c. Agent request limit " "(used for flow control) " "(infinity/pos integer)?", "infinity", fun verify_netif_req_limit/1), NetIfRecbuf = - case ask("25d. Receive buffer size of the " + case ask("26d. Receive buffer size of the " "agent (in bytes) " "(default/pos integer)?", "default", @@ -397,7 +399,7 @@ config_agent_sys() -> [{recbuf, RecBufSz}] end, NetIfSndbuf = - case ask("25e. Send buffer size of the agent " + case ask("26e. Send buffer size of the agent " "(in bytes) (default/pos integer)?", "default", fun verify_netif_sndbuf/1) of @@ -407,7 +409,7 @@ config_agent_sys() -> [{sndbuf, SndBufSz}] end, NetIfFilter = - case ask("25f. Do you wish to specify a " + case ask("26f. Do you wish to specify a " "network interface filter module " "(or use default)", "default", fun verify_module/1) of @@ -426,18 +428,18 @@ config_agent_sys() -> NetIf = [{module, NetIfMod}, {verbosity, NetIfVerb}, {options, NetIfOpts}], - TermDiscoEnable = ask("26a. Allow terminating discovery " + TermDiscoEnable = ask("27. Allow terminating discovery " "(true/false)?", "true", fun verify_bool/1), TermDiscoConf = case TermDiscoEnable of true -> TermDiscoStage2 = - ask("26b. Second stage behaviour " + ask("27a. Second stage behaviour " "(discovery/plain)?", "discovery", fun verify_term_disco_behaviour/1), TermDiscoTrigger = - ask("26c. Trigger username " + ask("27b. Trigger username " "(default/a string)?", "default", fun verify_term_disco_trigger_username/1), [{enable, TermDiscoEnable}, @@ -448,7 +450,7 @@ config_agent_sys() -> {stage2, discovery}, {trigger_username, ""}] end, - OrigDiscoEnable = ask("27a. Allow originating discovery " + OrigDiscoEnable = ask("28. Allow originating discovery " "(true/false)?", "true", fun verify_bool/1), OrigDiscoConf = @@ -471,7 +473,7 @@ config_agent_sys() -> {verbosity, NoteStoreVerb}]}, {net_if, NetIf}] ++ ATL; sub -> - SubAgentVerb = ask("14. Sub-agent verbosity " + SubAgentVerb = ask("15. Sub-agent verbosity " "(silence/info/log/debug/trace)?", "silence", fun verify_verbosity/1), @@ -480,11 +482,12 @@ config_agent_sys() -> {config, [{dir, ConfigDir}]}] end, SysConfig = - [{priority, Prio}, - {versions, Vsns}, - {db_dir, DbDir}, - {mib_storage, MibStorage}, - {target_cache, [{verbosity, TargetCacheVerb}]}, + [{priority, Prio}, + {versions, Vsns}, + {db_dir, DbDir}, + {db_init_error, DbInitError}, + {mib_storage, MibStorage}, + {target_cache, [{verbosity, TargetCacheVerb}]}, {symbolic_store, [{verbosity, SymStoreVerb}]}, {local_db, [{repair, LocalDbRepair}, {auto_save, LocalDbAutoSave}, @@ -630,19 +633,21 @@ config_manager_sys() -> fun verify_verbosity/1), ConfigDbDir = ask("5. Database directory (absolute path)?", DefDir, fun verify_dir/1), - ConfigDbRepair = ask("6. Database repair " + ConfigDbInitError = ask("6. How to handle DB init error?", + "terminate", fun verify_db_init_error/1), + ConfigDbRepair = ask("7. Database repair " "(true/false/force)?", "true", fun verify_dets_repair/1), - ConfigDbAutoSave = ask("7. Database auto save " + ConfigDbAutoSave = ask("8. Database auto save " "(infinity/milli seconds)?", "5000", fun verify_dets_auto_save/1), IRB = - case ask("8. Inform request behaviour (auto/user)?", + case ask("9. Inform request behaviour (auto/user)?", "auto", fun verify_irb/1) of auto -> auto; user -> - case ask("8b. Use default GC timeout" + case ask("9b. Use default GC timeout" "(default/seconds)?", "default", fun verify_irb_user/1) of default -> @@ -651,31 +656,31 @@ config_manager_sys() -> {user, IrbGcTo} end end, - ServerVerb = ask("9. Server verbosity " + ServerVerb = ask("10. Server verbosity " "(silence/info/log/debug/trace)?", "silence", fun verify_verbosity/1), - ServerTimeout = ask("10. Server GC timeout?", "30000", + ServerTimeout = ask("11. Server GC timeout?", "30000", fun verify_timeout/1), - NoteStoreVerb = ask("11. Note store verbosity " + NoteStoreVerb = ask("12. Note store verbosity " "(silence/info/log/debug/trace)?", "silence", fun verify_verbosity/1), - NoteStoreTimeout = ask("12. Note store GC timeout?", "30000", + NoteStoreTimeout = ask("13. Note store GC timeout?", "30000", fun verify_timeout/1), - NetIfMod = ask("13. Which network interface module shall be used?", + NetIfMod = ask("14. Which network interface module shall be used?", "snmpm_net_if", fun verify_module/1), - NetIfVerb = ask("14. Network interface verbosity " + NetIfVerb = ask("15. Network interface verbosity " "(silence/info/log/debug/trace)?", "silence", fun verify_verbosity/1), - NetIfBindTo = ask("15. Bind the manager IP address " + NetIfBindTo = ask("16. Bind the manager IP address " "(true/false)?", "false", fun verify_bool/1), - NetIfNoReuse = ask("16. Shall the manager IP address and port " + NetIfNoReuse = ask("17. Shall the manager IP address and port " "be not reusable (true/false)?", "false", fun verify_bool/1), NetIfRecbuf = - case ask("17. Receive buffer size of the manager (in bytes) " + case ask("18. Receive buffer size of the manager (in bytes) " "(default/pos integer)?", "default", fun verify_netif_recbuf/1) of default -> @@ -684,7 +689,7 @@ config_manager_sys() -> [{recbuf, RecBufSz}] end, NetIfSndbuf = - case ask("18. Send buffer size of the manager (in bytes) " + case ask("19. Send buffer size of the manager (in bytes) " "(default/pos integer)?", "default", fun verify_netif_sndbuf/1) of default -> @@ -700,28 +705,28 @@ config_manager_sys() -> {verbosity, NetIfVerb}, {options, NetIfOpts}], ATL = - case ask("19. Shall the manager use an audit trail log " + case ask("20. Shall the manager use an audit trail log " "(y/n)?", "n", fun verify_yes_or_no/1) of yes -> - ATLType = ask("19b. Audit trail log type " + ATLType = ask("20b. Audit trail log type " "(write/read_write)?", "read_write", fun verify_atl_type/1), - ATLDir = ask("19c. Where to store the " + ATLDir = ask("20c. Where to store the " "audit trail log?", DefDir, fun verify_dir/1), - ATLMaxFiles = ask("19d. Max number of files?", + ATLMaxFiles = ask("20d. Max number of files?", "10", fun verify_pos_integer/1), - ATLMaxBytes = ask("19e. Max size (in bytes) " + ATLMaxBytes = ask("20e. Max size (in bytes) " "of each file?", "10240", fun verify_pos_integer/1), ATLSize = {ATLMaxBytes, ATLMaxFiles}, - ATLRepair = ask("19f. Audit trail log repair " + ATLRepair = ask("20f. Audit trail log repair " "(true/false/truncate/snmp_repair)?", "true", fun verify_atl_repair/1), - ATLSeqNo = ask("19g. Audit trail log sequence-numbering " + ATLSeqNo = ask("20g. Audit trail log sequence-numbering " "(true/false)?", "false", fun verify_atl_seqno/1), [{audit_trail_log, [{type, ATLType}, @@ -733,14 +738,14 @@ config_manager_sys() -> [] end, DefUser = - case ask("20. Do you wish to assign a default user [yes] or use~n" + case ask("21. Do you wish to assign a default user [yes] or use~n" " the default settings [no] (y/n)?", "n", fun verify_yes_or_no/1) of yes -> - DefUserMod = ask("20b. Default user module?", + DefUserMod = ask("21b. Default user module?", "snmpm_user_default", fun verify_module/1), - DefUserData = ask("20c. Default user data?", "undefined", + DefUserData = ask("21c. Default user data?", "undefined", fun verify_user_data/1), [{def_user_mod, DefUserMod}, {def_user_data, DefUserData}]; @@ -750,11 +755,12 @@ config_manager_sys() -> SysConfig = [{priority, Prio}, {versions, Vsns}, - {config, [{dir, ConfigDir}, - {verbosity, ConfigVerb}, - {db_dir, ConfigDbDir}, - {repair, ConfigDbRepair}, - {auto_save, ConfigDbAutoSave}]}, + {config, [{dir, ConfigDir}, + {db_dir, ConfigDbDir}, + {db_init_error, ConfigDbInitError}, + {repair, ConfigDbRepair}, + {auto_save, ConfigDbAutoSave}, + {verbosity, ConfigVerb}]}, {inform_request_behaviour, IRB}, {mibs, []}, {server, [{timeout, ServerTimeout}, @@ -1069,6 +1075,16 @@ verify_dir(Dir) -> _E -> {error, "invalid directory (not absolute): " ++ Dir} end. + + +verify_db_init_error("terminate") -> + {ok, true}; +verify_db_init_error("create") -> + {ok, create}; +verify_db_init_error("create_db_and_dir") -> + {ok, create_db_and_dir}; +verify_db_init_error(R) -> + {error, "invalid DB init error: " ++ R}. verify_notif_type("trap") -> {ok, trap}; @@ -1164,13 +1180,20 @@ verify_dets_auto_save(I0) -> %% I know that this is a little of the edge, but... +verify_module(M) when is_atom(M) -> + {ok, M}; +verify_module(M0) when is_list(M0) -> + {ok, list_to_atom(M0)}; verify_module(M0) -> - case (catch list_to_atom(M0)) of - M when is_atom(M) -> - {ok, M}; - _ -> - {error, "invalid module: " ++ M0} - end. + {error, lists:flatten(io_lib:format("invalid module: ~p", [M0]))}. + +%% verify_module(M0) -> +%% case (catch list_to_atom(M0)) of +%% M when is_atom(M) -> +%% {ok, M}; +%% _ -> +%% {error, "invalid module: " ++ M0} +%% end. verify_agent_type("master") -> @@ -2168,6 +2191,8 @@ write_sys_config_file_agent_opt(Fid, {config, Opts}) -> ok = io:format(Fid, "}", []); write_sys_config_file_agent_opt(Fid, {db_dir, Dir}) -> ok = io:format(Fid, " {db_dir, \"~s\"}", [Dir]); +write_sys_config_file_agent_opt(Fid, {db_init_error, Action}) -> + ok = io:format(Fid, " {db_init_error, ~w}", [Action]); write_sys_config_file_agent_opt(Fid, {mib_storage, ets}) -> ok = io:format(Fid, " {mib_storage, ets}", []); write_sys_config_file_agent_opt(Fid, {mib_storage, {dets, Dir}}) -> @@ -2344,6 +2369,8 @@ write_sys_config_file_manager_config_opt(Fid, {dir, Dir}) -> ok = io:format(Fid, "{dir, \"~s\"}", [Dir]); write_sys_config_file_manager_config_opt(Fid, {db_dir, Dir}) -> ok = io:format(Fid, "{db_dir, \"~s\"}", [Dir]); +write_sys_config_file_manager_config_opt(Fid, {db_init_error, Action}) -> + ok = io:format(Fid, "{db_init_error, ~w}", [Action]); write_sys_config_file_manager_config_opt(Fid, {repair, Rep}) -> ok = io:format(Fid, "{repair, ~w}", [Rep]); write_sys_config_file_manager_config_opt(Fid, {auto_save, As}) -> diff --git a/lib/snmp/src/misc/snmp_log.erl b/lib/snmp/src/misc/snmp_log.erl index a8c5df0b64..ae28df37fa 100644 --- a/lib/snmp/src/misc/snmp_log.erl +++ b/lib/snmp/src/misc/snmp_log.erl @@ -24,8 +24,8 @@ create/4, create/5, create/6, open/1, open/2, change_size/2, close/1, sync/1, info/1, log/4, - log_to_txt/5, log_to_txt/6, log_to_txt/7, - log_to_io/4, log_to_io/5, log_to_io/6 + log_to_txt/6, log_to_txt/7, log_to_txt/8, + log_to_io/5, log_to_io/6, log_to_io/7 ]). -export([ upgrade/1, upgrade/2, @@ -34,7 +34,17 @@ -export([ validate/1, validate/2 ]). +%% <BACKWARD-COMPAT> +-export([ + log_to_txt/5, + log_to_io/4 + ]). +%% </BACKWARD-COMPAT> +-export_type([ + log/0, + log_time/0 + ]). -define(SNMP_USE_V3, true). -include("snmp_types.hrl"). @@ -42,12 +52,24 @@ -define(VMODULE,"LOG"). -include("snmp_verbosity.hrl"). --define(LOG_FORMAT, internal). --define(LOG_TYPE, wrap). +-define(LOG_FORMAT, internal). +-define(LOG_TYPE, wrap). +-define(BLOCK_DEFAULT, true). -record(snmp_log, {id, seqno}). +%%----------------------------------------------------------------- +%% Types +%%----------------------------------------------------------------- + +-opaque log() :: #snmp_log{}. +-type log_time() :: null | + calendar:datetime() | + {local_time, calendar:datetime()} | + {universal_time, calendar:datetime()}. + + %% -------------------------------------------------------------------- %% Exported functions %% -------------------------------------------------------------------- @@ -322,7 +344,6 @@ validate_loop(Error, _Log, _Write, _PrevTS, _PrevSN) -> %% log(Log, Packet, Addr, Port) %%----------------------------------------------------------------- - log(#snmp_log{id = Log, seqno = SeqNo}, Packet, Addr, Port) -> ?vtrace("log -> entry with" "~n Log: ~p" @@ -378,53 +399,86 @@ do_change_size(Log, NewSize) -> %% -- log_to_txt --- +%% <BACKWARD-COMPAT> log_to_txt(Log, FileName, Dir, Mibs, TextFile) -> - log_to_txt(Log, FileName, Dir, Mibs, TextFile, null, null). + log_to_txt(Log, ?BLOCK_DEFAULT, FileName, Dir, Mibs, TextFile). +%% </BACKWARD-COMPAT> +log_to_txt(Log, Block, FileName, Dir, Mibs, TextFile) + when ((Block =:= true) orelse (Block =:= false)) -> + log_to_txt(Log, Block, FileName, Dir, Mibs, TextFile, null, null); +%% <BACKWARD-COMPAT> log_to_txt(Log, FileName, Dir, Mibs, TextFile, Start) -> - log_to_txt(Log, FileName, Dir, Mibs, TextFile, Start, null). - -log_to_txt(Log, FileName, Dir, Mibs, TextFile, Start, Stop) - when is_list(Mibs) andalso is_list(TextFile) -> + log_to_txt(Log, ?BLOCK_DEFAULT, FileName, Dir, Mibs, TextFile, Start, null). +%% </BACKWARD-COMPAT> + +log_to_txt(Log, Block, FileName, Dir, Mibs, TextFile, Start) + when ((Block =:= true) orelse (Block =:= false)) -> + log_to_txt(Log, Block, FileName, Dir, Mibs, TextFile, Start, null); +%% <BACKWARD-COMPAT> +log_to_txt(Log, FileName, Dir, Mibs, TextFile, Start, Stop) -> + log_to_txt(Log, ?BLOCK_DEFAULT, FileName, Dir, Mibs, TextFile, Start, Stop). +%% </BACKWARD-COMPAT> + +log_to_txt(Log, Block, FileName, Dir, Mibs, TextFile, Start, Stop) + when (((Block =:= true) orelse (Block =:= false)) andalso + is_list(Mibs) andalso is_list(TextFile)) -> ?vtrace("log_to_txt -> entry with" "~n Log: ~p" + "~n Block: ~p" "~n FileName: ~p" "~n Dir: ~p" "~n Mibs: ~p" "~n TextFile: ~p" "~n Start: ~p" "~n Stop: ~p", - [Log, FileName, Dir, Mibs, TextFile, Start, Stop]), + [Log, Block, FileName, Dir, Mibs, TextFile, Start, Stop]), File = filename:join(Dir, FileName), Converter = fun(L) -> do_log_to_file(L, TextFile, Mibs, Start, Stop) end, - log_convert(Log, File, Converter). + log_convert(Log, Block, File, Converter). %% -- log_to_io --- +%% <BACKWARD-COMPAT> log_to_io(Log, FileName, Dir, Mibs) -> - log_to_io(Log, FileName, Dir, Mibs, null, null). + log_to_io(Log, ?BLOCK_DEFAULT, FileName, Dir, Mibs, null, null). +%% </BACKWARD-COMPAT> +log_to_io(Log, Block, FileName, Dir, Mibs) + when ((Block =:= true) orelse (Block =:= false)) -> + log_to_io(Log, Block, FileName, Dir, Mibs, null, null); +%% <BACKWARD-COMPAT> log_to_io(Log, FileName, Dir, Mibs, Start) -> - log_to_io(Log, FileName, Dir, Mibs, Start, null). - -log_to_io(Log, FileName, Dir, Mibs, Start, Stop) + log_to_io(Log, ?BLOCK_DEFAULT, FileName, Dir, Mibs, Start, null). +%% </BACKWARD-COMPAT> + +log_to_io(Log, Block, FileName, Dir, Mibs, Start) + when ((Block =:= true) orelse (Block =:= false)) -> + log_to_io(Log, Block, FileName, Dir, Mibs, Start, null); +%% <BACKWARD-COMPAT> +log_to_io(Log, FileName, Dir, Mibs, Start, Stop) -> + log_to_io(Log, ?BLOCK_DEFAULT, FileName, Dir, Mibs, Start, Stop). +%% </BACKWARD-COMPAT> + +log_to_io(Log, Block, FileName, Dir, Mibs, Start, Stop) when is_list(Mibs) -> ?vtrace("log_to_io -> entry with" "~n Log: ~p" + "~n Block: ~p" "~n FileName: ~p" "~n Dir: ~p" "~n Mibs: ~p" "~n Start: ~p" "~n Stop: ~p", - [Log, FileName, Dir, Mibs, Start, Stop]), + [Log, Block, FileName, Dir, Mibs, Start, Stop]), File = filename:join(Dir, FileName), Converter = fun(L) -> do_log_to_io(L, Mibs, Start, Stop) end, - log_convert(Log, File, Converter). + log_convert(Log, Block, File, Converter). %% -------------------------------------------------------------------- @@ -433,53 +487,121 @@ log_to_io(Log, FileName, Dir, Mibs, Start, Stop) %% -- log_convert --- -log_convert(#snmp_log{id = Log}, File, Converter) -> - do_log_convert(Log, File, Converter); -log_convert(Log, File, Converter) -> - do_log_convert(Log, File, Converter). +log_convert(#snmp_log{id = Log}, Block, File, Converter) -> + do_log_convert(Log, Block, File, Converter); +log_convert(Log, Block, File, Converter) -> + do_log_convert(Log, Block, File, Converter). -do_log_convert(Log, File, Converter) -> +do_log_convert(Log, Block, File, Converter) -> %% ?vtrace("do_log_converter -> entry with" - %% "~n Log: ~p" - %% "~n File: ~p" - %% "~n disk_log:info(Log): ~p", [Log, File, disk_log:info(Log)]), + %% "~n Log: ~p" + %% "~n Block: ~p" + %% "~n File: ~p" + %% [Log, Block, File]), + Verbosity = get(verbosity), {Pid, Ref} = erlang:spawn_monitor( fun() -> - Result = do_log_convert2(Log, File, Converter), + put(sname, lc), + put(verbosity, Verbosity), + ?vlog("begin converting", []), + Result = do_log_convert2(Log, Block, File, Converter), + ?vlog("convert result: ~p", [Result]), exit(Result) end), receive {'DOWN', Ref, process, Pid, Result} -> %% ?vtrace("do_log_converter -> received result" - %% "~n Result: ~p" - %% "~n disk_log:info(Log): ~p", - %% [Result, disk_log:info(Log)]), + %% "~n Result: ~p", [Result]), Result end. -do_log_convert2(Log, File, Converter) -> +do_log_convert2(Log, Block, File, Converter) -> + + %% ?vtrace("do_log_converter2 -> entry with" + %% "~n Log: ~p" + %% "~n Block: ~p" + %% "~n File: ~p" + %% "~n disk_log:info(Log): ~p", + %% [Log, Block, File, disk_log:info(Log)]), + %% First check if the caller process has already opened the %% log, because if we close an already open log we will cause %% a runtime error. + + ?vtrace("do_log_convert2 -> entry - check if owner", []), case is_owner(Log) of true -> - Converter(Log); + ?vtrace("do_log_converter2 -> convert an already owned log", []), + maybe_block(Log, Block), + Res = Converter(Log), + maybe_unblock(Log, Block), + Res; false -> %% Not yet member of the ruling party, apply for membership... + ?vtrace("do_log_converter2 -> convert log", []), case log_open(Log, File) of {ok, _} -> + ?vdebug("do_log_convert2 -> opened - now convert", []), + maybe_block(Log, Block), Res = Converter(Log), + maybe_unblock(Log, Block), disk_log:close(Log), + ?vdebug("do_log_convert2 -> converted - done: " + "~n Result: ~p", [Res]), Res; {error, {name_already_open, _}} -> - Converter(Log); + ?vdebug("do_log_convert2 -> " + "already opened - now convert", []), + maybe_block(Log, Block), + Res = Converter(Log), + maybe_unblock(Log, Block), + ?vdebug("do_log_convert2 -> converted - done: " + "~n Result: ~p", [Res]), + Res; {error, Reason} -> + ?vinfo("do_log_converter2 -> " + "failed converting log - open failed: " + "~n Reason: ~p", [Reason]), {error, {Log, Reason}} end end. +maybe_block(_Log, false = _Block) -> + %% ?vtrace("maybe_block(false) -> entry", []), + ok; +maybe_block(Log, true = _Block) -> + %% ?vtrace("maybe_block(true) -> entry when" + %% "~n Log Status: ~p", [log_status(Log)]), + Res = disk_log:block(Log, true), + %% ?vtrace("maybe_block(true) -> " + %% "~n Log Status: ~p" + %% "~n Res: ~p", [log_status(Log), Res]), + Res. + +maybe_unblock(_Log, false = _Block) -> + %% ?vtrace("maybe_unblock(false) -> entry", []), + ok; +maybe_unblock(Log, true = _Block) -> + %% ?vtrace("maybe_unblock(true) -> entry when" + %% "~n Log Status: ~p", [log_status(Log)]), + Res = disk_log:unblock(Log), + %% ?vtrace("maybe_unblock(true) -> " + %% "~n Log Status: ~p" + %% "~n Res: ~p", [log_status(Log), Res]), + Res. + +%% log_status(Log) -> +%% Info = disk_log:info(Log), +%% case lists:keysearch(status, 1, Info) of +%% {value, {status, Status}} -> +%% Status; +%% false -> +%% undefined +%% end. + + %% -- do_log_to_text --- do_log_to_file(Log, TextFile, Mibs, Start, Stop) -> diff --git a/lib/snmp/src/misc/snmp_usm.erl b/lib/snmp/src/misc/snmp_usm.erl index 67e3476816..32198deb8b 100644 --- a/lib/snmp/src/misc/snmp_usm.erl +++ b/lib/snmp/src/misc/snmp_usm.erl @@ -16,6 +16,8 @@ %% %% %CopyrightEnd% %% +%% AES: RFC 3826 +%% -module(snmp_usm). @@ -24,7 +26,7 @@ -export([passwd2localized_key/3, localize_key/3]). -export([auth_in/4, auth_out/4, set_msg_auth_params/3]). -export([des_encrypt/3, des_decrypt/3]). --export([aes_encrypt/3, aes_decrypt/5]). +-export([aes_encrypt/5, aes_decrypt/5]). -define(SNMP_USE_V3, true). @@ -42,6 +44,9 @@ -define(i32(Int), (Int bsr 24) band 255, (Int bsr 16) band 255, (Int bsr 8) band 255, Int band 255). +-define(BLOCK_CIPHER_AES, aes_cfb128). +-define(BLOCK_CIPHER_DES, des_cbc). + %%----------------------------------------------------------------- %% Func: passwd2localized_key/3 @@ -210,7 +215,8 @@ des_encrypt(PrivKey, Data, SaltFun) -> IV = list_to_binary(snmp_misc:str_xor(PreIV, Salt)), TailLen = (8 - (length(Data) rem 8)) rem 8, Tail = mk_tail(TailLen), - EncData = crypto:block_encrypt(des_cbc, DesKey, IV, [Data,Tail]), + EncData = crypto:block_encrypt(?BLOCK_CIPHER_DES, + DesKey, IV, [Data,Tail]), {ok, binary_to_list(EncData), Salt}. des_decrypt(PrivKey, MsgPrivParams, EncData) @@ -224,7 +230,8 @@ des_decrypt(PrivKey, MsgPrivParams, EncData) Salt = MsgPrivParams, IV = list_to_binary(snmp_misc:str_xor(PreIV, Salt)), %% Whatabout errors here??? E.g. not a mulitple of 8! - Data = binary_to_list(crypto:block_decrypt(des_cbc, DesKey, IV, EncData)), + Data = binary_to_list(crypto:block_decrypt(?BLOCK_CIPHER_DES, + DesKey, IV, EncData)), Data2 = snmp_pdus:strip_encrypted_scoped_pdu_data(Data), {ok, Data2}; des_decrypt(PrivKey, BadMsgPrivParams, EncData) -> @@ -236,13 +243,12 @@ des_decrypt(PrivKey, BadMsgPrivParams, EncData) -> throw({error, {bad_msgPrivParams, PrivKey, BadMsgPrivParams, EncData}}). -aes_encrypt(PrivKey, Data, SaltFun) -> +aes_encrypt(PrivKey, Data, SaltFun, EngineBoots, EngineTime) -> AesKey = PrivKey, Salt = SaltFun(), - EngineBoots = snmp_framework_mib:get_engine_boots(), - EngineTime = snmp_framework_mib:get_engine_time(), IV = list_to_binary([?i32(EngineBoots), ?i32(EngineTime) | Salt]), - EncData = crypto:block_encrypt(aes_cbf128, AesKey, IV, Data), + EncData = crypto:block_encrypt(?BLOCK_CIPHER_AES, + AesKey, IV, Data), {ok, binary_to_list(EncData), Salt}. aes_decrypt(PrivKey, MsgPrivParams, EncData, EngineBoots, EngineTime) @@ -251,7 +257,8 @@ aes_decrypt(PrivKey, MsgPrivParams, EncData, EngineBoots, EngineTime) Salt = MsgPrivParams, IV = list_to_binary([?i32(EngineBoots), ?i32(EngineTime) | Salt]), %% Whatabout errors here??? E.g. not a mulitple of 8! - Data = binary_to_list(crypto:block_decrypt(aes_cbf128, AesKey, IV, EncData)), + Data = binary_to_list(crypto:block_decrypt(?BLOCK_CIPHER_AES, + AesKey, IV, EncData)), Data2 = snmp_pdus:strip_encrypted_scoped_pdu_data(Data), {ok, Data2}. diff --git a/lib/snmp/src/misc/snmp_verbosity.erl b/lib/snmp/src/misc/snmp_verbosity.erl index df5986b7bc..f27c31db03 100644 --- a/lib/snmp/src/misc/snmp_verbosity.erl +++ b/lib/snmp/src/misc/snmp_verbosity.erl @@ -148,6 +148,8 @@ image_of_sname(mnifl) -> "M-NET-IF-LOGGER"; image_of_sname(mnifw) -> io_lib:format("M-NET-IF-worker(~p)", [self()]); image_of_sname(mconf) -> "M-CONF"; +image_of_sname(lc) -> io_lib:format("LOG-CONVERTER(~p)", [self()]); + image_of_sname(mgr) -> "MGR"; image_of_sname(mgr_misc) -> "MGR_MISC"; diff --git a/lib/snmp/test/snmp_agent_test.erl b/lib/snmp/test/snmp_agent_test.erl index 7e683e315a..b7d34eb198 100644 --- a/lib/snmp/test/snmp_agent_test.erl +++ b/lib/snmp/test/snmp_agent_test.erl @@ -34,6 +34,7 @@ %% all_tcs - misc app_info/1, info_test/1, + create_local_db_dir/1, %% all_tcs - test_v1 simple/1, @@ -1506,7 +1507,8 @@ finish_misc(Config) -> misc_cases() -> [ app_info, - info_test + info_test, + create_local_db_dir ]. app_info(suite) -> []; @@ -1539,7 +1541,75 @@ app_dir(App) -> "undefined" end. +create_local_db_dir(Config) when is_list(Config) -> + ?P(create_local_db_dir), + DataDir = snmp_test_lib:lookup(data_dir, Config), + T = erlang:now(), + [As,Bs,Cs] = [integer_to_list(I) || I <- tuple_to_list(T)], + DbDir = filename:join([DataDir, As, Bs, Cs]), + ok = del_dir(DbDir, 3), + Name = list_to_atom(atom_to_list(create_local_db_dir) + ++"-"++As++"-"++Bs++"-"++Cs), + Pa = filename:dirname(code:which(?MODULE)), + {ok,Node} = ?t:start_node(Name, slave, [{args, "-pa "++Pa}]), + + %% first start with a nonexisting DbDir + Fun1 = fun() -> + false = filelib:is_dir(DbDir), + process_flag(trap_exit,true), + {error, {error, {failed_open_dets, {file_error, _, _}}}} = + snmpa_local_db:start_link(normal, DbDir, [{verbosity,trace}]), + false = filelib:is_dir(DbDir), + {ok, not_found} + end, + {ok, not_found} = nodecall(Node, Fun1), + %% now start with a nonexisting DbDir but pass the + %% create_local_db_dir option as well + Fun2 = fun() -> + false = filelib:is_dir(DbDir), + process_flag(trap_exit,true), + {ok, _Pid} = + snmpa_local_db:start_link(normal, DbDir, + create_db_and_dir, [{verbosity,trace}]), + snmpa_local_db:stop(), + true = filelib:is_dir(DbDir), + {ok, found} + end, + {ok, found} = nodecall(Node, Fun2), + %% cleanup + ?t:stop_node(Node), + ok = del_dir(DbDir, 3), + ok. + +nodecall(Node, Fun) -> + Parent = self(), + Ref = make_ref(), + spawn_link(Node, + fun() -> + Res = Fun(), + unlink(Parent), + Parent ! {Ref, Res} + end), + receive + {Ref, Res} -> + Res + end. +del_dir(_Dir, 0) -> + ok; +del_dir(Dir, Depth) -> + case filelib:is_dir(Dir) of + true -> + {ok, Files} = file:list_dir(Dir), + lists:map(fun(F) -> + Nm = filename:join(Dir,F), + ok = file:delete(Nm) + end, Files), + ok = file:del_dir(Dir), + del_dir(filename:dirname(Dir), Depth-1); + false -> + ok + end. %v1_cases() -> [loop_mib]; v1_cases() -> diff --git a/lib/snmp/test/snmp_log_test.erl b/lib/snmp/test/snmp_log_test.erl index e9345b44cc..fb7285110f 100644 --- a/lib/snmp/test/snmp_log_test.erl +++ b/lib/snmp/test/snmp_log_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2012. All Rights Reserved. +%% Copyright Ericsson AB 2003-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -331,7 +331,7 @@ log_to_io1(doc) -> "Log to io from the same process that opened " log_to_io1(Config) when is_list(Config) -> p(log_to_io1), put(sname,l2i1), - put(verbosity,trace), + put(verbosity,debug), ?DBG("log_to_io1 -> start", []), Dir = ?config(log_dir, Config), Name = "snmp_test_l2i1", @@ -365,7 +365,7 @@ log_to_io1(Config) when is_list(Config) -> display_info(Info), ?DBG("log_to_io1 -> do the convert to io (stdout)", []), - ? line ok = snmp_log:log_to_io(Log, File, Dir, []), + ? line ok = snmp:log_to_io(Dir, [], Name, File, false), ?DBG("log_to_io1 -> close log", []), ?line ok = snmp_log:close(Log), @@ -377,7 +377,7 @@ log_to_io1(Config) when is_list(Config) -> %%====================================================================== %% Start a logger-process that logs messages with a certain interval. %% Start a reader-process that reads messages from the log at a certain -%% point of time. +%% point in time. log_to_io2(suite) -> []; log_to_io2(doc) -> "Log to io from a different process than which " @@ -386,7 +386,7 @@ log_to_io2(Config) when is_list(Config) -> process_flag(trap_exit, true), p(log_to_io2), put(sname, l2i2), - put(verbosity,trace), + put(verbosity,debug), ?DBG("log_to_io2 -> start", []), Dir = ?config(log_dir, Config), Name = "snmp_test_l2i2", @@ -414,13 +414,13 @@ log_to_io2(Config) when is_list(Config) -> log_reader_log_to(Reader, fun() -> I = disk_log:info(Log), - R = snmp_log:log_to_io(Log, File, Dir, []), + R = snmp:log_to_io(Dir, [], Name, File, true), {R, I} end), case Res of - {ok, Info} -> - ?DBG("log_to_io2 -> ~n Info: ~p", [Info]), + {ok, _Info} -> + ?DBG("log_to_io2 -> ~n Info: ~p", [_Info]), ok; {Error, Info} -> ?DBG("log_to_io2 -> log to io failed: " @@ -445,7 +445,7 @@ log_to_txt1(suite) -> []; log_to_txt1(Config) when is_list(Config) -> p(log_to_txt1), put(sname,l2t1), - put(verbosity,trace), + put(verbosity,debug), ?DBG("log_to_txt1 -> start", []), Name = "snmp_test_l2t1", @@ -463,7 +463,7 @@ log_to_txt2(suite) -> []; log_to_txt2(Config) when is_list(Config) -> p(log_to_txt2), put(sname,l2t2), - put(verbosity,trace), + put(verbosity,debug), ?DBG("log_to_txt2 -> start", []), Name = "snmp_test_l2t2", @@ -520,14 +520,21 @@ log_to_txt(Name, SeqNoGen, Config) when is_list(Config) -> ?line {ok, Info} = snmp_log:info(Log), display_info(Info), - Out1 = join(Dir, "snmp_text-1.txt"), - ?DBG("log_to_txt -> do the convert to a text file when" - "~n Out1: ~p", [Out1]), - ?line ok = snmp:log_to_txt(Dir, [], Out1, Log, File), + Out1a = join(Dir, "snmp_text-1-unblocked.txt"), + ?DBG("log_to_txt -> do the convert to a text file (~s) unblocked", [Out1a]), + ?line ok = snmp:log_to_txt(Dir, [], Out1a, Log, File, false), + + ?line {ok, #file_info{size = Size1a}} = file:read_file_info(Out1a), + ?DBG("log_to_txt -> text file size: ~p", [Size1a]), + validate_size(Size1a), + + Out1b = join(Dir, "snmp_text-1-blocked.txt"), + ?DBG("log_to_txt -> do the convert to a text file (~s) blocked", [Out1b]), + ?line ok = snmp:log_to_txt(Dir, [], Out1b, Log, File, true), - ?line {ok, #file_info{size = Size1}} = file:read_file_info(Out1), - ?DBG("log_to_txt -> text file size: ~p", [Size1]), - validate_size(Size1), + ?line {ok, #file_info{size = Size1b}} = file:read_file_info(Out1b), + ?DBG("log_to_txt -> text file size: ~p", [Size1b]), + validate_size(Size1b, {eq, Size1a}), Out2 = join(Dir, "snmp_text-2.txt"), ?DBG("log_to_txt -> do the convert to a text file when" @@ -538,7 +545,7 @@ log_to_txt(Name, SeqNoGen, Config) when is_list(Config) -> ?line {ok, #file_info{size = Size2}} = file:read_file_info(Out2), ?DBG("log_to_txt -> text file size: ~p", [Size2]), - validate_size(Size2, {le, Size1}), + validate_size(Size2, {le, Size1a}), %% Calculate new start / stop times... GStart = calendar:datetime_to_gregorian_seconds(Start), @@ -568,7 +575,7 @@ log_to_txt(Name, SeqNoGen, Config) when is_list(Config) -> ?line {ok, #file_info{size = Size3}} = file:read_file_info(Out3), ?DBG("log_to_txt -> text file size: ~p", [Size3]), - validate_size(Size3, {l, Size1}), + validate_size(Size3, {l, Size1a}), ?DBG("log_to_txt -> close log", []), ?line ok = snmp_log:close(Log), @@ -593,7 +600,7 @@ log_to_txt3(Config) when is_list(Config) -> process_flag(trap_exit, true), p(log_to_txt3), put(sname,l2t3), - put(verbosity,trace), + put(verbosity,debug), ?DBG("log_to_txt3 -> start", []), Dir = ?config(log_dir, Config), Name = "snmp_test_l2t3", @@ -637,8 +644,8 @@ log_to_txt3(Config) when is_list(Config) -> end), case Res of - {ok, Info} -> - ?DBG("log_to_txt3 -> ~n Info: ~p", [Info]), + {ok, _Info} -> + ?DBG("log_to_txt3 -> ~n Info: ~p", [_Info]), ?line {ok, #file_info{size = FileSize}} = file:read_file_info(TxtFile), ?DBG("log_to_txt3 -> text file size: ~p", [FileSize]), @@ -667,6 +674,8 @@ validate_size(_) -> validate_size(0, _) -> ?FAIL(invalid_size); +validate_size(A, {eq, A}) -> + ok; validate_size(A, {le, B}) when A =< B -> ok; validate_size(A, {l, B}) when A < B -> @@ -695,11 +704,11 @@ log_writer_start(Name, File, Size, Repair) -> log_writer_stop(Pid) -> Pid ! {stop, self()}, - T1 = t(), + _T1 = t(), receive {'EXIT', Pid, normal} -> - T2 = t(), - ?DBG("it took ~w ms to stop the writer", [T2 - T1]), + _T2 = t(), + ?DBG("it took ~w ms to stop the writer", [_T2 - _T1]), ok after 60000 -> Msg = receive Any -> Any after 0 -> nothing end, @@ -712,11 +721,11 @@ log_writer_info(Pid) -> log_writer_sleep(Pid, Time) -> Pid ! {sleep, Time, self()}, - T1 = t(), + _T1 = t(), receive {sleeping, Pid} -> - T2 = t(), - ?DBG("it took ~w ms to put the writer to sleep", [T2 - T1]), + _T2 = t(), + ?DBG("it took ~w ms to put the writer to sleep", [_T2 - _T1]), ok; {'EXIT', Pid, Reason} -> {error, Reason} @@ -784,11 +793,11 @@ lp(F, A) -> log_reader_start() -> Pid = spawn_link(?MODULE, log_reader_main, [self()]), - T1 = t(), + _T1 = t(), receive {started, Pid} -> - T2 = t(), - ?DBG("it took ~w ms to start the reader", [T2 - T1]), + _T2 = t(), + ?DBG("it took ~w ms to start the reader", [_T2 - _T1]), {ok, Pid}; {'EXIT', Pid, Reason} -> {error, Reason} @@ -798,11 +807,11 @@ log_reader_start() -> log_reader_stop(Pid) -> Pid ! {stop, self()}, - T1 = t(), + _T1 = t(), receive {'EXIT', Pid, normal} -> - T2 = t(), - ?DBG("it took ~w ms to put the reader to eleep", [T2 - T1]), + _T2 = t(), + ?DBG("it took ~w ms to put the reader to eleep", [_T2 - _T1]), ok after 1000 -> Msg = receive Any -> Any after 0 -> nothing end, diff --git a/lib/snmp/test/snmp_manager_config_test.erl b/lib/snmp/test/snmp_manager_config_test.erl index 3192fe1b40..7b9924b83c 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-2012. All Rights Reserved. +%% Copyright Ericsson AB 2004-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -57,6 +57,7 @@ start_with_invalid_users_conf_file1/1, start_with_invalid_agents_conf_file1/1, start_with_invalid_usm_conf_file1/1, + start_with_create_db_and_dir_opt/1, @@ -139,8 +140,13 @@ init_per_testcase(Case, Config) when is_list(Config) -> file:make_dir(MgrTopDir = filename:join(CaseTopDir, "manager/")), ?line ok = file:make_dir(MgrConfDir = filename:join(MgrTopDir, "conf/")), - ?line ok = - file:make_dir(MgrDbDir = filename:join(MgrTopDir, "db/")), + MgrDbDir = filename:join(MgrTopDir, "db/"), + case Case of + start_with_create_db_and_dir_opt -> + ok; + _ -> + ?line ok = file:make_dir(MgrDbDir) + end, ?line ok = file:make_dir(MgrLogDir = filename:join(MgrTopDir, "log/")), [{case_top_dir, CaseTopDir}, @@ -174,6 +180,7 @@ groups() -> start_without_mandatory_opts2, start_with_all_valid_opts, start_with_unknown_opts, start_with_incorrect_opts, + start_with_create_db_and_dir_opt, start_with_invalid_manager_conf_file1, start_with_invalid_users_conf_file1, start_with_invalid_agents_conf_file1, @@ -332,7 +339,8 @@ start_with_all_valid_opts(Conf) when is_list(Conf) -> {no_reuse, false}]}], ServerOpts = [{timeout, 10000}, {verbosity, trace}], NoteStoreOpts = [{timeout, 20000}, {verbosity, trace}], - ConfigOpts = [{dir, ConfDir}, {verbosity, trace}, {db_dir, DbDir}], + ConfigOpts = [{dir, ConfDir}, {verbosity, trace}, + {db_dir, DbDir}, {db_init_error, create}], Mibs = [join(StdMibDir, "SNMP-NOTIFICATION-MIB"), join(StdMibDir, "SNMP-USER-BASED-SM-MIB")], Prio = normal, @@ -1674,7 +1682,34 @@ start_with_invalid_usm_conf_file1(Conf) when is_list(Conf) -> %% --- %% +start_with_create_db_and_dir_opt(suite) -> []; +start_with_create_db_and_dir_opt(doc) -> + "Start the snmp manager config process with the\n" + "create_db_and_dir option."; +start_with_create_db_and_dir_opt(Conf) when is_list(Conf) -> + put(tname, swcdado), + p("start"), + process_flag(trap_exit, true), + ConfDir = ?config(manager_conf_dir, Conf), + DbDir = ?config(manager_db_dir, Conf), + true = not filelib:is_dir(DbDir) and not filelib:is_file(DbDir), + write_manager_conf(ConfDir), + + p("verify nonexistent db_dir"), + ConfigOpts01 = [{verbosity,trace}, {dir, ConfDir}, {db_dir, DbDir}], + {error, Reason01} = config_start([{config, ConfigOpts01}]), + p("nonexistent db_dir res: ~p", [Reason01]), + {invalid_conf_db_dir, _, not_found} = Reason01, + p("verify nonexistent db_dir gets created"), + ConfigOpts02 = [{db_init_error, create_db_and_dir} | ConfigOpts01], + {ok, _Pid} = config_start([{config, ConfigOpts02}]), + true = filelib:is_dir(DbDir), + p("verified: nonexistent db_dir was correctly created"), + ok = config_stop(), + + p("done"), + ok. %% %% --- diff --git a/lib/snmp/test/snmp_manager_test.erl b/lib/snmp/test/snmp_manager_test.erl index dedbae5ce4..5fe18980bc 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-2012. All Rights Reserved. +%% Copyright Ericsson AB 2003-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -1615,10 +1615,10 @@ simple_sync_get1(Config) when is_list(Config) -> ok. do_simple_sync_get(Node, Addr, Port, Oids) -> - ?line {ok, Reply, Rem} = mgr_user_sync_get(Node, Addr, Port, Oids), + ?line {ok, Reply, _Rem} = mgr_user_sync_get(Node, Addr, Port, Oids), ?DBG("~n Reply: ~p" - "~n Rem: ~w", [Reply, Rem]), + "~n Rem: ~w", [Reply, _Rem]), %% verify that the operation actually worked: %% The order should be the same, so no need to seach @@ -1682,10 +1682,10 @@ do_simple_sync_get2(Config, Get, PostVerify) -> do_simple_sync_get2(Node, TargetName, Oids, Get, PostVerify) when is_function(Get, 3) andalso is_function(PostVerify, 0) -> - ?line {ok, Reply, Rem} = Get(Node, TargetName, Oids), + ?line {ok, Reply, _Rem} = Get(Node, TargetName, Oids), ?DBG("~n Reply: ~p" - "~n Rem: ~w", [Reply, Rem]), + "~n Rem: ~w", [Reply, _Rem]), %% verify that the operation actually worked: %% The order should be the same, so no need to seach @@ -2061,10 +2061,10 @@ simple_sync_get_next1(Config) when is_list(Config) -> do_simple_get_next(N, Node, Addr, Port, Oids, Verify) -> p("issue get-next command ~w", [N]), case mgr_user_sync_get_next(Node, Addr, Port, Oids) of - {ok, Reply, Rem} -> + {ok, Reply, _Rem} -> ?DBG("get-next ok:" "~n Reply: ~p" - "~n Rem: ~w", [Reply, Rem]), + "~n Rem: ~w", [Reply, _Rem]), Verify(Reply); Error -> @@ -2217,10 +2217,10 @@ do_simple_sync_get_next2(Config, GetNext, PostVerify) do_simple_get_next(N, Node, TargetName, Oids, Verify, GetNext, PostVerify) -> p("issue get-next command ~w", [N]), case GetNext(Node, TargetName, Oids) of - {ok, Reply, Rem} -> + {ok, Reply, _Rem} -> ?DBG("get-next ok:" "~n Reply: ~p" - "~n Rem: ~w", [Reply, Rem]), + "~n Rem: ~w", [Reply, _Rem]), PostVerify(Verify(Reply)); Error -> @@ -2551,10 +2551,10 @@ simple_sync_set1(Config) when is_list(Config) -> do_simple_set1(Node, Addr, Port, VAVs) -> [SysName, SysLoc] = value_of_vavs(VAVs), - ?line {ok, Reply, Rem} = mgr_user_sync_set(Node, Addr, Port, VAVs), + ?line {ok, Reply, _Rem} = mgr_user_sync_set(Node, Addr, Port, VAVs), ?DBG("~n Reply: ~p" - "~n Rem: ~w", [Reply, Rem]), + "~n Rem: ~w", [Reply, _Rem]), %% verify that the operation actually worked: %% The order should be the same, so no need to seach @@ -2631,10 +2631,10 @@ do_simple_sync_set2(Config, Set, PostVerify) do_simple_set2(Node, TargetName, VAVs, Set, PostVerify) -> [SysName, SysLoc] = value_of_vavs(VAVs), - ?line {ok, Reply, Rem} = Set(Node, TargetName, VAVs), + ?line {ok, Reply, _Rem} = Set(Node, TargetName, VAVs), ?DBG("~n Reply: ~p" - "~n Rem: ~w", [Reply, Rem]), + "~n Rem: ~w", [Reply, _Rem]), %% verify that the operation actually worked: %% The order should be the same, so no need to seach @@ -3026,10 +3026,10 @@ fl(L) -> do_simple_get_bulk1(N, Node, Addr, Port, NonRep, MaxRep, Oids, Verify) -> p("issue get-bulk command ~w", [N]), case mgr_user_sync_get_bulk(Node, Addr, Port, NonRep, MaxRep, Oids) of - {ok, Reply, Rem} -> + {ok, Reply, _Rem} -> ?DBG("get-bulk ok:" "~n Reply: ~p" - "~n Rem: ~w", [Reply, Rem]), + "~n Rem: ~w", [Reply, _Rem]), Verify(Reply); Error -> @@ -3213,10 +3213,10 @@ do_simple_get_bulk2(N, is_function(PostVerify) -> p("issue get-bulk command ~w", [N]), case GetBulk(NonRep, MaxRep, Oids) of - {ok, Reply, Rem} -> + {ok, Reply, _Rem} -> ?DBG("get-bulk ok:" "~n Reply: ~p" - "~n Rem: ~w", [Reply, Rem]), + "~n Rem: ~w", [Reply, _Rem]), PostVerify(Verify(Reply)); Error -> @@ -5609,11 +5609,11 @@ init_mgr_user_data1(Conf) -> [{address, Addr}, {port, Port}, {engine_id, "agentEngine"}]), - Agents = mgr_user_which_own_agents(Node), - ?DBG("Own agents: ~p", [Agents]), + _Agents = mgr_user_which_own_agents(Node), + ?DBG("Own agents: ~p", [_Agents]), - ?line {ok, DefAgentConf} = mgr_user_agent_info(Node, TargetName, all), - ?DBG("Default agent config: ~n~p", [DefAgentConf]), + ?line {ok, _DefAgentConf} = mgr_user_agent_info(Node, TargetName, all), + ?DBG("Default agent config: ~n~p", [_DefAgentConf]), ?line ok = mgr_user_update_agent_info(Node, TargetName, community, "all-rights"), @@ -5624,8 +5624,8 @@ init_mgr_user_data1(Conf) -> ?line ok = mgr_user_update_agent_info(Node, TargetName, max_message_size, 1024), - ?line {ok, AgentConf} = mgr_user_agent_info(Node, TargetName, all), - ?DBG("Updated agent config: ~n~p", [AgentConf]), + ?line {ok, _AgentConf} = mgr_user_agent_info(Node, TargetName, all), + ?DBG("Updated agent config: ~n~p", [_AgentConf]), Conf. init_mgr_user_data2(Conf) -> @@ -5639,11 +5639,11 @@ init_mgr_user_data2(Conf) -> [{address, Addr}, {port, Port}, {engine_id, "agentEngine"}]), - Agents = mgr_user_which_own_agents(Node), - ?DBG("Own agents: ~p", [Agents]), + _Agents = mgr_user_which_own_agents(Node), + ?DBG("Own agents: ~p", [_Agents]), - ?line {ok, DefAgentConf} = mgr_user_agent_info(Node, TargetName, all), - ?DBG("Default agent config: ~n~p", [DefAgentConf]), + ?line {ok, _DefAgentConf} = mgr_user_agent_info(Node, TargetName, all), + ?DBG("Default agent config: ~n~p", [_DefAgentConf]), ?line ok = mgr_user_update_agent_info(Node, TargetName, community, "all-rights"), @@ -5652,8 +5652,8 @@ init_mgr_user_data2(Conf) -> ?line ok = mgr_user_update_agent_info(Node, TargetName, max_message_size, 1024), - ?line {ok, AgentConf} = mgr_user_agent_info(Node, TargetName, all), - ?DBG("Updated agent config: ~n~p", [AgentConf]), + ?line {ok, _AgentConf} = mgr_user_agent_info(Node, TargetName, all), + ?DBG("Updated agent config: ~n~p", [_AgentConf]), Conf. fin_mgr_user_data1(Conf) -> @@ -5853,12 +5853,12 @@ mgr_user_name_to_oid(Node, Name) -> start_manager(Node, Vsns, Config) -> start_manager(Node, Vsns, Config, []). -start_manager(Node, Vsns, Conf0, Opts) -> +start_manager(Node, Vsns, Conf0, _Opts) -> ?DBG("start_manager -> entry with" "~n Node: ~p" "~n Vsns: ~p" "~n Conf0: ~p" - "~n Opts: ~p", [Node, Vsns, Conf0, Opts]), + "~n Opts: ~p", [Node, Vsns, Conf0, _Opts]), AtlDir = ?config(manager_log_dir, Conf0), ConfDir = ?config(manager_conf_dir, Conf0), @@ -5908,12 +5908,12 @@ stop_manager(Node, Conf) -> start_agent(Node, Vsns, Config) -> start_agent(Node, Vsns, Config, []). -start_agent(Node, Vsns, Conf0, Opts) -> +start_agent(Node, Vsns, Conf0, _Opts) -> ?DBG("start_agent -> entry with" "~n Node: ~p" "~n Vsns: ~p" "~n Conf0: ~p" - "~n Opts: ~p", [Node, Vsns, Conf0, Opts]), + "~n Opts: ~p", [Node, Vsns, Conf0, _Opts]), AtlDir = ?config(agent_log_dir, Conf0), ConfDir = ?config(agent_conf_dir, Conf0), diff --git a/lib/snmp/test/snmp_manager_user.erl b/lib/snmp/test/snmp_manager_user.erl index 4e789bbaec..ddbe156130 100644 --- a/lib/snmp/test/snmp_manager_user.erl +++ b/lib/snmp/test/snmp_manager_user.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2012. All Rights Reserved. +%% Copyright Ericsson AB 2005-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -681,6 +681,15 @@ loop(#state{parent = Parent, id = Id} = S) -> Parent ! {async_event, TargetName, {report, SnmpReport}}, loop(S); + {handle_invalid_result, _Pid, In, Out} -> + d("loop -> received invalid result callback from manager for " + "~n In: ~p", + "~n Out: ~p", [In, Out]), + info("received invalid result message: " + "~n In: ~p" + "~n Out: ~p", [In, Out]), + loop(S); + {'EXIT', Parent, Reason} -> d("received exit signal from parent: ~n~p", [Reason]), info("received exit signal from parent: ~n~p", [Reason]), @@ -770,7 +779,7 @@ handle_pdu(TargetName, ReqId, SnmpResponse, UserPid) -> handle_trap(TargetName, SnmpTrap, UserPid) -> UserPid ! {handle_trap, self(), TargetName, SnmpTrap}, - ok. + ignore. handle_inform(TargetName, SnmpInform, UserPid) -> UserPid ! {handle_inform, self(), TargetName, SnmpInform}, @@ -778,12 +787,12 @@ handle_inform(TargetName, SnmpInform, UserPid) -> {handle_inform_no_response, TargetName} -> no_reply; {handle_inform_response, TargetName} -> - ok + ignore end. handle_report(TargetName, SnmpReport, UserPid) -> UserPid ! {handle_report, self(), TargetName, SnmpReport}, - ok. + ignore. %%---------------------------------------------------------------------- diff --git a/lib/snmp/test/snmp_test_manager.erl b/lib/snmp/test/snmp_test_manager.erl index 1f3383a7a8..925ae77ab5 100644 --- a/lib/snmp/test/snmp_test_manager.erl +++ b/lib/snmp/test/snmp_test_manager.erl @@ -47,7 +47,8 @@ handle_pdu/4, handle_trap/3, handle_inform/3, - handle_report/3 + handle_report/3, + handle_invalid_result/3 ]). @@ -279,12 +280,18 @@ handle_info({snmp_inform, TargetName, Info, Pid}, handle_info({snmp_report, TargetName, Info, Pid}, #state{parent = P} = State) -> info_msg("received snmp report: " - "~n TargetName: ~p" - "~n Info: ~p", [TargetName, Info]), + "~n TargetName: ~p" + "~n Info: ~p", [TargetName, Info]), Pid ! {snmp_report_reply, ignore, self()}, P ! {snmp_report, TargetName, Info}, {noreply, State}; +handle_info({snmp_invalid_result, In, Out}, State) -> + error_msg("Callback failure: " + "~n In: ~p" + "~n Out: ~p", [In, Out]), + {noreply, State}; + handle_info(Info, State) -> error_msg("received unknown info: " "~n Info: ~p", [Info]), @@ -369,7 +376,12 @@ handle_report(TargetName, SnmpInfo, Pid) -> after 10000 -> ignore end. - + + +handle_invalid_result(In, Out, Pid) -> + Pid ! {snmp_invalid_result, In, Out}, + ignore. + %%---------------------------------------------------------------------- diff --git a/lib/snmp/vsn.mk b/lib/snmp/vsn.mk index 2164121e86..70f7c2b19a 100644 --- a/lib/snmp/vsn.mk +++ b/lib/snmp/vsn.mk @@ -18,6 +18,6 @@ # %CopyrightEnd% APPLICATION = snmp -SNMP_VSN = 4.24.2 +SNMP_VSN = 4.25 PRE_VSN = APP_VSN = "$(APPLICATION)-$(SNMP_VSN)$(PRE_VSN)" diff --git a/lib/ssh/src/ssh_acceptor_sup.erl b/lib/ssh/src/ssh_acceptor_sup.erl index f37e1fe4ff..2be729d305 100644 --- a/lib/ssh/src/ssh_acceptor_sup.erl +++ b/lib/ssh/src/ssh_acceptor_sup.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -84,8 +84,8 @@ child_spec(ServerOpts) -> [{active, false}, {reuseaddr, true}] ++ SocketOpts, ServerOpts, Timeout]}, - Restart = permanent, - Shutdown = 3600, + Restart = transient, + Shutdown = brutal_kill, Modules = [ssh_acceptor], Type = worker, {Name, StartFunc, Restart, Shutdown, Type, Modules}. diff --git a/lib/ssh/src/ssh_connection.erl b/lib/ssh/src/ssh_connection.erl index 7016f349e8..03dddae3c8 100644 --- a/lib/ssh/src/ssh_connection.erl +++ b/lib/ssh/src/ssh_connection.erl @@ -730,7 +730,6 @@ handle_msg(#ssh_msg_request_success{data = Data}, {{replies, [{channel_requst_reply, From, {success, Data}}]}, Connection#connection{requests = Rest}}; -%%% This transport message will also be handled at the connection level handle_msg(#ssh_msg_disconnect{code = Code, description = Description, language = _Lang }, diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl index 7ba2179a76..3462b98172 100644 --- a/lib/ssh/src/ssh_connection_handler.erl +++ b/lib/ssh/src/ssh_connection_handler.erl @@ -519,7 +519,8 @@ connected({#ssh_msg_kexinit{}, _Payload} = Event, State) -> #state{}) -> gen_fsm_state_return(). %%-------------------------------------------------------------------- -handle_event(#ssh_msg_disconnect{description = Desc}, _StateName, #state{} = State) -> +handle_event(#ssh_msg_disconnect{description = Desc} = DisconnectMsg, _StateName, #state{} = State) -> + handle_disconnect(DisconnectMsg, State), {stop, {shutdown, Desc}, State}; handle_event(#ssh_msg_ignore{}, StateName, State) -> @@ -850,7 +851,11 @@ handle_info({Protocol, Socket, Data}, Statename, handle_info({CloseTag, _Socket}, _StateName, #state{transport_close_tag = CloseTag, ssh_params = #ssh{role = _Role, opts = _Opts}} = State) -> - {stop, {shutdown, "Connection Lost"}, State}; + DisconnectMsg = + #ssh_msg_disconnect{code = ?SSH_DISCONNECT_BY_APPLICATION, + description = "Connection closed", + language = "en"}, + handle_disconnect(DisconnectMsg, State); handle_info({timeout, {_, From} = Request}, Statename, #state{connection_state = #connection{requests = Requests} = Connection} = State) -> @@ -1377,10 +1382,16 @@ handle_ssh_packet(Length, StateName, #state{decoded_data_buffer = DecData0, handle_disconnect(DisconnectMsg, State0) end. -handle_disconnect(#ssh_msg_disconnect{description = Desc}, State) -> - {stop, {shutdown, Desc}, State}. -handle_disconnect(#ssh_msg_disconnect{description = Desc}, State, ErrorMsg) -> - {stop, {shutdown, {Desc, ErrorMsg}}, State}. +handle_disconnect(#ssh_msg_disconnect{description = Desc} = Msg, #state{connection_state = Connection0, + role = Role} = State0) -> + {disconnect, _, {{replies, Replies}, Connection}} = ssh_connection:handle_msg(Msg, Connection0, Role), + State = send_replies(Replies, State0), + {stop, {shutdown, Desc}, State#state{connection_state = Connection}}. +handle_disconnect(#ssh_msg_disconnect{description = Desc} = Msg, #state{connection_state = Connection0, + role = Role} = State0, ErrorMsg) -> + {disconnect, _, {{replies, Replies}, Connection}} = ssh_connection:handle_msg(Msg, Connection0, Role), + State = send_replies(Replies, State0), + {stop, {shutdown, {Desc, ErrorMsg}}, State#state{connection_state = Connection}}. counterpart_versions(NumVsn, StrVsn, #ssh{role = server} = Ssh) -> Ssh#ssh{c_vsn = NumVsn , c_version = StrVsn}; @@ -1420,9 +1431,9 @@ retry_fun(User, PeerAddr, Reason, Opts) -> do_retry_fun(Fun, User, PeerAddr, Reason) -> case erlang:fun_info(Fun, arity) of - 2 -> %% Backwards compatible + {arity, 2} -> %% Backwards compatible catch Fun(User, Reason); - 3 -> + {arity, 3} -> catch Fun(User, PeerAddr, Reason) end. diff --git a/lib/ssh/src/ssh_system_sup.erl b/lib/ssh/src/ssh_system_sup.erl index bf3c12a988..848133f838 100644 --- a/lib/ssh/src/ssh_system_sup.erl +++ b/lib/ssh/src/ssh_system_sup.erl @@ -54,13 +54,16 @@ stop_listener(SysSup) -> stop_listener(Address, Port) -> Name = make_name(Address, Port), stop_acceptor(whereis(Name)). - -stop_system(SysSup) when is_pid(SysSup)-> - exit(SysSup, shutdown). + +stop_system(SysSup) -> + Name = sshd_sup:system_name(SysSup), + spawn(fun() -> sshd_sup:stop_child(Name) end), + ok. stop_system(Address, Port) -> - stop_system(system_supervisor(Address, Port)). - + spawn(fun() -> sshd_sup:stop_child(Address, Port) end), + ok. + system_supervisor(Address, Port) -> Name = make_name(Address, Port), whereis(Name). @@ -136,7 +139,7 @@ ssh_acceptor_child_spec(ServerOpts) -> Port = proplists:get_value(port, ServerOpts), Name = id(ssh_acceptor_sup, Address, Port), StartFunc = {ssh_acceptor_sup, start_link, [ServerOpts]}, - Restart = permanent, + Restart = transient, Shutdown = infinity, Modules = [ssh_acceptor_sup], Type = supervisor, diff --git a/lib/ssh/src/sshd_sup.erl b/lib/ssh/src/sshd_sup.erl index 747906b2cf..60222f5172 100644 --- a/lib/ssh/src/sshd_sup.erl +++ b/lib/ssh/src/sshd_sup.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -58,12 +58,7 @@ start_child(ServerOpts) -> end. stop_child(Name) -> - case supervisor:terminate_child(?MODULE, Name) of - ok -> - supervisor:delete_child(?MODULE, Name); - Error -> - Error - end. + supervisor:terminate_child(?MODULE, Name). stop_child(Address, Port) -> Name = id(Address, Port), @@ -94,7 +89,7 @@ init([Servers]) -> child_spec(Address, Port, ServerOpts) -> Name = id(Address, Port), StartFunc = {ssh_system_sup, start_link, [ServerOpts]}, - Restart = transient, + Restart = temporary, Shutdown = infinity, Modules = [ssh_system_sup], Type = supervisor, diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl index b3281e433e..b4e3871efd 100644 --- a/lib/ssh/test/ssh_basic_SUITE.erl +++ b/lib/ssh/test/ssh_basic_SUITE.erl @@ -46,7 +46,7 @@ all() -> daemon_already_started, server_password_option, server_userpassword_option, - close]. + double_close]. groups() -> [{dsa_key, [], basic_tests()}, @@ -57,7 +57,7 @@ groups() -> ]. basic_tests() -> - [send, peername_sockname, + [send, close, peername_sockname, exec, exec_compressed, shell, cli, known_hosts, idle_time, rekey, openssh_zlib_basic_test]. @@ -487,7 +487,7 @@ internal_error(Config) when is_list(Config) -> {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, {user_dir, UserDir}, {failfun, fun ssh_test_lib:failfun/2}]), - {error,Error} = + {error, Error} = ssh:connect(Host, Port, [{silently_accept_hosts, true}, {user_dir, UserDir}, {user_interaction, false}]), @@ -566,9 +566,35 @@ ips(Name) when is_list(Name) -> ordsets:from_list(IPs4++IPs6). %%-------------------------------------------------------------------- + close() -> - [{doc, "Simulate that we try to close an already closed connection"}]. + [{doc, "Client receives close when server closes"}]. close(Config) when is_list(Config) -> + process_flag(trap_exit, true), + SystemDir = filename:join(?config(priv_dir, Config), system), + UserDir = ?config(priv_dir, Config), + + {Server, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, + {user_dir, UserDir}, + {failfun, fun ssh_test_lib:failfun/2}]), + Client = + ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, + {user_dir, UserDir}, + {user_interaction, false}]), + {ok, ChannelId} = ssh_connection:session_channel(Client, infinity), + + ssh:stop_daemon(Server), + receive + {ssh_cm, Client,{closed, ChannelId}} -> + ok + after 5000 -> + ct:fail(timeout) + end. + +%%-------------------------------------------------------------------- +double_close() -> + [{doc, "Simulate that we try to close an already closed connection"}]. +double_close(Config) when is_list(Config) -> SystemDir = ?config(data_dir, Config), PrivDir = ?config(priv_dir, Config), UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth @@ -587,6 +613,8 @@ close(Config) when is_list(Config) -> exit(CM, {shutdown, normal}), ok = ssh:close(CM). +%%-------------------------------------------------------------------- + openssh_zlib_basic_test() -> [{doc, "Test basic connection with openssh_zlib"}]. openssh_zlib_basic_test(Config) -> @@ -612,7 +640,7 @@ openssh_zlib_basic_test(Config) -> %% the "tcp-application" before the socket closed message is recived check_error("Internal error") -> ok; -check_error("Connection Lost") -> +check_error("Connection closed") -> ok; check_error(Error) -> ct:fail(Error). |