aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/common_test/src/ct_logs.erl58
-rw-r--r--lib/common_test/src/ct_telnet.erl39
-rw-r--r--lib/common_test/test/ct_group_leader_SUITE.erl6
-rw-r--r--lib/common_test/test/ct_group_leader_SUITE_data/group_leader_SUITE.erl41
-rw-r--r--lib/dialyzer/src/dialyzer_analysis_callgraph.erl9
-rw-r--r--lib/dialyzer/src/dialyzer_cl.erl2
-rw-r--r--lib/dialyzer/src/dialyzer_typesig.erl57
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/bs_constraints.erl32
-rw-r--r--lib/diameter/doc/src/diameter.xml5
-rw-r--r--lib/diameter/doc/src/diameter_tcp.xml20
-rw-r--r--lib/diameter/doc/src/diameter_transport.xml30
-rw-r--r--lib/diameter/examples/code/peer.erl28
-rw-r--r--lib/diameter/src/base/diameter_peer.erl8
-rw-r--r--lib/diameter/src/base/diameter_peer_fsm.erl13
-rw-r--r--lib/diameter/src/transport/diameter_tcp.erl79
-rw-r--r--lib/diameter/test/diameter_capx_SUITE.erl2
-rw-r--r--lib/diameter/test/diameter_event_SUITE.erl2
-rw-r--r--lib/diameter/test/diameter_examples_SUITE.erl2
-rw-r--r--lib/diameter/test/diameter_tls_SUITE.erl2
-rw-r--r--lib/diameter/test/diameter_transport_SUITE.erl32
-rw-r--r--lib/diameter/test/diameter_util.erl29
-rw-r--r--lib/diameter/test/diameter_watchdog_SUITE.erl2
-rw-r--r--lib/hipe/icode/hipe_icode_coordinator.erl18
-rw-r--r--lib/hipe/main/hipe.erl21
-rw-r--r--lib/stdlib/doc/src/sys.xml8
-rw-r--r--lib/stdlib/src/gen.erl31
-rw-r--r--lib/stdlib/test/dets_SUITE.erl77
-rw-r--r--lib/stdlib/test/ets_SUITE.erl17
-rw-r--r--lib/test_server/src/test_server_gl.erl2
-rw-r--r--lib/test_server/src/test_server_io.erl11
-rw-r--r--lib/test_server/test/test_server_SUITE.erl2
-rw-r--r--lib/test_server/test/test_server_SUITE_data/test_server_SUITE.erl13
-rw-r--r--lib/tools/src/cover.erl7
33 files changed, 406 insertions, 299 deletions
diff --git a/lib/common_test/src/ct_logs.erl b/lib/common_test/src/ct_logs.erl
index 0b204a681a..752033fdff 100644
--- a/lib/common_test/src/ct_logs.erl
+++ b/lib/common_test/src/ct_logs.erl
@@ -639,20 +639,21 @@ logger_loop(State) ->
case erlang:is_process_alive(TCGL) of
true ->
State1 = print_to_log(SyncOrAsync, Pid,
+ Category,
TCGL, List, State),
logger_loop(State1#logger_state{
tc_groupleaders = TCGLs});
false ->
%% Group leader is dead, so write to the
- %% CtLog instead
- Fd = State#logger_state.ct_log_fd,
- [begin io:format(Fd,Str,Args),
- io:nl(Fd) end || {Str,Args} <- List],
+ %% CtLog or unexpected_io log instead
+ unexpected_io(Pid,Category,List,State),
logger_loop(State)
end;
- {ct_log,Fd,TCGLs} ->
- [begin io:format(Fd,Str,Args),io:nl(Fd) end ||
- {Str,Args} <- List],
+ {ct_log,_Fd,TCGLs} ->
+ %% If category is ct_internal then write
+ %% to ct_log, else write to unexpected_io
+ %% log
+ unexpected_io(Pid,Category,List,State),
logger_loop(State#logger_state{
tc_groupleaders = TCGLs})
end;
@@ -746,27 +747,32 @@ create_io_fun(FromPid, State) ->
end
end.
-print_to_log(sync, FromPid, TCGL, List, State) ->
- IoFun = create_io_fun(FromPid, State),
+print_to_log(sync, FromPid, Category, TCGL, List, State) ->
%% in some situations (exceptions), the printout is made from the
%% test server IO process and there's no valid group leader to send to
- IoProc = if FromPid /= TCGL -> TCGL;
- true -> State#logger_state.ct_log_fd
- end,
- io:format(IoProc, "~ts", [lists:foldl(IoFun, [], List)]),
+ if FromPid /= TCGL ->
+ IoFun = create_io_fun(FromPid, State),
+ io:format(TCGL,"~ts", [lists:foldl(IoFun, [], List)]);
+ true ->
+ unexpected_io(FromPid,Category,List,State)
+ end,
State;
-print_to_log(async, FromPid, TCGL, List, State) ->
- IoFun = create_io_fun(FromPid, State),
+print_to_log(async, FromPid, Category, TCGL, List, State) ->
%% in some situations (exceptions), the printout is made from the
%% test server IO process and there's no valid group leader to send to
- IoProc = if FromPid /= TCGL -> TCGL;
- true -> State#logger_state.ct_log_fd
- end,
- Printer = fun() ->
- test_server:permit_io(IoProc, self()),
- io:format(IoProc, "~ts", [lists:foldl(IoFun, [], List)])
- end,
+ Printer =
+ if FromPid /= TCGL ->
+ IoFun = create_io_fun(FromPid, State),
+ fun() ->
+ test_server:permit_io(TCGL, self()),
+ io:format(TCGL, "~ts", [lists:foldl(IoFun, [], List)])
+ end;
+ true ->
+ fun() ->
+ unexpected_io(FromPid,Category,List,State)
+ end
+ end,
case State#logger_state.async_print_jobs of
[] ->
{_Pid,Ref} = spawn_monitor(Printer),
@@ -2514,3 +2520,11 @@ html_encoding(latin1) ->
"iso-8859-1";
html_encoding(utf8) ->
"utf-8".
+
+unexpected_io(Pid,ct_internal,List,#logger_state{ct_log_fd=Fd}=State) ->
+ IoFun = create_io_fun(Pid,State),
+ io:format(Fd, "~ts", [lists:foldl(IoFun, [], List)]);
+unexpected_io(Pid,_Category,List,State) ->
+ IoFun = create_io_fun(Pid,State),
+ Data = io_lib:format("~ts", [lists:foldl(IoFun, [], List)]),
+ test_server_io:print_unexpected(Data).
diff --git a/lib/common_test/src/ct_telnet.erl b/lib/common_test/src/ct_telnet.erl
index 02186864a5..beb3c1d649 100644
--- a/lib/common_test/src/ct_telnet.erl
+++ b/lib/common_test/src/ct_telnet.erl
@@ -728,7 +728,8 @@ teln_get_all_data(Pid,Prx,Data,Acc,LastLine) ->
haltpatterns=[],
seq=false,
repeat=false,
- found_prompt=false}).
+ found_prompt=false,
+ wait_for_linebreak=true}).
%% @hidden
%% @doc Externally the silent_teln_expect function shall only be used
@@ -754,20 +755,25 @@ silent_teln_expect(Pid,Data,Pattern,Prx,Opts) ->
%% condition is fullfilled.
%% 3b) Repeat (sequence): 2) is repeated either N times or until a
%% halt condition is fullfilled.
-teln_expect(Pid,Data,Pattern0,Prx,Opts) -> HaltPatterns = case
- get_ignore_prompt(Opts) of true -> get_haltpatterns(Opts); false
- -> [prompt | get_haltpatterns(Opts)] end,
-
+teln_expect(Pid,Data,Pattern0,Prx,Opts) ->
+ HaltPatterns = case get_ignore_prompt(Opts) of
+ true ->
+ get_haltpatterns(Opts);
+ false ->
+ [prompt | get_haltpatterns(Opts)]
+ end,
+ WaitForLineBreak = get_line_break_opt(Opts),
Seq = get_seq(Opts),
Pattern = convert_pattern(Pattern0,Seq),
-
+
Timeout = get_timeout(Opts),
-
+
EO = #eo{teln_pid=Pid,
prx=Prx,
timeout=Timeout,
seq=Seq,
- haltpatterns=HaltPatterns},
+ haltpatterns=HaltPatterns,
+ wait_for_linebreak=WaitForLineBreak},
case get_repeat(Opts) of
false ->
@@ -808,6 +814,11 @@ get_timeout(Opts) ->
{value,{timeout,T}} -> T;
false -> ?DEFAULT_TIMEOUT
end.
+get_line_break_opt(Opts) ->
+ case lists:keysearch(wait_for_linebreak,1,Opts) of
+ {value,{wait_for_linebreak,false}} -> false;
+ _ -> true
+ end.
get_repeat(Opts) ->
case lists:keysearch(repeat,1,Opts) of
{value,{repeat,N}} when is_integer(N) ->
@@ -1004,8 +1015,9 @@ seq_expect1(Data,[],Acc,Rest,_EO) ->
%% Split prompt-chunk at lines
match_lines(Data,Patterns,EO) ->
FoundPrompt = EO#eo.found_prompt,
+ NeedLineBreak = EO#eo.wait_for_linebreak,
case one_line(Data,[]) of
- {noline,Rest} when FoundPrompt=/=false ->
+ {noline,Rest} when FoundPrompt=/=false, NeedLineBreak =:= true ->
%% This is the line including the prompt
case match_line(Rest,Patterns,FoundPrompt,EO) of
nomatch ->
@@ -1013,7 +1025,14 @@ match_lines(Data,Patterns,EO) ->
{Tag,Match} ->
{Tag,Match,[]}
end;
- {noline,Rest} ->
+ {noline,Rest} when NeedLineBreak =:= false ->
+ case match_line(Rest,Patterns,FoundPrompt,EO) of
+ nomatch ->
+ {nomatch,prompt};
+ {Tag,Match} ->
+ {Tag,Match,[]}
+ end;
+ {noline, Rest} ->
{nomatch,Rest};
{Line,Rest} ->
case match_line(Line,Patterns,false,EO) of
diff --git a/lib/common_test/test/ct_group_leader_SUITE.erl b/lib/common_test/test/ct_group_leader_SUITE.erl
index cde3061d6a..6d54a4c004 100644
--- a/lib/common_test/test/ct_group_leader_SUITE.erl
+++ b/lib/common_test/test/ct_group_leader_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012. All Rights Reserved.
+%% Copyright Ericsson AB 2012-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
@@ -176,6 +176,10 @@ events_to_check(_Test) ->
{?eh,tc_done,{group_leader_SUITE,cap1,ok}},
{?eh,tc_start,{group_leader_SUITE,cap2}},
{?eh,tc_done,{group_leader_SUITE,cap2,ok}}]},
+ {parallel,[{?eh,tc_start,{group_leader_SUITE,unexp1}},
+ {?eh,tc_done,{group_leader_SUITE,unexp1,ok}},
+ {?eh,tc_start,{group_leader_SUITE,unexp2}},
+ {?eh,tc_done,{group_leader_SUITE,unexp2,ok}}]},
{?eh,test_done,{'DEF','STOP_TIME'}},
{?eh,stop_logging,[]}
].
diff --git a/lib/common_test/test/ct_group_leader_SUITE_data/group_leader_SUITE.erl b/lib/common_test/test/ct_group_leader_SUITE_data/group_leader_SUITE.erl
index 3f1844b4ae..804f722081 100644
--- a/lib/common_test/test/ct_group_leader_SUITE_data/group_leader_SUITE.erl
+++ b/lib/common_test/test/ct_group_leader_SUITE_data/group_leader_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012. All Rights Reserved.
+%% Copyright Ericsson AB 2012-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
@@ -112,7 +112,8 @@ groups() ->
{seq,[],[s1,s2,s3]},
{seq2,[],[s4,s5]},
{seq_in_par,[parallel],[p10,p11,{group,seq},p12,{group,seq2},p13]},
- {capture_io,[parallel],[cap1,cap2]}].
+ {capture_io,[parallel],[cap1,cap2]},
+ {unexpected_io,[parallel],[unexp1,unexp2]}].
%%--------------------------------------------------------------------
%% @spec all() -> GroupsAndTestCases | {skip,Reason}
@@ -126,7 +127,8 @@ all() ->
[tc1,{group,p},{group,p_restart},p3,
{group,seq_in_par},
cap1,cap2,
- {group,capture_io}].
+ {group,capture_io},
+ {group,unexpected_io}].
tc1(_C) ->
ok.
@@ -250,3 +252,36 @@ gen_io(Label, N, Acc) ->
S = lists:flatten(io_lib:format("~s: ~p\n", [Label,N])),
io:put_chars(S),
gen_io(Label, N-1, [S|Acc]).
+
+%% Test that unexpected I/O is sent to test_server's unexpeced_io log.
+%% To trigger this, run two test cases in parallel and send a printout
+%% (via ct logging functions) from an external process which has a
+%% different group leader than the test cases.
+unexp1(Config) ->
+ timer:sleep(1000),
+ gen_unexp_io(),
+ timer:sleep(1000),
+ check_unexp_io(Config),
+ ok.
+
+unexp2(_) ->
+ timer:sleep(2000),
+ ok.
+
+gen_unexp_io() ->
+ spawn(fun() ->
+ group_leader(whereis(user),self()),
+ ct:log("-x- Unexpected io ct:log -x-",[]),
+ ct:pal("-x- Unexpected io ct:pal -x-",[]),
+ ok
+ end).
+
+check_unexp_io(Config) ->
+ SuiteLog = ?config(tc_logfile,Config),
+ Dir = filename:dirname(SuiteLog),
+ UnexpLog = filename:join(Dir,"unexpected_io.log.html"),
+ {ok,SuiteBin} = file:read_file(SuiteLog),
+ nomatch = re:run(SuiteBin,"-x- Unexpected io ",[global,{capture,none}]),
+ {ok,UnexpBin} = file:read_file(UnexpLog),
+ {match,[_,_]} = re:run(UnexpBin,"-x- Unexpected io ",[global]),
+ ok.
diff --git a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
index ca6b403ac9..affb89385e 100644
--- a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
+++ b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
@@ -255,10 +255,13 @@ compile_and_store(Files, #analysis_state{codeserver = CServer,
CServer2 = dialyzer_codeserver:set_next_core_label(NextLabel, CServer),
case Failed =:= [] of
true ->
- NewFiles = lists:zip(lists:reverse(Modules), Files),
ModDict =
- lists:foldl(fun({Mod, F}, Dict) -> dict:append(Mod, F, Dict) end,
- dict:new(), NewFiles),
+ lists:foldl(fun(F, Dict) ->
+ ModFile = lists:last(filename:split(F)),
+ Mod = filename:basename(ModFile, ".beam"),
+ dict:append(Mod, F, Dict)
+ end,
+ dict:new(), Files),
check_for_duplicate_modules(ModDict);
false ->
Msg = io_lib:format("Could not scan the following file(s):~n~s",
diff --git a/lib/dialyzer/src/dialyzer_cl.erl b/lib/dialyzer/src/dialyzer_cl.erl
index 2456585bd0..365c0b36d4 100644
--- a/lib/dialyzer/src/dialyzer_cl.erl
+++ b/lib/dialyzer/src/dialyzer_cl.erl
@@ -509,7 +509,7 @@ hipe_compile(Files, #options{erlang_mode = ErlangMode} = Options) ->
dialyzer_codeserver, dialyzer_contracts,
dialyzer_coordinator, dialyzer_dataflow, dialyzer_dep,
dialyzer_plt, dialyzer_succ_typings, dialyzer_typesig,
- dialyzer_typesig, dialyzer_worker],
+ dialyzer_worker],
report_native_comp(Options),
{T1, _} = statistics(wall_clock),
native_compile(Mods),
diff --git a/lib/dialyzer/src/dialyzer_typesig.erl b/lib/dialyzer/src/dialyzer_typesig.erl
index 17a292a7d6..a418a11e65 100644
--- a/lib/dialyzer/src/dialyzer_typesig.erl
+++ b/lib/dialyzer/src/dialyzer_typesig.erl
@@ -246,18 +246,27 @@ traverse(Tree, DefinedVars, State) ->
Val = cerl:bitstr_val(Tree),
{State1, [SizeType, ValType]} =
traverse_list([Size, Val], DefinedVars, State),
- {State2, TypeConstr} =
+ {State2, TypeConstr, BinValTypeConstr} =
case cerl:bitstr_bitsize(Tree) of
- all -> {State1, t_bitstr(UnitVal, 0)};
- utf -> {State1, t_binary()}; % contains an integer number of bytes
- N when is_integer(N) -> {State1, t_bitstr(0, N)};
+ all ->
+ T = t_bitstr(UnitVal, 0),
+ {State1, T, T};
+ utf ->
+ %% contains an integer number of bytes
+ T = t_binary(),
+ {State1, T, T};
+ N when is_integer(N) ->
+ {State1, t_bitstr(0, N), t_bitstr(1, N)};
any -> % Size is not a literal
+ T1 = ?mk_fun_var(bitstr_constr(SizeType, UnitVal), [SizeType]),
+ T2 =
+ ?mk_fun_var(bitstr_constr(SizeType, UnitVal, match), [SizeType]),
{state__store_conj(SizeType, sub, t_non_neg_integer(), State1),
- ?mk_fun_var(bitstr_constr(SizeType, UnitVal), [SizeType])}
+ T1, T2}
end,
ValTypeConstr =
case cerl:concrete(cerl:bitstr_type(Tree)) of
- binary -> TypeConstr;
+ binary -> BinValTypeConstr;
float ->
case state__is_in_match(State1) of
true -> t_float();
@@ -947,12 +956,20 @@ get_type_test({erlang, is_tuple, 1}) -> {ok, t_tuple()};
get_type_test({M, F, A}) when is_atom(M), is_atom(F), is_integer(A) -> error.
bitstr_constr(SizeType, UnitVal) ->
+ bitstr_constr(SizeType, UnitVal, construct).
+
+bitstr_constr(SizeType, UnitVal, ConstructOrMatch) ->
+ Unit =
+ case ConstructOrMatch of
+ construct -> 0;
+ match -> 1
+ end,
fun(Map) ->
TmpSizeType = lookup_type(SizeType, Map),
case t_is_subtype(TmpSizeType, t_non_neg_integer()) of
true ->
case t_number_vals(TmpSizeType) of
- [OneSize] -> t_bitstr(0, OneSize * UnitVal);
+ [OneSize] -> t_bitstr(Unit, OneSize * UnitVal);
_ ->
MinSize = erl_types:number_min(TmpSizeType),
t_bitstr(UnitVal, MinSize * UnitVal)
@@ -1770,8 +1787,9 @@ minimize_state(#state{
opaques = Opaques,
solvers = Solvers
}) ->
- ETSCMap = ets:new(cmap,[{read_concurrency, true}]),
- ETSPropTypes = ets:new(prop_types,[{read_concurrency, true}]),
+ Opts = [{read_concurrency, true}],
+ ETSCMap = ets:new(cmap, Opts),
+ ETSPropTypes = ets:new(prop_types, Opts),
true = ets:insert(ETSCMap, dict:to_list(CMap)),
true = ets:insert(ETSPropTypes, dict:to_list(PropTypes)),
#state
@@ -2111,11 +2129,11 @@ restore_local_map(#v2_state{constr_data = ConData}, Id, Map0) ->
{ok, failed} -> Map0;
{ok, {[],_}} -> Map0;
{ok, {Part0,U}} ->
- Part = [{K,V} || {K,V} <- Part0, not lists:member(K, U)],
+ Part = [KV || {K,_V} = KV <- Part0, not lists:member(K, U)],
?debug("restore local map Id=~w U=~w\n", [Id, U]),
pp_map("Part", dict:from_list(Part)),
pp_map("Map0", Map0),
- Map = lists:foldl(fun({K,V}, D) -> dict:store(K, V, D)end, Map0, Part),
+ Map = lists:foldl(fun({K,V}, D) -> dict:store(K, V, D) end, Map0, Part),
pp_map("Map", Map),
Map
end.
@@ -3374,16 +3392,6 @@ pp_constraints([#constraint{}=C], Level, MaxDepth, _State) ->
pp_constraints([#constraint{}=C|Tail], Level, MaxDepth, State) ->
pp_op(C, Level),
pp_constraints(Tail, Level, MaxDepth, State);
-pp_constraints([#constraint_list{type = Type, list = List, id = Id}],
- Level, MaxDepth, State) ->
- pp_indent(Level),
- case Type of
- conj -> io:format("Conj ~w (", [Id]);
- disj -> io:format("Disj ~w (", [Id])
- end,
- NewMaxDepth = pp_constraints(List, Level + 1, MaxDepth, State),
- io:format(")", []),
- NewMaxDepth;
pp_constraints([#constraint_list{type = Type, list = List, id = Id}|Tail],
Level, MaxDepth, State) ->
pp_indent(Level),
@@ -3392,8 +3400,11 @@ pp_constraints([#constraint_list{type = Type, list = List, id = Id}|Tail],
disj -> io:format("Disj ~w (", [Id])
end,
NewMaxDepth = pp_constraints(List, Level+1, MaxDepth, State),
- io:format(")", []),
- pp_constraints(Tail, Level, NewMaxDepth, State).
+ io:format(")"),
+ case Tail =:= [] of
+ true -> NewMaxDepth + 1;
+ false -> pp_constraints(Tail, Level, NewMaxDepth, State)
+ end.
pp_op(#constraint{lhs = Lhs, op = Op, rhs = Rhs}, Level) ->
pp_indent(Level),
diff --git a/lib/dialyzer/test/small_SUITE_data/src/bs_constraints.erl b/lib/dialyzer/test/small_SUITE_data/src/bs_constraints.erl
new file mode 100644
index 0000000000..08dfb0808d
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/bs_constraints.erl
@@ -0,0 +1,32 @@
+%% Program which shows that the handling of binaries was not correct.
+%% The success typing inferred was:
+%% -spec bits1(<<_:3>>) -> <<_:3>>.
+%% while it should be:
+%% -spec bits1(<<_:3,_:_*1>>) -> <<_:3>>.
+%% because the only constraint which exists for the head variable is
+%% that it must be a bitstring of bit size at least 3, not a bitstring
+%% of bit size 3.
+-module(bs_constraints).
+
+-export([bits1/1, bits2/1, bits3/1, bins/1, test/0]).
+
+bits1(B) ->
+ <<B:3/bits>>.
+
+bits2(B) ->
+ <<B:4/bits>>.
+
+bits3(B) ->
+ {bits1(B), bits2(B)}.
+
+%% Same problem with the one below. The success typing should be:
+%% -spec bins(<<_:16,_:_*1>>) -> <<_:16>>.
+bins(B) ->
+ <<B:2/binary>>.
+
+%% Same problem, when unit size is a variable:
+test() ->
+ foo(8, 0, <<42>>).
+
+foo(N, S, A) ->
+ <<A:S/binary-unit:1, A:(N-S)/binary-unit:1>>.
diff --git a/lib/diameter/doc/src/diameter.xml b/lib/diameter/doc/src/diameter.xml
index 48914abaa2..318c98f786 100644
--- a/lib/diameter/doc/src/diameter.xml
+++ b/lib/diameter/doc/src/diameter.xml
@@ -343,8 +343,9 @@ Has one of the following types.</p>
An address list is available to the start function of a
&transport_module;, which
can return a new list for use in the subsequent CER or CEA.
-Host-IP-Address need not be specified if the transport start function
-returns an address list.</p>
+Host-IP-Address need not be specified if the transport module in
+question communicates an address list as described in
+&man_transport;</p>
</item>
<tag><c>{'Vendor-Id', &dict_Unsigned32;}</c></tag>
diff --git a/lib/diameter/doc/src/diameter_tcp.xml b/lib/diameter/doc/src/diameter_tcp.xml
index 01c781d553..8e509aa829 100644
--- a/lib/diameter/doc/src/diameter_tcp.xml
+++ b/lib/diameter/doc/src/diameter_tcp.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="latin1" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd" [
+ <!ENTITY start '<seealso marker="#start-3">start/3</seealso>'>
<!ENTITY gen_tcp_connect3
'<seealso marker="kernel:gen_tcp#connect-3">gen_tcp:connect/3</seealso>'>
<!ENTITY gen_tcp_listen2
@@ -81,7 +82,9 @@ before configuring TLS capability on diameter transports.</p>
<func>
<name>start({Type, Ref}, Svc, [Opt])
- -> {ok, Pid, [LAddr]} | {error, Reason}</name>
+ -> {ok, Pid}
+ | {ok, Pid, [LAddr]}
+ | {error, Reason}</name>
<fsummary>Start a transport process.</fsummary>
<type>
<v>Type = connect | accept</v>
@@ -153,13 +156,14 @@ that will not be forthcoming, which will eventually cause the RFC 3539
watchdog to take down the connection.</p>
<p>
-If the <c>#diameter_service{}</c> record has more than one
-<c>Host-IP-Address</c> and option <c>ip</c> is unspecified then the
-first of the these addresses is used as the local address.</p>
-
-<p>
-The returned local address list has length one.</p>
-
+If an <c>ip</c> option is not specified then the first element of a
+non-empty <c>Host-IP-Address</c> list in <c>Svc</c> provides the local
+IP address.
+If neither is specified then the default address selected by &gen_tcp;
+is used.
+In all cases, the selected address is either returned from
+&start; or passed in a <c>connected</c> message over the transport
+interface.</p>
</desc>
</func>
diff --git a/lib/diameter/doc/src/diameter_transport.xml b/lib/diameter/doc/src/diameter_transport.xml
index 55b531155f..8bccf6521e 100644
--- a/lib/diameter/doc/src/diameter_transport.xml
+++ b/lib/diameter/doc/src/diameter_transport.xml
@@ -1,6 +1,8 @@
<?xml version="1.0" encoding="latin1" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd" [
<!ENTITY message '<seealso marker="#message">message()</seealso>'>
+ <!ENTITY MESSAGES '<seealso marker="#MESSAGES">MESSAGES</seealso>'>
+ <!ENTITY start '<seealso marker="#Mod:start-3">start/3</seealso>'>
<!ENTITY ip_address
'<seealso marker="kernel:inet#type-ip_address">inet:ip_address()</seealso>'>
<!ENTITY % also SYSTEM "seealso.ent" >
@@ -12,7 +14,7 @@
<erlref>
<header>
<copyright>
-<year>2011</year><year>2012</year>
+<year>2011</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -125,7 +127,7 @@ Ref is the value that was returned from the call to &mod_add_transport;
that has lead to starting of a transport process.</p>
<p>
-<c>Svc</c> contains the capabilities passed to &mod_start_service; and
+<c>Svc</c> contains capabilities passed to &mod_start_service; and
&mod_add_transport;, values passed to the latter overriding those
passed to the former.</p>
@@ -134,13 +136,16 @@ passed to the former.</p>
&mod_transport_opt; list passed to &mod_add_transport;.</p>
<p>
-The start function should use the <c>Host-IP-Address</c> list and/or
-<c>Config</c> to select an appropriate list of local IP addresses,
-and should return this list if different from the
-<c>#diameter_service{}</c> addresses.
-The returned list is used to populate <c>Host-IP-Address</c> AVPs in
-outgoing capabilities exchange messages, the
-<c>#diameter_service{}</c> addresses being used otherwise.</p>
+The start function should use the <c>Host-IP-Address</c> list in
+<c>Svc</c> and/or <c>Config</c> to select an appropriate list of local
+IP addresses, and should return this list if different from the
+<c>Svc</c> addresses.
+In the connecting case, the local address list can instead be
+communicated in a <c>connected</c> message (see &MESSAGES; below)
+following connection establishment.
+In either case, the local address list is used to populate
+<c>Host-IP-Address</c> AVPs in outgoing capabilities exchange
+messages.</p>
<p>
A transport process must implement the message interface documented below.
@@ -230,13 +235,16 @@ Not sent if the transport process has <c>Type=connect</c>.</p>
</item>
<tag><c>{diameter, {self(), connected, Remote}}</c></tag>
+<tag><c>{diameter, {self(), connected, Remote, [LocalAddr]}}</c></tag>
<item>
<p>
Inform the parent that the transport process with <c>Type=connect</c>
has established a connection with a peer.
-Not sent if the transport process has <c>Type=accept</c>.
+Not sent if the transport process has <c>Type=accept</c>.&nbsp;
<c>Remote</c> is an arbitrary term that uniquely identifies the remote
-endpoint to which the transport has connected.</p>
+endpoint to which the transport has connected.
+A <c>LocalAddr</c> list has the same semantics as one returned from
+&start;.</p>
</item>
<tag><c>{diameter, {recv, &message;}}</c></tag>
diff --git a/lib/diameter/examples/code/peer.erl b/lib/diameter/examples/code/peer.erl
index 8fdeba57bf..b4ee17e4b7 100644
--- a/lib/diameter/examples/code/peer.erl
+++ b/lib/diameter/examples/code/peer.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2010-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
@@ -51,7 +51,6 @@
| {protocol(), ip_address(), non_neg_integer()}
| {protocol(), ip_address(), ip_address(), non_neg_integer()}.
--define(DEFAULT_ADDR, {127,0,0,1}).
-define(DEFAULT_PORT, 3868).
%% ---------------------------------------------------------------------------
@@ -111,7 +110,7 @@ server({T, Addr, Port}) ->
{port, Port}]}];
server(T) ->
- server({T, ?DEFAULT_ADDR, ?DEFAULT_PORT}).
+ server({T, loopback, ?DEFAULT_PORT}).
%% client/1
%%
@@ -124,21 +123,28 @@ client({all, LA, RA, RP}) ->
client({T, LA, RA, RP}) ->
[{transport_module, tmod(T)},
- {transport_config, [{ip, addr(LA)},
- {raddr, addr(RA)},
+ {transport_config, [{raddr, addr(RA)},
{rport, RP},
- {reuseaddr, true}]}];
+ {reuseaddr, true}
+ | ip(LA)]}];
-client({T, LA, RP}) ->
- client({T, LA, LA, RP});
+client({T, RA, RP}) ->
+ client({T, default, RA, RP});
client(T) ->
- client({T, ?DEFAULT_ADDR, ?DEFAULT_ADDR, ?DEFAULT_PORT}).
+ client({T, loopback, loopback, ?DEFAULT_PORT}).
tmod(tcp) -> diameter_tcp;
tmod(sctp) -> diameter_sctp.
-addr(default) ->
- ?DEFAULT_ADDR;
+ip(default) ->
+ [];
+ip(loopback) ->
+ [{ip, {127,0,0,1}}];
+ip(Addr) ->
+ [{ip, Addr}].
+
+addr(loopback) ->
+ {127,0,0,1};
addr(A) ->
A.
diff --git a/lib/diameter/src/base/diameter_peer.erl b/lib/diameter/src/base/diameter_peer.erl
index dfc76eb76e..0d2efd4d1f 100644
--- a/lib/diameter/src/base/diameter_peer.erl
+++ b/lib/diameter/src/base/diameter_peer.erl
@@ -24,7 +24,8 @@
%% Interface towards transport modules ...
-export([recv/2,
up/1,
- up/2]).
+ up/2,
+ up/3]).
%% ... and the stack.
-export([start/1,
@@ -180,7 +181,7 @@ start(Mod, Args) ->
apply(Mod, start, Args).
%%% ---------------------------------------------------------------------------
-%%% # up/[12]
+%%% # up/1-3
%%% ---------------------------------------------------------------------------
up(Pid) -> %% accepting transport
@@ -189,6 +190,9 @@ up(Pid) -> %% accepting transport
up(Pid, Remote) -> %% connecting transport
ifc_send(Pid, {self(), connected, Remote}).
+up(Pid, Remote, LAddrs) -> %% connecting transport
+ ifc_send(Pid, {self(), connected, Remote, LAddrs}).
+
%%% ---------------------------------------------------------------------------
%%% # recv/2
%%% ---------------------------------------------------------------------------
diff --git a/lib/diameter/src/base/diameter_peer_fsm.erl b/lib/diameter/src/base/diameter_peer_fsm.erl
index bee3e507fd..6be4259510 100644
--- a/lib/diameter/src/base/diameter_peer_fsm.erl
+++ b/lib/diameter/src/base/diameter_peer_fsm.erl
@@ -351,10 +351,17 @@ transition({diameter, {TPid, connected, Remote}},
mode = M}
= S) ->
{'Wait-Conn-Ack', _} = PS, %% assert
- connect = M, %%
+ connect = M, %%
keep_transport(TPid),
send_CER(S#state{mode = {M, Remote}});
+transition({diameter, {TPid, connected, Remote, LAddrs}},
+ #state{transport = TPid,
+ service = Svc}
+ = S) ->
+ transition({diameter, {TPid, connected, Remote}},
+ S#state{service = readdr(Svc, LAddrs)});
+
%% Connection from peer.
transition({diameter, {TPid, connected}},
#state{transport = TPid,
@@ -363,7 +370,7 @@ transition({diameter, {TPid, connected}},
parent = Pid}
= S) ->
{'Wait-Conn-Ack', Tmo} = PS, %% assert
- accept = M, %%
+ accept = M, %%
keep_transport(TPid),
Pid ! {accepted, self()},
start_timer(Tmo, S#state{state = recv_CER});
@@ -376,6 +383,8 @@ transition({diameter, {_, connected}}, _) ->
{stop, connection_timeout};
transition({diameter, {_, connected, _}}, _) ->
{stop, connection_timeout};
+transition({diameter, {_, connected, _, _}}, _) ->
+ {stop, connection_timeout};
%% Connection has timed out: start an alternate.
transition({connection_timeout = T, TPid},
diff --git a/lib/diameter/src/transport/diameter_tcp.erl b/lib/diameter/src/transport/diameter_tcp.erl
index 132088b514..cbbba714ac 100644
--- a/lib/diameter/src/transport/diameter_tcp.erl
+++ b/lib/diameter/src/transport/diameter_tcp.erl
@@ -100,6 +100,18 @@
%% # start/3
%% ---------------------------------------------------------------------------
+-spec start({accept, Ref}, Svc, [Opt])
+ -> {ok, pid(), [inet:ip_address()]}
+ when Ref :: diameter:transport_ref(),
+ Svc :: #diameter_service{},
+ Opt :: diameter:transport_opt();
+ ({connect, Ref}, Svc, [Opt])
+ -> {ok, pid(), [inet:ip_address()]}
+ | {ok, pid()}
+ when Ref :: diameter:transport_ref(),
+ Svc :: #diameter_service{},
+ Opt :: diameter:transport_opt().
+
start({T, Ref}, #diameter_service{capabilities = Caps}, Opts) ->
diameter_tcp_sup:start(), %% start tcp supervisors on demand
{Mod, Rest} = split(Opts),
@@ -172,7 +184,7 @@ i({T, Ref, Mod, Pid, Opts, Addrs})
OwnOpts,
?DEFAULT_FRAGMENT_TIMEOUT),
?IS_TIMEOUT(Tmo) orelse ?ERROR({fragment_timer, Tmo}),
- Sock = i(T, Ref, Mod, Pid, SslOpts, Rest, Addrs),
+ Sock = init(T, Ref, Mod, Pid, SslOpts, Rest, Addrs),
MPid ! {stop, self()}, %% tell the monitor to die
M = if SslOpts -> ssl; true -> Mod end,
setopts(M, Sock),
@@ -199,14 +211,21 @@ i(#monitor{parent = Pid, transport = TPid} = S) ->
i({listen, LRef, APid, {Mod, Opts, Addrs}}) ->
{[LA, LP], Rest} = proplists:split(Opts, [ip, port]),
- LAddr = get_addr(LA, Addrs),
+ LAddrOpt = get_addr(LA, Addrs),
LPort = get_port(LP),
- {ok, LSock} = Mod:listen(LPort, gen_opts(LAddr, Rest)),
+ {ok, LSock} = Mod:listen(LPort, gen_opts(LAddrOpt, Rest)),
+ LAddr = laddr(LAddrOpt, Mod, LSock),
true = diameter_reg:add_new({?MODULE, listener, {LRef, {LAddr, LSock}}}),
proc_lib:init_ack({ok, self(), {LAddr, LSock}}),
erlang:monitor(process, APid),
start_timer(#listener{socket = LSock}).
+laddr([], Mod, Sock) ->
+ {ok, {Addr, _Port}} = sockname(Mod, Sock),
+ Addr;
+laddr([{ip, Addr}], _, _) ->
+ Addr.
+
own(Opts) ->
{Own, Rest} = proplists:split(Opts, [fragment_timer]),
{lists:append(Own), Rest}.
@@ -225,17 +244,19 @@ ssl_opts([{ssl_options, Opts}])
ssl_opts(L) ->
?ERROR({ssl_options, L}).
-%% i/7
+%% init/7
%% Establish a TLS connection before capabilities exchange ...
-i(Type, Ref, Mod, Pid, true, Opts, Addrs) ->
- i(Type, Ref, ssl, Pid, [{cb_info, ?TCP_CB(Mod)} | Opts], Addrs);
+init(Type, Ref, Mod, Pid, true, Opts, Addrs) ->
+ init(Type, Ref, ssl, Pid, [{cb_info, ?TCP_CB(Mod)} | Opts], Addrs);
%% ... or not.
-i(Type, Ref, Mod, Pid, _, Opts, Addrs) ->
- i(Type, Ref, Mod, Pid, Opts, Addrs).
+init(Type, Ref, Mod, Pid, _, Opts, Addrs) ->
+ init(Type, Ref, Mod, Pid, Opts, Addrs).
+
+%% init/6
-i(accept = T, Ref, Mod, Pid, Opts, Addrs) ->
+init(accept = T, Ref, Mod, Pid, Opts, Addrs) ->
{LAddr, LSock} = listener(Ref, {Mod, Opts, Addrs}),
proc_lib:init_ack({ok, self(), [LAddr]}),
Sock = ok(accept(Mod, LSock)),
@@ -243,17 +264,28 @@ i(accept = T, Ref, Mod, Pid, Opts, Addrs) ->
diameter_peer:up(Pid),
Sock;
-i(connect = T, Ref, Mod, Pid, Opts, Addrs) ->
+init(connect = T, Ref, Mod, Pid, Opts, Addrs) ->
{[LA, RA, RP], Rest} = proplists:split(Opts, [ip, raddr, rport]),
- LAddr = get_addr(LA, Addrs),
- RAddr = get_addr(RA, []),
+ LAddrOpt = get_addr(LA, Addrs),
+ RAddr = get_addr(RA),
RPort = get_port(RP),
- proc_lib:init_ack({ok, self(), [LAddr]}),
- Sock = ok(connect(Mod, RAddr, RPort, gen_opts(LAddr, Rest))),
+ proc_lib:init_ack(init_rc(LAddrOpt)),
+ Sock = ok(connect(Mod, RAddr, RPort, gen_opts(LAddrOpt, Rest))),
publish(Mod, T, Ref, Sock),
- diameter_peer:up(Pid, {RAddr, RPort}),
+ up(Pid, {RAddr, RPort}, LAddrOpt, Mod, Sock),
Sock.
+init_rc([{ip, Addr}]) ->
+ {ok, self(), [Addr]};
+init_rc([]) ->
+ {ok, self()}.
+
+up(Pid, Remote, [{ip, _Addr}], _, _) ->
+ diameter_peer:up(Pid, Remote);
+up(Pid, Remote, [], Mod, Sock) ->
+ {Addr, _Port} = ok(sockname(Mod, Sock)),
+ diameter_peer:up(Pid, Remote, [Addr]).
+
publish(Mod, T, Ref, Sock) ->
true = diameter_reg:add_new({?MODULE, T, {Ref, Sock}}),
putr(?INFO_KEY, {Mod, Sock}). %% for info/1
@@ -281,10 +313,17 @@ l([], LRef, T) ->
{ok, _, AS} = diameter_tcp_sup:start_child({listen, LRef, self(), T}),
AS.
+%% get_addr/1
+
+get_addr(As) ->
+ diameter_lib:ipaddr(addr(As, [])).
+
%% get_addr/2
+get_addr([], []) ->
+ [];
get_addr(As, Def) ->
- diameter_lib:ipaddr(addr(As, Def)).
+ [{ip, diameter_lib:ipaddr(addr(As, Def))}].
%% Take the first address from the service if several are unspecified.
addr([], [Addr | _]) ->
@@ -305,14 +344,10 @@ get_port(Ps) ->
%% gen_opts/2
-gen_opts(LAddr, Opts) ->
+gen_opts(LAddrOpt, Opts) ->
{L,_} = proplists:split(Opts, [binary, packet, active]),
[[],[],[]] == L orelse ?ERROR({reserved_options, Opts}),
- [binary,
- {packet, 0},
- {active, once},
- {ip, LAddr}
- | Opts].
+ [binary, {packet, 0}, {active, once}] ++ LAddrOpt ++ Opts.
%% ---------------------------------------------------------------------------
%% # ports/1
diff --git a/lib/diameter/test/diameter_capx_SUITE.erl b/lib/diameter/test/diameter_capx_SUITE.erl
index 9e6619ecdd..8c9bb67e61 100644
--- a/lib/diameter/test/diameter_capx_SUITE.erl
+++ b/lib/diameter/test/diameter_capx_SUITE.erl
@@ -444,7 +444,7 @@ connect(Config, T, Opts) ->
{CRef, LRef}.
connect(LRef, Opts) ->
- [PortNr] = ?util:lport(tcp, LRef, 20),
+ [PortNr] = ?util:lport(tcp, LRef),
{ok, CRef} = diameter:add_transport(?CLIENT,
{connect, opts(PortNr, Opts)}),
CRef.
diff --git a/lib/diameter/test/diameter_event_SUITE.erl b/lib/diameter/test/diameter_event_SUITE.erl
index 18bdcb1f54..94b4967921 100644
--- a/lib/diameter/test/diameter_event_SUITE.erl
+++ b/lib/diameter/test/diameter_event_SUITE.erl
@@ -100,7 +100,7 @@ start_server(Config) ->
ok = diameter:start_service(?SERVER, ?SERVICE(?SERVER, [?DICT_COMMON])),
LRef = ?util:listen(?SERVER, tcp, [{capabilities_cb, fun capx_cb/2},
{capx_timeout, ?SERVER_CAPX_TMO}]),
- [PortNr] = ?util:lport(tcp, LRef, 20),
+ [PortNr] = ?util:lport(tcp, LRef),
?util:write_priv(Config, portnr, PortNr),
start = event(?SERVER).
diff --git a/lib/diameter/test/diameter_examples_SUITE.erl b/lib/diameter/test/diameter_examples_SUITE.erl
index 6d797f6911..585fc9d3b8 100644
--- a/lib/diameter/test/diameter_examples_SUITE.erl
+++ b/lib/diameter/test/diameter_examples_SUITE.erl
@@ -283,7 +283,7 @@ start(server) ->
ok = diameter:start(),
ok = server:start(),
{ok, Ref} = server:listen(tcp),
- [_] = ?util:lport(tcp, Ref, 20),
+ [_] = ?util:lport(tcp, Ref),
ok;
start(client) ->
diff --git a/lib/diameter/test/diameter_tls_SUITE.erl b/lib/diameter/test/diameter_tls_SUITE.erl
index 77194a0f56..5a79c63d36 100644
--- a/lib/diameter/test/diameter_tls_SUITE.erl
+++ b/lib/diameter/test/diameter_tls_SUITE.erl
@@ -343,7 +343,7 @@ join(Strs) ->
server(Host, {Caps, Opts}) ->
ok = diameter:start_service(Host, ?SERVICE(Host, ?DICT_COMMON)),
{ok, LRef} = diameter:add_transport(Host, ?LISTEN(Caps, Opts)),
- {LRef, hd([_] = ?util:lport(tcp, LRef, 20))}.
+ {LRef, hd([_] = ?util:lport(tcp, LRef))}.
sopts(?SERVER1, Dir) ->
{inband_security([?TLS]),
diff --git a/lib/diameter/test/diameter_transport_SUITE.erl b/lib/diameter/test/diameter_transport_SUITE.erl
index de097b886e..97f4cec11f 100644
--- a/lib/diameter/test/diameter_transport_SUITE.erl
+++ b/lib/diameter/test/diameter_transport_SUITE.erl
@@ -55,9 +55,6 @@
-define(RECV(Pat, Ret), receive Pat -> Ret end).
-define(RECV(Pat), ?RECV(Pat, now())).
-%% Or not.
--define(WAIT(Ms), receive after Ms -> now() end).
-
%% Sockets are opened on the loopback address.
-define(ADDR, {127,0,0,1}).
@@ -295,7 +292,7 @@ init(accept, {Prot, Ref}) ->
init(gen_connect, {Prot, Ref}) ->
%% Lookup the peer's listening socket.
- [PortNr] = ?util:lport(Prot, Ref, 20),
+ [PortNr] = ?util:lport(Prot, Ref),
%% Connect, send a message and receive it back.
{ok, Sock} = gen_connect(Prot, PortNr),
@@ -316,7 +313,8 @@ init(gen_accept, {Prot, Ref}) ->
init(connect, {Prot, Ref}) ->
%% Lookup the peer's listening socket.
- [{?TEST_LISTENER(_, PortNr), _}] = match(?TEST_LISTENER(Ref, '_')),
+ [{?TEST_LISTENER(_, PortNr), _}]
+ = diameter_reg:wait(?TEST_LISTENER(Ref, '_')),
%% Start a connecting transport and receive notification of
%% the connection.
@@ -332,18 +330,6 @@ init(connect, {Prot, Ref}) ->
MRef = erlang:monitor(process, TPid),
?RECV({'DOWN', MRef, process, _, _}).
-match(Pat) ->
- match(Pat, 20).
-
-match(Pat, T) ->
- L = diameter_reg:match(Pat),
- if [] /= L orelse 1 == T ->
- L;
- true ->
- ?WAIT(50),
- match(Pat, T-1)
- end.
-
bin(sctp, #diameter_packet{bin = Bin}) ->
Bin;
bin(tcp, Bin) ->
@@ -396,22 +382,18 @@ start_connect(tcp, T, Svc, Opts) ->
%% start_accept/2
%%
%% Start transports sequentially by having each wait for a message
-%% from a job in a queue before commencing. Only one transport with
-%% a pending accept is started at a time since diameter_sctp currently
-%% assumes (and diameter currently implements) this.
+%% from a job in a queue before commencing. Only one transport with a
+%% pending accept is started at a time since diameter_{tcp,sctp}
+%% currently assume (and diameter currently implements) this.
start_accept(Prot, Ref) ->
Pid = sync(accept, Ref),
-
- %% Configure the same port number for transports on the same
- %% reference.
- [PortNr | _] = ?util:lport(Prot, Ref) ++ [0],
{Mod, Opts} = tmod(Prot),
try
{ok, TPid, [?ADDR]} = Mod:start({accept, Ref},
?SVC([?ADDR]),
- [{port, PortNr} | Opts]),
+ [{port, 0} | Opts]),
?RECV(?TMSG({TPid, connected})),
TPid
after
diff --git a/lib/diameter/test/diameter_util.erl b/lib/diameter/test/diameter_util.erl
index a9872f32e1..aa489fef5f 100644
--- a/lib/diameter/test/diameter_util.erl
+++ b/lib/diameter/test/diameter_util.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2010-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
@@ -33,7 +33,6 @@
%% diameter-specific
-export([lport/2,
- lport/3,
listen/2, listen/3,
connect/3, connect/4,
disconnect/4,
@@ -251,27 +250,17 @@ path(Config, Name) ->
filename:join([Dir, Name]).
%% ---------------------------------------------------------------------------
-%% lport/2-3
+%% lport/2
%%
%% Lookup the port number of a tcp/sctp listening transport.
-lport(M, Ref) ->
- lport(M, Ref, 1).
+lport(M, {Node, Ref}) ->
+ rpc:call(Node, ?MODULE, lport, [M, Ref]);
-lport(M, {Node, Ref}, Tries) ->
- rpc:call(Node, ?MODULE, lport, [M, Ref, Tries]);
-
-lport(M, Ref, Tries) ->
- lp(tmod(M), Ref, Tries).
-
-lp(M, Ref, T) ->
- L = [N || {listen, N, _} <- M:ports(Ref)],
- if [] /= L orelse T =< 1 ->
- L;
- true ->
- receive after 50 -> ok end,
- lp(M, Ref, T-1)
- end.
+lport(Prot, Ref) ->
+ Mod = tmod(Prot),
+ [_] = diameter_reg:wait({'_', listener, {Ref, '_'}}),
+ [N || {listen, N, _} <- Mod:ports(Ref)].
%% ---------------------------------------------------------------------------
%% listen/2-3
@@ -297,7 +286,7 @@ connect(Client, Prot, LRef) ->
connect(Client, Prot, LRef, []).
connect(Client, Prot, LRef, Opts) ->
- [PortNr] = lport(Prot, LRef, 20),
+ [PortNr] = lport(Prot, LRef),
Client = diameter:service_info(Client, name), %% assert
true = diameter:subscribe(Client),
Ref = add_transport(Client, {connect, opts(Prot, PortNr) ++ Opts}),
diff --git a/lib/diameter/test/diameter_watchdog_SUITE.erl b/lib/diameter/test/diameter_watchdog_SUITE.erl
index 704bf110c7..b6e8730ec2 100644
--- a/lib/diameter/test/diameter_watchdog_SUITE.erl
+++ b/lib/diameter/test/diameter_watchdog_SUITE.erl
@@ -524,7 +524,7 @@ cfg(listen, _) ->
cfg(connect, Ref) ->
[{{_, _, SvcName}, _Pid}] = diameter_reg:wait({listen, Ref, '_'}),
[[{ref, LRef} | _]] = diameter:service_info(SvcName, transport),
- [LP] = ?util:lport(tcp, LRef, 20),
+ [LP] = ?util:lport(tcp, LRef),
[{raddr, ?ADDR}, {rport, LP}].
%% ===========================================================================
diff --git a/lib/hipe/icode/hipe_icode_coordinator.erl b/lib/hipe/icode/hipe_icode_coordinator.erl
index d8c82cf01c..79e3304e6f 100644
--- a/lib/hipe/icode/hipe_icode_coordinator.erl
+++ b/lib/hipe/icode/hipe_icode_coordinator.erl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2007-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
@@ -36,18 +36,16 @@
%%---------------------------------------------------------------------
--spec coordinate(hipe_digraph:hdg(), [{mfa(),boolean()}], [mfa()], module()) ->
+-spec coordinate(hipe_digraph:hdg(), [mfa()], [mfa()], module()) ->
no_return().
coordinate(CG, Escaping, NonEscaping, Mod) ->
ServerPid = initialize_server(Escaping, Mod),
- Clean = [MFA || {MFA, _} <- Escaping],
- All = NonEscaping ++ Clean,
- Restart =
- fun (MFALists, PM) -> restart_funs(MFALists, PM, All, ServerPid) end,
- LastAction =
- fun (PM) -> last_action(PM, ServerPid, Mod, All) end,
- coordinate({Clean,All}, CG, gb_trees:empty(), Restart, LastAction, ServerPid).
+ All = ordsets:from_list(Escaping ++ NonEscaping),
+ Restart = fun (MFALs, PM) -> restart_funs(MFALs, PM, All, ServerPid) end,
+ LastAction = fun (PM) -> last_action(PM, ServerPid, Mod, All) end,
+ MFALists = {Escaping, All},
+ coordinate(MFALists, CG, gb_trees:empty(), Restart, LastAction, ServerPid).
-type mfalists() :: {[mfa()], [mfa()]}.
@@ -129,7 +127,7 @@ restart_funs({Queue, Busy} = QB, PM, All, ServerPid) ->
initialize_server(Escaping, Mod) ->
Pid = spawn_link(fun () -> info_server(Mod) end),
- lists:foreach(fun ({MFA, _}) -> Pid ! {set_escaping, MFA} end, Escaping),
+ lists:foreach(fun (MFA) -> Pid ! {set_escaping, MFA} end, Escaping),
Pid.
safe_get_args(MFA, Cfg, Pid, Mod) ->
diff --git a/lib/hipe/main/hipe.erl b/lib/hipe/main/hipe.erl
index 6e00b13292..434d5c3061 100644
--- a/lib/hipe/main/hipe.erl
+++ b/lib/hipe/main/hipe.erl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2001-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
@@ -242,8 +242,7 @@
%%
%% @see load/2
--spec load(Mod) -> {'module', Mod} | {'error', term()}
- when is_subtype(Mod, mod()).
+-spec load(Mod) -> {'module', Mod} | {'error', term()} when Mod :: mod().
load(Mod) ->
load(Mod, beam_file(Mod)).
@@ -265,7 +264,7 @@ load(Mod) ->
%% @see load/1
-spec load(Mod, string()) -> {'module', Mod} | {'error', term()}
- when is_subtype(Mod, mod()).
+ when Mod :: mod().
load(Mod, BeamFileName) when is_list(BeamFileName) ->
Architecture = erlang:system_info(hipe_architecture),
@@ -522,7 +521,7 @@ compile(Name, Core, File, Opts) when is_atom(Name) ->
%% @equiv file(File, [])
-spec file(Mod) -> {'ok', Mod, compile_ret()} | {'error', term()}
- when is_subtype(Mod, mod()).
+ when Mod :: mod().
file(File) ->
file(File, []).
@@ -542,7 +541,7 @@ file(File) ->
-spec file(Mod, comp_options()) -> {'ok', Mod, compile_ret()}
| {'error', term()}
- when is_subtype(Mod, mod()).
+ when Mod :: mod().
file(File, Options) when is_atom(File) ->
case beam_lib:info(File) of
L when is_list(L) ->
@@ -760,13 +759,15 @@ finalize_fun_concurrent(MfaIcodeList, Exports, Opts) ->
case MfaIcodeList of
[{{M,_,_},_}|_] ->
CallGraph = hipe_icode_callgraph:construct_callgraph(MfaIcodeList),
- Closures = [{MFA, true} || {MFA, Icode} <- MfaIcodeList,
- hipe_icode:icode_is_closure(Icode)],
- Exported = [{{M, F, A}, false} || {F, A} <- Exports],
+ Exported = [{M, F, A} || {F, A} <- Exports],
+ Closures = [MFA || {MFA, Icode} <- MfaIcodeList,
+ hipe_icode:icode_is_closure(Icode)],
+ %% In principle, a function could both be exported and used as a
+ %% closure so make sure to add it only once in Escaping below
+ Escaping = ordsets:from_list(Exported ++ Closures),
NonEscaping = [MFA || {{_M, F, A} = MFA, Icode} <- MfaIcodeList,
not lists:member({F, A}, Exports),
not hipe_icode:icode_is_closure(Icode)],
- Escaping = Closures ++ Exported,
TypeServerFun =
fun() ->
hipe_icode_coordinator:coordinate(CallGraph, Escaping,
diff --git a/lib/stdlib/doc/src/sys.xml b/lib/stdlib/doc/src/sys.xml
index a177b80739..0ffc5bc433 100644
--- a/lib/stdlib/doc/src/sys.xml
+++ b/lib/stdlib/doc/src/sys.xml
@@ -234,8 +234,8 @@
<p>These functions are intended only to help with debugging. They are provided for
convenience, allowing developers to avoid having to create their own state extraction
functions and also avoid having to interactively extract state from the return values of
- <c><seealso marker="get_status/1">get_status/1</seealso></c> or
- <c><seealso marker="get_status/2">get_status/2</seealso></c> while debugging.</p>
+ <c><seealso marker="#get_status-1">get_status/1</seealso></c> or
+ <c><seealso marker="#get_status-2">get_status/2</seealso></c> while debugging.</p>
</note>
<p>The value of <c><anno>State</anno></c> varies for different types of
processes. For a <c>gen_server</c> process, the returned <c><anno>State</anno></c>
@@ -247,8 +247,8 @@
<c>Id</c> is the handler's ID (which is the value <c>false</c> if it was registered without
an ID), and <c>HandlerState</c> is the handler's state.</p>
<p>To obtain more information about a process, including its state, see
- <seealso marker="get_status/1">get_status/1</seealso> and
- <seealso marker="get_status/2">get_status/2</seealso>.</p>
+ <seealso marker="#get_status-1">get_status/1</seealso> and
+ <seealso marker="#get_status-2">get_status/2</seealso>.</p>
</desc>
</func>
<func>
diff --git a/lib/stdlib/src/gen.erl b/lib/stdlib/src/gen.erl
index 42555aedd7..5df5530ba1 100644
--- a/lib/stdlib/src/gen.erl
+++ b/lib/stdlib/src/gen.erl
@@ -17,6 +17,7 @@
%% %CopyrightEnd%
%%
-module(gen).
+-compile({inline,[get_node/1]}).
%%%-----------------------------------------------------------------
%%% This module implements the really generic stuff of the generic
@@ -194,16 +195,6 @@ call({_Name, Node}=Process, Label, Request, Timeout)
end.
do_call(Process, Label, Request, Timeout) ->
- %% We trust the arguments to be correct, i.e
- %% Process is either a local or remote pid,
- %% or a {Name, Node} tuple (of atoms) and in this
- %% case this node (node()) _is_ distributed and Node =/= node().
- Node = case Process of
- {_S, N} when is_atom(N) ->
- N;
- _ when is_pid(Process) ->
- node(Process)
- end,
try erlang:monitor(process, Process) of
Mref ->
%% If the monitor/2 call failed to set up a connection to a
@@ -222,15 +213,12 @@ do_call(Process, Label, Request, Timeout) ->
erlang:demonitor(Mref, [flush]),
{ok, Reply};
{'DOWN', Mref, _, _, noconnection} ->
+ Node = get_node(Process),
exit({nodedown, Node});
{'DOWN', Mref, _, _, Reason} ->
exit(Reason)
after Timeout ->
- erlang:demonitor(Mref),
- receive
- {'DOWN', Mref, _, _, _} -> true
- after 0 -> true
- end,
+ erlang:demonitor(Mref, [flush]),
exit(timeout)
end
catch
@@ -241,6 +229,7 @@ do_call(Process, Label, Request, Timeout) ->
%% Do the best possible with monitor_node/2.
%% This code may hang indefinitely if the Process
%% does not exist. It is only used for featureweak remote nodes.
+ Node = get_node(Process),
monitor_node(Node, true),
receive
{nodedown, Node} ->
@@ -253,6 +242,18 @@ do_call(Process, Label, Request, Timeout) ->
end
end.
+get_node(Process) ->
+ %% We trust the arguments to be correct, i.e
+ %% Process is either a local or remote pid,
+ %% or a {Name, Node} tuple (of atoms) and in this
+ %% case this node (node()) _is_ distributed and Node =/= node().
+ case Process of
+ {_S, N} when is_atom(N) ->
+ N;
+ _ when is_pid(Process) ->
+ node(Process)
+ end.
+
wait_resp(Node, Tag, Timeout) ->
receive
{Tag, Reply} ->
diff --git a/lib/stdlib/test/dets_SUITE.erl b/lib/stdlib/test/dets_SUITE.erl
index 065b74ad41..8ff7c3ccc9 100644
--- a/lib/stdlib/test/dets_SUITE.erl
+++ b/lib/stdlib/test/dets_SUITE.erl
@@ -33,8 +33,6 @@
-define(datadir(Conf), ?config(data_dir, Conf)).
-endif.
--compile(r13). % OTP-9607
-
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
newly_started/1, basic_v8/1, basic_v9/1,
@@ -54,7 +52,7 @@
simultaneous_open/1, insert_new/1, repair_continuation/1,
otp_5487/1, otp_6206/1, otp_6359/1, otp_4738/1, otp_7146/1,
otp_8070/1, otp_8856/1, otp_8898/1, otp_8899/1, otp_8903/1,
- otp_8923/1, otp_9282/1, otp_9607/1]).
+ otp_8923/1, otp_9282/1]).
-export([dets_dirty_loop/0]).
@@ -111,7 +109,7 @@ all() ->
many_clients, otp_4906, otp_5402, simultaneous_open,
insert_new, repair_continuation, otp_5487, otp_6206,
otp_6359, otp_4738, otp_7146, otp_8070, otp_8856, otp_8898,
- otp_8899, otp_8903, otp_8923, otp_9282, otp_9607
+ otp_8899, otp_8903, otp_8923, otp_9282
].
groups() ->
@@ -3899,77 +3897,6 @@ some_calls(Tab, Config) ->
ok = dets:close(T),
file:delete(File).
-otp_9607(doc) ->
- ["OTP-9607. Test downgrading the slightly changed format."];
-otp_9607(suite) ->
- [];
-otp_9607(Config) when is_list(Config) ->
- %% Note: the bug is about almost full tables. The fix of that
- %% problem is *not* tested here.
- Version = r13b,
- case ?t:is_release_available(atom_to_list(Version)) of
- true ->
- T = otp_9607,
- File = filename(T, Config),
- Key = a,
- Value = 1,
- Args = [{file,File}],
- {ok, T} = dets:open_file(T, Args),
- ok = dets:insert(T, {Key, Value}),
- ok = dets:close(T),
-
- Call = fun(P, A) ->
- P ! {self(), A},
- receive
- {P, Ans} ->
- Ans
- after 5000 ->
- exit(other_process_dead)
- end
- end,
- %% Create a file on the modified format, read the file
- %% with an emulator that doesn't know about the modified
- %% format.
- {ok, Node} = start_node_rel(Version, Version, slave),
- Pid = rpc:call(Node, erlang, spawn,
- [?MODULE, dets_dirty_loop, []]),
- {error,{needs_repair, File}} =
- Call(Pid, [open, T, Args++[{repair,false}]]),
- io:format("Expect repair:~n"),
- {ok, T} = Call(Pid, [open, T, Args]),
- [{Key,Value}] = Call(Pid, [read, T, Key]),
- ok = Call(Pid, [close, T]),
- file:delete(File),
-
- %% Create a file on the unmodified format. Modify the file
- %% using an emulator that must not turn the file into the
- %% modified format. Read the file and make sure it is not
- %% repaired.
- {ok, T} = Call(Pid, [open, T, Args]),
- ok = Call(Pid, [write, T, {Key,Value}]),
- [{Key,Value}] = Call(Pid, [read, T, Key]),
- ok = Call(Pid, [close, T]),
-
- Key2 = b,
- Value2 = 2,
-
- {ok, T} = dets:open_file(T, Args),
- [{Key,Value}] = dets:lookup(T, Key),
- ok = dets:insert(T, {Key2,Value2}),
- ok = dets:close(T),
-
- {ok, T} = Call(Pid, [open, T, Args++[{repair,false}]]),
- [{Key2,Value2}] = Call(Pid, [read, T, Key2]),
- ok = Call(Pid, [close, T]),
-
- ?t:stop_node(Node),
- file:delete(File),
- ok;
- false ->
- {skipped, "No support for old node"}
- end.
-
-
%%
%% Parts common to several test cases
diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl
index d40609eeb0..af5d5a8f21 100644
--- a/lib/stdlib/test/ets_SUITE.erl
+++ b/lib/stdlib/test/ets_SUITE.erl
@@ -3268,15 +3268,14 @@ delete_large_named_table_1(Name, Flags, Data, Fix) ->
end,
Parent = self(),
{Pid, MRef} = my_spawn_opt(fun() ->
- receive
- {trace,Parent,call,_} ->
- ets_new(Name, [named_table])
- end
- end, [link, monitor]),
- ?line erlang:trace(self(), true, [call,{tracer,Pid}]),
- ?line erlang:trace_pattern({ets,delete,1}, true, [global]),
- ?line erlang:yield(), true = ets:delete(Tab),
- ?line erlang:trace_pattern({ets,delete,1}, false, [global]),
+ receive
+ ets_new ->
+ ets_new(Name, [named_table])
+ end
+ end,
+ [link, monitor]),
+ true = ets:delete(Tab),
+ Pid ! ets_new,
receive {'DOWN',MRef,process,Pid,_} -> ok end,
ok.
diff --git a/lib/test_server/src/test_server_gl.erl b/lib/test_server/src/test_server_gl.erl
index 2e4f223811..1f7317c51d 100644
--- a/lib/test_server/src/test_server_gl.erl
+++ b/lib/test_server/src/test_server_gl.erl
@@ -166,7 +166,7 @@ handle_info({'DOWN',Ref,process,_,Reason}=D, #st{minor_monitor=Ref}=St) ->
Data = io_lib:format("=== WARNING === TC: ~w\n"
"Got down from minor Fd ~w: ~w\n\n",
[St#st.tc,St#st.minor,D]),
- test_server_io:print(xxxFrom, unexpected_io, Data)
+ test_server_io:print_unexpected(Data)
end,
{noreply,St#st{minor=none,minor_monitor=none}};
handle_info({permit_io,Pid}, #st{permit_io=P}=St) ->
diff --git a/lib/test_server/src/test_server_io.erl b/lib/test_server/src/test_server_io.erl
index 242c08f765..a979deffc3 100644
--- a/lib/test_server/src/test_server_io.erl
+++ b/lib/test_server/src/test_server_io.erl
@@ -30,7 +30,8 @@
-module(test_server_io).
-export([start_link/0,stop/0,get_gl/1,set_fd/2,
- start_transaction/0,end_transaction/0,print_buffered/1,print/3,
+ start_transaction/0,end_transaction/0,
+ print_buffered/1,print/3,print_unexpected/1,
set_footer/1,set_job_name/1,set_gl_props/1]).
-export([init/1,handle_call/3,handle_info/2,terminate/2]).
@@ -124,6 +125,14 @@ print(From, Tag, Msg) ->
print_buffered(Pid) ->
req({print_buffered,Pid}).
+%% print_unexpected(Msg)
+%% Msg = string or iolist
+%%
+%% Print the given string in the unexpected_io log.
+
+print_unexpected(Msg) ->
+ print(xxxFrom,unexpected_io,Msg).
+
%% set_footer(IoData)
%%
%% Set a footer for the file associated with the 'html' tag.
diff --git a/lib/test_server/test/test_server_SUITE.erl b/lib/test_server/test/test_server_SUITE.erl
index cf1df6df34..3db2f5f9f1 100644
--- a/lib/test_server/test/test_server_SUITE.erl
+++ b/lib/test_server/test/test_server_SUITE.erl
@@ -104,7 +104,7 @@ test_server_SUITE(Config) ->
% rpc:call(Node,dbg, tpl,[test_server_ctrl,x]),
run_test_server_tests("test_server_SUITE",
[{test_server_SUITE,skip_case7,"SKIPPED!"}],
- 39, 1, 31, 20, 9, 1, 11, 2, 26, Config).
+ 40, 1, 32, 21, 9, 1, 11, 2, 27, Config).
test_server_parallel01_SUITE(Config) ->
run_test_server_tests("test_server_parallel01_SUITE", [],
diff --git a/lib/test_server/test/test_server_SUITE_data/test_server_SUITE.erl b/lib/test_server/test/test_server_SUITE_data/test_server_SUITE.erl
index 6c50efa712..541e8fdefc 100644
--- a/lib/test_server/test/test_server_SUITE_data/test_server_SUITE.erl
+++ b/lib/test_server/test/test_server_SUITE_data/test_server_SUITE.erl
@@ -39,7 +39,7 @@
check_old_conf/1, conf_init_fail/1, start_stop_node/1,
cleanup_nodes_init/1, check_survive_nodes/1, cleanup_nodes_fin/1,
commercial/1,
- io_invalid_data/1]).
+ io_invalid_data/1, print_unexpected/1]).
-export([dummy_function/0,dummy_function/1,doer/1]).
@@ -48,7 +48,7 @@ all(suite) ->
[config, comment, timetrap, timetrap_cancel, multiply_timetrap,
init_per_s, init_per_tc, end_per_tc,
timeconv, msgs, capture, timecall, do_times, skip_cases,
- commercial, io_invalid_data,
+ commercial, io_invalid_data, print_unexpected,
{conf, conf_init, [check_new_conf], conf_cleanup},
check_old_conf,
{conf, conf_init_fail,[conf_member_skip],conf_cleanup_skip},
@@ -503,3 +503,12 @@ io_invalid_data(Config) when is_list(Config) ->
%% OTP-10991 caused this to hang and produce a timetrap timeout:
{'EXIT',{badarg,_}} = (catch io:put_chars("invalid: " ++ [42.0])),
ok.
+
+print_unexpected(Config) when is_list(Config) ->
+ Str = "-x-x-x- test_server_SUITE:print_unexpected -> Unexpected data -x-x-x-",
+ test_server_io:print_unexpected(Str),
+ UnexpectedLog = filename:join(filename:dirname(?config(tc_logfile,Config)),
+ "unexpected_io.log.html"),
+ {ok,Bin} = file:read_file(UnexpectedLog),
+ match = re:run(Bin, Str, [global,{capture,none}]),
+ ok.
diff --git a/lib/tools/src/cover.erl b/lib/tools/src/cover.erl
index c2c627abe0..bf21aa6b48 100644
--- a/lib/tools/src/cover.erl
+++ b/lib/tools/src/cover.erl
@@ -721,6 +721,11 @@ main_process_loop(State) ->
end,
State#main_state.nodes),
reload_originals(State#main_state.compiled),
+ ets:delete(?COVER_TABLE),
+ ets:delete(?COVER_CLAUSE_TABLE),
+ ets:delete(?BINARY_TABLE),
+ ets:delete(?COLLECTION_TABLE),
+ ets:delete(?COLLECTION_CLAUSE_TABLE),
unregister(?SERVER),
reply(From, ok);
@@ -876,6 +881,8 @@ remote_process_loop(State) ->
{remote,stop} ->
reload_originals(State#remote_state.compiled),
+ ets:delete(?COVER_TABLE),
+ ets:delete(?COVER_CLAUSE_TABLE),
unregister(?SERVER),
ok; % not replying since 'DOWN' message will be received anyway