diff options
30 files changed, 229 insertions, 141 deletions
@@ -73,4 +73,4 @@ Copyright and License [1]: http://www.erlang.org [2]: http://wiki.github.com/erlang/otp/submitting-patches - [3]: http://www.erlang.org/faq.html + [3]: http://www.erlang.org/static/doc/mailinglist.html diff --git a/erts/doc/src/erlc.xml b/erts/doc/src/erlc.xml index 3358b8f115..09ed4bd372 100644 --- a/erts/doc/src/erlc.xml +++ b/erts/doc/src/erlc.xml @@ -67,7 +67,7 @@ <item> <p>Instructs the compiler to search for include files in the specified directory. When encountering an - <c><![CDATA[-include]]></c> or <c><![CDATA[-include_dir]]></c> directive, the + <c><![CDATA[-include]]></c> or <c><![CDATA[-include_lib]]></c> directive, the compiler searches for header files in the following directories:</p> <list type="ordered"> diff --git a/erts/emulator/beam/erl_async.c b/erts/emulator/beam/erl_async.c index cb975d64b0..f308039baf 100644 --- a/erts/emulator/beam/erl_async.c +++ b/erts/emulator/beam/erl_async.c @@ -394,6 +394,8 @@ static ERTS_INLINE void call_async_ready(ErtsAsync *a) } erts_port_release(p); } + if (a->pdl) + driver_pdl_dec_refc(a->pdl); if (a->hndl) erts_ddll_dereference_driver(a->hndl); } @@ -403,9 +405,6 @@ static ERTS_INLINE void async_reply(ErtsAsync *a, ErtsThrQPrepEnQ_t *prep_enq) #if ERTS_USE_ASYNC_READY_Q ErtsAsyncReadyQ *arq; - if (a->pdl) - driver_pdl_dec_refc(a->pdl); - #if ERTS_ASYNC_PRINT_JOB erts_fprintf(stderr, "=>> %ld\n", a->async_id); #endif @@ -425,8 +424,6 @@ static ERTS_INLINE void async_reply(ErtsAsync *a, ErtsThrQPrepEnQ_t *prep_enq) #else /* ERTS_USE_ASYNC_READY_Q */ call_async_ready(a); - if (a->pdl) - driver_pdl_dec_refc(a->pdl); erts_free(ERTS_ALC_T_ASYNC, (void *) a); #endif /* ERTS_USE_ASYNC_READY_Q */ diff --git a/erts/emulator/beam/erl_time_sup.c b/erts/emulator/beam/erl_time_sup.c index f90daadadc..a44401d7b1 100644 --- a/erts/emulator/beam/erl_time_sup.c +++ b/erts/emulator/beam/erl_time_sup.c @@ -351,7 +351,7 @@ static int clock_resolution; /* ** The clock resolution should really be the resolution of the ** time function in use, which on most platforms -** is 1. On VxWorks the resolution shold be +** is 1. On VxWorks the resolution should be ** the number of ticks per second (or 1, which would work nicely to). ** ** Setting lower resolutions is mostly interesting when timers are used diff --git a/erts/preloaded/src/prim_file.erl b/erts/preloaded/src/prim_file.erl index 0fc56c8c8e..ec158ba970 100644 --- a/erts/preloaded/src/prim_file.erl +++ b/erts/preloaded/src/prim_file.erl @@ -453,7 +453,7 @@ position(#file_descriptor{module = ?MODULE, data = {Port, _}}, At) -> {error, Reason} end. -%% Returns {error, Reaseon} | ok. +%% Returns {error, Reason} | ok. truncate(#file_descriptor{module = ?MODULE, data = {Port, _}}) -> drv_command(Port, <<?FILE_TRUNCATE>>). diff --git a/lib/common_test/doc/src/write_test_chapter.xml b/lib/common_test/doc/src/write_test_chapter.xml index 90c08032ec..248d7de8b6 100644 --- a/lib/common_test/doc/src/write_test_chapter.xml +++ b/lib/common_test/doc/src/write_test_chapter.xml @@ -886,7 +886,7 @@ of its sub-groups. If a timetrap value is defined by <c>group/1</c> for a sub-group, it overrides that of its higher level groups. Timetrap values set by individual test cases (by means of the test case info - function) overrides both group- and suite- level timetraps.</p> + function) override both group- and suite- level timetraps.</p> <p>It is also possible to dynamically set/reset a timetrap during the excution of a test case, or configuration function. This is done by calling diff --git a/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1.cfg b/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1.cfg index 6466571623..b431301df6 100644 --- a/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1.cfg +++ b/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1.cfg @@ -1,5 +1,5 @@ %% -*- erlang -*- -{netconf1,[{ssh,"localhost"}, +{netconf1,[{ssh,"127.0.0.1"}, {port,2060}, {user,"xxx"}, {password,"xxx"}]}. diff --git a/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl b/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl index 79768a9a6a..d337158bce 100644 --- a/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl +++ b/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl @@ -107,7 +107,8 @@ all() -> connection_crash, get_event_streams, create_subscription, - receive_event] + receive_event + ] end. @@ -216,6 +217,7 @@ hello_required_exists(Config) -> ?NS:expect_do_reply('close-session',close,ok), ?ok = ct_netconfc:close_session(my_named_connection), + timer:sleep(500), %% Then check that it can be used again after the first is closed {ok,_Client2} = open_configured_success(my_named_connection,DataDir), @@ -234,7 +236,7 @@ hello_global_pwd(Config) -> hello_no_session_id(Config) -> DataDir = ?config(data_dir,Config), ?NS:hello(no_session_id), - ?NS:expect(hello), + ?NS:expect(no_session_id,hello), {error,{incorrect_hello,no_session_id_found}} = open(DataDir), ok. @@ -261,7 +263,7 @@ hello_no_caps(Config) -> no_server_hello(Config) -> DataDir = ?config(data_dir,Config), - ?NS:expect(hello), + ?NS:expect(undefined,hello), {error,{hello_session_failed,timeout}} = open(DataDir,[{timeout,2000}]), ok. @@ -435,7 +437,7 @@ kill_session(Config) -> {ok,Client} = open_success(DataDir), ?NS:hello(2), - ?NS:expect(hello), + ?NS:expect(2,hello), {ok,_OtherClient} = open(DataDir), ?NS:expect_do_reply('kill-session',{kill,2},ok), diff --git a/lib/common_test/test/ct_netconfc_SUITE_data/ns.erl b/lib/common_test/test/ct_netconfc_SUITE_data/ns.erl index 665b0e556c..2427f37f52 100644 --- a/lib/common_test/test/ct_netconfc_SUITE_data/ns.erl +++ b/lib/common_test/test/ct_netconfc_SUITE_data/ns.erl @@ -31,9 +31,13 @@ hello/1, hello/2, expect/1, + expect/2, expect_reply/2, + expect_reply/3, expect_do/2, + expect_do/3, expect_do_reply/3, + expect_do_reply/4, hupp/1, hupp/2]). @@ -110,22 +114,30 @@ hello(SessionId,Stuff) -> %% actions. To be called directly before sending a request. expect(Expect) -> expect_do_reply(Expect,undefined,undefined). +expect(SessionId,Expect) -> + expect_do_reply(SessionId,Expect,undefined,undefined). %% Tell server to expect the given message and reply with the give %% reply. To be called directly before sending a request. expect_reply(Expect,Reply) -> expect_do_reply(Expect,undefined,Reply). +expect_reply(SessionId,Expect,Reply) -> + expect_do_reply(SessionId,Expect,undefined,Reply). %% Tell server to expect the given message and perform an action. To %% be called directly before sending a request. expect_do(Expect,Do) -> expect_do_reply(Expect,Do,undefined). +expect_do(SessionId,Expect,Do) -> + expect_do_reply(SessionId,Expect,Do,undefined). %% Tell server to expect the given message, perform an action and %% reply with the given reply. To be called directly before sending a %% request. expect_do_reply(Expect,Do,Reply) -> - add_expect({Expect,Do,Reply}). + add_expect(1,{Expect,Do,Reply}). +expect_do_reply(SessionId,Expect,Do,Reply) -> + add_expect(SessionId,{Expect,Do,Reply}). %% Hupp the server - i.e. tell it to do something - %% e.g. hupp(send_event) will cause send_event(State) to be called on @@ -133,17 +145,19 @@ expect_do_reply(Expect,Do,Reply) -> hupp(send_event) -> hupp(send,[make_msg(event)]); hupp(kill) -> - hupp(fun hupp_kill/1,[]). + hupp(1,fun hupp_kill/1,[]). hupp(send,Data) -> - hupp(fun hupp_send/2,[Data]); -hupp(Fun,Args) when is_function(Fun) -> - [{_,Pid}] = lookup(channel_process), + hupp(1,fun hupp_send/2,[Data]). + +hupp(SessionId,Fun,Args) when is_function(Fun) -> + [{_,Pid}] = lookup({channel_process,SessionId}), Pid ! {hupp,Fun,Args}. %%%----------------------------------------------------------------- %%% Main loop of the netconf server init_server(Dir) -> + register(main_ns_proc,self()), ets:new(ns_tab,[set,named_table,public]), Config = ?ssh_config(Dir), {_,Host} = lists:keyfind(interface, 1, Config), @@ -165,7 +179,12 @@ loop(Daemon) -> receive {stop,From} -> ssh:stop_daemon(Daemon), - From ! stopped + From ! stopped; + {table_trans,Fun,Args,From} -> + %% Simple transaction mechanism for ets table + R = apply(Fun,Args), + From ! {table_trans_done,R}, + loop(Daemon) end. %%---------------------------------------------------------------------- @@ -178,7 +197,7 @@ terminate(_Reason, _State) -> ok. handle_ssh_msg({ssh_cm,CM,{data, Ch, _Type = 0, Data}}, State) -> - %% erlang:display({self(),data,CM,Ch,State}), + %% io:format("~p~n",[{self(),Data,CM,Ch,State}]), data_for_channel(CM, Ch, Data, State); handle_ssh_msg({ssh_cm,CM,{closed, Ch}}, State) -> %% erlang:display({self(),closed,CM,Ch,State}), @@ -194,7 +213,7 @@ handle_msg({ssh_channel_up,Ch,CM},undefined) -> %% erlang:display({self(),up,CM,Ch}), ConnRef = {CM,Ch}, SessionId = maybe_hello(ConnRef), - insert(channel_process,self()), % used to hupp the server + insert({channel_process,SessionId},self()), % used to hupp the server {ok, #session{connection = ConnRef, session_id = SessionId}}; handle_msg({hupp,Fun,Args},State) -> @@ -214,17 +233,19 @@ data_for_channel(CM, Ch, Data, State) -> Stacktrace = erlang:get_stacktrace(), error_logger:error_report([{?MODULE, data_for_channel}, {request, Data}, + {buffer, State#session.buffer}, {reason, {Class, Reason}}, {stacktrace, Stacktrace}]), stop_channel(CM, Ch, State) end. data(Data, State = #session{connection = ConnRef, - buffer = Buffer}) -> + buffer = Buffer, + session_id = SessionId}) -> AllData = <<Buffer/binary,Data/binary>>, case find_endtag(AllData) of {ok,Msgs,Rest} -> - [check_expected(ConnRef,Msg) || Msg <- Msgs], + [check_expected(SessionId,ConnRef,Msg) || Msg <- Msgs], {ok,State#session{buffer=Rest}}; need_more -> {ok,State#session{buffer=AllData}} @@ -258,15 +279,42 @@ send({CM,Ch},Data) -> kill({CM,_Ch}) -> ssh:close(CM). -add_expect(Add) -> - case lookup(expect) of +add_expect(SessionId,Add) -> + table_trans(fun do_add_expect/2,[SessionId,Add]). + +table_trans(Fun,Args) -> + S = self(), + case whereis(main_ns_proc) of + S -> + apply(Fun,Args); + Pid -> + Pid ! {table_trans,Fun,Args,self()}, + receive + {table_trans_done,Result} -> + Result + after 5000 -> + exit(table_trans_timeout) + end + end. + +do_add_expect(SessionId,Add) -> + case lookup({expect,SessionId}) of [] -> - insert(expect,[Add]); - [{expect,First}] -> - insert(expect,First ++ [Add]) + insert({expect,SessionId},[Add]); + [{_,First}] -> + insert({expect,SessionId},First ++ [Add]) end, ok. +do_get_expect(SessionId) -> + case lookup({expect,SessionId}) of + [{_,[{Expect,Do,Reply}|Rest]}] -> + insert({expect,SessionId},Rest), + {Expect,Do,Reply}; + _ -> + error + end. + insert(Key,Value) -> ets:insert(ns_tab,{Key,Value}). lookup(Key) -> @@ -292,17 +340,18 @@ find_endtag(Data) -> {ok,lists:sublist(Msgs,length(Msgs)-1),lists:last(Msgs)} end. -check_expected(ConnRef,Msg) -> - case lookup(expect) of - [{expect,[{Expect,Do,Reply}|Rest]}] -> - insert(expect,Rest), +check_expected(SessionId,ConnRef,Msg) -> + %% io:format("~p~n",[{check_expected,SessionId,Msg}]), + case table_trans(fun do_get_expect/1,[SessionId]) of + {Expect,Do,Reply} -> %% erlang:display({got,io_lib:format("~s",[Msg])}), %% erlang:display({expected,Expect}), match(Msg,Expect), do(ConnRef, Do), reply(ConnRef,Reply); - Expected -> - exit({error,{got_unexpected,Msg,Expected}}) + error -> + timer:sleep(1000), + exit({error,{got_unexpected,SessionId,Msg,ets:tab2list(ns_tab)}}) end. match(Msg,Expect) -> diff --git a/lib/compiler/doc/src/compile.xml b/lib/compiler/doc/src/compile.xml index be9eb1cd75..27d750f929 100644 --- a/lib/compiler/doc/src/compile.xml +++ b/lib/compiler/doc/src/compile.xml @@ -316,7 +316,7 @@ module.beam: module.erl \ <item> <p>Add <c>Dir</c> to the list of directories to be searched when including a file. When encountering an - <c>-include</c> or <c>-include_dir</c> directive, + <c>-include</c> or <c>-include_lib</c> directive, the compiler searches for header files in the following directories:</p> <list type="ordered"> diff --git a/lib/diameter/src/base/diameter.erl b/lib/diameter/src/base/diameter.erl index 6703841f80..789a5db5f0 100644 --- a/lib/diameter/src/base/diameter.erl +++ b/lib/diameter/src/base/diameter.erl @@ -312,7 +312,7 @@ call(SvcName, App, Message) -> -type transport_opt() :: {transport_module, atom()} | {transport_config, any()} - | {transport_timeout, non_neg_integer() | infinity} + | {transport_config, any(), non_neg_integer() | infinity} | {applications, [app_alias()]} | {capabilities, [capability()]} | {capabilities_cb, evaluable()} diff --git a/lib/diameter/src/base/diameter_peer.erl b/lib/diameter/src/base/diameter_peer.erl index a2a1c567d8..74ba709aac 100644 --- a/lib/diameter/src/base/diameter_peer.erl +++ b/lib/diameter/src/base/diameter_peer.erl @@ -91,10 +91,21 @@ start(_T, _Opts, #diameter_service{}) -> Opt :: diameter:transport_opt(), TPid :: pid(), Addr :: inet:ip_address(), - Tmo :: non_neg_integer(), + Tmo :: non_neg_integer() | infinity, Data :: {{T, Mod, Cfg}, [Mod], [{T, [Mod], Cfg}], [Err]}, Mod :: module(), Cfg :: term(), + Err :: term() + ; ({#diameter_service{}, Tmo, Data}) + -> {TPid, [Addr], Tmo, Data} + | {error, [term()]} + when TPid :: pid(), + Addr :: inet:ip_address(), + Tmo :: non_neg_integer() | infinity, + Data :: {{T, Mod, Cfg}, [Mod], [{T, [Mod], Cfg}], [Err]}, + T :: {connect|accept, diameter:transport_ref()}, + Mod :: module(), + Cfg :: term(), Err :: term(). %% Initial start. diff --git a/lib/diameter/src/base/diameter_service.erl b/lib/diameter/src/base/diameter_service.erl index 5b8a399758..54594db292 100644 --- a/lib/diameter/src/base/diameter_service.erl +++ b/lib/diameter/src/base/diameter_service.erl @@ -2951,7 +2951,7 @@ info_stats(#state{peerT = PeerT}) -> %% the accumulated values for the ref and associated peer pids. info_transport(S) -> - PeerD = peer_dict(S), + PeerD = peer_dict(S, config_dict(S)), RefsD = dict:map(fun(_, Ls) -> [P || L <- Ls, {peer, {P,_}} <- L] end, PeerD), Refs = lists:append(dict:fold(fun(R, Ps, A) -> [[R|Ps] | A] end, @@ -2966,18 +2966,29 @@ info_transport(S) -> [], PeerD). +%% Only a config entry for a listening transport: use it. +transport([[{type, listen}, _] = L]) -> + L ++ [{accept, []}]; + +%% Only one config or peer entry for a connecting transport: use it. transport([[{type, connect} | _] = L]) -> L; +%% Peer entries: discard config. Note that the peer entries have +%% length at least 3. +transport([[_,_] | L]) -> + transport(L); + +%% Possibly many peer entries for a listening transport. Note that all +%% have the same options by construction, which is not terribly space +%% efficient. (TODO: all entries for the same Ref should share options.) transport([[{type, accept}, {options, Opts} | _] | _] = Ls) -> [{type, listen}, {options, Opts}, {accept, [lists:nthtail(2,L) || L <- Ls]}]. -%% Note that all peer records for a listening transport (ie. same Ref) -%% have the same options. (TODO) -peer_dict(#state{peerT = PeerT, connT = ConnT}) -> - ets:foldl(fun(T,A) -> peer_acc(ConnT, A, T) end, dict:new(), PeerT). +peer_dict(#state{peerT = PeerT, connT = ConnT}, Dict0) -> + ets:foldl(fun(T,A) -> peer_acc(ConnT, A, T) end, Dict0, PeerT). peer_acc(ConnT, Acc, #peer{pid = Pid, type = Type, @@ -3000,6 +3011,22 @@ info_conn(ConnT, TPid, true) info_conn(_, _, _) -> []. +%% The point of extracting the config here is so that 'transport' info +%% has one entry for each transport ref, the peer table only +%% containing entries that have a living watchdog. + +config_dict(#state{service_name = SvcName}) -> + lists:foldl(fun config_acc/2, + dict:new(), + diameter_config:lookup(SvcName)). + +config_acc({Ref, T, Opts}, Dict) + when T == listen; + T == connect -> + dict:store(Ref, [[{type, T}, {options, Opts}]], Dict); +config_acc(_, Dict) -> + Dict. + wd_state({_,S}) -> S; wd_state(?STATE_UP) -> @@ -3023,7 +3050,9 @@ info_port(Pid) -> {TPid, {_Type, TMod, _Cfg}} = T, {_, TD} = process_info(TPid, dictionary), {_, Data} = lists:keyfind({TMod, info}, 1, TD), - [{owner, TPid}, {module, TMod} | [_|_] = TMod:info(Data)]. + [{owner, TPid}, + {module, TMod} + | try TMod:info(Data) catch _:_ -> [] end]. %% Use the fields names from diameter_caps instead of %% diameter_base_CER to distinguish between the 2-tuple values @@ -3036,14 +3065,8 @@ info_caps(#diameter_caps{} = C) -> info_apps(#state{service = #diameter_service{applications = Apps}}) -> lists:map(fun mk_app/1, Apps). -mk_app(#diameter_app{alias = Alias, - dictionary = Dict, - module = ModX, - id = Id}) -> - [{alias, Alias}, - {dictionary, Dict}, - {module, ModX}, - {id, Id}]. +mk_app(#diameter_app{} = A) -> + lists:zip(record_info(fields, diameter_app), tl(tuple_to_list(A))). %% info_pending/1 %% @@ -3074,7 +3097,7 @@ info_connections(S) -> [L ++ [stats([P], Stats)] || L <- ConnL, {peer, {P,_}} <- L]. conn_list(S) -> - lists:append(dict:fold(fun conn_acc/3, [], peer_dict(S))). + lists:append(dict:fold(fun conn_acc/3, [], peer_dict(S, dict:new()))). conn_acc(Ref, Peers, Acc) -> [[[{ref, Ref} | L] || L <- Peers, lists:keymember(peer, 1, L)] @@ -3095,26 +3118,24 @@ stats_acc(Ref, Dict, Stats) -> %% info_peers/1 %% %% One entry per peer Origin-Host. Statistics for each entry are -%% accumulated values for all associated transport refs and peer pids. +%% accumulated values for all peer pids. info_peers(S) -> - ConnL = conn_list(S), {PeerD, RefD} = lists:foldl(fun peer_acc/2, {dict:new(), dict:new()}, - ConnL), - Refs = lists:append(dict:fold(fun(_, Rs, A) -> [lists:append(Rs) | A] end, + conn_list(S)), + Refs = lists:append(dict:fold(fun(_, Rs, A) -> [Rs|A] end, [], RefD)), Stats = diameter_stats:read(Refs), dict:fold(fun(OH, Cs, A) -> - Rs = lists:append(dict:fetch(OH, RefD)), - [{OH, [{connections, Cs}, stats(Rs, Stats)]} - | A] + Rs = dict:fetch(OH, RefD), + [{OH, [{connections, Cs}, stats(Rs, Stats)]} | A] end, [], PeerD). peer_acc(Peer, {PeerD, RefD}) -> - [Ref, {TPid, _}, [{origin_host, {_, OH}} | _]] - = [proplists:get_value(K, Peer) || K <- [ref, peer, caps]], - {dict:append(OH, Peer, PeerD), dict:append(OH, [Ref, TPid], RefD)}. + [{TPid, _}, [{origin_host, {_, OH}} | _]] + = [proplists:get_value(K, Peer) || K <- [peer, caps]], + {dict:append(OH, Peer, PeerD), dict:append(OH, TPid, RefD)}. diff --git a/lib/diameter/src/transport/diameter_tcp.erl b/lib/diameter/src/transport/diameter_tcp.erl index 597f2f14d7..f3fbbee609 100644 --- a/lib/diameter/src/transport/diameter_tcp.erl +++ b/lib/diameter/src/transport/diameter_tcp.erl @@ -80,7 +80,7 @@ %% Accepting/connecting transport process state. -record(transport, - {socket :: inet:socket(), %% accept or connect socket + {socket :: inet:socket() | ssl:sslsock(), %% accept or connect socket parent :: pid(), %% of process that started us module :: module(), %% gen_tcp-like module frag = <<>> :: binary() | {tref(), frag()}, %% message fragment diff --git a/lib/diameter/test/diameter_ct.erl b/lib/diameter/test/diameter_ct.erl index f8ee3dc1d7..ded50bf6c5 100644 --- a/lib/diameter/test/diameter_ct.erl +++ b/lib/diameter/test/diameter_ct.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% Copyright Ericsson AB 2010-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -25,15 +25,14 @@ -export([run/1]). -%% ct:run_test/1 is currently documented as returning a list of test -%% results ... but no. Instead it returns 'ok' regardless of whether -%% or not the suite in question has failed testcases. +%% The makefile looks for signs of failure so ignore the ct:run_test/1 +%% return value. run([Suite]) -> Start = info(), - ok = ct:run_test([{suite, Suite}, - {logdir, "./log"}, - {auto_compile, false}]), + ct:run_test([{suite, Suite}, + {logdir, "./log"}, + {auto_compile, false}]), info(Start , info()). info() -> diff --git a/lib/diameter/test/diameter_gen_sctp_SUITE.erl b/lib/diameter/test/diameter_gen_sctp_SUITE.erl index 5e65b84b56..2fde7b9fdb 100644 --- a/lib/diameter/test/diameter_gen_sctp_SUITE.erl +++ b/lib/diameter/test/diameter_gen_sctp_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% Copyright Ericsson AB 2010-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -175,7 +175,8 @@ send(Sock, Id) -> send_from_multiple_clients(_) -> {S, Rs} = T = send_from_multiple_clients(8, 1024), - {false, [], _} = {?FOREVER < S, + Max = ?FOREVER*1000, + {false, [], _} = {Max < S, Rs -- [OI || {O,_} = OI <- Rs, is_integer(O)], T}. @@ -223,6 +224,11 @@ send_from_multiple_clients(_) -> %% {134,100}, %% {117,98}, %% {149,125}]} +%% +%% This turns out to have been due to SCTP resends as a consequence of +%% the listener having an insufficient recbuf. Increasing the size +%% solves the problem. +%% send_from_multiple_clients(N, Sz) when is_integer(N), 0 < N, is_integer(Sz), 0 < Sz -> diff --git a/lib/hipe/cerl/erl_bif_types.erl b/lib/hipe/cerl/erl_bif_types.erl index 1ef73da1be..fbb77b6a42 100644 --- a/lib/hipe/cerl/erl_bif_types.erl +++ b/lib/hipe/cerl/erl_bif_types.erl @@ -1483,6 +1483,8 @@ type(erlang, statistics, 1, Xs) -> t_tuple([t_non_neg_integer(), t_integer(0)]); ['wall_clock'] -> t_tuple([t_non_neg_integer(), t_integer(0)]); + ['scheduler_wall_time'] -> + t_list(t_tuple([t_integer(), t_number(), t_number()])); List when is_list(List) -> T_statistics_1; unknown -> @@ -1532,6 +1534,8 @@ type(erlang, system_flag, 2, Xs) -> t_sequential_tracer(); ['trace_control_word'] -> t_integer(); + ['scheduler_wall_time'] -> + t_boolean(); List when is_list(List) -> T_system_flag_2; unknown -> @@ -3901,6 +3905,7 @@ arg_types(erlang, statistics, 1) -> t_atom('reductions'), t_atom('run_queue'), t_atom('runtime'), + t_atom('scheduler_wall_time'), t_atom('wall_clock')])]; arg_types(erlang, subtract, 2) -> arg_types(erlang, '--', 2); @@ -3925,6 +3930,7 @@ arg_types(erlang, system_flag, 2) -> t_atom('trace_control_word'), %% 'internal_cpu_topology' is an undocumented internal feature. t_atom('internal_cpu_topology'), + t_atom('scheduler_wall_time'), t_integer()]), t_sup([t_integer(), %% 'cpu_topology' @@ -3940,6 +3946,9 @@ arg_types(erlang, system_flag, 2) -> %% The following two are for 'multi_scheduling' t_atom('block'), t_atom('unblock'), + %% For 'scheduler_wall_time' + t_atom('true'), + t_atom('false'), %% The following is for 'internal_cpu_topology' t_internal_cpu_topology()])]; arg_types(erlang, system_info, 1) -> @@ -4267,7 +4276,7 @@ arg_types(hipe_bifs, ref_get, 1) -> arg_types(hipe_bifs, ref_set, 2) -> [t_hiperef(), t_immediate()]; arg_types(hipe_bifs, remove_refs_from, 1) -> - [t_mfa()]; + [t_sup([t_mfa(), t_atom('all')])]; arg_types(hipe_bifs, set_funinfo_native_address, 3) -> arg_types(hipe_bifs, set_native_address, 3); arg_types(hipe_bifs, set_native_address, 3) -> diff --git a/lib/inets/src/http_client/httpc_handler.erl b/lib/inets/src/http_client/httpc_handler.erl index 6fe05dec80..923213d34d 100644 --- a/lib/inets/src/http_client/httpc_handler.erl +++ b/lib/inets/src/http_client/httpc_handler.erl @@ -55,7 +55,7 @@ status_line, % {Version, StatusCode, ReasonPharse} headers, % #http_response_h{} body, % binary() - mfa, % {Moduel, Function, Args} + mfa, % {Module, Function, Args} pipeline = queue:new(), % queue() keep_alive = queue:new(), % queue() status, % undefined | new | pipeline | keep_alive | close | ssl_tunnel diff --git a/lib/inets/src/http_server/httpd_log.erl b/lib/inets/src/http_server/httpd_log.erl index 60ab326a20..a34435e0e8 100644 --- a/lib/inets/src/http_server/httpd_log.erl +++ b/lib/inets/src/http_server/httpd_log.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2011. All Rights Reserved. +%% Copyright Ericsson AB 2008-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -36,8 +36,8 @@ AuthUser :: string(), Date :: string(), StatusCode :: pos_integer(), - Size :: pos_integer() | string()) -> - {Log :: atom() | pid(), Entry :: string()}. + Size :: 0 | pos_integer() | string()) -> + {Log :: atom() | pid(), Entry :: string()} | term() . access_entry(Log, NoLog, Info, RFC931, AuthUser, Date, StatusCode, SizeStr) when is_list(SizeStr) -> @@ -69,7 +69,7 @@ access_entry(Log, NoLog, Info :: #mod{}, Date :: string(), Reason :: term()) -> - {Log :: atom() | pid(), Entry :: string()}. + {Log :: atom() | pid(), Entry :: string()} | term(). error_entry(Log, NoLog, #mod{config_db = ConfigDB, @@ -87,7 +87,7 @@ error_entry(Log, NoLog, ConfigDB :: term(), Date :: string(), ErrroStr :: string()) -> - {Log :: atom() | pid(), Entry :: string()}. + {Log :: atom() | pid(), Entry :: string()} | term(). error_report_entry(Log, NoLog, ConfigDb, Date, ErrorStr) -> MakeEntry = fun() -> io_lib:format("[~s], ~s~n", [Date, ErrorStr]) end, @@ -99,7 +99,7 @@ error_report_entry(Log, NoLog, ConfigDb, Date, ErrorStr) -> ConfigDB :: term(), Date :: string(), Reason :: term()) -> - {Log :: atom() | pid(), Entry :: string()}. + {Log :: atom() | pid(), Entry :: string()} | term(). security_entry(Log, NoLog, #mod{config_db = ConfigDB}, Date, Reason) -> MakeEntry = fun() -> io_lib:format("[~s] ~s~n", [Date, Reason]) end, diff --git a/lib/kernel/doc/src/code.xml b/lib/kernel/doc/src/code.xml index ee687511a3..214e61cc00 100644 --- a/lib/kernel/doc/src/code.xml +++ b/lib/kernel/doc/src/code.xml @@ -91,7 +91,7 @@ of the additional library directories will override modules with the same name in OTP, except for modules in Kernel and STDLIB.</p> - <p>The environment variable <c>ERL_LIBS</c> (if defined) shold contain + <p>The environment variable <c>ERL_LIBS</c> (if defined) should contain a colon-separated (for Unix-like systems) or semicolon-separated (for Windows) list of additional libraries.</p> <p>Example: On an Unix-like system, <c>ERL_LIBS</c> could be set to diff --git a/lib/reltool/doc/src/reltool.xml b/lib/reltool/doc/src/reltool.xml index 9b43640d83..2567a72999 100644 --- a/lib/reltool/doc/src/reltool.xml +++ b/lib/reltool/doc/src/reltool.xml @@ -144,7 +144,7 @@ value <c>include</c> implies that all applications and escripts that do not have any explicit <c>incl_cond</c> setting will be included. <c>exclude</c> implies that all - applications and escripts) that do not have any explicit + applications and escripts that do not have any explicit <c>incl_cond</c> setting will be excluded.</p> </item> diff --git a/lib/ssh/src/ssh.appup.src b/lib/ssh/src/ssh.appup.src index 0542054596..d08dbafc32 100644 --- a/lib/ssh/src/ssh.appup.src +++ b/lib/ssh/src/ssh.appup.src @@ -18,12 +18,26 @@ %% {"%VSN%", - [ - {<<"2\\.*">>, [{restart_application, ssh}]}, - {<<"1\\.*">>, [{restart_application, ssh}]} + [ + {<<"2.1">>, [{load_module, ssh_sftpd_file_api, soft_purge, soft_purge, []}, + {load_module, ssh_connection, soft_purge, soft_purge, []}, + {load_module, ssh_connection_manager, soft_purge, soft_purge, []}, + {load_module, ssh_auth, soft_purge, soft_purge, []}, + {load_module, ssh_channel, soft_purge, soft_purge, []}, + {load_module, ssh_file, soft_purge, soft_purge, []}]}, + {load_module, ssh, soft_purge, soft_purge, []}]}, + {<<"2.0\\.*">>, [{restart_application, ssh}]}, + {<<"1\\.*">>, [{restart_application, ssh}]} ], [ - {<<"2\\.*">>, [{restart_application, ssh}]}, - {<<"1\\.*">>, [{restart_application, ssh}]} + {<<"2.1">>,[{load_module, ssh_sftpd_file_api, soft_purge, soft_purge, []}, + {load_module, ssh_connection, soft_purge, soft_purge, []}, + {load_module, ssh_connection_manager, soft_purge, soft_purge, []}, + {load_module, ssh_auth, soft_purge, soft_purge, []}, + {load_module, ssh_channel, soft_purge, soft_purge, []}, + {load_module, ssh_file, soft_purge, soft_purge, []}]}, + {load_module, ssh, soft_purge, soft_purge, []}]}, + {<<"2.0\\.*">>, [{restart_application, ssh}]}, + {<<"1\\.*">>, [{restart_application, ssh}]} ] }. diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl index 85f5f680e6..3395f73884 100644 --- a/lib/ssh/src/ssh.erl +++ b/lib/ssh/src/ssh.erl @@ -91,10 +91,8 @@ do_connect(Host, Port, SocketOptions, SshOptions, Timeout, DisableIpv6) -> {ok, ConnectionSup} -> {ok, Manager} = ssh_connection_sup:connection_manager(ConnectionSup), - MRef = erlang:monitor(process, Manager), receive {Manager, is_connected} -> - do_demonitor(MRef, Manager), {ok, Manager}; %% When the connection fails %% ssh_connection_sup:connection_manager @@ -102,30 +100,13 @@ do_connect(Host, Port, SocketOptions, SshOptions, Timeout, DisableIpv6) -> %% could allready have terminated, so we will not %% match the Manager in this case {_, not_connected, {error, econnrefused}} when DisableIpv6 == false -> - do_demonitor(MRef, Manager), do_connect(Host, Port, proplists:delete(inet6, SocketOptions), SshOptions, Timeout, true); {_, not_connected, {error, Reason}} -> - do_demonitor(MRef, Manager), {error, Reason}; {_, not_connected, Other} -> - do_demonitor(MRef, Manager), - {error, Other}; - {'DOWN', MRef, _, Manager, Reason} when is_pid(Manager) -> - error_logger:warning_report([{ssh, connect}, - {diagnose, - "Connection was closed before properly set up."}, - {host, Host}, - {port, Port}, - {reason, Reason}]), - receive %% Clear EXIT message from queue - {'EXIT', Manager, _What} -> - {error, channel_closed} - after 0 -> - {error, channel_closed} - end + {error, Other} after Timeout -> - do_demonitor(MRef, Manager), ssh_connection_manager:stop(Manager), {error, timeout} end @@ -134,16 +115,6 @@ do_connect(Host, Port, SocketOptions, SshOptions, Timeout, DisableIpv6) -> {error, ssh_not_started} end. -do_demonitor(MRef, Manager) -> - erlang:demonitor(MRef), - receive - {'DOWN', MRef, _, Manager, _} -> - ok - after 0 -> - ok - end. - - %%-------------------------------------------------------------------- %% Function: close(ConnectionRef) -> ok %% diff --git a/lib/ssh/src/ssh_connection.erl b/lib/ssh/src/ssh_connection.erl index c46f799b6d..c2a7c63cbe 100644 --- a/lib/ssh/src/ssh_connection.erl +++ b/lib/ssh/src/ssh_connection.erl @@ -436,32 +436,32 @@ handle_msg(#ssh_msg_channel_window_adjust{recipient_channel = ChannelId, #connection{channel_cache = Cache} = Connection, ConnectionPid, _) -> - #channel{send_window_size = Size} = + #channel{send_window_size = Size, remote_id = RemoteId} = Channel0 = ssh_channel:cache_lookup(Cache, ChannelId), - + {SendList, Channel} = %% TODO: Datatype 0 ? update_send_window(Channel0#channel{send_window_size = Size + Add}, 0, <<>>, Connection), Replies = lists:map(fun({Type, Data}) -> {connection_reply, ConnectionPid, - channel_data_msg(ChannelId, Type, Data)} + channel_data_msg(RemoteId, Type, Data)} end, SendList), FlowCtrlMsgs = flow_control(Channel, Cache), {{replies, Replies ++ FlowCtrlMsgs}, Connection}; handle_msg(#ssh_msg_channel_open{channel_type = "session" = Type, - sender_channel = ChannelId, + sender_channel = RemoteId, initial_window_size = WindowSz, maximum_packet_size = PacketSz}, Connection0, ConnectionPid, server) -> - try setup_session(Connection0, ConnectionPid, ChannelId, + try setup_session(Connection0, ConnectionPid, RemoteId, Type, WindowSz, PacketSz) of Result -> Result catch _:_ -> - FailMsg = channel_open_failure_msg(ChannelId, + FailMsg = channel_open_failure_msg(RemoteId, ?SSH_OPEN_CONNECT_FAILED, "Connection refused", "en"), {{replies, [{connection_reply, ConnectionPid, FailMsg}]}, @@ -532,9 +532,9 @@ handle_msg(#ssh_msg_channel_open{channel_type = "forwarded-tcpip", {{replies, [{connection_reply, ConnectionPid, FailMsg}]}, Connection}; -handle_msg(#ssh_msg_channel_open{sender_channel = ChannelId}, Connection, +handle_msg(#ssh_msg_channel_open{sender_channel = RemoteId}, Connection, ConnectionPid, _) -> - FailMsg = channel_open_failure_msg(ChannelId, + FailMsg = channel_open_failure_msg(RemoteId, ?SSH_OPEN_ADMINISTRATIVELY_PROHIBITED, "Not allowed", "en"), {{replies, [{connection_reply, ConnectionPid, FailMsg}]}, Connection}; diff --git a/lib/ssh/src/ssh_connection_sup.erl b/lib/ssh/src/ssh_connection_sup.erl index e3544af1c6..b620056310 100644 --- a/lib/ssh/src/ssh_connection_sup.erl +++ b/lib/ssh/src/ssh_connection_sup.erl @@ -48,8 +48,12 @@ start_manager_child(Sup, Args) -> supervisor:start_child(Sup, Spec). connection_manager(SupPid) -> - Children = supervisor:which_children(SupPid), - {ok, ssh_connection_manager(Children)}. + try supervisor:which_children(SupPid) of + Children -> + {ok, ssh_connection_manager(Children)} + catch exit:{noproc,_} -> + {ok, undefined} + end. %%%========================================================================= %%% Supervisor callback @@ -107,6 +111,8 @@ handler_spec([Role, Socket, Opts]) -> Type = worker, {Name, StartFunc, Restart, Shutdown, Type, Modules}. +ssh_connection_manager([]) -> + undefined; ssh_connection_manager([{_, Child, _, [ssh_connection_manager]} | _]) -> Child; ssh_connection_manager([_ | Rest]) -> diff --git a/lib/ssh/src/ssh_file.erl b/lib/ssh/src/ssh_file.erl index d05fa8e09a..a6b82a7a13 100644 --- a/lib/ssh/src/ssh_file.erl +++ b/lib/ssh/src/ssh_file.erl @@ -232,7 +232,7 @@ lookup_host_key_fd(Fd, Host, KeyType) -> eof -> {error, not_found}; Line -> - case public_key:ssh_decode(Line, known_hosts) of + case ssh_decode_line(Line, known_hosts) of [{Key, Attributes}] -> handle_host(Fd, Host, proplists:get_value(hostnames, Attributes), Key, KeyType); [] -> @@ -240,6 +240,13 @@ lookup_host_key_fd(Fd, Host, KeyType) -> end end. +ssh_decode_line(Line, Type) -> + try + public_key:ssh_decode(Line, Type) + catch _:_ -> + [] + end. + handle_host(Fd, Host, HostList, Key, KeyType) -> Host1 = host_name(Host), case lists:member(Host1, HostList) and key_match(Key, KeyType) of @@ -285,7 +292,7 @@ lookup_user_key_fd(Fd, Key) -> eof -> {error, not_found}; Line -> - case public_key:ssh_decode(Line, auth_keys) of + case ssh_decode_line(Line, auth_keys) of [{AuthKey, _}] -> case is_auth_key(Key, AuthKey) of true -> diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk index bff73a1b40..defa47f824 100644 --- a/lib/ssh/vsn.mk +++ b/lib/ssh/vsn.mk @@ -1,5 +1,5 @@ #-*-makefile-*- ; force emacs to enter makefile-mode -SSH_VSN = 2.1 +SSH_VSN = 2.1.1 APP_VSN = "ssh-$(SSH_VSN)" diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl index b39c995552..63731ee25c 100644 --- a/lib/ssl/test/ssl_test_lib.erl +++ b/lib/ssl/test/ssl_test_lib.erl @@ -150,7 +150,7 @@ run_client(Opts) -> {ok, Socket} -> Pid ! { connected, Socket }, test_server:format("Client: connected~n", []), - %% In specail cases we want to know the client port, it will + %% In special cases we want to know the client port, it will %% be indicated by sending {port, 0} in options list! send_selected_port(Pid, proplists:get_value(port, Options), Socket), {Module, Function, Args} = proplists:get_value(mfa, Opts), diff --git a/lib/syntax_tools/src/erl_syntax.erl b/lib/syntax_tools/src/erl_syntax.erl index 76a6a6dc36..151f04b03b 100644 --- a/lib/syntax_tools/src/erl_syntax.erl +++ b/lib/syntax_tools/src/erl_syntax.erl @@ -5979,13 +5979,9 @@ is_literal(T) -> revert(Node) -> case is_tree(Node) of false -> - %% Just remove any wrapper and copy the position. `erl_parse' - %% nodes never contain abstract syntax tree nodes as subtrees. - case unwrap(Node) of - {error, Info} -> {error, setelement(1,Info,get_pos(Node))}; - {warning, Info} -> {warning, setelement(1,Info,get_pos(Node))}; - Node1 -> setelement(2,Node1,get_pos(Node)) - end; + %% Just remove any wrapper. `erl_parse' nodes never contain + %% abstract syntax tree nodes as subtrees. + unwrap(Node); true -> case is_leaf(Node) of true -> diff --git a/lib/tools/doc/src/xref_chapter.xml b/lib/tools/doc/src/xref_chapter.xml index 39c5545af9..169313cb9c 100644 --- a/lib/tools/doc/src/xref_chapter.xml +++ b/lib/tools/doc/src/xref_chapter.xml @@ -301,7 +301,7 @@ and <c>|||</c>) are the only operators that accept both representations. This means that in order to analyze indirect calls using restriction, the <c>closure</c> operator (which creates the - <c>digraph</c> representation of graphs) has to been + <c>digraph</c> representation of graphs) has to be applied explicitly. </p> <p>As an example of analyzing indirect calls, the following Erlang |