diff options
Diffstat (limited to 'lib')
151 files changed, 4933 insertions, 1516 deletions
diff --git a/lib/asn1/c_src/asn1_erl_nif.c b/lib/asn1/c_src/asn1_erl_nif.c index 9c9f83bc2a..accd368af1 100644 --- a/lib/asn1/c_src/asn1_erl_nif.c +++ b/lib/asn1/c_src/asn1_erl_nif.c @@ -580,7 +580,7 @@ int per_insert_bits_as_bits(int desired_no, int no_bytes, unsigned char **input_ptr, unsigned char **output_ptr, int *unused) { unsigned char *in_ptr = *input_ptr; unsigned char val; - int no_bits, ret, ret2; + int no_bits, ret; if (desired_no == (no_bytes * 8)) { if (per_insert_octets_unaligned(no_bytes, &in_ptr, output_ptr, *unused) @@ -606,8 +606,7 @@ int per_insert_bits_as_bits(int desired_no, int no_bytes, == ASN1_ERROR ) return ASN1_ERROR; - ret2 = per_pad_bits(desired_no - (no_bytes * 8), output_ptr, unused); - /* printf("ret2 = %d\n\r",ret2); */ + per_pad_bits(desired_no - (no_bytes * 8), output_ptr, unused); ret = CEIL(desired_no,8); /* printf("ret = %d\n\r",ret); */ } diff --git a/lib/compiler/src/Makefile b/lib/compiler/src/Makefile index 7a237608ad..3415517fff 100644 --- a/lib/compiler/src/Makefile +++ b/lib/compiler/src/Makefile @@ -53,6 +53,7 @@ MODULES = \ beam_dead \ beam_dict \ beam_disasm \ + beam_except \ beam_flatten \ beam_jump \ beam_listing \ diff --git a/lib/compiler/src/beam_except.erl b/lib/compiler/src/beam_except.erl new file mode 100644 index 0000000000..fb1a43cd9e --- /dev/null +++ b/lib/compiler/src/beam_except.erl @@ -0,0 +1,149 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(beam_except). +-export([module/2]). + +%%% Rewrite certain calls to erlang:error/{1,2} to specialized +%%% instructions: +%%% +%%% erlang:error({badmatch,Value}) => badmatch Value +%%% erlang:error({case_clause,Value}) => case_end Value +%%% erlang:error({try_clause,Value}) => try_case_end Value +%%% erlang:error(if_clause) => if_end +%%% erlang:error(function_clause, Args) => jump FuncInfoLabel +%%% + +-import(lists, [reverse/1]). + +module({Mod,Exp,Attr,Fs0,Lc}, _Opt) -> + Fs = [function(F) || F <- Fs0], + {ok,{Mod,Exp,Attr,Fs,Lc}}. + +function({function,Name,Arity,CLabel,Is0}) -> + try + Is = function_1(Is0), + {function,Name,Arity,CLabel,Is} + catch + Class:Error -> + Stack = erlang:get_stacktrace(), + io:fwrite("Function: ~w/~w\n", [Name,Arity]), + erlang:raise(Class, Error, Stack) + end. + +-record(st, + {lbl, %func_info label + loc %location for func_info + }). + +function_1(Is0) -> + case Is0 of + [{label,Lbl},{line,Loc}|_] -> + St = #st{lbl=Lbl,loc=Loc}, + translate(Is0, St, []); + [{label,_}|_] -> + %% No line numbers. The source must be a .S file. + %% There is no need to do anything. + Is0 + end. + +translate([{call_ext,Ar,{extfunc,erlang,error,Ar}}=I|Is], St, Acc) -> + translate_1(Ar, I, Is, St, Acc); +translate([{call_ext_only,Ar,{extfunc,erlang,error,Ar}}=I|Is], St, Acc) -> + translate_1(Ar, I, Is, St, Acc); +translate([{call_ext_last,Ar,{extfunc,erlang,error,Ar},_}=I|Is], St, Acc) -> + translate_1(Ar, I, Is, St, Acc); +translate([I|Is], St, Acc) -> + translate(Is, St, [I|Acc]); +translate([], _, Acc) -> + reverse(Acc). + +translate_1(Ar, I, Is, St, [{line,_}=Line|Acc1]=Acc0) -> + case dig_out(Ar, Acc1) of + no -> + translate(Is, St, [I|Acc0]); + {yes,function_clause,Acc2} -> + case {Line,St} of + {{line,Loc},#st{lbl=Fi,loc=Loc}} -> + Instr = {jump,{f,Fi}}, + translate(Is, St, [Instr|Acc2]); + {_,_} -> + %% This must be "error(function_clause, Args)" in + %% the Erlang source code. Don't translate. + translate(Is, St, [I|Acc0]) + end; + {yes,Instr,Acc2} -> + translate(Is, St, [Instr,Line|Acc2]) + end. + +dig_out(Ar, [{kill,_}|Is]) -> + dig_out(Ar, Is); +dig_out(1, [{block,Bl0}|Is]) -> + case dig_out_block(reverse(Bl0)) of + no -> no; + {yes,What,[]} -> + {yes,What,Is}; + {yes,What,Bl} -> + {yes,What,[{block,Bl}|Is]} + end; +dig_out(2, [{block,Bl}|Is]) -> + case dig_out_block_fc(Bl) of + no -> no; + {yes,What} -> {yes,What,Is} + end; +dig_out(_, _) -> no. + +dig_out_block([{set,[{x,0}],[{atom,if_clause}],move}]) -> + {yes,if_end,[]}; +dig_out_block([{set,[{x,0}],[{literal,{Exc,Value}}],move}|Is]) -> + translate_exception(Exc, {literal,Value}, Is, 0); +dig_out_block([{set,[{x,0}],[Tuple],move}, + {set,[],[Value],put}, + {set,[],[{atom,Exc}],put}, + {set,[Tuple],[],{put_tuple,2}}|Is]) -> + translate_exception(Exc, Value, Is, 3); +dig_out_block([{set,[],[Value],put}, + {set,[],[{atom,Exc}],put}, + {set,[{x,0}],[],{put_tuple,2}}|Is]) -> + translate_exception(Exc, Value, Is, 3); +dig_out_block(_) -> no. + +translate_exception(badmatch, Val, Is, Words) -> + {yes,{badmatch,Val},fix_block(Is, Words)}; +translate_exception(case_clause, Val, Is, Words) -> + {yes,{case_end,Val},fix_block(Is, Words)}; +translate_exception(try_clause, Val, Is, Words) -> + {yes,{try_case_end,Val},fix_block(Is, Words)}; +translate_exception(_, _, _, _) -> no. + +fix_block(Is, 0) -> + reverse(Is); +fix_block(Is0, Words) -> + [{set,[],[],{alloc,Live,{F1,F2,Needed,F3}}}|Is] = reverse(Is0), + [{set,[],[],{alloc,Live,{F1,F2,Needed-Words,F3}}}|Is]. + +dig_out_block_fc([{set,[],[],{alloc,Live,_}}|Bl]) -> + dig_out_fc(Bl, Live-1, nil); +dig_out_block_fc(_) -> no. + +dig_out_fc([{set,[Dst],[{x,Reg},Dst0],put_list}|Is], Reg, Dst0) -> + dig_out_fc(Is, Reg-1, Dst); +dig_out_fc([{set,[{x,0}],[{atom,function_clause}],move}], -1, {x,1}) -> + {yes,function_clause}; +dig_out_fc(_, _, _) -> no. diff --git a/lib/compiler/src/beam_utils.erl b/lib/compiler/src/beam_utils.erl index a631b8cd69..116ede0bc9 100644 --- a/lib/compiler/src/beam_utils.erl +++ b/lib/compiler/src/beam_utils.erl @@ -474,8 +474,15 @@ check_liveness(R, [{make_fun2,_,_,_,NumFree}|Is], St) -> end; check_liveness(R, [{try_end,Y}|Is], St) -> case R of - Y -> {killed,St}; - _ -> check_liveness(R, Is, St) + Y -> + {killed,St}; + {y,_} -> + %% y registers will be used if an exception occurs and + %% control transfers to the label given in the previous + %% try/2 instruction. + {used,St}; + _ -> + check_liveness(R, Is, St) end; check_liveness(R, [{catch_end,Y}|Is], St) -> case R of diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl index a17a10046e..9b505ad15c 100644 --- a/lib/compiler/src/compile.erl +++ b/lib/compiler/src/compile.erl @@ -629,6 +629,8 @@ asm_passes() -> [{unless,no_postopt, [{pass,beam_block}, {iff,dblk,{listing,"block"}}, + {unless,no_except,{pass,beam_except}}, + {iff,dexcept,{listing,"except"}}, {unless,no_bopt,{pass,beam_bool}}, {iff,dbool,{listing,"bool"}}, {unless,no_topt,{pass,beam_type}}, diff --git a/lib/compiler/src/compiler.app.src b/lib/compiler/src/compiler.app.src index fb06f2521c..1133882728 100644 --- a/lib/compiler/src/compiler.app.src +++ b/lib/compiler/src/compiler.app.src @@ -28,6 +28,7 @@ beam_dead, beam_dict, beam_disasm, + beam_except, beam_flatten, beam_jump, beam_listing, diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl index 6ea67741fa..5b155398dc 100644 --- a/lib/compiler/src/sys_core_fold.erl +++ b/lib/compiler/src/sys_core_fold.erl @@ -2641,9 +2641,9 @@ bsm_leftmost_2([_|Ps], Cs, N, Pos) -> bsm_leftmost_2([], Cs, _, Pos) -> bsm_leftmost_1(Cs, Pos). -%% bsm_notempty(Cs, Pos) -> true|false +%% bsm_nonempty(Cs, Pos) -> true|false %% Check if at least one of the clauses matches a non-empty -%% binary in the given argumet position. +%% binary in the given argument position. %% bsm_nonempty([#c_clause{pats=Ps}|Cs], Pos) -> case nth(Pos, Ps) of @@ -2704,7 +2704,7 @@ bsm_ensure_no_partition_2([P|_], 1, _, Vstate, State) -> %% %% But if the clauses can't be freely rearranged, as in %% - %% b(Var, <<>>) -> ... + %% b(Var, <<X>>) -> ... %% b(1, 2) -> ... %% %% we do have a problem. diff --git a/lib/compiler/src/v3_codegen.erl b/lib/compiler/src/v3_codegen.erl index e7dae67085..6623485609 100644 --- a/lib/compiler/src/v3_codegen.erl +++ b/lib/compiler/src/v3_codegen.erl @@ -53,7 +53,6 @@ %% Main codegen structure. -record(cg, {lcount=1, %Label counter - finfo, %Function info label bfail, %Fail label for BIFs break, %Break label recv, %Receive label @@ -126,7 +125,6 @@ cg_fun(Les, Hvs, Vdb, AtomMod, NameArity, Anno, St0) -> stk=[]}, 0, Vdb), {B,_Aft,St} = cg_list(Les, 0, Vdb, Bef, St3#cg{bfail=0, - finfo=Fi, ultimate_failure=UltimateMatchFail, is_top_block=true}), {Name,Arity} = NameArity, @@ -147,8 +145,6 @@ cg({match,M,Rs}, Le, Vdb, Bef, St) -> match_cg(M, Rs, Le, Vdb, Bef, St); cg({guard_match,M,Rs}, Le, Vdb, Bef, St) -> guard_match_cg(M, Rs, Le, Vdb, Bef, St); -cg({match_fail,F}, Le, Vdb, Bef, St) -> - match_fail_cg(F, Le, Vdb, Bef, St); cg({call,Func,As,Rs}, Le, Vdb, Bef, St) -> call_cg(Func, As, Rs, Le, Vdb, Bef, St); cg({enter,Func,As}, Le, Vdb, Bef, St) -> @@ -294,39 +290,6 @@ match_cg({block,Es}, Le, _Fail, Bef, St) -> Int = clear_dead(Bef, Le#l.i, Le#l.vdb), block_cg(Es, Le, Int, St). -%% match_fail_cg(FailReason, Le, Vdb, StackReg, State) -> -%% {[Ainstr],StackReg,State}. -%% Generate code for the match_fail "call". N.B. there is no generic -%% case for when the fail value has been created elsewhere. - -match_fail_cg({function_clause,As}, Le, Vdb, Bef, St) -> - %% Must have the args in {x,0}, {x,1},... - {Sis,Int} = cg_setup_call(As, Bef, Le#l.i, Vdb), - {Sis ++ [{jump,{f,St#cg.finfo}}], - Int#sr{reg=clear_regs(Int#sr.reg)},St}; -match_fail_cg({badmatch,Term}, Le, Vdb, Bef, St) -> - R = cg_reg_arg(Term, Bef), - Int0 = clear_dead(Bef, Le#l.i, Vdb), - {Sis,Int} = adjust_stack(Int0, Le#l.i, Le#l.i+1, Vdb), - {Sis ++ [line(Le),{badmatch,R}], - Int#sr{reg=clear_regs(Int0#sr.reg)},St}; -match_fail_cg({case_clause,Reason}, Le, Vdb, Bef, St) -> - R = cg_reg_arg(Reason, Bef), - Int0 = clear_dead(Bef, Le#l.i, Vdb), - {Sis,Int} = adjust_stack(Int0, Le#l.i, Le#l.i+1, Vdb), - {Sis++[line(Le),{case_end,R}], - Int#sr{reg=clear_regs(Bef#sr.reg)},St}; -match_fail_cg(if_clause, Le, Vdb, Bef, St) -> - Int0 = clear_dead(Bef, Le#l.i, Vdb), - {Sis,Int1} = adjust_stack(Int0, Le#l.i, Le#l.i+1, Vdb), - {Sis++[line(Le),if_end],Int1#sr{reg=clear_regs(Int1#sr.reg)},St}; -match_fail_cg({try_clause,Reason}, Le, Vdb, Bef, St) -> - R = cg_reg_arg(Reason, Bef), - Int0 = clear_dead(Bef, Le#l.i, Vdb), - {Sis,Int} = adjust_stack(Int0, Le#l.i, Le#l.i+1, Vdb), - {Sis ++ [line(Le),{try_case_end,R}], - Int#sr{reg=clear_regs(Int0#sr.reg)},St}. - %% bsm_rename_ctx([Clause], Var) -> [Clause] %% We know from an annotation that the register for a binary can %% be reused for the match context because the two are not truly diff --git a/lib/compiler/src/v3_kernel.erl b/lib/compiler/src/v3_kernel.erl index d76291f57f..f2eaa37617 100644 --- a/lib/compiler/src/v3_kernel.erl +++ b/lib/compiler/src/v3_kernel.erl @@ -83,6 +83,7 @@ -import(lists, [map/2,foldl/3,foldr/3,mapfoldl/3,splitwith/2,member/2, keymember/3,keyfind/3]). -import(ordsets, [add_element/2,del_element/2,union/2,union/1,subtract/2]). +-import(cerl, [c_tuple/1]). -include("core_parse.hrl"). -include("v3_kernel.hrl"). @@ -422,10 +423,11 @@ expr(#c_call{anno=A,module=M0,name=F0,args=Cargs}, Sub, St0) -> end; expr(#c_primop{anno=A,name=#c_literal{val=match_fail},args=Cargs0}, Sub, St0) -> Cargs = translate_match_fail(Cargs0, Sub, A, St0), - %% This special case will disappear. {Kargs,Ap,St} = atomic_list(Cargs, Sub, St0), Ar = length(Cargs), - Call = #k_call{anno=A,op=#k_internal{name=match_fail,arity=Ar},args=Kargs}, + Call = #k_call{anno=A,op=#k_remote{mod=#k_atom{val=erlang}, + name=#k_atom{val=error}, + arity=Ar},args=Kargs}, {Call,Ap,St}; expr(#c_primop{anno=A,name=#c_literal{val=N},args=Cargs}, Sub, St0) -> {Kargs,Ap,St1} = atomic_list(Cargs, Sub, St0), @@ -455,14 +457,14 @@ expr(#ireceive_accept{anno=A}, _Sub, St) -> {#k_receive_accept{anno=A},[],St}. translate_match_fail(Args, Sub, Anno, St) -> case Args of [#c_tuple{es=[#c_literal{val=function_clause}|As]}] -> - translate_match_fail_1(Anno, Args, As, Sub, St); + translate_match_fail_1(Anno, As, Sub, St); [#c_literal{val=Tuple}] when is_tuple(Tuple) -> %% The inliner may have created a literal out of %% the original #c_tuple{}. case tuple_to_list(Tuple) of [function_clause|As0] -> As = [#c_literal{val=E} || E <- As0], - translate_match_fail_1(Anno, Args, As, Sub, St); + translate_match_fail_1(Anno, As, Sub, St); _ -> Args end; @@ -471,7 +473,7 @@ translate_match_fail(Args, Sub, Anno, St) -> Args end. -translate_match_fail_1(Anno, Args, As, Sub, #kern{ff=FF}) -> +translate_match_fail_1(Anno, As, Sub, #kern{ff=FF}) -> AnnoFunc = case keyfind(function_name, 1, Anno) of false -> none; %Force rewrite. @@ -481,10 +483,10 @@ translate_match_fail_1(Anno, Args, As, Sub, #kern{ff=FF}) -> case {AnnoFunc,FF} of {Same,Same} -> %% Still in the correct function. - Args; + translate_fc(As); {{F,_},F} -> %% Still in the correct function. - Args; + translate_fc(As); _ -> %% Wrong function or no function_name annotation. %% @@ -493,9 +495,12 @@ translate_match_fail_1(Anno, Args, As, Sub, #kern{ff=FF}) -> %% the current function). match_fail(function_clause) will %% only work at the top level of the function it was originally %% defined in, so we will need to rewrite it to a case_clause. - [#c_tuple{es=[#c_literal{val=case_clause},#c_tuple{es=As}]}] + [c_tuple([#c_literal{val=case_clause},c_tuple(As)])] end. +translate_fc(Args) -> + [#c_literal{val=function_clause},make_list(Args)]. + %% call_type(Module, Function, Arity) -> call | bif | apply | error. %% Classify the call. call_type(#c_literal{val=M}, #c_literal{val=F}, Ar) when is_atom(M), is_atom(F) -> @@ -1494,7 +1499,6 @@ iletrec_funs_gen(Fs, FreeVs, St) -> %% is_exit_expr(Kexpr) -> boolean(). %% Test whether Kexpr always exits and never returns. -is_exit_expr(#k_call{op=#k_internal{name=match_fail,arity=1}}) -> true; is_exit_expr(#k_receive_next{}) -> true; is_exit_expr(_) -> false. diff --git a/lib/compiler/src/v3_life.erl b/lib/compiler/src/v3_life.erl index fac9a9843d..93f8034230 100644 --- a/lib/compiler/src/v3_life.erl +++ b/lib/compiler/src/v3_life.erl @@ -89,19 +89,8 @@ function(#k_fdef{anno=#k{a=Anno},func=F,arity=Ar,vars=Vs,body=Kb}) -> end. %% body(Kbody, I, Vdb) -> {[Expr],MaxI,Vdb}. -%% Handle a body, need special cases for transforming match_fails. -%% We KNOW that they only occur last in a body. - -body(#k_seq{arg=#k_put{anno=Pa,arg=Arg,ret=[R]}, - body=#k_enter{anno=Ea,op=#k_internal{name=match_fail,arity=1}, - args=[R]}}, - I, Vdb0) -> - Vdb1 = use_vars(Pa#k.us, I, Vdb0), %All used here - {[match_fail(Arg, I, Pa#k.a ++ Ea#k.a)],I,Vdb1}; -body(#k_enter{anno=Ea,op=#k_internal{name=match_fail,arity=1},args=[Arg]}, - I, Vdb0) -> - Vdb1 = use_vars(Ea#k.us, I, Vdb0), - {[match_fail(Arg, I, Ea#k.a)],I,Vdb1}; +%% Handle a body. + body(#k_seq{arg=Ke,body=Kb}, I, Vdb0) -> %%ok = io:fwrite("life ~w:~p~n", [?LINE,{Ke,I,Vdb0}]), A = get_kanno(Ke), @@ -353,25 +342,6 @@ guard_clause(#k_guard_clause{anno=A,guard=Kg,body=Kb}, Ls, I, Ctxt, Vdb0) -> i=I,vdb=use_vars((get_kanno(Kg))#k.us, I+2, Vdb1), a=A#k.a}. -%% match_fail(FailValue, I, Anno) -> Expr. -%% Generate the correct match_fail instruction. N.B. there is no -%% generic case for when the fail value has been created elsewhere. - -match_fail(#k_literal{anno=Anno,val={Atom,Val}}, I, A) when is_atom(Atom) -> - match_fail(#k_tuple{anno=Anno,es=[#k_atom{val=Atom},#k_literal{val=Val}]}, I, A); -match_fail(#k_literal{anno=Anno,val={Atom}}, I, A) when is_atom(Atom) -> - match_fail(#k_tuple{anno=Anno,es=[#k_atom{val=Atom}]}, I, A); -match_fail(#k_tuple{es=[#k_atom{val=function_clause}|As]}, I, A) -> - #l{ke={match_fail,{function_clause,literal_list(As, [])}},i=I,a=A}; -match_fail(#k_tuple{es=[#k_atom{val=badmatch},Val]}, I, A) -> - #l{ke={match_fail,{badmatch,literal(Val, [])}},i=I,a=A}; -match_fail(#k_tuple{es=[#k_atom{val=case_clause},Val]}, I, A) -> - #l{ke={match_fail,{case_clause,literal(Val, [])}},i=I,a=A}; -match_fail(#k_atom{val=if_clause}, I, A) -> - #l{ke={match_fail,if_clause},i=I,a=A}; -match_fail(#k_tuple{es=[#k_atom{val=try_clause},Val]}, I, A) -> - #l{ke={match_fail,{try_clause,literal(Val, [])}},i=I,a=A}. - %% type(Ktype) -> Type. type(k_literal) -> literal; diff --git a/lib/compiler/test/Makefile b/lib/compiler/test/Makefile index b90adaf917..e13ad4ae90 100644 --- a/lib/compiler/test/Makefile +++ b/lib/compiler/test/Makefile @@ -10,6 +10,7 @@ MODULES= \ apply_SUITE \ beam_validator_SUITE \ beam_disasm_SUITE \ + beam_expect_SUITE \ bs_bincomp_SUITE \ bs_bit_binaries_SUITE \ bs_construct_SUITE \ @@ -29,7 +30,6 @@ MODULES= \ misc_SUITE \ num_bif_SUITE \ pmod_SUITE \ - parteval_SUITE \ receive_SUITE \ record_SUITE \ trycatch_SUITE \ @@ -39,6 +39,7 @@ MODULES= \ NO_OPT= \ andor \ apply \ + beam_expect \ bs_construct \ bs_match \ bs_utf \ diff --git a/lib/compiler/test/beam_expect_SUITE.erl b/lib/compiler/test/beam_expect_SUITE.erl new file mode 100644 index 0000000000..6f216eac4f --- /dev/null +++ b/lib/compiler/test/beam_expect_SUITE.erl @@ -0,0 +1,67 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +-module(beam_expect_SUITE). + +-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, + init_per_group/2,end_per_group/2, + coverage/1]). + +suite() -> [{ct_hooks,[ts_install_cth]}]. + +all() -> + [coverage]. + +groups() -> + []. + +init_per_suite(Config) -> + Config. + +end_per_suite(_Config) -> + ok. + +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. + +coverage(_) -> + File = {file,"fake.erl"}, + ok = fc(a), + {'EXIT',{function_clause, + [{?MODULE,fc,[[x]],[File,{line,2}]}|_]}} = + (catch fc([x])), + {'EXIT',{function_clause, + [{?MODULE,fc,[y],[File,{line,2}]}|_]}} = + (catch fc(y)), + {'EXIT',{function_clause, + [{?MODULE,fc,[[a,b,c]],[File,{line,6}]}|_]}} = + (catch fc([a,b,c])), + + {'EXIT',{undef,[{erlang,error,[a,b,c],_}|_]}} = + (catch erlang:error(a, b, c)), + ok. + +-file("fake.erl", 1). +fc(a) -> %Line 2 + ok; %Line 3 +fc(L) when length(L) > 2 -> %Line 4 + %% Not the same as a "real" function_clause error. + error(function_clause, [L]). %Line 6 diff --git a/lib/compiler/test/beam_validator_SUITE.erl b/lib/compiler/test/beam_validator_SUITE.erl index 556dc54a8f..902867bc19 100644 --- a/lib/compiler/test/beam_validator_SUITE.erl +++ b/lib/compiler/test/beam_validator_SUITE.erl @@ -79,21 +79,18 @@ beam_files(Config) when is_list(Config) -> %% a grammatical error in the output of the io:format/2 call below. ;-) ?line [_,_|_] = Fs = filelib:wildcard(Wc), ?line io:format("~p files\n", [length(Fs)]), - beam_files_1(Fs, 0). - -beam_files_1([F|Fs], Errors) -> - ?line case beam_validator:file(F) of - ok -> - beam_files_1(Fs, Errors); - {error,Es} -> - io:format("File: ~s", [F]), - io:format("Error: ~p\n", [Es]), - beam_files_1(Fs, Errors+1) - end; -beam_files_1([], 0) -> ok; -beam_files_1([], Errors) -> - ?line io:format("~p error(s)", [Errors]), - ?line ?t:fail(). + test_lib:p_run(fun do_beam_file/1, Fs). + + +do_beam_file(F) -> + case beam_validator:file(F) of + ok -> + ok; + {error,Es} -> + io:format("File: ~s", [F]), + io:format("Error: ~p\n", [Es]), + error + end. compiler_bug(Config) when is_list(Config) -> %% Check that the compiler returns an error if we try to diff --git a/lib/compiler/test/bs_match_SUITE.erl b/lib/compiler/test/bs_match_SUITE.erl index f8c71a0257..01b7568122 100644 --- a/lib/compiler/test/bs_match_SUITE.erl +++ b/lib/compiler/test/bs_match_SUITE.erl @@ -342,6 +342,10 @@ partitioned_bs_match(Config) when is_list(Config) -> ?line fc(partitioned_bs_match_2, [4,<<0:17>>], catch partitioned_bs_match_2(4, <<0:17>>)), + + anything = partitioned_bs_match_3(anything, <<42>>), + ok = partitioned_bs_match_3(1, 2), + ok. partitioned_bs_match(_, <<42:8,T/binary>>) -> @@ -356,6 +360,9 @@ partitioned_bs_match_2(1, <<B:8,T/binary>>) -> partitioned_bs_match_2(Len, <<_:8,T/binary>>) -> {Len,T}. +partitioned_bs_match_3(Var, <<_>>) -> Var; +partitioned_bs_match_3(1, 2) -> ok. + function_clause(Config) when is_list(Config) -> ?line ok = function_clause_1(<<0,7,0,7,42>>), ?line fc(function_clause_1, [<<0,1,2,3>>], diff --git a/lib/compiler/test/compilation_SUITE.erl b/lib/compiler/test/compilation_SUITE.erl index 1343fbd1c9..664582a3a8 100644 --- a/lib/compiler/test/compilation_SUITE.erl +++ b/lib/compiler/test/compilation_SUITE.erl @@ -44,7 +44,7 @@ all() -> 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]. + string_table,otp_8949_a,otp_8949_a,split_cases]. groups() -> [{vsn, [], [vsn_1, vsn_2, vsn_3]}]. @@ -427,9 +427,9 @@ self_compile_1(Config, Prefix, Opts) -> %% Compile the compiler again using the newly compiled compiler. %% (In another node because reloading the compiler would disturb cover.) CompilerB = Prefix++"compiler_b", - ?line CompB = make_compiler_dir(Priv, Prefix++"compiler_b"), + CompB = make_compiler_dir(Priv, CompilerB), ?line VsnB = VsnA ++ ".0", - ?line self_compile_node(CompilerB, CompA, CompB, VsnB, Opts), + self_compile_node(CompA, CompB, VsnB, Opts), %% Compare compiler directories. ?line compare_compilers(CompA, CompB), @@ -438,21 +438,26 @@ self_compile_1(Config, Prefix, Opts) -> ?line CompilerC = Prefix++"compiler_c", ?line CompC = make_compiler_dir(Priv, CompilerC), ?line VsnC = VsnB ++ ".0", - ?line self_compile_node(CompilerC, CompB, CompC, VsnC, Opts), + self_compile_node(CompB, CompC, VsnC, Opts), ?line compare_compilers(CompB, CompC), ?line test_server:timetrap_cancel(Dog), ok. -self_compile_node(NodeName0, CompilerDir, OutDir, Version, Opts) -> - ?line NodeName = list_to_atom(NodeName0), - ?line Dog = test_server:timetrap(test_server:minutes(10)), +self_compile_node(CompilerDir, OutDir, Version, Opts) -> + ?line Dog = test_server:timetrap(test_server:minutes(15)), ?line Pa = "-pa " ++ filename:dirname(code:which(?MODULE)) ++ " -pa " ++ CompilerDir, - ?line {ok,Node} = start_node(NodeName, Pa), ?line Files = compiler_src(), - ?line ok = rpc:call(Node, ?MODULE, compile_compiler, [Files,OutDir,Version,Opts]), - ?line test_server:stop_node(Node), + + %% We don't want the cover server started on the other node, + %% because it will load the same cover-compiled code as on this + %% node. Use a shielded node to prevent the cover server from + %% being started. + ?t:run_on_shielded_node( + fun() -> + compile_compiler(Files, OutDir, Version, Opts) + end, Pa), ?line test_server:timetrap_cancel(Dog), ok. @@ -465,9 +470,12 @@ compile_compiler(Files, OutDir, Version, InlineOpts) -> {d,'COMPILER_VSN',"\""++Version++"\""}, nowarn_shadow_vars, {i,filename:join(code:lib_dir(stdlib), "include")}|InlineOpts], - lists:foreach(fun(File) -> - {ok,_} = compile:file(File, Opts) - end, Files). + test_lib:p_run(fun(File) -> + case compile:file(File, Opts) of + {ok,_} -> ok; + _ -> error + end + end, Files). compiler_src() -> filelib:wildcard(filename:join([code:lib_dir(compiler), "src", "*.erl"])). @@ -657,5 +665,19 @@ otp_8949_b(A, B) -> id(Var) end. +split_cases(_) -> + dummy1 = do_split_cases(x), + {'EXIT',{{badmatch,b},_}} = (catch do_split_cases(y)), + ok. + +do_split_cases(A) -> + case A of + x -> + Z = dummy1; + _ -> + Z = dummy2, + a=b + end, + Z. id(I) -> I. diff --git a/lib/compiler/test/compile_SUITE.erl b/lib/compiler/test/compile_SUITE.erl index fedbd98f71..640849f2ec 100644 --- a/lib/compiler/test/compile_SUITE.erl +++ b/lib/compiler/test/compile_SUITE.erl @@ -29,7 +29,8 @@ binary/1, makedep/1, cond_and_ifdef/1, listings/1, listings_big/1, other_output/1, package_forms/1, encrypted_abstr/1, bad_record_use1/1, bad_record_use2/1, strict_record/1, - missing_testheap/1, cover/1, env/1, core/1, asm/1]). + missing_testheap/1, cover/1, env/1, core/1, asm/1, + sys_pre_attributes/1]). -export([init/3]). @@ -45,7 +46,8 @@ all() -> binary, makedep, cond_and_ifdef, listings, listings_big, other_output, package_forms, encrypted_abstr, {group, bad_record_use}, strict_record, - missing_testheap, cover, env, core, asm]. + missing_testheap, cover, env, core, asm, + sys_pre_attributes]. groups() -> [{bad_record_use, [], @@ -785,6 +787,37 @@ do_asm(Beam, Outdir) -> error end. +sys_pre_attributes(Config) -> + DataDir = ?config(data_dir, Config), + File = filename:join(DataDir, "attributes.erl"), + Mod = attributes, + CommonOpts = [binary,report,verbose, + {parse_transform,sys_pre_attributes}], + PreOpts = [{attribute,delete,deleted}], + PostOpts = [{attribute,insert,inserted,"value"}], + PrePostOpts = [{attribute,replace,replaced,42}, + {attribute,replace,replace_nonexisting,new}], + {ok,Mod,Code} = compile:file(File, PrePostOpts ++ PreOpts ++ + PostOpts ++ CommonOpts), + code:load_binary(Mod, File, Code), + Attr = Mod:module_info(attributes), + io:format("~p", [Attr]), + {inserted,"value"} = lists:keyfind(inserted, 1, Attr), + {replaced,[42]} = lists:keyfind(replaced, 1, Attr), + {replace_nonexisting,[new]} = lists:keyfind(replace_nonexisting, 1, Attr), + false = lists:keymember(deleted, 1, Attr), + + %% Cover more code. + {ok,Mod,_} = compile:file(File, PostOpts ++ CommonOpts), + {ok,Mod,_} = compile:file(File, CommonOpts -- [verbose]), + {ok,Mod,_} = compile:file(File, PreOpts ++ CommonOpts), + {ok,Mod,_} = compile:file(File, + [{attribute,replace,replaced,42}|CommonOpts]), + {ok,Mod,_} = compile:file(File, PrePostOpts ++ PreOpts ++ + PostOpts ++ CommonOpts -- + [report,verbose]), + ok. + %%% %%% Utilities. %%% diff --git a/lib/compiler/test/compile_SUITE_data/attributes.erl b/lib/compiler/test/compile_SUITE_data/attributes.erl new file mode 100644 index 0000000000..9c3451d272 --- /dev/null +++ b/lib/compiler/test/compile_SUITE_data/attributes.erl @@ -0,0 +1,23 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2012. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(attributes). +-deleted(dummy). +-replaced(dummy). + diff --git a/lib/compiler/test/compiler.cover b/lib/compiler/test/compiler.cover index 9fc4c7dd43..3fd7fc1937 100644 --- a/lib/compiler/test/compiler.cover +++ b/lib/compiler/test/compiler.cover @@ -1,5 +1,5 @@ {incl_app,compiler,details}. %% -*- erlang -*- -{excl_mods,[sys_pre_attributes,core_scan,core_parse]}. +{excl_mods,compiler,[core_scan,core_parse]}. diff --git a/lib/compiler/test/core_SUITE.erl b/lib/compiler/test/core_SUITE.erl index 26173c62b8..874e02803d 100644 --- a/lib/compiler/test/core_SUITE.erl +++ b/lib/compiler/test/core_SUITE.erl @@ -21,7 +21,9 @@ -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2, init_per_testcase/2,end_per_testcase/2, - dehydrated_itracer/1,nested_tries/1]). + dehydrated_itracer/1,nested_tries/1, + make_effect_seq/1,eval_is_boolean/1, + unsafe_case/1,nomatch_shadow/1,reversed_annos/1]). -include_lib("test_server/include/test_server.hrl"). @@ -41,7 +43,8 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> test_lib:recompile(?MODULE), - [dehydrated_itracer, nested_tries]. + [dehydrated_itracer,nested_tries,make_effect_seq, + eval_is_boolean,unsafe_case,nomatch_shadow,reversed_annos]. groups() -> []. @@ -61,19 +64,18 @@ end_per_group(_GroupName, Config) -> ?comp(dehydrated_itracer). ?comp(nested_tries). +?comp(make_effect_seq). +?comp(eval_is_boolean). +?comp(unsafe_case). +?comp(nomatch_shadow). +?comp(reversed_annos). try_it(Mod, Conf) -> - ?line Src = filename:join(?config(data_dir, Conf), atom_to_list(Mod)), - ?line Out = ?config(priv_dir,Conf), - ?line io:format("Compiling: ~s\n", [Src]), - ?line CompRc0 = compile:file(Src, [from_core,{outdir,Out},report,time]), - ?line io:format("Result: ~p\n",[CompRc0]), - ?line {ok,Mod} = CompRc0, - - ?line {module,Mod} = code:load_abs(filename:join(Out, Mod)), - ?line ok = Mod:Mod(), - ok. - - - - + Src = filename:join(?config(data_dir, Conf), atom_to_list(Mod)), + compile_and_load(Src, []), + compile_and_load(Src, [no_copt]). + +compile_and_load(Src, Opts) -> + {ok,Mod,Bin} = compile:file(Src, [from_core,report,time,binary|Opts]), + {module,Mod} = code:load_binary(Mod, Mod, Bin), + ok = Mod:Mod(). diff --git a/lib/compiler/test/core_SUITE_data/eval_is_boolean.core b/lib/compiler/test/core_SUITE_data/eval_is_boolean.core new file mode 100644 index 0000000000..6a68b1414d --- /dev/null +++ b/lib/compiler/test/core_SUITE_data/eval_is_boolean.core @@ -0,0 +1,22 @@ +module 'eval_is_boolean' ['eval_is_boolean'/0] + attributes [] +'eval_is_boolean'/0 = + %% Line 4 + fun () -> + case <> of + <> when 'true' -> + case call 'erlang':'is_boolean'(call 'erlang':'make_ref'()) of + <'false'> when 'true' -> + 'ok' + ( <_cor1> when 'true' -> + primop 'match_fail' + ({'badmatch',_cor1}) + -| ['compiler_generated'] ) + end + ( <> when 'true' -> + ( primop 'match_fail' + ({'function_clause'}) + -| [{'function_name',{'eval_is_boolean',0}}] ) + -| ['compiler_generated'] ) + end +end diff --git a/lib/compiler/test/core_SUITE_data/make_effect_seq.core b/lib/compiler/test/core_SUITE_data/make_effect_seq.core new file mode 100644 index 0000000000..9941e63b76 --- /dev/null +++ b/lib/compiler/test/core_SUITE_data/make_effect_seq.core @@ -0,0 +1,51 @@ +module 'make_effect_seq' ['make_effect_seq'/0] + attributes [] +'make_effect_seq'/0 = + fun () -> + case <> of + <> when 'true' -> + let <_cor0> = + catch + apply 't'/1 + ('a') + in + case _cor0 of + <{'EXIT',{'badarg',_cor3}}> when 'true' -> + let <_cor4> = + apply 't'/1 + ({'a','b','c'}) + in + case _cor4 of + <'ok'> when 'true' -> + ( _cor4 + -| ['compiler_generated'] ) + ( <_cor2> when 'true' -> + primop 'match_fail' + ({'badmatch',_cor2}) + -| ['compiler_generated'] ) + end + ( <_cor1> when 'true' -> + primop 'match_fail' + ({'badmatch',_cor1}) + -| ['compiler_generated'] ) + end + ( <> when 'true' -> + ( primop 'match_fail' + ({'function_clause'}) + -| [{'function_name',{'make_effect_seq',0}}] ) + -| ['compiler_generated'] ) + end +'t'/1 = + fun (_cor0) -> + case _cor0 of + <T> when 'true' -> + do + {'ok',call 'erlang':'element'(2, T)} + 'ok' + ( <_cor2> when 'true' -> + ( primop 'match_fail' + ({'function_clause',_cor2}) + -| [{'function_name',{'t',1}}] ) + -| ['compiler_generated'] ) + end +end diff --git a/lib/compiler/test/core_SUITE_data/nomatch_shadow.core b/lib/compiler/test/core_SUITE_data/nomatch_shadow.core new file mode 100644 index 0000000000..565d9dc0f3 --- /dev/null +++ b/lib/compiler/test/core_SUITE_data/nomatch_shadow.core @@ -0,0 +1,28 @@ +module 'nomatch_shadow' ['nomatch_shadow'/0] + attributes [] +'nomatch_shadow'/0 = + fun () -> + case <> of + <> when 'true' -> + apply 't'/1 + (42) + ( <> when 'true' -> + ( primop 'match_fail' + ({'function_clause'}) + -| [{'function_name',{'nomatch_shadow',0}}] ) + -| ['compiler_generated'] ) + end +'t'/1 = + fun (_cor0) -> + case _cor0 of + <42> when 'true' -> + 'ok' + <42> when 'true' -> + 'ok' + ( <_cor1> when 'true' -> + ( primop 'match_fail' + ({'function_clause',_cor1}) + -| [{'function_name',{'t',1}}] ) + -| ['compiler_generated'] ) + end +end diff --git a/lib/compiler/test/core_SUITE_data/reversed_annos.core b/lib/compiler/test/core_SUITE_data/reversed_annos.core new file mode 100644 index 0000000000..95b3cd52d6 --- /dev/null +++ b/lib/compiler/test/core_SUITE_data/reversed_annos.core @@ -0,0 +1,49 @@ +module 'reversed_annos' ['reversed_annos'/0] + attributes [] +'reversed_annos'/0 = + fun () -> + case <> of + <> when 'true' -> + case apply 't'/1 + (['a']) of + <'ok'> when 'true' -> + let <_cor2> = + apply 't'/1 + (['a'|['b']]) + in + case _cor2 of + <'ok'> when 'true' -> + ( _cor2 + -| ['compiler_generated'] ) + ( <_cor1> when 'true' -> + primop 'match_fail' + ({'badmatch',_cor1}) + -| ['compiler_generated'] ) + end + ( <_cor0> when 'true' -> + primop 'match_fail' + ({'badmatch',_cor0}) + -| ['compiler_generated'] ) + end + ( <> when 'true' -> + ( primop 'match_fail' + ({'function_clause'}) + -| [{'function_name',{'reversed_annos',0}}] ) + -| ['compiler_generated'] ) + end +'t'/1 = + fun (_cor0) -> + case _cor0 of + <[_cor2|_cor3]> when 'true' -> + 'ok' + %% Cover v3_kernel:get_line/1. + ( <['a']> when 'true' -> + 'error' + -| [{'file',"reversed_annos.erl"},11] ) + ( <_cor1> when 'true' -> + ( primop 'match_fail' + ({'function_clause',_cor1}) + -| [{'function_name',{'t',1}}] ) + -| ['compiler_generated'] ) + end +end diff --git a/lib/compiler/test/core_SUITE_data/unsafe_case.core b/lib/compiler/test/core_SUITE_data/unsafe_case.core new file mode 100644 index 0000000000..84cb2c310a --- /dev/null +++ b/lib/compiler/test/core_SUITE_data/unsafe_case.core @@ -0,0 +1,25 @@ +module 'unsafe_case' ['unsafe_case'/0] + attributes [] +'unsafe_case'/0 = + fun () -> + case apply 't'/1 + (42) of + <{'ok',42}> when 'true' -> + 'ok' + ( <_cor0> when 'true' -> + primop 'match_fail' + ({'badmatch',_cor0}) + -| ['compiler_generated'] ) + end +'t'/1 = + fun (_cor0) -> + case _cor0 of + <X> + when call 'erlang':'>' + (_cor0, + 0) -> + {'ok',X} + %% The default case is intentionally missing + %% to cover v3_kernel:build_match/2. + end +end diff --git a/lib/compiler/test/core_fold_SUITE.erl b/lib/compiler/test/core_fold_SUITE.erl index ac14d36e82..fb5ec88c9f 100644 --- a/lib/compiler/test/core_fold_SUITE.erl +++ b/lib/compiler/test/core_fold_SUITE.erl @@ -214,6 +214,7 @@ coverage(Config) when is_list(Config) -> (catch cover_will_match_list_type({a,b,c,d})), ?line a = cover_remove_non_vars_alias({a,b,c}), ?line error = cover_will_match_lit_list(), + {ok,[a]} = cover_is_safe_bool_expr(a), %% Make sure that we don't attempt to make literals %% out of pids. (Putting a pid into a #c_literal{} @@ -249,4 +250,17 @@ cover_will_match_lit_list() -> error end. +cover_is_safe_bool_expr(X) -> + %% Use a try...catch that looks like a try...catch in a guard. + try + %% let V = [X] in {ok,V} + %% is_safe_simple([X]) ==> true + %% is_safe_bool_expr([X]) ==> false + V = [X], + {ok,V} + catch + _:_ -> + false + end. + id(I) -> I. diff --git a/lib/compiler/test/misc_SUITE.erl b/lib/compiler/test/misc_SUITE.erl index 9b414cade6..5e13a93c52 100644 --- a/lib/compiler/test/misc_SUITE.erl +++ b/lib/compiler/test/misc_SUITE.erl @@ -190,6 +190,15 @@ silly_coverage(Config) when is_list(Config) -> {label,2}|non_proper_list]}],99}, ?line expect_error(fun() -> beam_block:module(BlockInput, []) end), + %% beam_except + ExceptInput = {?MODULE,[{foo,0}],[], + [{function,foo,0,2, + [{label,1}, + {line,loc}, + {func_info,{atom,?MODULE},{atom,foo},0}, + {label,2}|non_proper_list]}],99}, + expect_error(fun() -> beam_except:module(ExceptInput, []) end), + %% beam_bool BoolInput = {?MODULE,[{foo,0}],[], [{function,foo,0,2, @@ -253,8 +262,15 @@ expect_error(Fun) -> io:format("~p", [Any]), ?t:fail(call_was_supposed_to_fail) catch - _:_ -> - io:format("~p\n", [erlang:get_stacktrace()]) + Class:Reason -> + Stk = erlang:get_stacktrace(), + io:format("~p:~p\n~p\n", [Class,Reason,Stk]), + case {Class,Reason} of + {error,undef} -> + ?t:fail(not_supposed_to_fail_with_undef); + {_,_} -> + ok + end end. confused_literals(Config) when is_list(Config) -> diff --git a/lib/compiler/test/parteval_SUITE.erl b/lib/compiler/test/parteval_SUITE.erl deleted file mode 100644 index 6b1ae38c1b..0000000000 --- a/lib/compiler/test/parteval_SUITE.erl +++ /dev/null @@ -1,66 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1998-2011. All Rights Reserved. -%% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% %CopyrightEnd% -%% --module(parteval_SUITE). - --include_lib("test_server/include/test_server.hrl"). - --export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, - init_per_group/2,end_per_group/2, pe2/1]). - -suite() -> [{ct_hooks,[ts_install_cth]}]. - -all() -> - [pe2]. - -groups() -> - []. - -init_per_suite(Config) -> - Config. - -end_per_suite(_Config) -> - ok. - -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(_GroupName, Config) -> - Config. - - -%% (This is more general than needed, since we once compiled the same -%% source code with and without a certain option.) -compile_and_load(Srcname, Outdir, Module, Options) -> - ?line Objname = filename:join(Outdir, "t1") ++ code:objfile_extension(), - ?line {ok, Module} = - compile:file(Srcname, - [{d, 'M', Module}, {outdir, Outdir}] ++ Options), - ?line {ok, B} = file:read_file(Objname), - ?line {module, Module} = code:load_binary(Module, Objname, B), - B. - -pe2(Config) when is_list(Config) -> - ?line DataDir = ?config(data_dir, Config), - ?line PrivDir = ?config(priv_dir, Config), - ?line Srcname = filename:join(DataDir, "t1.erl"), - ?line compile_and_load(Srcname, PrivDir, t1, []), - - ?line {Correct, Actual} = t1:run(), - ?line Correct = Actual, - ok. diff --git a/lib/compiler/test/parteval_SUITE_data/t1.erl b/lib/compiler/test/parteval_SUITE_data/t1.erl deleted file mode 100644 index 5e4a40f103..0000000000 --- a/lib/compiler/test/parteval_SUITE_data/t1.erl +++ /dev/null @@ -1,140 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1998-2009. All Rights Reserved. -%% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% %CopyrightEnd% -%% --module(?M). - --compile(export_all). - -%%% The arity-0 functions are all called from the test suite. - -f2() -> - size({1,2}). - -i() -> - case [] of - [] -> - ok; - X -> - hopp - end. - -e() -> - case 4+5 of -% X when X>10 -> kvock; % not removed by BEAM opt. - {X,X} when list(X) -> - kvack; - 9 -> - ok; - _ -> - ko - end. - -f() -> - element(2,{a,b,c,d}), - erlang:element(2,{a,b,c,d}), - "hej" ++ "hopp". - -g(X) -> - if - float(3.4) -> - hej; - X == 5, 4==4 -> - japp; - 4 == 4, size({1,2}) == 1 -> - ok - end. - -g() -> - {g(3),g(5)}. - -bliff() -> - if - 3==4 -> - himm - end. - -fi() -> - case 4 of - X when 4==3 -> - {X}; - 4 -> - 4; - _ -> - ok - end. - -iff() when 3==2 -> - if - 3 == 4 -> - baff; - 3 == 3 -> - nipp - end. - -sleep(I) -> receive after I -> ok end. - -sleep() -> - sleep(45). - -s() -> - case 4 of - 3 -> - ok - end. - -error_reason(R) when atom(R) -> - R; -error_reason(R) when tuple(R) -> - error_reason(element(1, R)). - -plusplus() -> - ?MODULE ++ " -> mindre snygg felhantering". - -call_it(F) -> - case (catch apply(?MODULE, F, [])) of - {'EXIT', R0} -> - {'EXIT', error_reason(R0)}; - V -> - V - end. - -run() -> - L = [{f2, 2}, - {i, ok}, - {e, ok}, - {f, "hejhopp"}, - {g, {hej, hej}}, - {bliff, {'EXIT', if_clause}}, - {fi, 4}, - {iff, {'EXIT', function_clause}}, - {sleep, ok}, - {s, {'EXIT', case_clause}, - {plusplus, {'EXIT', badarg}}}], - Actual = [call_it(F) || {F, _} <- L], - Correct = [C || {_, C} <- L], - {Correct, Actual}. - - -%%% Don't call, only compile. -t(A) -> - receive - A when 1==2 -> - ok; - B -> - B - end. diff --git a/lib/compiler/test/test_lib.erl b/lib/compiler/test/test_lib.erl index 53d8c04169..2295592a38 100644 --- a/lib/compiler/test/test_lib.erl +++ b/lib/compiler/test/test_lib.erl @@ -77,7 +77,14 @@ get_data_dir(Config) -> %% Will fail the test case if there were any errors. p_run(Test, List) -> - N = erlang:system_info(schedulers) + 1, + N = case ?t:is_cover() of + false -> + erlang:system_info(schedulers); + true -> + %% Cover is running. Using more than one process + %% will probably only slow down compilation. + 1 + end, p_run_loop(Test, List, N, [], 0, 0). p_run_loop(_, [], _, [], Errors, Ws) -> diff --git a/lib/compiler/test/trycatch_SUITE.erl b/lib/compiler/test/trycatch_SUITE.erl index 760cf17225..09a23724fe 100644 --- a/lib/compiler/test/trycatch_SUITE.erl +++ b/lib/compiler/test/trycatch_SUITE.erl @@ -24,7 +24,7 @@ catch_oops/1,after_oops/1,eclectic/1,rethrow/1, nested_of/1,nested_catch/1,nested_after/1, nested_horrid/1,last_call_optimization/1,bool/1, - plain_catch_coverage/1,andalso_orelse/1]). + plain_catch_coverage/1,andalso_orelse/1,get_in_try/1]). -include_lib("test_server/include/test_server.hrl"). @@ -35,7 +35,7 @@ all() -> [basic, lean_throw, try_of, try_after, catch_oops, after_oops, eclectic, rethrow, nested_of, nested_catch, nested_after, nested_horrid, last_call_optimization, - bool, plain_catch_coverage, andalso_orelse]. + bool, plain_catch_coverage, andalso_orelse, get_in_try]. groups() -> []. @@ -928,3 +928,17 @@ andalso_orelse_2({Type,Keyval}) -> zero() -> 0.0. + +get_in_try(_) -> + undefined = get_valid_line([a], []), + ok. + +get_valid_line([_|T]=Path, Annotations) -> + try + get(Path) + %% beam_dead used to optimize away an assignment to {y,1} + %% because it didn't appear to be used. + catch + _:not_found -> + get_valid_line(T, Annotations) + end. diff --git a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl index b42f5e8191..458f3a4c81 100644 --- a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl +++ b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl @@ -359,8 +359,17 @@ store_core(Mod, Core, NoWarn, Callgraph, CServer) -> store_code_and_build_callgraph(Mod, LabeledCore, Callgraph, CServer3, NoWarn). abs_get_nowarn(Abs, M) -> - [{M, F, A} - || {attribute, _, compile, {nowarn_unused_function, {F, A}}} <- Abs]. + Opts = lists:flatten([C || {attribute, _, compile, C} <- Abs]), + Warn = erl_lint:bool_option(warn_unused_function, nowarn_unused_function, + true, Opts), + case Warn of + false -> + [{M, F, A} || {function, _, F, A, _} <- Abs]; % all functions + true -> + [{M, F, A} || + {nowarn_unused_function, FAs} <- Opts, + {F, A} <- lists:flatten([FAs])] + end. get_exported_types_from_core(Core) -> Attrs = cerl:module_attrs(Core), diff --git a/lib/dialyzer/test/user_SUITE_data/results/nowarn_unused_function_1 b/lib/dialyzer/test/user_SUITE_data/results/nowarn_unused_function_1 new file mode 100644 index 0000000000..de416455e2 --- /dev/null +++ b/lib/dialyzer/test/user_SUITE_data/results/nowarn_unused_function_1 @@ -0,0 +1,2 @@ + +nowarn_unused_function_1.erl:17: Function f3/1 will never be called diff --git a/lib/dialyzer/test/user_SUITE_data/results/nowarn_unused_function_2 b/lib/dialyzer/test/user_SUITE_data/results/nowarn_unused_function_2 new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/lib/dialyzer/test/user_SUITE_data/results/nowarn_unused_function_2 diff --git a/lib/dialyzer/test/user_SUITE_data/results/nowarn_unused_function_3 b/lib/dialyzer/test/user_SUITE_data/results/nowarn_unused_function_3 new file mode 100644 index 0000000000..8ae78673d5 --- /dev/null +++ b/lib/dialyzer/test/user_SUITE_data/results/nowarn_unused_function_3 @@ -0,0 +1,3 @@ + +nowarn_unused_function_3.erl:12: Function f2/1 will never be called +nowarn_unused_function_3.erl:9: Function f1/1 will never be called diff --git a/lib/dialyzer/test/user_SUITE_data/src/nowarn_unused_function_1.erl b/lib/dialyzer/test/user_SUITE_data/src/nowarn_unused_function_1.erl new file mode 100644 index 0000000000..fcce532f73 --- /dev/null +++ b/lib/dialyzer/test/user_SUITE_data/src/nowarn_unused_function_1.erl @@ -0,0 +1,18 @@ +%% Test that option 'nowarn_unused_funcion' works similarly in +%% Dialyzer as in the compiler. + +-module(nowarn_unused_function_1). + +-compile(warn_unused_function). + +-compile({nowarn_unused_function,f1/1}). +f1(_) -> + a. + +-compile({nowarn_unused_function,[{f2,1}]}). +f2(_) -> + a. + +-compile({warn_unused_function,[{f3,1}]}). +f3(_) -> + a. diff --git a/lib/dialyzer/test/user_SUITE_data/src/nowarn_unused_function_2.erl b/lib/dialyzer/test/user_SUITE_data/src/nowarn_unused_function_2.erl new file mode 100644 index 0000000000..9bc3ab14ea --- /dev/null +++ b/lib/dialyzer/test/user_SUITE_data/src/nowarn_unused_function_2.erl @@ -0,0 +1,18 @@ +%% Test that option 'nowarn_unused_funcion' works similarly in +%% Dialyzer as in the compiler. + +-module(nowarn_unused_function_2). + +-compile(nowarn_unused_function). + +-compile({warn_unused_function,f1/1}). +f1(_) -> + a. + +-compile({warn_unused_function,[{f2,1}]}). +f2(_) -> + a. + +-compile({nowarn_unused_function,[{f3,1}]}). +f3(_) -> + a. diff --git a/lib/dialyzer/test/user_SUITE_data/src/nowarn_unused_function_3.erl b/lib/dialyzer/test/user_SUITE_data/src/nowarn_unused_function_3.erl new file mode 100644 index 0000000000..604c5e436b --- /dev/null +++ b/lib/dialyzer/test/user_SUITE_data/src/nowarn_unused_function_3.erl @@ -0,0 +1,16 @@ +%% Test that option 'nowarn_unused_funcion' works similarly in +%% Dialyzer as in the compiler. + +-module(nowarn_unused_function_3). + +-compile({warn_unused_function,[{f1,1},{f2,1}]}). +-compile({nowarn_unused_function,[{f3,1}]}). + +f1(_) -> + a. + +f2(_) -> + a. + +f3(_) -> + a. diff --git a/lib/diameter/examples/GNUmakefile b/lib/diameter/examples/code/GNUmakefile index 4c3f87939b..a0669119d2 100644 --- a/lib/diameter/examples/GNUmakefile +++ b/lib/diameter/examples/code/GNUmakefile @@ -1,19 +1,19 @@ -# +# # %CopyrightBegin% -# +# # Copyright Ericsson AB 2010-2011. All Rights Reserved. -# +# # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in # compliance with the License. You should have received a copy of the # Erlang Public License along with this software. If not, it can be # retrieved online at http://www.erlang.org/. -# +# # Software distributed under the License is distributed on an "AS IS" # basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See # the License for the specific language governing rights and limitations # under the License. -# +# # %CopyrightEnd% # diff --git a/lib/diameter/examples/client.erl b/lib/diameter/examples/code/client.erl index 36a77dd524..9e65f98de0 100644 --- a/lib/diameter/examples/client.erl +++ b/lib/diameter/examples/code/client.erl @@ -112,7 +112,7 @@ cast(Name) -> {'Auth-Application-Id', 0}, {'Re-Auth-Request-Type', 1}], diameter:call(Name, ?APP_ALIAS, RAR, [detach]). - + cast() -> cast(?SVC_NAME). diff --git a/lib/diameter/examples/client_cb.erl b/lib/diameter/examples/code/client_cb.erl index 524a8f94a1..524a8f94a1 100644 --- a/lib/diameter/examples/client_cb.erl +++ b/lib/diameter/examples/code/client_cb.erl diff --git a/lib/diameter/examples/peer.erl b/lib/diameter/examples/code/peer.erl index 89203e15c3..89203e15c3 100644 --- a/lib/diameter/examples/peer.erl +++ b/lib/diameter/examples/code/peer.erl diff --git a/lib/diameter/examples/redirect.erl b/lib/diameter/examples/code/redirect.erl index b54701243f..b54701243f 100644 --- a/lib/diameter/examples/redirect.erl +++ b/lib/diameter/examples/code/redirect.erl diff --git a/lib/diameter/examples/redirect_cb.erl b/lib/diameter/examples/code/redirect_cb.erl index ea7ad38749..ea7ad38749 100644 --- a/lib/diameter/examples/redirect_cb.erl +++ b/lib/diameter/examples/code/redirect_cb.erl diff --git a/lib/diameter/examples/relay.erl b/lib/diameter/examples/code/relay.erl index deecb1cfc0..deecb1cfc0 100644 --- a/lib/diameter/examples/relay.erl +++ b/lib/diameter/examples/code/relay.erl diff --git a/lib/diameter/examples/relay_cb.erl b/lib/diameter/examples/code/relay_cb.erl index 9ed6517d5c..9ed6517d5c 100644 --- a/lib/diameter/examples/relay_cb.erl +++ b/lib/diameter/examples/code/relay_cb.erl diff --git a/lib/diameter/examples/sctp.erl b/lib/diameter/examples/code/sctp.erl index 2e0e9d8b0b..08de023571 100644 --- a/lib/diameter/examples/sctp.erl +++ b/lib/diameter/examples/code/sctp.erl @@ -1,3 +1,21 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% -module(sctp). diff --git a/lib/diameter/examples/server.erl b/lib/diameter/examples/code/server.erl index ebb408e501..ebb408e501 100644 --- a/lib/diameter/examples/server.erl +++ b/lib/diameter/examples/code/server.erl diff --git a/lib/diameter/examples/server_cb.erl b/lib/diameter/examples/code/server_cb.erl index 43b8e24b5c..43b8e24b5c 100644 --- a/lib/diameter/examples/server_cb.erl +++ b/lib/diameter/examples/code/server_cb.erl diff --git a/lib/diameter/examples/dict/rfc4004_mip.dia b/lib/diameter/examples/dict/rfc4004_mip.dia new file mode 100644 index 0000000000..575ad4394a --- /dev/null +++ b/lib/diameter/examples/dict/rfc4004_mip.dia @@ -0,0 +1,280 @@ +;; +;; %CopyrightBegin% +;; +;; Copyright Ericsson AB 2010-2011. All Rights Reserved. +;; +;; The contents of this file are subject to the Erlang Public License, +;; Version 1.1, (the "License"); you may not use this file except in +;; compliance with the License. You should have received a copy of the +;; Erlang Public License along with this software. If not, it can be +;; retrieved online at http://www.erlang.org/. +;; +;; Software distributed under the License is distributed on an "AS IS" +;; basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +;; the License for the specific language governing rights and limitations +;; under the License. +;; +;; %CopyrightEnd% +;; + +;; +;; RFC 4004, Diameter Mobile IPv4 Application +;; +;; Edits: +;; +;; - MIP-nonce -> MIP-Nonce +;; - Session-ID -> Session-Id +;; - Omit MIP-HA-to-MN-SPI, MIP-MN-FA-SPI and MIP-MN-HA-SPI, none of +;; which are defined. +;; + +@id 2 + +@inherits rfc3588_base + +;; =========================================================================== + +@avp_types + + MIP-Reg-Request 320 OctetString M + MIP-Reg-Reply 321 OctetString M + MIP-MN-AAA-Auth 322 Grouped M + MIP-Mobile-Node-Address 333 Address M + MIP-Home-Agent-Address 334 Address M + MIP-Candidate-Home-Agent-Host 336 DiamIdent M + MIP-Feature-Vector 337 Unsigned32 M + MIP-Auth-Input-Data-Length 338 Unsigned32 M + MIP-Authenticator-Length 339 Unsigned32 M + MIP-Authenticator-Offset 340 Unsigned32 M + MIP-MN-AAA-SPI 341 Unsigned32 M + MIP-Filter-Rule 342 IPFilterRule M + MIP-FA-Challenge 344 OctetString M + MIP-Originating-Foreign-AAA 347 Grouped M + MIP-Home-Agent-Host 348 Grouped M + + MIP-FA-to-HA-SPI 318 Unsigned32 M + MIP-FA-to-MN-SPI 319 Unsigned32 M + MIP-HA-to-FA-SPI 323 Unsigned32 M + MIP-MN-to-FA-MSA 325 Grouped M + MIP-FA-to-MN-MSA 326 Grouped M + MIP-FA-to-HA-MSA 328 Grouped M + MIP-HA-to-FA-MSA 329 Grouped M + MIP-MN-to-HA-MSA 331 Grouped M + MIP-HA-to-MN-MSA 332 Grouped M + MIP-Nonce 335 OctetString M + MIP-Session-Key 343 OctetString M + MIP-Algorithm-Type 345 Enumerated M + MIP-Replay-Mode 346 Enumerated M + MIP-MSA-Lifetime 367 Unsigned32 M + +;; =========================================================================== + +@messages + + ;; 5.1. AA-Mobile-Node-Request + + AMR ::= < Diameter Header: 260, REQ, PXY > + + < Session-Id > + { Auth-Application-Id } + { User-Name } + { Destination-Realm } + { Origin-Host } + { Origin-Realm } + { MIP-Reg-Request } + { MIP-MN-AAA-Auth } + [ Acct-Multi-Session-Id ] + [ Destination-Host ] + [ Origin-State-Id ] + [ MIP-Mobile-Node-Address ] + [ MIP-Home-Agent-Address ] + [ MIP-Feature-Vector ] + [ MIP-Originating-Foreign-AAA ] + [ Authorization-Lifetime ] + [ Auth-Session-State ] + [ MIP-FA-Challenge ] + [ MIP-Candidate-Home-Agent-Host ] + [ MIP-Home-Agent-Host ] + [ MIP-HA-to-FA-SPI ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + ;; 5.2. AA-Mobile-Node-Answer + + AMA ::= < Diameter Header: 260, PXY > + + < Session-Id > + { Auth-Application-Id } + { Result-Code } + { Origin-Host } + { Origin-Realm } + [ Acct-Multi-Session-Id ] + [ User-Name ] + [ Authorization-Lifetime ] + [ Auth-Session-State ] + [ Error-Message ] + [ Error-Reporting-Host ] + [ Re-Auth-Request-Type ] + [ MIP-Feature-Vector ] + [ MIP-Reg-Reply ] + [ MIP-MN-to-FA-MSA ] + [ MIP-MN-to-HA-MSA ] + [ MIP-FA-to-MN-MSA ] + [ MIP-FA-to-HA-MSA ] + [ MIP-HA-to-MN-MSA ] + [ MIP-MSA-Lifetime ] + [ MIP-Home-Agent-Address ] + [ MIP-Mobile-Node-Address ] + * [ MIP-Filter-Rule ] + [ Origin-State-Id ] + * [ Proxy-Info ] + * [ AVP ] + + ;; 5.3. Home-Agent-MIP-Request + + HAR ::= < Diameter Header: 262, REQ, PXY > + + < Session-Id > + { Auth-Application-Id } + { Authorization-Lifetime } + { Auth-Session-State } + { MIP-Reg-Request } + { Origin-Host } + { Origin-Realm } + { User-Name } + { Destination-Realm } + { MIP-Feature-Vector } + [ Destination-Host ] + [ MIP-MN-to-HA-MSA ] + [ MIP-MN-to-FA-MSA ] + [ MIP-HA-to-MN-MSA ] + [ MIP-HA-to-FA-MSA ] + [ MIP-MSA-Lifetime ] + [ MIP-Originating-Foreign-AAA ] + [ MIP-Mobile-Node-Address ] + [ MIP-Home-Agent-Address ] + * [ MIP-Filter-Rule ] + [ Origin-State-Id ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + ;; 5.4. Home-Agent-MIP-Answer + + HAA ::= < Diameter Header: 262, PXY > + + < Session-Id > + { Auth-Application-Id } + { Result-Code } + { Origin-Host } + { Origin-Realm } + [ Acct-Multi-Session-Id ] + [ User-Name ] + [ Error-Reporting-Host ] + [ Error-Message ] + [ MIP-Reg-Reply ] + [ MIP-Home-Agent-Address ] + [ MIP-Mobile-Node-Address ] + [ MIP-FA-to-HA-SPI ] + [ MIP-FA-to-MN-SPI ] + [ Origin-State-Id ] + * [ Proxy-Info ] + * [ AVP ] + +;; =========================================================================== + +@grouped + + MIP-MN-AAA-Auth ::= < AVP Header: 322 > + + { MIP-MN-AAA-SPI } + { MIP-Auth-Input-Data-Length } + { MIP-Authenticator-Length } + { MIP-Authenticator-Offset } + * [ AVP ] + + + MIP-Originating-Foreign-AAA ::= < AVP Header: 347 > + + { Origin-Realm } + { Origin-Host } + * [ AVP ] + + MIP-Home-Agent-Host ::= < AVP Header: 348 > + + { Destination-Realm } + { Destination-Host } + * [ AVP ] + + MIP-FA-to-MN-MSA ::= < AVP Header: 326 > + + { MIP-FA-to-MN-SPI } + { MIP-Algorithm-Type } + { MIP-Session-Key } + * [ AVP ] + + MIP-FA-to-HA-MSA ::= < AVP Header: 328 > + + { MIP-FA-to-HA-SPI } + { MIP-Algorithm-Type } + { MIP-Session-Key } + * [ AVP ] + + MIP-HA-to-FA-MSA ::= < AVP Header: 329 > + + { MIP-HA-to-FA-SPI } + { MIP-Algorithm-Type } + { MIP-Session-Key } + * [ AVP ] + + MIP-HA-to-MN-MSA ::= < AVP Header: 332 > + + ; { MIP-HA-to-MN-SPI } + { MIP-Algorithm-Type } + { MIP-Replay-Mode } + { MIP-Session-Key } + * [ AVP ] + + MIP-MN-to-FA-MSA ::= < AVP Header: 325 > + + ; { MIP-MN-FA-SPI } + { MIP-Algorithm-Type } + { MIP-Nonce } + * [ AVP ] + + MIP-MN-to-HA-MSA ::= < AVP Header: 331 > + + ; { MIP-MN-HA-SPI } + { MIP-Algorithm-Type } + { MIP-Replay-Mode } + { MIP-Nonce } + * [ AVP ] + +;; =========================================================================== + +@enum MIP-Algorithm-Type + + HMAC-SHA-1 2 + +@enum MIP-Replay-Mode + + NONE 1 + TIMESTAMPS 2 + NONCES 3 + +;; =========================================================================== + +@define Result-Code + + ;; 6.1. Transient Failures + + MIP_REPLY_FAILURE 4005 + HA_NOT_AVAILABLE 4006 + BAD_KEY 4007 + MIP_FILTER_NOT_SUPPORTED 4008 + + ;; 6.2. Permanent Failures + + NO_FOREIGN_HA_SERVICE 5024 + END_TO_END_MIP_KEY_ENCRYPTION 5025 diff --git a/lib/diameter/examples/dict/rfc4005_nas.dia b/lib/diameter/examples/dict/rfc4005_nas.dia new file mode 100644 index 0000000000..a4b44e38bb --- /dev/null +++ b/lib/diameter/examples/dict/rfc4005_nas.dia @@ -0,0 +1,740 @@ +;; +;; %CopyrightBegin% +;; +;; Copyright Ericsson AB 2010-2011. All Rights Reserved. +;; +;; The contents of this file are subject to the Erlang Public License, +;; Version 1.1, (the "License"); you may not use this file except in +;; compliance with the License. You should have received a copy of the +;; Erlang Public License along with this software. If not, it can be +;; retrieved online at http://www.erlang.org/. +;; +;; Software distributed under the License is distributed on an "AS IS" +;; basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +;; the License for the specific language governing rights and limitations +;; under the License. +;; +;; %CopyrightEnd% +;; + +;; +;; RFC 4005, Diameter Network Access Server Application +;; +;; Edits: +;; +;; - Acounting-Auth-Method -> Accounting-Auth-Method +;; - Connection-Info -> ConnectInfo +;; - Framed-Appletalk-Link -> Framed-AppleTalk-Link +;; - Framed-Appletalk-Network -> Framed-AppleTalk-Network +;; - Framed-Appletalk-Zone -> Framed-AppleTalk-Zone +;; - Qos-Filter-Rule -> QoS-Filter-Rule +;; - Redirect-Host-Usase -> Redirect-Host-Usage +;; - Redirected-Host -> Redirect-Host +;; - Redirected-Host-Usage -> Redirect-Host-Usage +;; - Redirected-Host-Cache-Time -> Redirect-Max-Cache-Time +;; - Redirected-Max-Cache-Time -> Redirect-Max-Cache-Time +;; + +@id 1 + +@inherits rfc3588_base + +;; =========================================================================== + +@avp_types + + ;; 4. NAS Session AVPs + + NAS-Port 5 Unsigned32 M + NAS-Port-Id 87 UTF8String M + NAS-Port-Type 61 Enumerated M + Called-Station-Id 30 UTF8String M + Calling-Station-Id 31 UTF8String M + Connect-Info 77 UTF8String M + Originating-Line-Info 94 OctetString - + Reply-Message 18 UTF8String M + + ;; 5. NAS Authentication AVPs + + User-Password 2 OctetString M + Password-Retry 75 Unsigned32 M + Prompt 76 Enumerated M + CHAP-Auth 402 Grouped M + CHAP-Algorithm 403 Enumerated M + CHAP-Ident 404 OctetString M + CHAP-Response 405 OctetString M + CHAP-Challenge 60 OctetString M + ARAP-Password 70 OctetString M + ARAP-Challenge-Response 84 OctetString M + ARAP-Security 73 Unsigned32 M + ARAP-Security-Data 74 OctetString M + + ;; 6. NAS Authorization AVPs + + Service-Type 6 Enumerated M + Callback-Number 19 UTF8String M + Callback-Id 20 UTF8String M + Idle-Timeout 28 Unsigned32 M + Port-Limit 62 Unsigned32 M + NAS-Filter-Rule 400 IPFilterRule M + Filter-Id 11 UTF8String M + Configuration-Token 78 OctetString M + QoS-Filter-Rule 407 QoSFilterRule - + Framed-Protocol 7 Enumerated M + Framed-Routing 10 Enumerated M + Framed-MTU 12 Unsigned32 M + Framed-Compression 13 Enumerated M + Framed-IP-Address 8 OctetString M + Framed-IP-Netmask 9 OctetString M + Framed-Route 22 UTF8String M + Framed-Pool 88 OctetString M + Framed-Interface-Id 96 Unsigned64 M + Framed-IPv6-Prefix 97 OctetString M + Framed-IPv6-Route 99 UTF8String M + Framed-IPv6-Pool 100 OctetString M + Framed-IPX-Network 23 UTF8String M + Framed-AppleTalk-Link 37 Unsigned32 M + Framed-AppleTalk-Network 38 Unsigned32 M + Framed-AppleTalk-Zone 39 OctetString M + ARAP-Features 71 OctetString M + ARAP-Zone-Access 72 Enumerated M + Login-IP-Host 14 OctetString M + Login-IPv6-Host 98 OctetString M + Login-Service 15 Enumerated M + Login-TCP-Port 16 Unsigned32 M + Login-LAT-Service 34 OctetString M + Login-LAT-Node 35 OctetString M + Login-LAT-Group 36 OctetString M + Login-LAT-Port 63 OctetString M + + ;; 7. NAS Tunneling + + Tunneling 401 Grouped M + Tunnel-Type 64 Enumerated M + Tunnel-Medium-Type 65 Enumerated M + Tunnel-Client-Endpoint 66 UTF8String M + Tunnel-Server-Endpoint 67 UTF8String M + Tunnel-Password 69 OctetString M + Tunnel-Private-Group-Id 81 OctetString M + Tunnel-Assignment-Id 82 OctetString M + Tunnel-Preference 83 Unsigned32 M + Tunnel-Client-Auth-Id 90 UTF8String M + Tunnel-Server-Auth-Id 91 UTF8String M + + ;; 8. NAS Accounting + + Accounting-Input-Octets 363 Unsigned64 M + Accounting-Output-Octets 364 Unsigned64 M + Accounting-Input-Packets 365 Unsigned64 M + Accounting-Output-Packets 366 Unsigned64 M + Acct-Session-Time 46 Unsigned32 M + Acct-Authentic 45 Enumerated M + Accounting-Auth-Method 406 Enumerated M + Acct-Delay-Time 41 Unsigned32 M + Acct-Link-Count 51 Unsigned32 M + Acct-Tunnel-Connection 68 OctetString M + Acct-Tunnel-Packets-Lost 86 Unsigned32 M + + ;; 9.3. AVPs Used Only for Compatibility + + NAS-Identifier 32 UTF8String M + NAS-IP-Address 4 OctetString M + NAS-IPv6-Address 95 OctetString M + State 24 OctetString M + ;;Termination-Cause 295 Enumerated M + Origin-AAA-Protocol 408 Enumerated M + +;; =========================================================================== + +@messages + + AAR ::= < Diameter Header: 265, REQ, PXY > + + < Session-Id > + { Auth-Application-Id } + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + { Auth-Request-Type } + [ Destination-Host ] + [ NAS-Identifier ] + [ NAS-IP-Address ] + [ NAS-IPv6-Address ] + [ NAS-Port ] + [ NAS-Port-Id ] + [ NAS-Port-Type ] + [ Origin-AAA-Protocol ] + [ Origin-State-Id ] + [ Port-Limit ] + [ User-Name ] + [ User-Password ] + [ Service-Type ] + [ State ] + [ Authorization-Lifetime ] + [ Auth-Grace-Period ] + [ Auth-Session-State ] + [ Callback-Number ] + [ Called-Station-Id ] + [ Calling-Station-Id ] + [ Originating-Line-Info ] + [ Connect-Info ] + [ CHAP-Auth ] + [ CHAP-Challenge ] + * [ Framed-Compression ] + [ Framed-Interface-Id ] + [ Framed-IP-Address ] + * [ Framed-IPv6-Prefix ] + [ Framed-IP-Netmask ] + [ Framed-MTU ] + [ Framed-Protocol ] + [ ARAP-Password ] + [ ARAP-Security ] + * [ ARAP-Security-Data ] + * [ Login-IP-Host ] + * [ Login-IPv6-Host ] + [ Login-LAT-Group ] + [ Login-LAT-Node ] + [ Login-LAT-Port ] + [ Login-LAT-Service ] + * [ Tunneling ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + AAA ::= < Diameter Header: 265, PXY > + + < Session-Id > + { Auth-Application-Id } + { Auth-Request-Type } + { Result-Code } + { Origin-Host } + { Origin-Realm } + [ User-Name ] + [ Service-Type ] + * [ Class ] + * [ Configuration-Token ] + [ Acct-Interim-Interval ] + [ Error-Message ] + [ Error-Reporting-Host ] + * [ Failed-AVP ] + [ Idle-Timeout ] + [ Authorization-Lifetime ] + [ Auth-Grace-Period ] + [ Auth-Session-State ] + [ Re-Auth-Request-Type ] + [ Multi-Round-Time-Out ] + [ Session-Timeout ] + [ State ] + * [ Reply-Message ] + [ Origin-AAA-Protocol ] + [ Origin-State-Id ] + * [ Filter-Id ] + [ Password-Retry ] + [ Port-Limit ] + [ Prompt ] + [ ARAP-Challenge-Response ] + [ ARAP-Features ] + [ ARAP-Security ] + * [ ARAP-Security-Data ] + [ ARAP-Zone-Access ] + [ Callback-Id ] + [ Callback-Number ] + [ Framed-AppleTalk-Link ] + * [ Framed-AppleTalk-Network ] + [ Framed-AppleTalk-Zone ] + * [ Framed-Compression ] + [ Framed-Interface-Id ] + [ Framed-IP-Address ] + * [ Framed-IPv6-Prefix ] + [ Framed-IPv6-Pool ] + * [ Framed-IPv6-Route ] + [ Framed-IP-Netmask ] + * [ Framed-Route ] + [ Framed-Pool ] + [ Framed-IPX-Network ] + [ Framed-MTU ] + [ Framed-Protocol ] + [ Framed-Routing ] + * [ Login-IP-Host ] + * [ Login-IPv6-Host ] + [ Login-LAT-Group ] + [ Login-LAT-Node ] + [ Login-LAT-Port ] + [ Login-LAT-Service ] + [ Login-Service ] + [ Login-TCP-Port ] + * [ NAS-Filter-Rule ] + * [ QoS-Filter-Rule ] + * [ Tunneling ] + * [ Redirect-Host ] + [ Redirect-Host-Usage ] + [ Redirect-Max-Cache-Time ] + * [ Proxy-Info ] + * [ AVP ] + + RAR ::= < Diameter Header: 258, REQ, PXY > + + < Session-Id > + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + { Destination-Host } + { Auth-Application-Id } + { Re-Auth-Request-Type } + [ User-Name ] + [ Origin-AAA-Protocol ] + [ Origin-State-Id ] + [ NAS-Identifier ] + [ NAS-IP-Address ] + [ NAS-IPv6-Address ] + [ NAS-Port ] + [ NAS-Port-Id ] + [ NAS-Port-Type ] + [ Service-Type ] + [ Framed-IP-Address ] + [ Framed-IPv6-Prefix ] + [ Framed-Interface-Id ] + [ Called-Station-Id ] + [ Calling-Station-Id ] + [ Originating-Line-Info ] + [ Acct-Session-Id ] + [ Acct-Multi-Session-Id ] + [ State ] + * [ Class ] + [ Reply-Message ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + RAA ::= < Diameter Header: 258, PXY > + + < Session-Id > + { Result-Code } + { Origin-Host } + { Origin-Realm } + [ User-Name ] + [ Origin-AAA-Protocol ] + [ Origin-State-Id ] + [ Error-Message ] + [ Error-Reporting-Host ] + * [ Failed-AVP ] + * [ Redirect-Host ] + [ Redirect-Host-Usage ] + [ Redirect-Max-Cache-Time ] + [ Service-Type ] + * [ Configuration-Token ] + [ Idle-Timeout ] + [ Authorization-Lifetime ] + [ Auth-Grace-Period ] + [ Re-Auth-Request-Type ] + [ State ] + * [ Class ] + * [ Reply-Message ] + [ Prompt ] + * [ Proxy-Info ] + * [ AVP ] + + STR ::= < Diameter Header: 275, REQ, PXY > + + < Session-Id > + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + { Auth-Application-Id } + { Termination-Cause } + [ User-Name ] + [ Destination-Host ] + * [ Class ] + [ Origin-AAA-Protocol ] + [ Origin-State-Id ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + STA ::= < Diameter Header: 275, PXY > + + < Session-Id > + { Result-Code } + { Origin-Host } + { Origin-Realm } + [ User-Name ] + * [ Class ] + [ Error-Message ] + [ Error-Reporting-Host ] + * [ Failed-AVP ] + [ Origin-AAA-Protocol ] + [ Origin-State-Id ] + * [ Redirect-Host ] + [ Redirect-Host-Usage ] + [ Redirect-Max-Cache-Time ] + * [ Proxy-Info ] + * [ AVP ] + + ASR ::= < Diameter Header: 274, REQ, PXY > + + < Session-Id > + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + { Destination-Host } + { Auth-Application-Id } + [ User-Name ] + [ Origin-AAA-Protocol ] + [ Origin-State-Id ] + [ NAS-Identifier ] + [ NAS-IP-Address ] + [ NAS-IPv6-Address ] + [ NAS-Port ] + [ NAS-Port-Id ] + [ NAS-Port-Type ] + [ Service-Type ] + [ Framed-IP-Address ] + [ Framed-IPv6-Prefix ] + [ Framed-Interface-Id ] + [ Called-Station-Id ] + [ Calling-Station-Id ] + [ Originating-Line-Info ] + [ Acct-Session-Id ] + [ Acct-Multi-Session-Id ] + [ State ] + * [ Class ] + * [ Reply-Message ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + ASA ::= < Diameter Header: 274, PXY > + + < Session-Id > + { Result-Code } + { Origin-Host } + { Origin-Realm } + [ User-Name ] + [ Origin-AAA-Protocol ] + [ Origin-State-Id ] + [ State] + [ Error-Message ] + [ Error-Reporting-Host ] + * [ Failed-AVP ] + * [ Redirect-Host ] + [ Redirect-Host-Usage ] + [ Redirect-Max-Cache-Time ] + * [ Proxy-Info ] + * [ AVP ] + + ACR ::= < Diameter Header: 271, REQ, PXY > + + < Session-Id > + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + { Accounting-Record-Type } + { Accounting-Record-Number } + [ Acct-Application-Id ] + [ Vendor-Specific-Application-Id ] + [ User-Name ] + [ Accounting-Sub-Session-Id ] + [ Acct-Session-Id ] + [ Acct-Multi-Session-Id ] + [ Origin-AAA-Protocol ] + [ Origin-State-Id ] + [ Destination-Host ] + [ Event-Timestamp ] + [ Acct-Delay-Time ] + [ NAS-Identifier ] + [ NAS-IP-Address ] + [ NAS-IPv6-Address ] + [ NAS-Port ] + [ NAS-Port-Id ] + [ NAS-Port-Type ] + * [ Class ] + [ Service-Type ] + [ Termination-Cause ] + [ Accounting-Input-Octets ] + [ Accounting-Input-Packets ] + [ Accounting-Output-Octets ] + [ Accounting-Output-Packets ] + [ Acct-Authentic ] + [ Accounting-Auth-Method ] + [ Acct-Link-Count ] + [ Acct-Session-Time ] + [ Acct-Tunnel-Connection ] + [ Acct-Tunnel-Packets-Lost ] + [ Callback-Id ] + [ Callback-Number ] + [ Called-Station-Id ] + [ Calling-Station-Id ] + * [ Connect-Info ] + [ Originating-Line-Info ] + [ Authorization-Lifetime ] + [ Session-Timeout ] + [ Idle-Timeout ] + [ Port-Limit ] + [ Accounting-Realtime-Required ] + [ Acct-Interim-Interval ] + * [ Filter-Id ] + * [ NAS-Filter-Rule ] + * [ QoS-Filter-Rule ] + [ Framed-AppleTalk-Link ] + [ Framed-AppleTalk-Network ] + [ Framed-AppleTalk-Zone ] + [ Framed-Compression ] + [ Framed-Interface-Id ] + [ Framed-IP-Address ] + [ Framed-IP-Netmask ] + * [ Framed-IPv6-Prefix ] + [ Framed-IPv6-Pool ] + * [ Framed-IPv6-Route ] + [ Framed-IPX-Network ] + [ Framed-MTU ] + [ Framed-Pool ] + [ Framed-Protocol ] + * [ Framed-Route ] + [ Framed-Routing ] + * [ Login-IP-Host ] + * [ Login-IPv6-Host ] + [ Login-LAT-Group ] + [ Login-LAT-Node ] + [ Login-LAT-Port ] + [ Login-LAT-Service ] + [ Login-Service ] + [ Login-TCP-Port ] + * [ Tunneling ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + ACA ::= < Diameter Header: 271, PXY > + + < Session-Id > + { Result-Code } + { Origin-Host } + { Origin-Realm } + { Accounting-Record-Type } + { Accounting-Record-Number } + [ Acct-Application-Id ] + [ Vendor-Specific-Application-Id ] + [ User-Name ] + [ Accounting-Sub-Session-Id ] + [ Acct-Session-Id ] + [ Acct-Multi-Session-Id ] + [ Event-Timestamp ] + [ Error-Message ] + [ Error-Reporting-Host ] + * [ Failed-AVP ] + [ Origin-AAA-Protocol ] + [ Origin-State-Id ] + [ NAS-Identifier ] + [ NAS-IP-Address ] + [ NAS-IPv6-Address ] + [ NAS-Port ] + [ NAS-Port-Id ] + [ NAS-Port-Type ] + [ Service-Type ] + [ Termination-Cause ] + [ Accounting-Realtime-Required ] + [ Acct-Interim-Interval ] + * [ Class ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + +;; =========================================================================== + +@grouped + + CHAP-Auth ::= < AVP Header: 402 > + + { CHAP-Algorithm } + { CHAP-Ident } + [ CHAP-Response ] + * [ AVP ] + + Tunneling ::= < AVP Header: 401 > + + { Tunnel-Type } + { Tunnel-Medium-Type } + { Tunnel-Client-Endpoint } + { Tunnel-Server-Endpoint } + [ Tunnel-Preference ] + [ Tunnel-Client-Auth-Id ] + [ Tunnel-Server-Auth-Id ] + [ Tunnel-Assignment-Id ] + [ Tunnel-Password ] + [ Tunnel-Private-Group-Id ] + +;; =========================================================================== + +@enum NAS-Port-Type + + ASYNC 0 + SYNC 1 + ISDN_SYNC 2 + ISDN_ASYNC_V120 3 + ISDN_ASYNC_V110 4 + VIRTUAL 5 + PIAFS 6 + HDLC_CLEAR_CHANNEL 7 + X25 8 + X75 9 + G3FAX 10 + SDSL 11 + ADSL-CAP 12 + ADSL-DMT 13 + IDSL 14 + ETHERNET 15 + XDSL 16 + CABLE 17 + WIRELESS_OTHER 18 + 'WIRELESS_802.11' 19 + TOKEN-RING 20 + FDDI 21 + WIRELESS_CDMA2000 22 + WIRELESS_UMTS 23 + WIRELESS_1X-EV 24 + IAPP 25 + +@enum Prompt + + NO_ECHO 0 + ECHO 1 + +@enum CHAP-Algorithm + + WITH_MD5 5 + +@enum Service-Type + + LOGIN 1 + FRAMED 2 + CALLBACK_LOGIN 3 + CALLBACK_FRAMED 4 + OUTBOUND 5 + ADMINISTRATIVE 6 + NAS_PROMPT 7 + AUTHENTICATE_ONLY 8 + CALLBACK_NAS_PROMPT 9 + CALL_CHECK 10 + CALLBACK_ADMINISTRATIVE 11 + VOICE 12 + FAX 13 + MODEM_RELAY 14 + IAPP-REGISTER 15 + IAPP-AP-CHECK 16 + AUTHORIZE_ONLY 17 + +@enum Framed-Protocol + + PPP 1 + SLIP 2 + ARAP 3 + GANDALF 4 + XYLOGICS 5 + X75 6 + +@enum Framed-Routing + + NONE 0 + SEND 1 + LISTEN 2 + SEND_AND_LISTEN 3 + +@enum Framed-Compression + + NONE 0 + VJ 1 + IPX 2 + STAC-LZS 3 + +@enum ARAP-Zone-Access + + DEFAULT 1 + FILTER_INCLUSIVELY 2 + FILTER_EXCLUSIVELY 4 + +@enum Login-Service + + TELNET 0 + RLOGIN 1 + TCP_CLEAR 2 + PORTMASTER 3 + LAT 4 + X25-PAD 5 + X25-T3POS 6 + TCP_CLEAR_QUIET 8 + +@enum Tunnel-Type + + PPTP 1 + L2F 2 + L2TP 3 + ATMP 4 + VTP 5 + AH 6 + IP-IP 7 + MIN-IP-IP 8 + ESP 9 + GRE 10 + DVS 11 + IP-IN-IP 12 + VLAN 13 + +@enum Tunnel-Medium-Type + + IPV4 1 + IPV6 2 + NSAP 3 + HDLC 4 + BBN_1822 5 + '802' 6 + E163 7 + E164 8 + F69 9 + X121 10 + IPX 11 + APPLETALK 12 + DECNET_IV 13 + BANYAN_VINES 14 + E164_NSAP 15 + + +@enum Acct-Authentic + + RADIUS 1 + LOCAL 2 + REMOTE 3 + DIAMETER 4 + +@enum Accounting-Auth-Method + + PAP 1 + CHAP 2 + MS-CHAP-1 3 + MS-CHAP-2 4 + EAP 5 + NONE 7 + +@enum Termination-Cause + + USER_REQUEST 11 + LOST_CARRIER 12 + LOST_SERVICE 13 + IDLE_TIMEOUT 14 + SESSION_TIMEOUT 15 + ADMIN_RESET 16 + ADMIN_REBOOT 17 + PORT_ERROR 18 + NAS_ERROR 19 + NAS_REQUEST 20 + NAS_REBOOT 21 + PORT_UNNEEDED 22 + PORT_PREEMPTED 23 + PORT_SUSPENDED 24 + SERVICE_UNAVAILABLE 25 + CALLBACK 26 + USER_ERROR 27 + HOST_REQUEST 28 + SUPPLICANT_RESTART 29 + REAUTHORIZATION_FAILURE 30 + PORT_REINIT 31 + PORT_DISABLED 32 diff --git a/lib/diameter/examples/dict/rfc4006_cc.dia b/lib/diameter/examples/dict/rfc4006_cc.dia new file mode 100644 index 0000000000..b723e4ddbb --- /dev/null +++ b/lib/diameter/examples/dict/rfc4006_cc.dia @@ -0,0 +1,349 @@ +;; +;; %CopyrightBegin% +;; +;; Copyright Ericsson AB 2010-2011. All Rights Reserved. +;; +;; The contents of this file are subject to the Erlang Public License, +;; Version 1.1, (the "License"); you may not use this file except in +;; compliance with the License. You should have received a copy of the +;; Erlang Public License along with this software. If not, it can be +;; retrieved online at http://www.erlang.org/. +;; +;; Software distributed under the License is distributed on an "AS IS" +;; basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +;; the License for the specific language governing rights and limitations +;; under the License. +;; +;; %CopyrightEnd% +;; + +;; +;; RFC 4006, Diameter Credit-Control Application +;; + +@id 4 + +@inherits rfc3588_base +@inherits rfc4005_nas Filter-Id + +;; =========================================================================== + +@avp_types + + CC-Correlation-Id 411 OctetString - + CC-Input-Octets 412 Unsigned64 M + CC-Money 413 Grouped M + CC-Output-Octets 414 Unsigned64 M + CC-Request-Number 415 Unsigned32 M + CC-Request-Type 416 Enumerated M + CC-Service-Specific-Units 417 Unsigned64 M + CC-Session-Failover 418 Enumerated M + CC-Sub-Session-Id 419 Unsigned64 M + CC-Time 420 Unsigned32 M + CC-Total-Octets 421 Unsigned64 M + CC-Unit-Type 454 Enumerated M + Check-Balance-Result 422 Enumerated M + Cost-Information 423 Grouped M + Cost-Unit 424 UTF8String M + Credit-Control 426 Enumerated M + Credit-Control-Failure-Handling 427 Enumerated M + Currency-Code 425 Unsigned32 M + Direct-Debiting-Failure-Handling 428 Enumerated M + Exponent 429 Integer32 M + Final-Unit-Action 449 Enumerated M + Final-Unit-Indication 430 Grouped M + Granted-Service-Unit 431 Grouped M + G-S-U-Pool-Identifier 453 Unsigned32 M + G-S-U-Pool-Reference 457 Grouped M + Multiple-Services-Credit-Control 456 Grouped M + Multiple-Services-Indicator 455 Enumerated M + Rating-Group 432 Unsigned32 M + Redirect-Address-Type 433 Enumerated M + Redirect-Server 434 Grouped M + Redirect-Server-Address 435 UTF8String M + Requested-Action 436 Enumerated M + Requested-Service-Unit 437 Grouped M + Restriction-Filter-Rule 438 IPFilterRule M + Service-Context-Id 461 UTF8String M + Service-Identifier 439 Unsigned32 M + Service-Parameter-Info 440 Grouped - + Service-Parameter-Type 441 Unsigned32 - + Service-Parameter-Value 442 OctetString - + Subscription-Id 443 Grouped M + Subscription-Id-Data 444 UTF8String M + Subscription-Id-Type 450 Enumerated M + Tariff-Change-Usage 452 Enumerated M + Tariff-Time-Change 451 Time M + Unit-Value 445 Grouped M + Used-Service-Unit 446 Grouped M + User-Equipment-Info 458 Grouped - + User-Equipment-Info-Type 459 Enumerated - + User-Equipment-Info-Value 460 OctetString - + Value-Digits 447 Integer64 M + Validity-Time 448 Unsigned32 M + +;; =========================================================================== + +@messages + + CCR ::= < Diameter Header: 272, REQ, PXY > + + < Session-Id > + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + { Auth-Application-Id } + { Service-Context-Id } + { CC-Request-Type } + { CC-Request-Number } + [ Destination-Host ] + [ User-Name ] + [ CC-Sub-Session-Id ] + [ Acct-Multi-Session-Id ] + [ Origin-State-Id ] + [ Event-Timestamp ] + * [ Subscription-Id ] + [ Service-Identifier ] + [ Termination-Cause ] + [ Requested-Service-Unit ] + [ Requested-Action ] + * [ Used-Service-Unit ] + [ Multiple-Services-Indicator ] + * [ Multiple-Services-Credit-Control ] + * [ Service-Parameter-Info ] + [ CC-Correlation-Id ] + [ User-Equipment-Info ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + CCA ::= < Diameter Header: 272, PXY > + + < Session-Id > + { Result-Code } + { Origin-Host } + { Origin-Realm } + { Auth-Application-Id } + { CC-Request-Type } + { CC-Request-Number } + [ User-Name ] + [ CC-Session-Failover ] + [ CC-Sub-Session-Id ] + [ Acct-Multi-Session-Id ] + [ Origin-State-Id ] + [ Event-Timestamp ] + [ Granted-Service-Unit ] + * [ Multiple-Services-Credit-Control ] + [ Cost-Information] + [ Final-Unit-Indication ] + [ Check-Balance-Result ] + [ Credit-Control-Failure-Handling ] + [ Direct-Debiting-Failure-Handling ] + [ Validity-Time] + * [ Redirect-Host] + [ Redirect-Host-Usage ] + [ Redirect-Max-Cache-Time ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ Failed-AVP ] + * [ AVP ] + +;; =========================================================================== + +@grouped + + Cost-Information ::= < AVP Header: 423 > + + { Unit-Value } + { Currency-Code } + [ Cost-Unit ] + + Unit-Value ::= < AVP Header: 445 > + + { Value-Digits } + [ Exponent ] + + Multiple-Services-Credit-Control ::= < AVP Header: 456 > + + [ Granted-Service-Unit ] + [ Requested-Service-Unit ] + * [ Used-Service-Unit ] + [ Tariff-Change-Usage ] + * [ Service-Identifier ] + [ Rating-Group ] + * [ G-S-U-Pool-Reference ] + [ Validity-Time ] + [ Result-Code ] + [ Final-Unit-Indication ] + * [ AVP ] + + Granted-Service-Unit ::= < AVP Header: 431 > + + [ Tariff-Time-Change ] + [ CC-Time ] + [ CC-Money ] + [ CC-Total-Octets ] + [ CC-Input-Octets ] + [ CC-Output-Octets ] + [ CC-Service-Specific-Units ] + * [ AVP ] + + Requested-Service-Unit ::= < AVP Header: 437 > + + [ CC-Time ] + [ CC-Money ] + [ CC-Total-Octets ] + [ CC-Input-Octets ] + [ CC-Output-Octets ] + [ CC-Service-Specific-Units ] + * [ AVP ] + + Used-Service-Unit ::= < AVP Header: 446 > + + [ Tariff-Change-Usage ] + [ CC-Time ] + [ CC-Money ] + [ CC-Total-Octets ] + [ CC-Input-Octets ] + [ CC-Output-Octets ] + [ CC-Service-Specific-Units ] + * [ AVP ] + + CC-Money ::= < AVP Header: 413 > + + { Unit-Value } + [ Currency-Code ] + + G-S-U-Pool-Reference ::= < AVP Header: 457 > + + { G-S-U-Pool-Identifier } + { CC-Unit-Type } + { Unit-Value } + + Final-Unit-Indication ::= < AVP Header: 430 > + + { Final-Unit-Action } + * [ Restriction-Filter-Rule ] + * [ Filter-Id ] + [ Redirect-Server ] + + Redirect-Server ::= < AVP Header: 434 > + + { Redirect-Address-Type } + { Redirect-Server-Address } + + Service-Parameter-Info ::= < AVP Header: 440 > + + { Service-Parameter-Type } + { Service-Parameter-Value } + + Subscription-Id ::= < AVP Header: 443 > + + { Subscription-Id-Type } + { Subscription-Id-Data } + + User-Equipment-Info ::= < AVP Header: 458 > + + { User-Equipment-Info-Type } + { User-Equipment-Info-Value } + +;; =========================================================================== + +@enum CC-Request-Type + + INITIAL_REQUEST 1 + UPDATE_REQUEST 2 + TERMINATION_REQUEST 3 + EVENT_REQUEST 4 + +@enum CC-Session-Failover + + NOT_SUPPORTED 0 + SUPPORTED 1 + +@enum Check-Balance-Result + + ENOUGH_CREDIT 0 + NO_CREDIT 1 + +@enum Credit-Control + + AUTHORIZATION 0 + RE_AUTHORIZATION 1 + +@enum Credit-Control-Failure-Handling + + TERMINATE 0 + CONTINUE 1 + RETRY_AND_TERMINATE 2 + +@enum Direct-Debiting-Failure-Handling + + TERMINATE_OR_BUFFER 0 + CONTINUE 1 + +@enum Tariff-Change-Usage + + UNIT_BEFORE_TARIFF_CHANGE 0 + UNIT_AFTER_TARIFF_CHANGE 1 + UNIT_INDETERMINATE 2 + +@enum CC-Unit-Type + + TIME 0 + MONEY 1 + TOTAL-OCTETS 2 + INPUT-OCTETS 3 + OUTPUT-OCTETS 4 + SERVICE-SPECIFIC-UNITS 5 + +@enum Final-Unit-Action + + TERMINATE 0 + REDIRECT 1 + RESTRICT_ACCESS 2 + +@enum Redirect-Address-Type + + IPV4 0 + IPV6 1 + URL 2 + SIP_URI 3 + +@enum Multiple-Services-Indicator + + NOT_SUPPORTED 0 + SUPPORTED 1 + +@enum Requested-Action + + DIRECT_DEBITING 0 + REFUND_ACCOUNT 1 + CHECK_BALANCE 2 + PRICE_ENQUIRY 3 + +@enum Subscription-Id-Type + + END_USER_E164 0 + END_USER_IMSI 1 + END_USER_SIP_URI 2 + END_USER_NAI 3 + END_USER_PRIVATE 4 + +@enum User-Equipment-Info-Type + + IMEISV 0 + MAC 1 + EUI64 2 + MODIFIED_EUI64 3 + +;; =========================================================================== + +@define Result-Code + + END_USER_SERVICE_DENIED 4010 + CREDIT_CONTROL_NOT_APPLICABLE 4011 + CREDIT_LIMIT_REACHED 4012 + + USER_UNKNOWN 5030 + RATING_FAILED 5031 diff --git a/lib/diameter/examples/dict/rfc4072_eap.dia b/lib/diameter/examples/dict/rfc4072_eap.dia new file mode 100644 index 0000000000..111516b347 --- /dev/null +++ b/lib/diameter/examples/dict/rfc4072_eap.dia @@ -0,0 +1,150 @@ +;; +;; %CopyrightBegin% +;; +;; Copyright Ericsson AB 2010-2011. All Rights Reserved. +;; +;; The contents of this file are subject to the Erlang Public License, +;; Version 1.1, (the "License"); you may not use this file except in +;; compliance with the License. You should have received a copy of the +;; Erlang Public License along with this software. If not, it can be +;; retrieved online at http://www.erlang.org/. +;; +;; Software distributed under the License is distributed on an "AS IS" +;; basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +;; the License for the specific language governing rights and limitations +;; under the License. +;; +;; %CopyrightEnd% +;; + +;; +;; RFC 4072, Diameter Extensible Authentication Protocol (EAP) Application +;; +;; Edits: +;; +;; - Move EAP-Payload to not break fixed/required/optional order +;; - Framed-Appletalk-Link -> Framed-AppleTalk-Link +;; - Framed-Appletalk-Network -> Framed-AppleTalk-Network +;; - Framed-Appletalk-Zone -> Framed-AppleTalk-Zone +;; + +@id 5 + +@inherits rfc3588_base +@inherits rfc4005_nas + +;; =========================================================================== + +@avp_types + + EAP-Master-Session-Key 464 OctetString - + EAP-Key-Name 102 OctetString - + EAP-Payload 462 OctetString - + EAP-Reissued-Payload 463 OctetString - + Accounting-EAP-Auth-Method 465 Unsigned64 - + +;; =========================================================================== + +@messages + + DER ::= < Diameter Header: 268, REQ, PXY > + + < Session-Id > + { Auth-Application-Id } + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + { Auth-Request-Type } + { EAP-Payload } + [ Destination-Host ] + [ NAS-Identifier ] + [ NAS-IP-Address ] + [ NAS-IPv6-Address ] + [ NAS-Port ] + [ NAS-Port-Id ] + [ NAS-Port-Type ] + [ Origin-State-Id ] + [ Port-Limit ] + [ User-Name ] + [ EAP-Key-Name ] + [ Service-Type ] + [ State ] + [ Authorization-Lifetime ] + [ Auth-Grace-Period ] + [ Auth-Session-State ] + [ Callback-Number ] + [ Called-Station-Id ] + [ Calling-Station-Id ] + [ Originating-Line-Info ] + [ Connect-Info ] + * [ Framed-Compression ] + [ Framed-Interface-Id ] + [ Framed-IP-Address ] + * [ Framed-IPv6-Prefix ] + [ Framed-IP-Netmask ] + [ Framed-MTU ] + [ Framed-Protocol ] + * [ Tunneling ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + DEA ::= < Diameter Header: 268, PXY > + + < Session-Id > + { Auth-Application-Id } + { Auth-Request-Type } + { Result-Code } + { Origin-Host } + { Origin-Realm } + [ User-Name ] + [ EAP-Payload ] + [ EAP-Reissued-Payload ] + [ EAP-Master-Session-Key ] + [ EAP-Key-Name ] + [ Multi-Round-Time-Out ] + [ Accounting-EAP-Auth-Method ] + [ Service-Type ] + * [ Class ] + * [ Configuration-Token ] + [ Acct-Interim-Interval ] + [ Error-Message ] + [ Error-Reporting-Host ] + * [ Failed-AVP ] + [ Idle-Timeout ] + [ Authorization-Lifetime ] + [ Auth-Grace-Period ] + [ Auth-Session-State ] + [ Re-Auth-Request-Type ] + [ Session-Timeout ] + [ State ] + * [ Reply-Message ] + [ Origin-State-Id ] + * [ Filter-Id ] + [ Port-Limit ] + [ Callback-Id ] + [ Callback-Number ] + [ Framed-AppleTalk-Link ] + * [ Framed-AppleTalk-Network ] + [ Framed-AppleTalk-Zone ] + * [ Framed-Compression ] + [ Framed-Interface-Id ] + [ Framed-IP-Address ] + * [ Framed-IPv6-Prefix ] + [ Framed-IPv6-Pool ] + * [ Framed-IPv6-Route ] + [ Framed-IP-Netmask ] + * [ Framed-Route ] + [ Framed-Pool ] + [ Framed-IPX-Network ] + [ Framed-MTU ] + [ Framed-Protocol ] + [ Framed-Routing ] + * [ NAS-Filter-Rule ] + * [ QoS-Filter-Rule ] + * [ Tunneling ] + * [ Redirect-Host ] + [ Redirect-Host-Usage ] + [ Redirect-Max-Cache-Time ] + * [ Proxy-Info ] + * [ AVP ] diff --git a/lib/diameter/examples/dict/rfc4590_digest.dia b/lib/diameter/examples/dict/rfc4590_digest.dia new file mode 100644 index 0000000000..a4ebe0c456 --- /dev/null +++ b/lib/diameter/examples/dict/rfc4590_digest.dia @@ -0,0 +1,45 @@ +;; +;; %CopyrightBegin% +;; +;; Copyright Ericsson AB 2010-2011. All Rights Reserved. +;; +;; The contents of this file are subject to the Erlang Public License, +;; Version 1.1, (the "License"); you may not use this file except in +;; compliance with the License. You should have received a copy of the +;; Erlang Public License along with this software. If not, it can be +;; retrieved online at http://www.erlang.org/. +;; +;; Software distributed under the License is distributed on an "AS IS" +;; basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +;; the License for the specific language governing rights and limitations +;; under the License. +;; +;; %CopyrightEnd% +;; + +;; +;; RFC 4590, RADIUS Extension for Digest Authentication +;; + +@avp_types + + Digest-Response 103 OctetString - + Digest-Realm 104 OctetString - + Digest-Nonce 105 OctetString - + Digest-Response-Auth 106 OctetString - + Digest-Nextnonce 107 OctetString - + Digest-Method 108 OctetString - + Digest-URI 109 OctetString - + Digest-Qop 110 OctetString - + Digest-Algorithm 111 OctetString - + Digest-Entity-Body-Hash 112 OctetString - + Digest-CNonce 113 OctetString - + Digest-Nonce-Count 114 OctetString - + Digest-Username 115 OctetString - + Digest-Opaque 116 OctetString - + Digest-Auth-Param 117 OctetString - + Digest-AKA-Auts 118 OctetString - + Digest-Domain 119 OctetString - + Digest-Stale 120 OctetString - + Digest-HA1 121 OctetString - + SIP-AOR 122 OctetString - diff --git a/lib/diameter/examples/dict/rfc4740_sip.dia b/lib/diameter/examples/dict/rfc4740_sip.dia new file mode 100644 index 0000000000..8c21882649 --- /dev/null +++ b/lib/diameter/examples/dict/rfc4740_sip.dia @@ -0,0 +1,446 @@ +;; +;; %CopyrightBegin% +;; +;; Copyright Ericsson AB 2010-2011. All Rights Reserved. +;; +;; The contents of this file are subject to the Erlang Public License, +;; Version 1.1, (the "License"); you may not use this file except in +;; compliance with the License. You should have received a copy of the +;; Erlang Public License along with this software. If not, it can be +;; retrieved online at http://www.erlang.org/. +;; +;; Software distributed under the License is distributed on an "AS IS" +;; basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +;; the License for the specific language governing rights and limitations +;; under the License. +;; +;; %CopyrightEnd% +;; + +;; +;; RFC 4740, Diameter Session Initiation Protocol (SIP) Application +;; + +@id 6 + +@inherits rfc3588_base +@inherits rfc4590_digest + +;; =========================================================================== + +@avp_types + + SIP-Accounting-Information 368 Grouped M + SIP-Accounting-Server-URI 369 DiameterURI M + SIP-Credit-Control-Server-URI 370 DiameterURI M + SIP-Server-URI 371 UTF8String M + SIP-Server-Capabilities 372 Grouped M + SIP-Mandatory-Capability 373 Unsigned32 M + SIP-Optional-Capability 374 Unsigned32 M + SIP-Server-Assignment-Type 375 Enumerated M + SIP-Auth-Data-Item 376 Grouped M + SIP-Authentication-Scheme 377 Enumerated M + SIP-Item-Number 378 Unsigned32 M + SIP-Authenticate 379 Grouped M + SIP-Authorization 380 Grouped M + SIP-Authentication-Info 381 Grouped M + SIP-Number-Auth-Items 382 Unsigned32 M + SIP-Deregistration-Reason 383 Grouped M + SIP-Reason-Code 384 Enumerated M + SIP-Reason-Info 385 UTF8String M + SIP-Visited-Network-Id 386 UTF8String M + SIP-User-Authorization-Type 387 Enumerated M + SIP-Supported-User-Data-Type 388 UTF8String M + SIP-User-Data 389 Grouped M + SIP-User-Data-Type 390 UTF8String M + SIP-User-Data-Contents 391 OctetString M + SIP-User-Data-Already-Available 392 Enumerated M + SIP-Method 393 UTF8String M + +;; =========================================================================== + +@messages + + ;; 8.1. User-Authorization-Request + + UAR ::= < Diameter Header: 283, REQ, PXY > + + < Session-Id > + { Auth-Application-Id } + { Auth-Session-State } + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + { SIP-AOR } + [ Destination-Host ] + [ User-Name ] + [ SIP-Visited-Network-Id ] + [ SIP-User-Authorization-Type ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + ;; 8.2. User-Authorization-Answer + + UAA ::= < Diameter Header: 283, PXY > + + < Session-Id > + { Auth-Application-Id } + { Auth-Session-State } + { Result-Code } + { Origin-Host } + { Origin-Realm } + [ SIP-Server-URI ] + [ SIP-Server-Capabilities ] + [ Authorization-Lifetime ] + [ Auth-Grace-Period ] + [ Redirect-Host ] + [ Redirect-Host-Usage ] + [ Redirect-Max-Cache-Time ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + ;; 8.3. Server-Assignment-Request + + SAR ::= < Diameter Header: 284, REQ, PXY > + + < Session-Id > + { Auth-Application-Id } + { Auth-Session-State } + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + { SIP-Server-Assignment-Type } + { SIP-User-Data-Already-Available } + [ Destination-Host ] + [ User-Name ] + [ SIP-Server-URI ] + * [ SIP-Supported-User-Data-Type ] + * [ SIP-AOR ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + ;; 8.4. Server-Assignment-Answer + + SAA ::= < Diameter Header: 284, PXY > + + < Session-Id > + { Auth-Application-Id } + { Result-Code } + { Auth-Session-State } + { Origin-Host } + { Origin-Realm } + * [ SIP-User-Data ] + [ SIP-Accounting-Information ] + * [ SIP-Supported-User-Data-Type ] + [ User-Name ] + [ Auth-Grace-Period ] + [ Authorization-Lifetime ] + [ Redirect-Host ] + [ Redirect-Host-Usage ] + [ Redirect-Max-Cache-Time ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + ;; 8.5. Location-Info-Request + + LIR ::= < Diameter Header: 285, REQ, PXY > + + < Session-Id > + { Auth-Application-Id } + { Auth-Session-State } + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + { SIP-AOR } + [ Destination-Host ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + ;; 8.6. Location-Info-Answer + + LIA ::= < Diameter Header: 285, PXY > + + < Session-Id > + { Auth-Application-Id } + { Result-Code } + { Auth-Session-State } + { Origin-Host } + { Origin-Realm } + [ SIP-Server-URI ] + [ SIP-Server-Capabilities ] + [ Auth-Grace-Period ] + [ Authorization-Lifetime ] + [ Redirect-Host ] + [ Redirect-Host-Usage ] + [ Redirect-Max-Cache-Time ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + ;; 8.7. Multimedia-Auth-Request + + MAR ::= < Diameter Header: 286, REQ, PXY > + + < Session-Id > + { Auth-Application-Id } + { Auth-Session-State } + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + { SIP-AOR } + { SIP-Method } + [ Destination-Host ] + [ User-Name ] + [ SIP-Server-URI ] + [ SIP-Number-Auth-Items ] + [ SIP-Auth-Data-Item ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + ;; 8.8. Multimedia-Auth-Answer + + MAA ::= < Diameter Header: 286, PXY > + + < Session-Id > + { Auth-Application-Id } + { Result-Code } + { Auth-Session-State } + { Origin-Host } + { Origin-Realm } + [ User-Name ] + [ SIP-AOR ] + [ SIP-Number-Auth-Items ] + * [ SIP-Auth-Data-Item ] + [ Authorization-Lifetime ] + [ Auth-Grace-Period ] + [ Redirect-Host ] + [ Redirect-Host-Usage ] + [ Redirect-Max-Cache-Time ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + ;; 8.9. Registration-Termination-Request + + RTR ::= < Diameter Header: 287, REQ, PXY > + + < Session-Id > + { Auth-Application-Id } + { Auth-Session-State } + { Origin-Host } + { Origin-Realm } + { Destination-Host } + { SIP-Deregistration-Reason } + [ Destination-Realm ] + [ User-Name ] + * [ SIP-AOR ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + ;; 8.10. Registration-Termination-Answer + + RTA ::= < Diameter Header: 287, PXY > + + < Session-Id > + { Auth-Application-Id } + { Result-Code } + { Auth-Session-State } + { Origin-Host } + { Origin-Realm } + [ Authorization-Lifetime ] + [ Auth-Grace-Period ] + [ Redirect-Host ] + [ Redirect-Host-Usage ] + [ Redirect-Max-Cache-Time ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + ;; 8.11. Push-Profile-Request + + PPR ::= < Diameter Header: 288, REQ, PXY > + + < Session-Id > + { Auth-Application-Id } + { Auth-Session-State } + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + { User-Name } + * [ SIP-User-Data ] + [ SIP-Accounting-Information ] + [ Destination-Host ] + [ Authorization-Lifetime ] + [ Auth-Grace-Period ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + ;; 8.12. Push-Profile-Answer + + PPA ::= < Diameter Header: 288, PXY > + + < Session-Id > + { Auth-Application-Id } + { Result-Code } + { Auth-Session-State } + { Origin-Host } + { Origin-Realm } + [ Redirect-Host ] + [ Redirect-Host-Usage ] + [ Redirect-Max-Cache-Time ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + +;; =========================================================================== + +@grouped + + SIP-Accounting-Information ::= < AVP Header: 368 > + + * [ SIP-Accounting-Server-URI ] + * [ SIP-Credit-Control-Server-URI ] + * [ AVP] + + SIP-Server-Capabilities ::= < AVP Header: 372 > + + * [ SIP-Mandatory-Capability ] + * [ SIP-Optional-Capability ] + * [ SIP-Server-URI ] + * [ AVP ] + + SIP-Auth-Data-Item ::= < AVP Header: 376 > + + { SIP-Authentication-Scheme } + [ SIP-Item-Number ] + [ SIP-Authenticate ] + [ SIP-Authorization ] + [ SIP-Authentication-Info ] + * [ AVP ] + + SIP-Authenticate ::= < AVP Header: 379 > + + { Digest-Realm } + { Digest-Nonce } + [ Digest-Domain ] + [ Digest-Opaque ] + [ Digest-Stale ] + [ Digest-Algorithm ] + [ Digest-Qop ] + [ Digest-HA1] + * [ Digest-Auth-Param ] + * [ AVP ] + + SIP-Authorization ::= < AVP Header: 380 > + + { Digest-Username } + { Digest-Realm } + { Digest-Nonce } + { Digest-URI } + { Digest-Response } + [ Digest-Algorithm ] + [ Digest-CNonce ] + [ Digest-Opaque ] + [ Digest-Qop ] + [ Digest-Nonce-Count ] + [ Digest-Method] + [ Digest-Entity-Body-Hash ] + * [ Digest-Auth-Param ] + * [ AVP ] + + SIP-Authentication-Info ::= < AVP Header: 381 > + + [ Digest-Nextnonce ] + [ Digest-Qop ] + [ Digest-Response-Auth ] + [ Digest-CNonce ] + [ Digest-Nonce-Count ] + * [ AVP ] + + SIP-Deregistration-Reason ::= < AVP Header: 383 > + + { SIP-Reason-Code } + [ SIP-Reason-Info ] + * [ AVP ] + + SIP-User-Data ::= < AVP Header: 389 > + + { SIP-User-Data-Type } + { SIP-User-Data-Contents } + * [ AVP ] + +;; =========================================================================== + +@enum SIP-Server-Assignment-Type + + NO_ASSIGNMENT 0 + REGISTRATION 1 + RE_REGISTRATION 2 + UNREGISTERED_USER 3 + TIMEOUT_DEREGISTRATION 4 + USER_DEREGISTRATION 5 + TIMEOUT_DEREGISTRATION_STORE 6 + USER_DEREGISTRATION_STORE 7 + ADMINISTRATIVE_DEREGISTRATION 8 + AUTHENTICATION_FAILURE 9 + AUTHENTICATION_TIMEOUT 10 + DEREGISTRATION_TOO_MUCH_DATA 11 + +@enum SIP-Authentication-Scheme + + DIGEST 0 + +@enum SIP-Reason-Code + + PERMANENT_TERMINATION 0 + NEW_SIP_SERVER_ASSIGNED 1 + SIP_SERVER_CHANGE 2 + REMOVE_SIP_SERVER 3 + +@enum SIP-User-Authorization-Type + + REGISTRATION 0 + DEREGISTRATION 1 + REGISTRATION_AND_CAPABILITIES 2 + +@enum SIP-User-Data-Already-Available + + USER_DATA_NOT_AVAILABLE 0 + USER_DATA_ALREADY_AVAILABLE 1 + +;; =========================================================================== + +@define Result-Code + + ;; Success + + FIRST_REGISTRATION 2003 + SUBSEQUENT_REGISTRATION 2004 + UNREGISTERED_SERVICE 2005 + SUCCESS_SERVER_NAME_NOT_STORED 2006 + SERVER_SELECTION 2007 + SUCCESS_AUTH_SENT_SERVER_NOT_STORED 2008 + + ;; Transient Failures + + USER_NAME_REQUIRED 4013 + + ;; Permanent Failures + + USER_UNKNOWN 5032 + IDENTITIES_DONT_MATCH 5033 + IDENTITY_NOT_REGISTERED 5034 + ROAMING_NOT_ALLOWED 5035 + IDENTITY_ALREADY_REGISTERED 5036 + AUTH_SCHEME_NOT_SUPPORTED 5037 + IN_ASSIGNMENT_TYPE 5038 + TOO_MUCH_DATA 5039 + NOT_SUPPORTED_USER_DATA 5040 diff --git a/lib/diameter/src/Makefile b/lib/diameter/src/Makefile index 2ec016ecbc..dbfaa4e140 100644 --- a/lib/diameter/src/Makefile +++ b/lib/diameter/src/Makefile @@ -88,6 +88,9 @@ TARGET_FILES = \ # Subdirectories of src to release modules into. TARGET_DIRS = $(sort $(dir $(TARGET_MODULES))) +# Ditto for examples. +EXAMPLE_DIRS = $(sort $(dir $(EXAMPLES))) + APP_FILE = diameter.app APP_SRC = $(APP_FILE).src APP_TARGET = $(EBIN)/$(APP_FILE) @@ -169,6 +172,8 @@ info: @echo @$(call list,EXAMPLES) @echo + @$(call list,EXAMPLE_DIRS) + @echo @$(call list,BINS) @echo ======================================== @@ -189,23 +194,29 @@ endif # Can't $(INSTALL_DIR) more than one directory at a time on Solaris. release_spec: opt - for d in bin ebin examples include src/dict $(TARGET_DIRS:%/=src/%); do \ + for d in bin ebin include src/dict; do \ $(INSTALL_DIR) $(RELSYSDIR)/$$d; \ done $(INSTALL_SCRIPT) $(BINS:%=../bin/%) $(RELSYSDIR)/bin $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin - $(INSTALL_DATA) $(EXAMPLES:%=../examples/%) $(RELSYSDIR)/examples $(INSTALL_DATA) $(EXTERNAL_HRLS:%=../include/%) $(DICT_HRLS) \ $(RELSYSDIR)/include $(INSTALL_DATA) $(DICTS:%=dict/%.dia) $(RELSYSDIR)/src/dict $(MAKE) $(TARGET_DIRS:%/=release_src_%) + $(MAKE) $(EXAMPLE_DIRS:%/=release_examples_%) $(TARGET_DIRS:%/=release_src_%): release_src_%: + $(INSTALL_DIR) $(RELSYSDIR)/src/$* $(INSTALL_DATA) $(filter $*/%, $(TARGET_MODULES:%=%.erl) \ $(INTERNAL_HRLS)) \ $(filter $*/%, compiler/$(DICT_YRL).yrl) \ $(RELSYSDIR)/src/$* +$(EXAMPLE_DIRS:%/=release_examples_%): release_examples_%: + $(INSTALL_DIR) $(RELSYSDIR)/examples/$* + $(INSTALL_DATA) $(patsubst %, ../examples/%, $(filter $*/%, $(EXAMPLES))) \ + $(RELSYSDIR)/examples/$* + release_docs_spec: # ---------------------------------------------------- @@ -237,6 +248,7 @@ depend.mk: depend.sed $(MODULES:%=%.erl) Makefile .PHONY: app clean depend dict info release_subdir .PHONY: debug opt release_docs_spec release_spec .PHONY: $(TARGET_DIRS:%/=%) $(TARGET_DIRS:%/=release_src_%) +.PHONY: $(EXAMPLE_DIRS:%/=release_examples_%) # Keep intermediate files. .SECONDARY: $(DICT_ERLS) $(DICT_HRLS) gen/$(DICT_YRL:%=%.erl) diff --git a/lib/diameter/src/base/diameter_service.erl b/lib/diameter/src/base/diameter_service.erl index 0893956f97..3dfdcee2b2 100644 --- a/lib/diameter/src/base/diameter_service.erl +++ b/lib/diameter/src/base/diameter_service.erl @@ -629,10 +629,6 @@ insert(Tbl, Rec) -> ets:insert(Tbl, Rec), Rec. -monitor(Pid) -> - erlang:monitor(process, Pid), - Pid. - %% Using the process dictionary for the callback state was initially %% just a way to make what was horrendous trace (big state record and %% much else everywhere) somewhat more readable. There's not as much @@ -814,10 +810,10 @@ start(Ref, Type, Opts, #state{peerT = PeerT, service = Svc}) when Type == connect; Type == accept -> - Pid = monitor(s(Type, Ref, {ConnT, - Opts, - SvcName, - merge_service(Opts, Svc)})), + Pid = s(Type, Ref, {ConnT, + Opts, + SvcName, + merge_service(Opts, Svc)}), insert(PeerT, #peer{pid = Pid, type = Type, ref = Ref, @@ -830,7 +826,13 @@ start(Ref, Type, Opts, #state{peerT = PeerT, %% callbacks. s(Type, Ref, T) -> - diameter_watchdog:start({Type, Ref}, T). + case diameter_watchdog:start({Type, Ref}, T) of + {_MRef, Pid} -> + Pid; + Pid when is_pid(Pid) -> %% from old code + erlang:monitor(process, Pid), + Pid + end. %% merge_service/2 diff --git a/lib/diameter/src/base/diameter_watchdog.erl b/lib/diameter/src/base/diameter_watchdog.erl index 6dc53d9f31..fb22fd8275 100644 --- a/lib/diameter/src/base/diameter_watchdog.erl +++ b/lib/diameter/src/base/diameter_watchdog.erl @@ -59,10 +59,19 @@ message_data}). %% term passed into diameter_service with message %% start/2 +%% +%% Start a monitor before the watchdog is allowed to proceed to ensure +%% that a failed capabilities exchange produces the desired exit +%% reason. start({_,_} = Type, T) -> - {ok, Pid} = diameter_watchdog_sup:start_child({Type, self(), T}), - Pid. + Ref = make_ref(), + {ok, Pid} = diameter_watchdog_sup:start_child({Ref, {Type, self(), T}}), + try + {erlang:monitor(process, Pid), Pid} + after + Pid ! Ref + end. start_link(T) -> {ok, _} = proc_lib:start_link(?MODULE, @@ -80,14 +89,29 @@ init(T) -> proc_lib:init_ack({ok, self()}), gen_server:enter_loop(?MODULE, [], i(T)). -i({T, Pid, {ConnT, Opts, SvcName, #diameter_service{applications = Apps, - capabilities = Caps} - = Svc}}) -> - {M,S,U} = now(), - random:seed(M,S,U), +i({Ref, {_, Pid, _} = T}) -> + MRef = erlang:monitor(process, Pid), + receive + Ref -> + make_state(T); + {'DOWN', MRef, process, _, _} = D -> + exit({shutdown, D}) + end; + +i({_, Pid, _} = T) -> %% from old code + erlang:monitor(process, Pid), + make_state(T). + +make_state({T, Pid, {ConnT, + Opts, + SvcName, + #diameter_service{applications = Apps, + capabilities = Caps} + = Svc}}) -> + random:seed(now()), putr(restart, {T, Opts, Svc}), %% save seeing it in trace putr(dwr, dwr(Caps)), %% - #watchdog{parent = monitor(Pid), + #watchdog{parent = Pid, transport = monitor(diameter_peer_fsm:start(T, Opts, Svc)), tw = proplists:get_value(watchdog_timer, Opts, diff --git a/lib/diameter/src/compiler/diameter_dict_util.erl b/lib/diameter/src/compiler/diameter_dict_util.erl index e4cd29ab7f..36a6efa294 100644 --- a/lib/diameter/src/compiler/diameter_dict_util.erl +++ b/lib/diameter/src/compiler/diameter_dict_util.erl @@ -630,13 +630,28 @@ reset(K, Dict, Opts) -> opt({inherits = Key, "-"}, Dict) -> dict:erase(Key, Dict); + opt({inherits = Key, Mod}, Dict) -> - dict:append(Key, [0, {word, 0, Mod}], Dict); + case lists:splitwith(fun(C) -> C /= $/ end, Mod) of + {Mod, ""} -> + dict:append(Key, [0, {word, 0, Mod}], Dict); + {From, [$/|To]} -> + dict:store(Key, + [reinherit(From, To, M) || M <- find(Key, Dict)], + Dict) + end; + opt({Key, Val}, Dict) -> - dict:store(Key, [0, {word, 0, Val}], Dict); + dict:store(Key, [[0, {word, 0, Val}]], Dict); + opt(_, Dict) -> Dict. +reinherit(From, To, [L, {word, _, From} = T | Avps]) -> + [L, setelement(3, T, To) | Avps]; +reinherit(_, _, T) -> + T. + %% =========================================================================== %% pass1/1 %% diff --git a/lib/diameter/src/modules.mk b/lib/diameter/src/modules.mk index 11d354e57e..7a700a6d53 100644 --- a/lib/diameter/src/modules.mk +++ b/lib/diameter/src/modules.mk @@ -88,11 +88,17 @@ BINS = \ # Released files relative to ../examples. EXAMPLES = \ - GNUmakefile \ - peer.erl \ - client.erl \ - client_cb.erl \ - server.erl \ - server_cb.erl \ - relay.erl \ - relay_cb.erl + code/GNUmakefile \ + code/peer.erl \ + code/client.erl \ + code/client_cb.erl \ + code/server.erl \ + code/server_cb.erl \ + code/relay.erl \ + code/relay_cb.erl \ + dict/rfc4004_mip.dia \ + dict/rfc4005_nas.dia \ + dict/rfc4006_cc.dia \ + dict/rfc4072_eap.dia \ + dict/rfc4590_digest.dia \ + dict/rfc4740_sip.dia diff --git a/lib/diameter/test/Makefile b/lib/diameter/test/Makefile index 97d9069f4a..ab5b45ff3d 100644 --- a/lib/diameter/test/Makefile +++ b/lib/diameter/test/Makefile @@ -50,6 +50,8 @@ TARGET_FILES = $(MODULES:%=%.$(EMULATOR)) SUITE_MODULES = $(filter diameter_%_SUITE, $(MODULES)) SUITES = $(SUITE_MODULES:diameter_%_SUITE=%) +DATA_DIRS = $(sort $(dir $(DATA))) + # ---------------------------------------------------- # FLAGS # ---------------------------------------------------- @@ -121,12 +123,12 @@ help: # diameter_ct:run/1 itself can't tell (it seems). The absolute -pa is # because ct will change directories. $(SUITES): log opt - $(ERL) -noshell \ + $(ERL) -noinput \ -pa $(realpath ../ebin) \ -sname diameter_test_$@ \ -s diameter_ct run diameter_$@_SUITE \ -s init stop \ - | awk '1{rc=0} {print} / FAILED /{rc=1} END{exit rc}' + | awk '{print} / FAILED /{rc=1} END{exit rc}' rc=0 # Shorter in sed but requires a GNU extension (ie. Q). log: @@ -147,9 +149,7 @@ else include $(ERL_TOP)/make/otp_release_targets.mk endif -release_spec: - -release_docs_spec: +release_spec release_docs_spec: release_tests_spec: $(INSTALL_DIR) $(RELSYSDIR) @@ -157,12 +157,18 @@ release_tests_spec: $(COVER_SPEC_FILE) \ $(HRL_FILES) \ $(RELSYSDIR) + $(MAKE) $(DATA_DIRS:%/=release_data_%) $(MAKE) $(ERL_FILES:%=/%) +$(DATA_DIRS:%/=release_data_%): release_data_%: + $(INSTALL_DIR) $(RELSYSDIR)/$* + $(INSTALL_DATA) $(filter $*/%, $(DATA)) $(RELSYSDIR)/$* + force: .PHONY: release_spec release_docs_spec release_test_specs .PHONY: force +.PHONY: $(DATA_DIRS:%/=release_data_%) # Can't just make $(ERL_FILES:%=/%) phony since then implicit rule # searching is skipped. diff --git a/lib/diameter/test/diameter_capx_SUITE.erl b/lib/diameter/test/diameter_capx_SUITE.erl index e6b1558bf6..54a161d606 100644 --- a/lib/diameter/test/diameter_capx_SUITE.erl +++ b/lib/diameter/test/diameter_capx_SUITE.erl @@ -27,8 +27,6 @@ -export([suite/0, all/0, groups/0, - init_per_group/2, - end_per_group/2, init_per_testcase/2, end_per_testcase/2]). @@ -93,30 +91,26 @@ -define(cea, #diameter_base_CEA). -define(answer_message, #'diameter_base_answer-message'). +-define(fail(T), erlang:error({T, process_info(self(), messages)})). + +-define(TIMEOUT, 2000). + %% =========================================================================== suite() -> [{timetrap, {seconds, 10}}]. -all() -> - [start, start_services, add_listeners - | [{group, N} || {N, _, _} <- groups()]] - ++ [remove_listeners, stop_services, stop]. +all() -> [start, + start_services, + add_listeners, + {group, all}, + {group, all, [parallel]}, + remove_listeners, + stop_services, + stop]. groups() -> - Ts = testcases(), - [{grp(P), P, Ts} || P <- [[], [parallel]]]. - -grp([]) -> - sequential; -grp([parallel = P]) -> - P. - -init_per_group(_Name, Config) -> - Config. - -end_per_group(_, _) -> - ok. + [{all, [], lists:flatmap(fun tc/1, tc())}]. %% Generate a unique hostname for each testcase so that watchdogs %% don't prevent a connection from being brought up immediately. @@ -137,9 +131,6 @@ end_per_testcase(Name, Config) -> ok = diameter:remove_transport(?CLIENT, CRef). %% Testcases all come in two flavours, client and server. -testcases() -> - lists:flatmap(fun tc/1, tc()). - tc(Name) -> [?A([C,$_|?L(Name)]) || C <- "cs"]. @@ -270,8 +261,8 @@ s_client_reject(Config) -> ?packet{}}} = Info -> Info - after 2000 -> - fail({LRef, OH}) + after ?TIMEOUT -> + ?fail({LRef, OH}) end. c_client_reject(Config) -> @@ -307,12 +298,12 @@ server_closed(Config, F, RC) -> = Reason, {listen, _}}} -> Reason - after 2000 -> - fail({LRef, OH}) + after ?TIMEOUT -> + ?fail({LRef, OH}) end. %% server_reject/3 - + server_reject(Config, F, RC) -> true = diameter:subscribe(?SERVER), OH = host(Config), @@ -328,8 +319,8 @@ server_reject(Config, F, RC) -> = Reason, {listen, _}}} -> Reason - after 2000 -> - fail({LRef, OH}) + after ?TIMEOUT -> + ?fail({LRef, OH}) end. %% cliient_closed/4 @@ -345,13 +336,13 @@ client_closed(Config, Host, F, RC) -> %% client_recv/1 -client_recv(CRef) -> +client_recv(CRef) -> receive ?event{service = ?CLIENT, info = {closed, CRef, Reason, {connect, _}}} -> Reason - after 2000 -> - fail(CRef) + after ?TIMEOUT -> + ?fail(CRef) end. %% server_capx/3 @@ -373,9 +364,6 @@ client_capx(_, ?caps{origin_host = {[_,$_|"client_reject." ++ _], _}}) -> %% =========================================================================== -fail(T) -> - erlang:error({T, process_info(self(), messages)}). - host(Config) -> {_, H} = lists:keyfind(host, 1, Config), ?HOST(H). diff --git a/lib/diameter/test/diameter_codec_SUITE.erl b/lib/diameter/test/diameter_codec_SUITE.erl index 30c60be8e9..2e219bbb10 100644 --- a/lib/diameter/test/diameter_codec_SUITE.erl +++ b/lib/diameter/test/diameter_codec_SUITE.erl @@ -35,7 +35,8 @@ %% testcases -export([base/1, gen/1, - lib/1]). + lib/1, + unknown/1]). -include("diameter_ct.hrl"). @@ -47,7 +48,7 @@ suite() -> [{timetrap, {seconds, 10}}]. all() -> - [base, gen, lib]. + [base, gen, lib, unknown]. init_per_testcase(gen, Config) -> [{application, ?APP, App}] = diameter_util:consult(?APP, app), @@ -74,3 +75,26 @@ gen([{dicts, Ms} | _]) -> lib(_Config) -> diameter_codec_test:lib(). + +%% Have a separate AVP dictionary just to exercise more code. +unknown(Config) -> + Priv = proplists:get_value(priv_dir, Config), + Data = proplists:get_value(data_dir, Config), + ok = make(Data, "recv.dia"), + ok = make(Data, "avps.dia"), + {ok, _, _} = compile("diameter_test_avps.erl"), + ok = make(Data, "send.dia"), + {ok, _, _} = compile("diameter_test_send.erl"), + {ok, _, _} = compile("diameter_test_recv.erl"), + {ok, _, _} = compile(filename:join([Data, "diameter_test_unknown.erl"]), + [{i, Priv}]), + diameter_test_unknown:run(). + +make(Dir, File) -> + diameter_make:codec(filename:join([Dir, File])). + +compile(File) -> + compile(File, []). + +compile(File, Opts) -> + compile:file(File, [return | Opts]). diff --git a/lib/diameter/test/diameter_codec_SUITE_data/avps.dia b/lib/diameter/test/diameter_codec_SUITE_data/avps.dia new file mode 100644 index 0000000000..c9d80a37a9 --- /dev/null +++ b/lib/diameter/test/diameter_codec_SUITE_data/avps.dia @@ -0,0 +1,25 @@ +;; +;; %CopyrightBegin% +;; +;; Copyright Ericsson AB 2010-2011. All Rights Reserved. +;; +;; The contents of this file are subject to the Erlang Public License, +;; Version 1.1, (the "License"); you may not use this file except in +;; compliance with the License. You should have received a copy of the +;; Erlang Public License along with this software. If not, it can be +;; retrieved online at http://www.erlang.org/. +;; +;; Software distributed under the License is distributed on an "AS IS" +;; basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +;; the License for the specific language governing rights and limitations +;; under the License. +;; +;; %CopyrightEnd% +;; + +@name diameter_test_avps + +@avp_types + + XXX 111 Unsigned32 M + YYY 222 Unsigned32 - diff --git a/lib/diameter/test/diameter_codec_SUITE_data/diameter_test_unknown.erl b/lib/diameter/test/diameter_codec_SUITE_data/diameter_test_unknown.erl new file mode 100644 index 0000000000..bce3d78a37 --- /dev/null +++ b/lib/diameter/test/diameter_codec_SUITE_data/diameter_test_unknown.erl @@ -0,0 +1,76 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(diameter_test_unknown). + +-compile(export_all). + +%% +%% Test reception of unknown AVP's. +%% + +-include_lib("diameter/include/diameter.hrl"). +-include("diameter_test_send.hrl"). +-include("diameter_test_recv.hrl"). + +-define(HOST, "test.erlang.org"). +-define(REALM, "erlang.org"). + +%% Patterns to match decoded AVP's. +-define(MANDATORY_XXX, #diameter_avp{code = 111}). +-define(NOT_MANDATORY_YYY, #diameter_avp{code = 222}). + +%% Ensure that an unknown AVP with an M flag is regarded as an error +%% while one without an M flag is returned as 'AVP'. + +run() -> + H = #diameter_header{version = 1, + end_to_end_id = 1, + hop_by_hop_id = 1}, + Vs = [{'Origin-Host', ?HOST}, + {'Origin-Realm', ?REALM}, + {'XXX', [0]}, + {'YYY', [1]}], + Pkt = #diameter_packet{header = H, + msg = Vs}, + + [] = diameter_util:run([{?MODULE, [run, M, enc(M, Pkt)]} + || M <- ['AR','BR']]). + +enc(M, #diameter_packet{msg = Vs} = P) -> + diameter_codec:encode(diameter_test_send, + P#diameter_packet{msg = [M|Vs]}). + +run(M, Pkt) -> + dec(M, diameter_codec:decode(diameter_test_recv, Pkt)). +%% Note that the recv dictionary defines neither XXX nor YYY. + +dec('AR', #diameter_packet + {msg = #recv_AR{'Origin-Host' = ?HOST, + 'Origin-Realm' = ?REALM, + 'AVP' = [?NOT_MANDATORY_YYY]}, + errors = [{5001, ?MANDATORY_XXX}]}) -> + ok; + +dec('BR', #diameter_packet + {msg = #recv_BR{'Origin-Host' = ?HOST, + 'Origin-Realm' = ?REALM}, + errors = [{5008, ?NOT_MANDATORY_YYY}, + {5001, ?MANDATORY_XXX}]}) -> + ok. diff --git a/lib/diameter/test/diameter_codec_SUITE_data/recv.dia b/lib/diameter/test/diameter_codec_SUITE_data/recv.dia new file mode 100644 index 0000000000..15fec5a5dd --- /dev/null +++ b/lib/diameter/test/diameter_codec_SUITE_data/recv.dia @@ -0,0 +1,51 @@ +;; +;; %CopyrightBegin% +;; +;; Copyright Ericsson AB 2010-2011. All Rights Reserved. +;; +;; The contents of this file are subject to the Erlang Public License, +;; Version 1.1, (the "License"); you may not use this file except in +;; compliance with the License. You should have received a copy of the +;; Erlang Public License along with this software. If not, it can be +;; retrieved online at http://www.erlang.org/. +;; +;; Software distributed under the License is distributed on an "AS IS" +;; basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +;; the License for the specific language governing rights and limitations +;; under the License. +;; +;; %CopyrightEnd% +;; + +@id 17 +@name diameter_test_recv +@prefix recv + +@inherits diameter_gen_base_rfc3588 + + Origin-Host + Origin-Realm + Result-Code + +@messages + + AR ::= < Diameter Header: 123, REQ > + { Origin-Host } + { Origin-Realm } + * [ AVP ] + + AA ::= < Diameter Header: 123 > + { Result-Code } + { Origin-Host } + { Origin-Realm } + * [ AVP ] + + BR ::= < Diameter Header: 124, REQ > + { Origin-Host } + { Origin-Realm } + + BA ::= < Diameter Header: 124 > + { Result-Code } + { Origin-Host } + { Origin-Realm } + * [ AVP ] diff --git a/lib/diameter/test/diameter_codec_SUITE_data/send.dia b/lib/diameter/test/diameter_codec_SUITE_data/send.dia new file mode 100644 index 0000000000..1472f146ae --- /dev/null +++ b/lib/diameter/test/diameter_codec_SUITE_data/send.dia @@ -0,0 +1,56 @@ +;; +;; %CopyrightBegin% +;; +;; Copyright Ericsson AB 2010-2011. All Rights Reserved. +;; +;; The contents of this file are subject to the Erlang Public License, +;; Version 1.1, (the "License"); you may not use this file except in +;; compliance with the License. You should have received a copy of the +;; Erlang Public License along with this software. If not, it can be +;; retrieved online at http://www.erlang.org/. +;; +;; Software distributed under the License is distributed on an "AS IS" +;; basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +;; the License for the specific language governing rights and limitations +;; under the License. +;; +;; %CopyrightEnd% +;; + +@id 17 +@name diameter_test_send +@prefix send + +@inherits diameter_gen_base_rfc3588 + + Origin-Host + Origin-Realm + Result-Code + +@inherits diameter_test_avps + +@messages + + AR ::= < Diameter Header: 123, REQ > + { Origin-Host } + { Origin-Realm } + [ XXX ] + [ YYY ] + + AA ::= < Diameter Header: 123 > + { Result-Code } + { Origin-Host } + { Origin-Realm } + * [ AVP ] + + BR ::= < Diameter Header: 124, REQ > + { Origin-Host } + { Origin-Realm } + [ XXX ] + [ YYY ] + + BA ::= < Diameter Header: 124 > + { Result-Code } + { Origin-Host } + { Origin-Realm } + * [ AVP ] diff --git a/lib/diameter/test/diameter_compiler_SUITE.erl b/lib/diameter/test/diameter_compiler_SUITE.erl index 66d788f6ec..3b4c9706e0 100644 --- a/lib/diameter/test/diameter_compiler_SUITE.erl +++ b/lib/diameter/test/diameter_compiler_SUITE.erl @@ -29,9 +29,10 @@ end_per_suite/1]). %% testcases --export([format/1, format/2, - replace/1, replace/2, - generate/1, generate/4, generate/0]). +-export([format/1, format/2, + replace/1, replace/2, + generate/1, generate/4, generate/0, + examples/1, examples/0]). -export([dict/0]). %% fake dictionary module @@ -327,6 +328,14 @@ "@codecs mymod " "Origin-Host Origin-Realm\n&"}]}]). +%% Standard dictionaries in examples/dict. +-define(EXAMPLES, [rfc4004_mip, + rfc4005_nas, + rfc4006_cc, + rfc4072_eap, + rfc4590_digest, + rfc4740_sip]). + %% =========================================================================== suite() -> @@ -335,7 +344,8 @@ suite() -> all() -> [format, replace, - generate]. + generate, + examples]. %% Error handling testcases will make an erroneous dictionary out of %% the base dictionary and check that the expected error results. @@ -349,8 +359,6 @@ end_per_suite(_Config) -> ok. %% =========================================================================== -%% testcases - %% format/1 %% %% Ensure that parse o format is the identity map. @@ -367,6 +375,7 @@ format(Mods, Bin) -> {ok, D} = diameter_dict_util:parse(diameter_dict_util:format(Dict), []), {Dict, Dict} = {Dict, D}. +%% =========================================================================== %% replace/1 %% %% Ensure the expected success/error when parsing a morphed common @@ -393,12 +402,13 @@ replace({E, Mods}, Bin) -> re({RE, Repl}, Bin) -> re:replace(Bin, RE, Repl, [multiline]). +%% =========================================================================== %% generate/1 %% %% Ensure success when generating code and compiling. generate() -> - [{timetrap, {seconds, length(?REPLACE)}}]. + [{timetrap, {seconds, 2*length(?REPLACE)}}]. generate(Config) -> Bin = proplists:get_value(base, Config), @@ -422,6 +432,44 @@ generate(Mods, Bin, N, Mode) -> andalso ({ok, _} = compile:file(File ++ ".erl", [return_errors])). %% =========================================================================== +%% examples/1 +%% +%% Compile dictionaries extracted from various standards. + +examples() -> + [{timetrap, {seconds, 3*length(?EXAMPLES)}}]. + +examples(_Config) -> + Dir = filename:join([code:lib_dir(diameter, examples), "dict"]), + [D || D <- ?EXAMPLES, _ <- [examples(?S(D), Dir)]]. + +examples(Dict, Dir) -> + {Name, Pre} = make_name(Dict), + ok = diameter_make:codec(filename:join([Dir, Dict ++ ".dia"]), + [{name, Name}, + {prefix, Pre}, + inherits("rfc3588_base") + | opts(Dict)]), + {ok, _, _} = compile:file(Name ++ ".erl", [return]). + +opts(M) + when M == "rfc4006_cc"; + M == "rfc4072_eap" -> + [inherits("rfc4005_nas")]; +opts("rfc4740_sip") -> + [inherits("rfc4590_digest")]; +opts(_) -> + []. + +inherits(File) -> + {Name, _} = make_name(File), + {inherits, File ++ "/" ++ Name}. + +make_name(File) -> + {R, [$_|N]} = lists:splitwith(fun(C) -> C /= $_ end, File), + {string:join(["diameter_gen", N, R], "_"), "diameter_" ++ N}. + +%% =========================================================================== modify(Bin, Mods) -> lists:foldl(fun re/2, Bin, Mods). diff --git a/lib/diameter/test/diameter_dict_SUITE.erl b/lib/diameter/test/diameter_dict_SUITE.erl index 87bb9727fe..5cf8506d3f 100644 --- a/lib/diameter/test/diameter_dict_SUITE.erl +++ b/lib/diameter/test/diameter_dict_SUITE.erl @@ -25,9 +25,7 @@ -export([suite/0, all/0, - groups/0, - init_per_group/2, - end_per_group/2]). + groups/0]). %% testcases -export([append/1, @@ -53,10 +51,11 @@ suite() -> [{timetrap, {seconds, 10}}]. all() -> - [{group, all} | tc()]. + [{group, all}, + {group, all, [parallel]}]. groups() -> - [{all, [parallel], tc()}]. + [{all, [], tc()}]. tc() -> [append, @@ -71,12 +70,6 @@ tc() -> update, update_counter]. -init_per_group(_, Config) -> - Config. - -end_per_group(_, _) -> - ok. - %% =========================================================================== -define(KV100, [{N,[N]} || N <- lists:seq(1,100)]). diff --git a/lib/diameter/test/diameter_failover_SUITE.erl b/lib/diameter/test/diameter_failover_SUITE.erl index 429b6328e6..53398dd93e 100644 --- a/lib/diameter/test/diameter_failover_SUITE.erl +++ b/lib/diameter/test/diameter_failover_SUITE.erl @@ -174,7 +174,7 @@ realm(Host) -> call(Req, Opts) -> diameter:call(?CLIENT, ?APP_ALIAS, Req, Opts). - + set([H|T], Vs) -> [H | Vs ++ T]. diff --git a/lib/diameter/test/diameter_gen_sctp_SUITE.erl b/lib/diameter/test/diameter_gen_sctp_SUITE.erl new file mode 100644 index 0000000000..7f435a6b7a --- /dev/null +++ b/lib/diameter/test/diameter_gen_sctp_SUITE.erl @@ -0,0 +1,354 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% Some gen_sctp-specific tests demonstrating problems that were +%% encountered during diameter development but have nothing +%% specifically to do with diameter. At least one of them can cause +%% diameter_transport_SUITE testcases to fail. +%% + +-module(diameter_gen_sctp_SUITE). + +-export([suite/0, + all/0, + init_per_suite/1, + end_per_suite/1]). + +%% testcases +-export([send_not_from_controlling_process/1, + send_from_multiple_clients/1, + receive_what_was_sent/1]). + +-include_lib("kernel/include/inet_sctp.hrl"). + +%% Message from gen_sctp are of this form. +-define(SCTP(Sock, Data), {sctp, Sock, _, _, Data}). + +%% Open sockets on the loopback address. +-define(ADDR, {127,0,0,1}). + +%% Snooze, nap, siesta. +-define(SLEEP(T), receive after T -> ok end). + +%% An indescribably long number of milliseconds after which everthing +%% that should have happened has. +-define(FOREVER, 2000). + +%% The first byte in each message we send as a simple guard against +%% not receiving what was sent. +-define(MAGIC, 42). + +%% =========================================================================== + +suite() -> + [{timetrap, {minutes, 2}}]. + +all() -> + [send_not_from_controlling_process, + send_from_multiple_clients, + receive_what_was_sent]. + +init_per_suite(Config) -> + case gen_sctp:open() of + {ok, Sock} -> + gen_sctp:close(Sock), + Config; + {error, E} when E == eprotonosupport; + E == esocktnosupport -> + {skip, no_sctp} + end. + +end_per_suite(_Config) -> + ok. + +%% =========================================================================== + +%% send_not_from_controlling_process/1 +%% +%% This testcase failing shows gen_sctp:send/4 hanging when called +%% outside the controlling process of the socket in question. + +send_not_from_controlling_process(_) -> + Pids = send_not_from_controlling_process(), + ?SLEEP(?FOREVER), + try + [] = [{P,I} || P <- Pids, I <- [process_info(P)], I /= undefined] + after + lists:foreach(fun(P) -> exit(P, kill) end, Pids) + end. + +%% send_not_from_controlling_process/0 +%% +%% Returns the pids of three spawned processes: a listening process, a +%% connecting process and a sending process. +%% +%% The expected behaviour is that all three processes exit: +%% +%% - The listening process exits upon receiving an SCTP message +%% sent by the sending process. +%% - The connecting process exits upon listening process exit. +%% - The sending process exits upon gen_sctp:send/4 return. +%% +%% The observed behaviour is that all three processes remain alive +%% indefinitely: +%% +%% - The listening process never receives the SCTP message sent +%% by the sending process. +%% - The connecting process has an inet_reply message in its mailbox +%% as a consequence of the call to gen_sctp:send/4 call from the +%% sending process. +%% - The call to gen_sctp:send/4 in the sending process doesn't return, +%% hanging in prim_inet:getopts/2. + +send_not_from_controlling_process() -> + FPid = self(), + {L, MRef} = spawn_monitor(fun() -> listen(FPid) end),%% listening process + receive + {?MODULE, C, S} -> + erlang:demonitor(MRef, [flush]), + [L,C,S]; + {'DOWN', MRef, process, _, _} = T -> + error(T) + end. + +%% listen/1 + +listen(FPid) -> + {ok, Sock} = open(), + ok = gen_sctp:listen(Sock, true), + {ok, PortNr} = inet:port(Sock), + LPid = self(), + spawn(fun() -> connect1(PortNr, FPid, LPid) end), %% connecting process + Id = assoc(Sock), + ?SCTP(Sock, {[#sctp_sndrcvinfo{assoc_id = Id}], _Bin}) + = recv(). %% Waits with this as current_function. + +%% recv/0 + +recv() -> + receive T -> T end. + +%% connect1/3 + +connect1(PortNr, FPid, LPid) -> + {ok, Sock} = open(), + ok = gen_sctp:connect_init(Sock, ?ADDR, PortNr, []), + Id = assoc(Sock), + FPid ! {?MODULE, + self(), + spawn(fun() -> send(Sock, Id) end)}, %% sending process + MRef = erlang:monitor(process, LPid), + down(MRef). %% Waits with this as current_function. + +%% down/1 + +down(MRef) -> + receive {'DOWN', MRef, process, _, Reason} -> Reason end. + +%% send/2 + +send(Sock, Id) -> + ok = gen_sctp:send(Sock, Id, 0, <<0:32>>). + +%% =========================================================================== + +%% send_from_multiple_clients/0 +%% +%% Demonstrates sluggish delivery of messages. + +send_from_multiple_clients(_) -> + {S, Rs} = T = send_from_multiple_clients(8, 1024), + {false, [], _} = {?FOREVER < S, + Rs -- [OI || {O,_} = OI <- Rs, is_integer(O)], + T}. + +%% send_from_multiple_clients/2 +%% +%% Opens a listening socket and then spawns a specified number of +%% processes, each of which connects to the listening socket. Each +%% connecting process then sends a message, whose size in bytes is +%% passed as an argument, the listening process sends a reply +%% containing the time at which the message was received, and the +%% connecting process then exits upon reception of this reply. +%% +%% Returns the elapsed time for all connecting process to exit +%% together with a list of exit reasons for the connecting processes. +%% In the successful case a connecting process exits with the +%% outbound/inbound transit times for the sent/received message as +%% reason. +%% +%% The observed behaviour is that some outbound messages (that is, +%% from a connecting process to the listening process) can take an +%% unexpectedly long time to complete their journey. The more +%% connecting processes, the longer the possible delay it seems. +%% +%% eg. (With F = fun send_from_multiple_clients/2.) +%% +%% 5> F(2, 1024). +%% {875,[{128,116},{113,139}]} +%% 6> F(4, 1024). +%% {2995290,[{2994022,250},{2994071,80},{200,130},{211,113}]} +%% 7> F(8, 1024). +%% {8997461,[{8996161,116}, +%% {2996471,86}, +%% {2996278,116}, +%% {2996360,95}, +%% {246,112}, +%% {213,159}, +%% {373,173}, +%% {376,118}]} +%% 8> F(8, 1024). +%% {21001891,[{20999968,128}, +%% {8997891,172}, +%% {8997927,91}, +%% {2995716,164}, +%% {2995860,87}, +%% {134,100}, +%% {117,98}, +%% {149,125}]} + +send_from_multiple_clients(N, Sz) + when is_integer(N), 0 < N, is_integer(Sz), 0 < Sz -> + timer:tc(fun listen/2, [N, <<?MAGIC, 0:Sz/unit:8>>]). + +%% listen/2 + +listen(N, Bin) -> + {ok, Sock} = open(), + ok = gen_sctp:listen(Sock, true), + {ok, PortNr} = inet:port(Sock), + + %% Spawn a middleman that in turn spawns N connecting processes, + %% collects a list of exit reasons and then exits with the list as + %% reason. loop/3 returns when we receive this list from the + %% middleman's 'DOWN'. + + Self = self(), + Fun = fun() -> exit(connect2(Self, PortNr, Bin)) end, + {_, MRef} = spawn_monitor(fun() -> exit(fold(N, Fun)) end), + loop(Sock, MRef, Bin). + +%% fold/2 +%% +%% Spawn N processes and collect their exit reasons in a list. + +fold(N, Fun) -> + start(N, Fun), + acc(N, []). + +start(0, _) -> + ok; +start(N, Fun) -> + spawn_monitor(Fun), + start(N-1, Fun). + +acc(0, Acc) -> + Acc; +acc(N, Acc) -> + receive + {'DOWN', _MRef, process, _, RC} -> + acc(N-1, [RC | Acc]) + end. + +%% loop/3 + +loop(Sock, MRef, Bin) -> + receive + ?SCTP(Sock, {[#sctp_sndrcvinfo{assoc_id = Id}], B}) -> + Sz = size(Bin), + {Sz, Bin} = {size(B), B}, %% assert + ok = send(Sock, Id, mark(Bin)), + loop(Sock, MRef, Bin); + ?SCTP(Sock, _) -> + loop(Sock, MRef, Bin); + {'DOWN', MRef, process, _, Reason} -> + Reason + end. + +%% connect2/3 + +connect2(Pid, PortNr, Bin) -> + erlang:monitor(process, Pid), + + {ok, Sock} = open(), + ok = gen_sctp:connect_init(Sock, ?ADDR, PortNr, []), + Id = assoc(Sock), + + %% T1 = time before send + %% T2 = time after listening process received our message + %% T3 = time after reply is received + + T1 = now(), + ok = send(Sock, Id, Bin), + T2 = unmark(recv(Sock, Id)), + T3 = now(), + {timer:now_diff(T2, T1), timer:now_diff(T3, T2)}. %% {Outbound, Inbound} + +%% recv/2 + +recv(Sock, Id) -> + receive + ?SCTP(Sock, {[#sctp_sndrcvinfo{assoc_id = Id}], Bin}) -> + Bin; + T -> %% eg. 'DOWN' + exit(T) + end. + +%% send/3 + +send(Sock, Id, Bin) -> + gen_sctp:send(Sock, Id, 0, Bin). + +%% mark/1 + +mark(Bin) -> + Info = term_to_binary(now()), + <<Info/binary, Bin/binary>>. + +%% unmark/1 + +unmark(Bin) -> + {_,_,_} = binary_to_term(Bin). + +%% =========================================================================== + +%% receive_what_was_sent/1 +%% +%% Demonstrates reception of a message that differs from that sent. + +receive_what_was_sent(_Config) -> + send_from_multiple_clients(1, 1024*32). %% fails + +%% =========================================================================== + +%% open/0 + +open() -> + gen_sctp:open([{ip, ?ADDR}, {port, 0}, {active, true}, binary]). + +%% assoc/1 + +assoc(Sock) -> + receive + ?SCTP(Sock, {[], #sctp_assoc_change{state = S, + assoc_id = Id}}) -> + comm_up = S, %% assert + Id + end. diff --git a/lib/diameter/test/diameter_reg_SUITE.erl b/lib/diameter/test/diameter_reg_SUITE.erl index ade824c9dd..ec6a0ca731 100644 --- a/lib/diameter/test/diameter_reg_SUITE.erl +++ b/lib/diameter/test/diameter_reg_SUITE.erl @@ -26,8 +26,6 @@ -export([suite/0, all/0, groups/0, - init_per_group/2, - end_per_group/2, init_per_suite/1, end_per_suite/1]). @@ -48,10 +46,11 @@ suite() -> [{timetrap, {seconds, 10}}]. all() -> - [{group, all} | tc()]. + [{group, all}, + {group, all, [parallel]}]. groups() -> - [{all, [parallel], tc()}]. + [{all, [], tc()}]. tc() -> [add, @@ -61,12 +60,6 @@ tc() -> terms, pids]. -init_per_group(_, Config) -> - Config. - -end_per_group(_, _) -> - ok. - init_per_suite(Config) -> ok = diameter:start(), Config. diff --git a/lib/diameter/test/diameter_relay_SUITE.erl b/lib/diameter/test/diameter_relay_SUITE.erl index c0351f8cf2..70e1866791 100644 --- a/lib/diameter/test/diameter_relay_SUITE.erl +++ b/lib/diameter/test/diameter_relay_SUITE.erl @@ -35,9 +35,7 @@ -export([suite/0, all/0, - groups/0, - init_per_group/2, - end_per_group/2]). + groups/0]). %% testcases -export([start/1, @@ -117,21 +115,17 @@ suite() -> [{timetrap, {seconds, 10}}]. all() -> - [start, start_services, connect] - ++ tc() - ++ [{group, all}, - disconnect, - stop_services, - stop]. + [start, + start_services, + connect, + {group, all}, + {group, all, [parallel]}, + disconnect, + stop_services, + stop]. groups() -> - [{all, [parallel], tc()}]. - -init_per_group(_, Config) -> - Config. - -end_per_group(_, _) -> - ok. + [{all, [], tc()}]. %% Traffic cases run when services are started and connections %% established. @@ -248,7 +242,7 @@ call(Server) -> call(Req, Opts) -> diameter:call(?CLIENT, ?APP_ALIAS, Req, Opts). - + set([H|T], Vs) -> [H | Vs ++ T]. diff --git a/lib/diameter/test/diameter_stats_SUITE.erl b/lib/diameter/test/diameter_stats_SUITE.erl index e50a0050a6..e7807fd360 100644 --- a/lib/diameter/test/diameter_stats_SUITE.erl +++ b/lib/diameter/test/diameter_stats_SUITE.erl @@ -26,8 +26,6 @@ -export([suite/0, all/0, groups/0, - init_per_group/2, - end_per_group/2, init_per_suite/1, end_per_suite/1]). @@ -44,21 +42,16 @@ suite() -> [{timetrap, {seconds, 10}}]. all() -> - [{group, all} | tc()]. + [{group, all}, + {group, all, [parallel]}]. groups() -> - [{all, [parallel], tc()}]. + [{all, [], tc()}]. tc() -> [an, twa]. -init_per_group(_, Config) -> - Config. - -end_per_group(_, _) -> - ok. - init_per_suite(Config) -> ok = diameter:start(), Config. diff --git a/lib/diameter/test/diameter_sync_SUITE.erl b/lib/diameter/test/diameter_sync_SUITE.erl index 84f77b6066..ab629fb1c1 100644 --- a/lib/diameter/test/diameter_sync_SUITE.erl +++ b/lib/diameter/test/diameter_sync_SUITE.erl @@ -26,8 +26,6 @@ -export([suite/0, all/0, groups/0, - init_per_group/2, - end_per_group/2, init_per_suite/1, end_per_suite/1]). @@ -48,10 +46,11 @@ suite() -> [{timetrap, {seconds, 10}}]. all() -> - [{group, all} | tc()]. + [{group, all}, + {group, all, [parallel]}]. groups() -> - [{all, [parallel], tc()}]. + [{all, [], tc()}]. tc() -> [call, @@ -59,12 +58,6 @@ tc() -> timeout, flush]. -init_per_group(_, Config) -> - Config. - -end_per_group(_, _) -> - ok. - init_per_suite(Config) -> ok = diameter:start(), Config. diff --git a/lib/diameter/test/diameter_tls_SUITE.erl b/lib/diameter/test/diameter_tls_SUITE.erl index 38282282b8..85b953dc1a 100644 --- a/lib/diameter/test/diameter_tls_SUITE.erl +++ b/lib/diameter/test/diameter_tls_SUITE.erl @@ -36,8 +36,6 @@ -export([suite/0, all/0, groups/0, - init_per_group/2, - end_per_group/2, init_per_suite/1, end_per_suite/1]). @@ -136,20 +134,16 @@ all() -> start_diameter, make_certs, start_services, - add_transports] - ++ [{group, N} || {N, _, _} <- groups()] - ++ [remove_transports, stop_services, stop_diameter, stop_ssl]. + add_transports, + {group, all}, + {group, all, [parallel]}, + remove_transports, + stop_services, + stop_diameter, + stop_ssl]. groups() -> - Ts = tc(), - [{all, [], Ts}, - {p, [parallel], Ts}]. - -init_per_group(_, Config) -> - Config. - -end_per_group(_, _) -> - ok. + [{all, [], tc()}]. %% Shouldn't really have to know about crypto here but 'ok' from %% ssl:start() isn't enough to guarantee that TLS is available. diff --git a/lib/diameter/test/diameter_traffic_SUITE.erl b/lib/diameter/test/diameter_traffic_SUITE.erl index 78131b4ec4..6eed8d3b5d 100644 --- a/lib/diameter/test/diameter_traffic_SUITE.erl +++ b/lib/diameter/test/diameter_traffic_SUITE.erl @@ -162,27 +162,16 @@ suite() -> [{timetrap, {seconds, 10}}]. all() -> - [start, start_services, add_transports, result_codes - | [{group, N} || {N, _, _} <- groups()]] + [start, start_services, add_transports, result_codes] + ++ [{group, E, P} || E <- ?ENCODINGS, P <- [[], [parallel]]] ++ [remove_transports, stop_services, stop]. groups() -> Ts = tc(), - [{grp(E,P), P, Ts} || E <- ?ENCODINGS, P <- [[], [parallel]]]. - -grp(E, []) -> - E; -grp(E, [parallel]) -> - ?P(E). + [{E, [], Ts} || E <- ?ENCODINGS]. init_per_group(Name, Config) -> - E = case ?L(Name) of - "p_" ++ Rest -> - ?A(Rest); - _ -> - Name - end, - [{encode, E} | Config]. + [{encode, Name} | Config]. end_per_group(_, _) -> ok. @@ -516,10 +505,10 @@ send_multiple_filters(Config, Fs) -> %% Ensure that we can pass a request in any form to diameter:call/4, %% only the return value from the prepare_request callback being %% significant. -send_anything(Config) -> +send_anything(Config) -> #diameter_base_STA{'Result-Code' = ?SUCCESS} = call(Config, anything). - + %% =========================================================================== call(Config, Req) -> diff --git a/lib/diameter/test/diameter_transport_SUITE.erl b/lib/diameter/test/diameter_transport_SUITE.erl index df7161fd1e..893b7ba2f9 100644 --- a/lib/diameter/test/diameter_transport_SUITE.erl +++ b/lib/diameter/test/diameter_transport_SUITE.erl @@ -27,8 +27,6 @@ -export([suite/0, all/0, groups/0, - init_per_group/2, - end_per_group/2, init_per_suite/1, end_per_suite/1]). @@ -92,10 +90,13 @@ suite() -> [{timetrap, {minutes, 2}}]. all() -> - [start | tc()] ++ [{group, all}, stop]. + [start, + {group, all}, + {group, all, [parallel]}, + stop]. groups() -> - [{all, [parallel], tc()}]. + [{all, [], tc()}]. tc() -> [tcp_accept, @@ -103,12 +104,6 @@ tc() -> sctp_accept, sctp_connect]. -init_per_group(_, Config) -> - Config. - -end_per_group(_, _) -> - ok. - init_per_suite(Config) -> [{sctp, have_sctp()} | Config]. @@ -175,16 +170,13 @@ connect(Prot) -> %% have_sctp/0 have_sctp() -> - try gen_sctp:open() of + case gen_sctp:open() of {ok, Sock} -> gen_sctp:close(Sock), true; {error, E} when E == eprotonosupport; E == esocktnosupport -> %% fail on any other reason false - catch - error: badarg -> - false end. %% if_sctp/2 @@ -220,7 +212,7 @@ init(gen_connect, {Prot, Ref}) -> [PortNr] = ?util:lport(Prot, Ref, 20), %% Connect, send a message and receive it back. - {ok, Sock} = gen_connect(Prot, PortNr, Ref), + {ok, Sock} = gen_connect(Prot, PortNr), Bin = make_msg(), ok = gen_send(Prot, Sock, Bin), Bin = gen_recv(Prot, Sock); @@ -359,20 +351,7 @@ tmod(tcp) -> %% =========================================================================== -%% gen_connect/3 - -gen_connect(Prot, PortNr, Ref) -> - Pid = sync(connect, Ref), - - %% Stagger connect attempts to avoid the situation that no - %% transport process is accepting yet. - receive after 250 -> ok end, - - try - gen_connect(Prot, PortNr) - after - Pid ! Ref - end. +%% gen_connect/2 gen_connect(sctp = P, PortNr) -> {ok, Sock} = Ok = gen_sctp:open([{ip, ?ADDR}, {port, 0} | ?SCTP_OPTS]), diff --git a/lib/diameter/test/diameter_util.erl b/lib/diameter/test/diameter_util.erl index 6b1dc1f0c9..0c42f955ad 100644 --- a/lib/diameter/test/diameter_util.erl +++ b/lib/diameter/test/diameter_util.erl @@ -212,7 +212,7 @@ read_priv(Config, Name) -> read(Path) -> {ok, Bin} = file:read_file(Path), binary_to_term(Bin). - + %% map_priv/3 %% %% Modify a term in a file and return both old and new values. diff --git a/lib/diameter/test/diameter_watchdog_SUITE.erl b/lib/diameter/test/diameter_watchdog_SUITE.erl index b40d7c104d..ff40326947 100644 --- a/lib/diameter/test/diameter_watchdog_SUITE.erl +++ b/lib/diameter/test/diameter_watchdog_SUITE.erl @@ -306,11 +306,8 @@ watchdog(Type, Ref, TPid, Wd) -> Opts = [{transport_module, ?MODULE}, {transport_config, TPid}, {watchdog_timer, Wd}], - monitor(diameter_watchdog:start({Type, Ref}, - {false, Opts, false, ?SERVICE})). - -monitor(Pid) -> - erlang:monitor(process, Pid), + {_MRef, Pid} = diameter_watchdog:start({Type, Ref}, + {false, Opts, false, ?SERVICE}), Pid. %% =========================================================================== @@ -350,6 +347,10 @@ init(_, _, TPid, _) -> monitor(TPid), 3. +monitor(Pid) -> + erlang:monitor(process, Pid), + Pid. + %% Generate a unique hostname for the faked peer. hostname() -> lists:flatten(io_lib:format("~p-~p-~p", tuple_to_list(now()))). diff --git a/lib/diameter/test/modules.mk b/lib/diameter/test/modules.mk index 54978d820c..7f163536fb 100644 --- a/lib/diameter/test/modules.mk +++ b/lib/diameter/test/modules.mk @@ -33,6 +33,7 @@ MODULES = \ diameter_sync_SUITE \ diameter_stats_SUITE \ diameter_watchdog_SUITE \ + diameter_gen_sctp_SUITE \ diameter_transport_SUITE \ diameter_capx_SUITE \ diameter_traffic_SUITE \ @@ -42,3 +43,9 @@ MODULES = \ HRL_FILES = \ diameter_ct.hrl + +DATA = \ + diameter_codec_SUITE_data/avps.dia \ + diameter_codec_SUITE_data/send.dia \ + diameter_codec_SUITE_data/recv.dia \ + diameter_codec_SUITE_data/diameter_test_unknown.erl diff --git a/lib/erl_docgen/priv/xsl/db_html.xsl b/lib/erl_docgen/priv/xsl/db_html.xsl index bdef7bfd3d..4f6c758e7b 100644 --- a/lib/erl_docgen/priv/xsl/db_html.xsl +++ b/lib/erl_docgen/priv/xsl/db_html.xsl @@ -3,7 +3,7 @@ # # %CopyrightBegin% # - # Copyright Ericsson AB 2009-2011. All Rights Reserved. + # Copyright Ericsson AB 2009-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 @@ -40,6 +40,11 @@ <xsl:variable name="m2a" select="document($mod2app_file)"></xsl:variable> <xsl:key name="mod2app" match="module" use="@name"/> + <xsl:key + name="mfa" + match="func/name[string-length(@arity) > 0 and ancestor::erlref]" + use="concat(ancestor::erlref/module,':',@name, '/', @arity)"/> + <xsl:template name="err"> <xsl:param name="f"/> <xsl:param name="m"/> @@ -101,10 +106,14 @@ </xsl:message> </xsl:when> <xsl:when test="ancestor::erlref"> + <!-- Do not to use preceding since it is very slow! --> + <xsl:variable name="curModule" select="ancestor::erlref/module"/> + <xsl:variable name="mfas" + select="key('mfa', + concat($curModule,':',$name,'/',$arity))"/> <xsl:choose> - <xsl:when test="preceding-sibling::name[position() = 1 - and @name = $name and @arity = $arity]"> - <!-- Avoid duplicated anchors.--> + <xsl:when test="generate-id($mfas[1]) != generate-id(.)"> + <!-- Avoid duplicated anchors. See also menu.funcs. --> </xsl:when> <xsl:otherwise> <a name="{$name}-{$arity}"></a> @@ -1319,6 +1328,7 @@ <xsl:with-param name="entries" select="funcs/func/name"/> <xsl:with-param name="basename"><xsl:value-of select="$link_cval"/></xsl:with-param> + <xsl:with-param name="cval" select="$cval"/> </xsl:call-template> </ul> </li> @@ -1349,6 +1359,7 @@ <xsl:template name="menu.funcs"> <xsl:param name="entries"/> <xsl:param name="basename"/> + <xsl:param name="cval"/> <xsl:for-each select="$entries"> @@ -1434,9 +1445,14 @@ </xsl:choose> </xsl:variable> + <!-- Avoid duplicated entries. See also template "spec_name" --> + <!-- Do not to use preceding since it is very slow! --> + <xsl:variable name="mfas" + select="key('mfa', + concat($cval,':',$fname,'/',$arity))"/> <xsl:choose> - <xsl:when test="preceding-sibling::name[position() = 1 - and @name = $fname and @arity = $arity]"> + <xsl:when test="string-length(@name) > 0 and + generate-id($mfas[1]) != generate-id(.)"> <!-- Skip. Only works for Dialyzer specs. --> </xsl:when> <xsl:otherwise> @@ -1854,18 +1870,24 @@ <xsl:choose> <xsl:when test="string-length($filepart) > 0"> - <xsl:variable name="modulepart"><xsl:value-of select="substring-before($filepart, ':')"/></xsl:variable> + <!-- "Filepart#Linkpart" (or "Filepart#") --> + <xsl:variable name="app_part"><xsl:value-of select="substring-before($filepart, ':')"/></xsl:variable> <xsl:choose> - <xsl:when test="string-length($modulepart) > 0"> - <xsl:variable name="filepart1"><xsl:value-of select="substring-after($filepart, ':')"/></xsl:variable> - <span class="bold_code"><a href="javascript:erlhref('{$topdocdir}/../','{$modulepart}','{$filepart1}.html#{$linkpart}');"><xsl:apply-templates/></a></span> + <xsl:when test="string-length($app_part) > 0"> + <!-- "AppPart:ModPart#Linkpart" --> + <xsl:variable name="mod_part"><xsl:value-of select="substring-after($filepart, ':')"/></xsl:variable> + <span class="bold_code"><a href="javascript:erlhref('{$topdocdir}/../','{$app_part}','{$mod_part}.html#{$linkpart}');"><xsl:apply-templates/></a></span> </xsl:when> <xsl:otherwise> + <!-- "Filepart#Linkpart (there is no ':' in Filepart) --> + <xsl:variable name="minus_prefix" + select="substring-before($linkpart, '-')"/> <xsl:choose> - <!-- Dialyzer seealso (the application is unknown) --> - <xsl:when test="string-length($specs_file) > 0 + <xsl:when test="$minus_prefix = 'type' + and string-length($specs_file) > 0 and count($i/specs/module[@name=$filepart]) = 0"> - <!-- Deemed to slow; use key() instead + <!-- Dialyzer seealso (the application is unknown) --> + <!-- Following code deemed too slow; use key() instead <xsl:variable name="app" select="$m2a/mod2app/module[@name=$filepart]"/> --> @@ -1877,41 +1899,45 @@ <span class="bold_code"><a href="javascript:erlhref('{$topdocdir}/../','{$app}','{$filepart}.html#{$linkpart}');"><xsl:value-of select="$this"/></a></span> </xsl:when> <xsl:otherwise> - <!-- Unknown application; no link --> - <xsl:value-of select="$this"/> + <!-- Unknown application --> + <xsl:message terminate="yes"> + Error <xsl:value-of select="$filepart"/>: cannot find module exporting type + </xsl:message> </xsl:otherwise> </xsl:choose> </xsl:for-each> </xsl:when> <xsl:when test="string-length($linkpart) > 0"> + <!-- Still Filepart#Linkpart (there is no ':' in Filepart --> <span class="bold_code"><a href="{$filepart}.html#{$linkpart}"><xsl:apply-templates/></a></span> </xsl:when> <xsl:otherwise> + <!-- "Filepart#" (there is no ':' in Filepart --> <span class="bold_code"><a href="{$filepart}.html"><xsl:apply-templates/></a></span> </xsl:otherwise> </xsl:choose> </xsl:otherwise> </xsl:choose> + </xsl:when> <!-- string-length($filepart) > 0 --> + <xsl:when test="string-length($linkpart) > 0"> + <!-- "#Linkpart" --> + <span class="bold_code"><a href="#{$linkpart}"><xsl:apply-templates/></a></span> </xsl:when> <xsl:otherwise> - <xsl:choose> - <xsl:when test="string-length($linkpart) > 0"> - <span class="bold_code"><a href="#{$linkpart}"><xsl:apply-templates/></a></span> - </xsl:when> - <xsl:otherwise> - <xsl:variable name="modulepart"><xsl:value-of select="substring-before(@marker, ':')"/></xsl:variable> + <!-- "AppPart:Mod" or "Mod" (there is no '#') --> + <xsl:variable name="app_part"><xsl:value-of select="substring-before(@marker, ':')"/></xsl:variable> - <xsl:choose> - <xsl:when test="string-length($modulepart) > 0"> - <xsl:variable name="filepart1"><xsl:value-of select="substring-after(@marker, ':')"/></xsl:variable> - <span class="bold_code"><a href="javascript:erlhref('{$topdocdir}/../','{$modulepart}','{$filepart1}.html');"><xsl:apply-templates/></a></span> - </xsl:when> - <xsl:otherwise> - <span class="bold_code"><a href="{@marker}.html"><xsl:apply-templates/></a></span> - </xsl:otherwise> - </xsl:choose> - </xsl:otherwise> - </xsl:choose> + <xsl:choose> + <xsl:when test="string-length($app_part) > 0"> + <!-- "App:Mod" --> + <xsl:variable name="mod_part"><xsl:value-of select="substring-after(@marker, ':')"/></xsl:variable> + <span class="bold_code"><a href="javascript:erlhref('{$topdocdir}/../','{$app_part}','{$mod_part}.html');"><xsl:apply-templates/></a></span> + </xsl:when> + <xsl:otherwise> + <!-- "Mod" --> + <span class="bold_code"><a href="{@marker}.html"><xsl:apply-templates/></a></span> + </xsl:otherwise> + </xsl:choose> </xsl:otherwise> </xsl:choose> diff --git a/lib/erl_interface/src/misc/ei_format.c b/lib/erl_interface/src/misc/ei_format.c index cf50f12451..c1e5d998e4 100644 --- a/lib/erl_interface/src/misc/ei_format.c +++ b/lib/erl_interface/src/misc/ei_format.c @@ -149,7 +149,7 @@ static int pdigit(const char** fmt, ei_x_buff* x) { const char* start = *fmt; char c; - int len, dotp=0; + int dotp=0; double d; long l; @@ -166,7 +166,6 @@ static int pdigit(const char** fmt, ei_x_buff* x) break; } --(*fmt); - len = *fmt - start; if (dotp) { sscanf(start, "%lf", &d); return ei_x_encode_double(x, d); diff --git a/lib/hipe/flow/Makefile b/lib/hipe/flow/Makefile index 02f610587b..bbe8ef8666 100644 --- a/lib/hipe/flow/Makefile +++ b/lib/hipe/flow/Makefile @@ -65,7 +65,7 @@ DOC_FILES= $(MODULES:%=$(DOCS)/%.html) include ../native.mk -ERL_COMPILE_FLAGS += +warn_exported_vars +warn_missing_spec +warn_untyped_record +ERL_COMPILE_FLAGS += +warn_exported_vars +warn_missing_spec # +warn_untyped_record # ---------------------------------------------------- # Targets diff --git a/lib/hipe/icode/Makefile b/lib/hipe/icode/Makefile index eced90b0ec..bd6436c8b3 100644 --- a/lib/hipe/icode/Makefile +++ b/lib/hipe/icode/Makefile @@ -83,7 +83,7 @@ DOC_FILES= $(DOC_MODULES:%=$(DOCS)/%.html) include ../native.mk -ERL_COMPILE_FLAGS += +warn_unused_import +warn_missing_spec +warn_untyped_record +ERL_COMPILE_FLAGS += +warn_unused_import +warn_missing_spec # +warn_untyped_record # ---------------------------------------------------- # Targets diff --git a/lib/hipe/opt/Makefile b/lib/hipe/opt/Makefile index 74fde26c0b..4596201801 100644 --- a/lib/hipe/opt/Makefile +++ b/lib/hipe/opt/Makefile @@ -63,7 +63,7 @@ DOC_FILES= $(MODULES:%=$(DOCS)/%.html) include ../native.mk -ERL_COMPILE_FLAGS += +warn_exported_vars +warn_missing_spec +warn_untyped_record +ERL_COMPILE_FLAGS += +warn_exported_vars +warn_missing_spec # +warn_untyped_record # ---------------------------------------------------- # Targets diff --git a/lib/hipe/rtl/Makefile b/lib/hipe/rtl/Makefile index 690045b978..48086ec79f 100644 --- a/lib/hipe/rtl/Makefile +++ b/lib/hipe/rtl/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2001-2011. All Rights Reserved. +# Copyright Ericsson AB 2001-2012. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -139,27 +139,35 @@ hipe_literals.hrl: $(HIPE_MKLITERALS) ../main/hipe.hrl: ../vsn.mk ../main/hipe.hrl.src (cd ../main && $(MAKE) hipe.hrl) -$(EBIN)/hipe_rtl.beam: hipe_rtl.hrl ../main/hipe.hrl -$(EBIN)/hipe_rtl_arch.beam: hipe_rtl.hrl hipe_literals.hrl -$(EBIN)/hipe_rtl_binary.beam: hipe_rtl.hrl hipe_literals.hrl -$(EBIN)/hipe_rtl_bin_util.beam: hipe_rtl.hrl hipe_literals.hrl -$(EBIN)/hipe_rtl_cfg.beam: hipe_rtl.hrl ../flow/cfg.hrl ../flow/cfg.inc ../main/hipe.hrl -$(EBIN)/hipe_rtl_cleanup_const.beam: hipe_rtl.hrl -$(EBIN)/hipe_rtl_liveness.beam: hipe_rtl.hrl ../flow/cfg.hrl ../flow/liveness.inc -$(EBIN)/hipe_icode2rtl.beam: hipe_literals.hrl ../main/hipe.hrl ../icode/hipe_icode.hrl -$(EBIN)/hipe_tagscheme.beam: hipe_rtl.hrl hipe_literals.hrl -$(EBIN)/hipe_rtl_primops.beam: hipe_rtl.hrl ../icode/hipe_icode_primops.hrl hipe_literals.hrl ../main/hipe.hrl +# 2012-02-24. Please keep these dependencies up to date. They tend to rot. +# grep ^-include *.erl says a lot, but you need to dig further, e.g: +# grep ^-include ../flow/*.{hrl,inc} +$(EBIN)/hipe_icode2rtl.beam: \ + ../main/hipe.hrl ../icode/hipe_icode.hrl hipe_literals.hrl +$(EBIN)/hipe_rtl_arch.beam: hipe_literals.hrl $(EBIN)/hipe_rtl_arith_32.beam: ../main/hipe.hrl hipe_rtl_arith.inc $(EBIN)/hipe_rtl_arith_64.beam: ../main/hipe.hrl hipe_rtl_arith.inc -$(EBIN)/hipe_rtl_bs_ops.beam: hipe_literals.hrl ../main/hipe.hrl -$(EBIN)/hipe_rtl_cerl_bs_ops.beam: ../main/hipe.hrl hipe_literals.hrl hipe_rtl.hrl -$(EBIN)/hipe_rtl_exceptions.beam: hipe_literals.hrl ../main/hipe.hrl -$(EBIN)/hipe_rtl_inline_bs_ops.beam: hipe_rtl.hrl hipe_literals.hrl ../main/hipe.hrl +$(EBIN)/hipe_rtl_binary_construct.beam: \ + ../main/hipe.hrl hipe_rtl.hrl hipe_literals.hrl +$(EBIN)/hipe_rtl_binary_match.beam: hipe_literals.hrl +$(EBIN)/hipe_rtl_cfg.beam: \ + ../main/hipe.hrl hipe_rtl.hrl ../flow/cfg.hrl ../flow/cfg.inc +$(EBIN)/hipe_rtl_cleanup_const.beam: hipe_rtl.hrl +$(EBIN)/hipe_rtl.beam: ../main/hipe.hrl hipe_rtl.hrl +$(EBIN)/hipe_rtl_exceptions.beam: ../main/hipe.hrl hipe_literals.hrl +$(EBIN)/hipe_rtl_lcm.beam: ../main/hipe.hrl hipe_rtl.hrl ../flow/cfg.hrl +$(EBIN)/hipe_rtl_liveness.beam: hipe_rtl.hrl ../flow/cfg.hrl ../flow/liveness.inc $(EBIN)/hipe_rtl_mk_switch.beam: ../main/hipe.hrl -$(EBIN)/hipe_rtl_lcm.beam: ../flow/cfg.hrl hipe_rtl.hrl -$(EBIN)/hipe_rtl_symbolic.beam: hipe_rtl.hrl hipe_literals.hrl ../flow/cfg.hrl ../icode/hipe_icode_primops.hrl -$(EBIN)/hipe_rtl_varmap.beam: ../main/hipe.hrl ../icode/hipe_icode.hrl - -$(EBIN)/hipe_rtl_ssa.beam: ../ssa/hipe_ssa.inc ../main/hipe.hrl ../ssa/hipe_ssa_liveness.inc hipe_rtl.hrl -$(EBIN)/hipe_rtl_ssa_const_prop.beam: hipe_rtl.hrl ../main/hipe.hrl ../flow/cfg.hrl ../ssa/hipe_ssa_const_prop.inc -$(EBIN)/hipe_rtl_ssapre.beam: ../main/hipe.hrl ../flow/cfg.hrl hipe_rtl.hrl +$(EBIN)/hipe_rtl_primops.beam: ../main/hipe.hrl \ + ../icode/hipe_icode_primops.hrl hipe_rtl.hrl hipe_literals.hrl +$(EBIN)/hipe_rtl_ssa_avail_expr.beam: ../main/hipe.hrl hipe_rtl.hrl +$(EBIN)/hipe_rtl_ssa_const_prop.beam: ../main/hipe.hrl hipe_rtl.hrl \ + ../flow/cfg.hrl ../ssa/hipe_ssa_const_prop.inc +$(EBIN)/hipe_rtl_ssa.beam: hipe_rtl.hrl \ + ../main/hipe.hrl ../ssa/hipe_ssa_liveness.inc ../ssa/hipe_ssa.inc +$(EBIN)/hipe_rtl_ssapre.beam: ../main/hipe.hrl hipe_rtl.hrl +$(EBIN)/hipe_rtl_symbolic.beam: hipe_rtl.hrl hipe_literals.hrl \ + ../icode/hipe_icode_primops.hrl +$(EBIN)/hipe_rtl_varmap.beam: ../main/hipe.hrl \ + ../misc/hipe_consttab.hrl ../icode/hipe_icode.hrl +$(EBIN)/hipe_tagscheme.beam: hipe_rtl.hrl hipe_literals.hrl diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpMbox.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpMbox.java index 71a419497a..d6f319d378 100644 --- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpMbox.java +++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpMbox.java @@ -31,7 +31,7 @@ package com.ericsson.otp.erlang; * the recipient of the message. When sending messages to other mailboxes, the * recipient can only respond if the sender includes the pid as part of the * message contents. The sender can determine his own pid by calling - * {@link #self self()}. + * {@link #self() self()}. * </p> * * <p> diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpNode.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpNode.java index d499fae3fb..be7c8e5b1a 100644 --- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpNode.java +++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpNode.java @@ -182,7 +182,7 @@ public class OtpNode extends OtpLocalNode { * Create an unnamed {@link OtpMbox mailbox} that can be used to send and * receive messages with other, similar mailboxes and with Erlang processes. * Messages can be sent to this mailbox by using its associated - * {@link OtpMbox#self pid}. + * {@link OtpMbox#self() pid}. * * @return a mailbox. */ @@ -248,7 +248,7 @@ public class OtpNode extends OtpLocalNode { * Create an named mailbox that can be used to send and receive messages * with other, similar mailboxes and with Erlang processes. Messages can be * sent to this mailbox by using its registered name or the associated - * {@link OtpMbox#self pid}. + * {@link OtpMbox#self() pid}. * * @param name * a name to register for this mailbox. The name must be unique diff --git a/lib/kernel/src/code_server.erl b/lib/kernel/src/code_server.erl index 32a12e2b52..5d4f2eb70c 100644 --- a/lib/kernel/src/code_server.erl +++ b/lib/kernel/src/code_server.erl @@ -1317,15 +1317,21 @@ int_list([H|T]) when is_integer(H) -> int_list(T); int_list([_|_]) -> false; int_list([]) -> true. +load_file(Mod0, {From,_}=Caller, St0) -> + Mod = to_atom(Mod0), + case pending_on_load(Mod, From, St0) of + no -> load_file_1(Mod, Caller, St0); + {yes,St} -> {noreply,St} + end. -load_file(Mod, Caller, #state{path=Path,cache=no_cache}=St) -> +load_file_1(Mod, Caller, #state{path=Path,cache=no_cache}=St) -> case mod_to_bin(Path, Mod) of error -> {reply,{error,nofile},St}; {Mod,Binary,File} -> try_load_module(File, Mod, Binary, Caller, St) end; -load_file(Mod, Caller, #state{cache=Cache}=St0) -> +load_file_1(Mod, Caller, #state{cache=Cache}=St0) -> Key = {obj,Mod}, case ets:lookup(Cache, Key) of [] -> diff --git a/lib/kernel/src/gen_sctp.erl b/lib/kernel/src/gen_sctp.erl index 77ca26b845..d8954f0cf7 100644 --- a/lib/kernel/src/gen_sctp.erl +++ b/lib/kernel/src/gen_sctp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2011. All Rights Reserved. +%% Copyright Ericsson AB 2007-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 @@ -314,7 +314,7 @@ eof_or_abort(S, AssocId, Action) -> -spec send(Socket, SndRcvInfo, Data) -> ok | {error, Reason} when Socket :: sctp_socket(), SndRcvInfo :: #sctp_sndrcvinfo{}, - Data :: binary | iolist(), + Data :: binary() | iolist(), Reason :: term(). %% Full-featured send. Rarely needed. @@ -331,7 +331,7 @@ send(S, SRI, Data) -> Socket :: sctp_socket(), Assoc :: #sctp_assoc_change{} | assoc_id(), Stream :: integer(), - Data :: binary | iolist(), + Data :: binary() | iolist(), Reason :: term(). send(S, #sctp_assoc_change{assoc_id=AssocId}, Stream, Data) diff --git a/lib/kernel/test/code_SUITE.erl b/lib/kernel/test/code_SUITE.erl index 10ab3e4370..99b0cd2ffb 100644 --- a/lib/kernel/test/code_SUITE.erl +++ b/lib/kernel/test/code_SUITE.erl @@ -30,9 +30,9 @@ load_cached/1, start_node_with_cache/1, add_and_rehash/1, where_is_file_cached/1, where_is_file_no_cache/1, purge_stacktrace/1, mult_lib_roots/1, bad_erl_libs/1, - code_archive/1, code_archive2/1, on_load/1, - big_boot_embedded/1, - on_load_embedded/1, on_load_errors/1, native_early_modules/1]). + code_archive/1, code_archive2/1, on_load/1, on_load_binary/1, + on_load_embedded/1, on_load_errors/1, big_boot_embedded/1, + native_early_modules/1]). -export([init_per_testcase/2, end_per_testcase/2, init_per_suite/1, end_per_suite/1, @@ -55,8 +55,8 @@ all() -> add_and_rehash, where_is_file_no_cache, where_is_file_cached, purge_stacktrace, mult_lib_roots, bad_erl_libs, code_archive, code_archive2, on_load, - on_load_embedded, big_boot_embedded, on_load_errors, - native_early_modules]. + on_load_binary, on_load_embedded, on_load_errors, + big_boot_embedded, native_early_modules]. groups() -> []. @@ -1286,6 +1286,45 @@ on_load_wait_for_all([Ref|T]) -> end; on_load_wait_for_all([]) -> ok. +on_load_binary(_) -> + Master = on_load_binary_test_case_process, + register(Master, self()), + + %% Construct, compile and pretty-print. + Mod = on_load_binary, + File = atom_to_list(Mod) ++ ".erl", + Forms = [{attribute,1,file,{File,1}}, + {attribute,1,module,Mod}, + {attribute,2,export,[{ok,0}]}, + {attribute,3,on_load,{init,0}}, + {function,5,init,0, + [{clause,5,[],[], + [{op,6,'!', + {atom,6,Master}, + {tuple,6,[{atom,6,Mod},{call,6,{atom,6,self},[]}]}}, + {'receive',7,[{clause,8,[{atom,8,go}],[],[{atom,8,ok}]}]}]}]}, + {function,11,ok,0,[{clause,11,[],[],[{atom,11,true}]}]}], + {ok,Mod,Bin} = compile:forms(Forms, [report]), + [io:put_chars(erl_pp:form(F)) || F <- Forms], + + {Pid1,Ref1} = spawn_monitor(fun() -> + code:load_binary(Mod, File, Bin), + true = on_load_binary:ok() + end), + receive {Mod,OnLoadPid} -> ok end, + {Pid2,Ref2} = spawn_monitor(fun() -> + true = on_load_binary:ok() + end), + erlang:yield(), + OnLoadPid ! go, + receive {'DOWN',Ref1,process,Pid1,Exit1} -> ok end, + receive {'DOWN',Ref2,process,Pid2,Exit2} -> ok end, + normal = Exit1, + normal = Exit2, + true = code:delete(on_load_binary), + false = code:purge(on_load_binary), + ok. + on_load_embedded(Config) when is_list(Config) -> try on_load_embedded_1(Config) diff --git a/lib/kernel/test/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl index 85346762ac..2b6af7e1fb 100644 --- a/lib/kernel/test/file_SUITE.erl +++ b/lib/kernel/test/file_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2011. All Rights Reserved. +%% Copyright Ericsson AB 1996-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -78,7 +78,7 @@ -export([altname/1]). --export([large_file/1]). +-export([large_file/1, large_write/1]). -export([read_line_1/1, read_line_2/1, read_line_3/1,read_line_4/1]). @@ -92,6 +92,8 @@ -export([bytes/2, iterate/3]). +%% System probe functions that might be handy to check from the shell +-export([disc_free/1, memsize/0]). -include_lib("test_server/include/test_server.hrl"). -include_lib("kernel/include/file.hrl"). @@ -106,7 +108,7 @@ all() -> {group, compression}, {group, links}, copy, delayed_write, read_ahead, segment_read, segment_write, ipread, pid2name, interleaved_read_write, otp_5814, - large_file, read_line_1, read_line_2, read_line_3, + large_file, large_write, read_line_1, read_line_2, read_line_3, read_line_4, standard_io]. groups() -> @@ -143,6 +145,13 @@ end_per_group(_GroupName, Config) -> init_per_suite(Config) when is_list(Config) -> + SaslConfig = case application:start(sasl) of + {error, {already_started, sasl}} -> + []; + ok -> + [{sasl,started}] + end, + ok = application:start(os_mon), case os:type() of {win32, _} -> Priv = ?config(priv_dir, Config), @@ -154,9 +163,9 @@ init_per_suite(Config) when is_list(Config) -> {ok, _} -> [] end, - ?FILE_INIT(HasAccessTime++Config); + ?FILE_INIT(HasAccessTime++Config++SaslConfig); _ -> - ?FILE_INIT(Config) + ?FILE_INIT(Config++SaslConfig) end. end_per_suite(Config) when is_list(Config) -> @@ -166,6 +175,13 @@ end_per_suite(Config) when is_list(Config) -> _ -> ok end, + application:stop(os_mon), + case proplists:get_value(sasl, Config) of + started -> + application:stop(sasl); + _Else -> + ok + end, ?FILE_FINI(Config). init_per_testcase(_Func, Config) -> @@ -394,6 +410,7 @@ make_del_dir(Config) when is_list(Config) -> %% Don't worry ;-) the parent directory should never be empty, right? ?line case ?FILE_MODULE:del_dir('..') of {error, eexist} -> ok; + {error, eacces} -> ok; %OpenBSD {error, einval} -> ok %FreeBSD end, ?line {error, enoent} = ?FILE_MODULE:del_dir(""), @@ -3287,50 +3304,13 @@ large_file(suite) -> large_file(doc) -> ["Tests positioning in large files (> 4G)"]; large_file(Config) when is_list(Config) -> - case {os:type(),os:version()} of - {{win32,nt},_} -> - do_large_file(Config); - {{unix,sunos},{A,B,C}} - when A == 5, B == 5, C >= 1; A == 5, B >= 6; A >= 6 -> - do_large_file(Config); - {{unix,Unix},_} when Unix =/= sunos -> - N = unix_free(Config), - io:format("Free: ~w KByte~n", [N]), - if N < 5 * (1 bsl 20) -> - %% Less than 5 GByte free - {skipped,"Less than 5 GByte free"}; - true -> - do_large_file(Config) - end; - _ -> - {skipped,"Only supported on Win32, Unix or SunOS >= 5.5.1"} - end. + run_large_file_test(Config, + fun(Name) -> do_large_file(Name) end, + "_large_file"). -unix_free(Config) -> - Cmd = ["df -k '",?config(priv_dir, Config),"'"], - DF0 = os:cmd(Cmd), - io:format("$ ~s~n~s", [Cmd,DF0]), - [$\n|DF1] = lists:dropwhile(fun ($\n) -> false; (_) -> true end, DF0), - {ok,[N],_} = io_lib:fread(" ~*s ~d", DF1), - N. +do_large_file(Name) -> + ?line Watchdog = ?t:timetrap(?t:minutes(20)), -do_large_file(Config) -> - ?line Watchdog = ?t:timetrap(?t:minutes(5)), - %% - ?line Name = filename:join(?config(priv_dir, Config), - ?MODULE_STRING ++ "_large_file"), - ?line Tester = self(), - Deleter = - spawn( - fun() -> - Mref = erlang:monitor(process, Tester), - receive - {'DOWN',Mref,_,_,_} -> ok; - {Tester,done} -> ok - end, - ?FILE_MODULE:delete(Name) - end), - %% ?line S = "1234567890", L = length(S), R = lists:reverse(S), @@ -3366,15 +3346,36 @@ do_large_file(Config) -> ?line {ok,R} = ?FILE_MODULE:read(F1, L+1), ?line ok = ?FILE_MODULE:close(F1), %% - ?line Mref = erlang:monitor(process, Deleter), - ?line Deleter ! {Tester,done}, - ?line receive {'DOWN',Mref,_,_,_} -> ok end, - %% ?line ?t:timetrap_cancel(Watchdog), ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +large_write(Config) when is_list(Config) -> + run_large_file_test(Config, + fun(Name) -> do_large_write(Name) end, + "_large_write"). + +do_large_write(Name) -> + Memsize = memsize(), + io:format("Memsize = ~w Bytes~n", [Memsize]), + case {erlang:system_info(wordsize),Memsize} of + {4,_} -> + {skip,"Needs a 64-bit emulator"}; + {8,N} when N < 6 bsl 30 -> + {skip, + "This machine has < 6 GB memory: " + ++integer_to_list(N)}; + {8,_} -> + Size = 4*1024*1024*1024+1, + Bin = <<0:Size/unit:8>>, + ok = file:write_file(Name, Bin), + {ok,#file_info{size=Size}} = file:read_file_info(Name), + ok + end. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + response_analysis(Module, Function, Arguments) -> @@ -3950,3 +3951,67 @@ flush(Msgs) -> after 0 -> lists:reverse(Msgs) end. + +%%% +%%% Support for testing large files. +%%% + +run_large_file_test(Config, Run, Name) -> + case {os:type(),os:version()} of + {{win32,nt},_} -> + do_run_large_file_test(Config, Run, Name); + {{unix,sunos},OsVersion} when OsVersion < {5,5,1} -> + {skip,"Only supported on Win32, Unix or SunOS >= 5.5.1"}; + {{unix,_},_} -> + N = disc_free(?config(priv_dir, Config)), + io:format("Free disk: ~w KByte~n", [N]), + if N < 5 * (1 bsl 20) -> + %% Less than 5 GByte free + {skip,"Less than 5 GByte free"}; + true -> + do_run_large_file_test(Config, Run, Name) + end; + _ -> + {skip,"Only supported on Win32, Unix or SunOS >= 5.5.1"} + end. + + +do_run_large_file_test(Config, Run, Name0) -> + Name = filename:join(?config(priv_dir, Config), + ?MODULE_STRING ++ Name0), + + %% Set up a process that will delete this file. + Tester = self(), + Deleter = + spawn( + fun() -> + Mref = erlang:monitor(process, Tester), + receive + {'DOWN',Mref,_,_,_} -> ok; + {Tester,done} -> ok + end, + ?FILE_MODULE:delete(Name) + end), + + %% Run the test case. + Res = Run(Name), + + %% Delete file and finish deleter process. + Mref = erlang:monitor(process, Deleter), + Deleter ! {Tester,done}, + receive {'DOWN',Mref,_,_,_} -> ok end, + + Res. + +disc_free(Path) -> + Data = disksup:get_disk_data(), + {_,Tot,Perc} = hd(lists:filter( + fun({P,_Size,_Full}) -> + lists:prefix(filename:nativename(P), + filename:nativename(Path)) + end, lists:reverse(lists:sort(Data)))), + round(Tot * (1-(Perc/100))). + +memsize() -> + {Tot,_Used,_} = memsup:get_memory_data(), + Tot. diff --git a/lib/kernel/test/prim_file_SUITE.erl b/lib/kernel/test/prim_file_SUITE.erl index ccf26ee034..3e2202922c 100644 --- a/lib/kernel/test/prim_file_SUITE.erl +++ b/lib/kernel/test/prim_file_SUITE.erl @@ -52,6 +52,10 @@ list_dir_limit/1]). -export([advise/1]). +-export([large_write/1]). + +%% System probe functions that might be handy to check from the shell +-export([unix_free/1]). -include_lib("test_server/include/test_server.hrl"). -include_lib("kernel/include/file.hrl"). @@ -83,7 +87,7 @@ groups() -> cur_dir_1a, cur_dir_1b]}, {files, [], [{group, open}, {group, pos}, {group, file_info}, - truncate, sync, datasync, advise]}, + truncate, sync, datasync, advise, large_write]}, {open, [], [open1, modes, close, access, read_write, pread_write, append, exclusive]}, @@ -290,6 +294,7 @@ make_del_dir(Config, Handle, Suffix) -> %% Don't worry ;-) the parent directory should never be empty, right? ?line case ?PRIM_FILE_call(del_dir, Handle, [".."]) of {error, eexist} -> ok; + {error, eacces} -> ok; %OpenBSD {error, einval} -> ok %FreeBSD end, ?line {error, enoent} = ?PRIM_FILE_call(del_dir, Handle, [""]), @@ -1322,6 +1327,41 @@ advise(Config) when is_list(Config) -> ?line test_server:timetrap_cancel(Dog), ok. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +large_write(Config) when is_list(Config) -> + run_large_file_test(Config, + fun(Name) -> do_large_write(Name) end, + "_large_write"). + +do_large_write(Name) -> + Dog = test_server:timetrap(test_server:minutes(60)), + ChunkSize = (256 bsl 20) + 1, % 256 M + 1 + Chunks = 16, % times 16 -> 4 G + 16 + Base = 100, + Interleave = lists:seq(Base+1, Base+Chunks), + Chunk = <<0:ChunkSize/unit:8>>, + Data = zip_data(lists:duplicate(Chunks, Chunk), Interleave), + Size = Chunks * ChunkSize + Chunks, % 4 G + 32 + Wordsize = erlang:system_info(wordsize), + case prim_file:write_file(Name, Data) of + ok when Wordsize =:= 8 -> + {ok,#file_info{size=Size}} = file:read_file_info(Name), + {ok,Fd} = prim_file:open(Name, [read]), + check_large_write(Dog, Fd, ChunkSize, 0, Interleave); + {error,einval} when Wordsize =:= 4 -> + ok + end. + +check_large_write(Dog, Fd, ChunkSize, Pos, [X|Interleave]) -> + Pos1 = Pos + ChunkSize, + {ok,Pos1} = prim_file:position(Fd, {cur,ChunkSize}), + {ok,[X]} = prim_file:read(Fd, 1), + check_large_write(Dog, Fd, ChunkSize, Pos1+1, Interleave); +check_large_write(Dog, Fd, _, _, []) -> + eof = prim_file:read(Fd, 1), + test_server:timetrap_cancel(Dog), + ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -2044,3 +2084,70 @@ list_dir_limit_cleanup(Dir, Handle, N, Cnt) -> ?PRIM_FILE:delete(Handle, filename:join(Dir, Name)), list_dir_limit_cleanup(Dir, Handle, N, Cnt+1). +%%% +%%% Support for testing large files. +%%% + +run_large_file_test(Config, Run, Name) -> + case {os:type(),os:version()} of + {{win32,nt},_} -> + do_run_large_file_test(Config, Run, Name); + {{unix,sunos},OsVersion} when OsVersion < {5,5,1} -> + {skip,"Only supported on Win32, Unix or SunOS >= 5.5.1"}; + {{unix,_},_} -> + N = unix_free(?config(priv_dir, Config)), + io:format("Free disk: ~w KByte~n", [N]), + if N < 5 bsl 20 -> + %% Less than 5 GByte free + {skip,"Less than 5 GByte free disk"}; + true -> + do_run_large_file_test(Config, Run, Name) + end; + _ -> + {skip,"Only supported on Win32, Unix or SunOS >= 5.5.1"} + end. + + +do_run_large_file_test(Config, Run, Name0) -> + Name = filename:join(?config(priv_dir, Config), + ?MODULE_STRING ++ Name0), + + %% Set up a process that will delete this file. + Tester = self(), + Deleter = + spawn( + fun() -> + Mref = erlang:monitor(process, Tester), + receive + {'DOWN',Mref,_,_,_} -> ok; + {Tester,done} -> ok + end, + prim_file:delete(Name) + end), + + %% Run the test case. + Res = Run(Name), + + %% Delete file and finish deleter process. + Mref = erlang:monitor(process, Deleter), + Deleter ! {Tester,done}, + receive {'DOWN',Mref,_,_,_} -> ok end, + + Res. + +unix_free(Path) -> + Cmd = ["df -k '",Path,"'"], + DF0 = os:cmd(Cmd), + io:format("$ ~s~n~s", [Cmd,DF0]), + Lines = re:split(DF0, "\n", [trim,{return,list}]), + Last = lists:last(Lines), + RE = "^[^\\s]*\\s+\\d+\\s+\\d+\\s+(\\d+)", + {match,[Avail]} = re:run(Last, RE, [{capture,all_but_first,list}]), + list_to_integer(Avail). + +zip_data([A|As], [B|Bs]) -> + [[A,B]|zip_data(As, Bs)]; +zip_data([], Bs) -> + Bs; +zip_data(As, []) -> + As. diff --git a/lib/kernel/vsn.mk b/lib/kernel/vsn.mk index 76c62ece67..76d3003ff4 100644 --- a/lib/kernel/vsn.mk +++ b/lib/kernel/vsn.mk @@ -1 +1 @@ -KERNEL_VSN = 2.15 +KERNEL_VSN = 2.15.1 diff --git a/lib/mnesia/src/mnesia_locker.erl b/lib/mnesia/src/mnesia_locker.erl index de4811f8e4..a22c95d454 100644 --- a/lib/mnesia/src/mnesia_locker.erl +++ b/lib/mnesia/src/mnesia_locker.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2011. All Rights Reserved. +%% Copyright Ericsson AB 1996-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -66,7 +66,7 @@ -record(queue, {oid, tid, op, pid, lucky}). -%% mnesia_held_locks: contain {Oid, Op, Tid} entries (bag) +%% mnesia_held_locks: contain {Oid, MaxLock, [{Op, Tid}]} entries -define(match_oid_held_locks(Oid), {Oid, '_', '_'}). %% mnesia_tid_locks: contain {Tid, Oid, Op} entries (bag) -define(match_oid_tid_locks(Tid), {Tid, '_', '_'}). @@ -83,7 +83,7 @@ start() -> init(Parent) -> register(?MODULE, self()), process_flag(trap_exit, true), - ?ets_new_table(mnesia_held_locks, [bag, private, named_table]), + ?ets_new_table(mnesia_held_locks, [ordered_set, private, named_table]), ?ets_new_table(mnesia_tid_locks, [bag, private, named_table]), ?ets_new_table(mnesia_sticky_locks, [set, private, named_table]), ?ets_new_table(mnesia_lock_queue, [bag, private, named_table, {keypos, 2}]), @@ -235,10 +235,17 @@ loop(State) -> loop(State) end. -set_lock(Tid, Oid, Op) -> - ?dbg("Granted ~p ~p ~p~n", [Tid,Oid,Op]), - ?ets_insert(mnesia_held_locks, {Oid, Op, Tid}), - ?ets_insert(mnesia_tid_locks, {Tid, Oid, Op}). +set_lock(Tid, Oid, Op, []) -> + ?ets_insert(mnesia_tid_locks, {Tid, Oid, Op}), + ?ets_insert(mnesia_held_locks, {Oid, Op, [{Op, Tid}]}); +set_lock(Tid, Oid, read, [{Oid, Prev, Items}]) -> + ?ets_insert(mnesia_tid_locks, {Tid, Oid, read}), + ?ets_insert(mnesia_held_locks, {Oid, Prev, [{read, Tid}|Items]}); +set_lock(Tid, Oid, write, [{Oid, _Prev, Items}]) -> + ?ets_insert(mnesia_tid_locks, {Tid, Oid, write}), + ?ets_insert(mnesia_held_locks, {Oid, write, [{write, Tid}|Items]}); +set_lock(Tid, Oid, Op, undefined) -> + set_lock(Tid, Oid, Op, ?ets_lookup(mnesia_held_locks, Oid)). %%%%%%%%%%%%%%%%%%%%%%%%%%% %% Acquire locks @@ -261,14 +268,14 @@ try_lock(Tid, Op, Pid, Oid) -> try_lock(Tid, Op, SimpleOp, Lock, Pid, Oid) -> case can_lock(Tid, Lock, Oid, {no, bad_luck}) of - yes -> - Reply = grant_lock(Tid, SimpleOp, Lock, Oid), + {yes, Default} -> + Reply = grant_lock(Tid, SimpleOp, Lock, Oid, Default), reply(Pid, Reply); - {no, Lucky} -> + {{no, Lucky},_} -> C = #cyclic{op = SimpleOp, lock = Lock, oid = Oid, lucky = Lucky}, ?dbg("Rejected ~p ~p ~p ~p ~n", [Tid, Oid, Lock, Lucky]), reply(Pid, {not_granted, C}); - {queue, Lucky} -> + {{queue, Lucky},_} -> ?dbg("Queued ~p ~p ~p ~p ~n", [Tid, Oid, Lock, Lucky]), %% Append to queue: Nice place for trace output ?ets_insert(mnesia_lock_queue, @@ -277,16 +284,16 @@ try_lock(Tid, Op, SimpleOp, Lock, Pid, Oid) -> ?ets_insert(mnesia_tid_locks, {Tid, Oid, {queued, Op}}) end. -grant_lock(Tid, read, Lock, Oid = {Tab, Key}) +grant_lock(Tid, read, Lock, Oid = {Tab, Key}, Default) when Key /= ?ALL, Tab /= ?GLOBAL -> case node(Tid#tid.pid) == node() of true -> - set_lock(Tid, Oid, Lock), + set_lock(Tid, Oid, Lock, Default), {granted, lookup_in_client}; false -> try Val = mnesia_lib:db_get(Tab, Key), %% lookup as well - set_lock(Tid, Oid, Lock), + set_lock(Tid, Oid, Lock, Default), {granted, Val} catch _:_Reason -> %% Table has been deleted from this node, @@ -296,19 +303,19 @@ grant_lock(Tid, read, Lock, Oid = {Tab, Key}) {not_granted, C} end end; -grant_lock(Tid, {ix_read,IxKey,Pos}, Lock, Oid = {Tab, _}) -> +grant_lock(Tid, {ix_read,IxKey,Pos}, Lock, Oid = {Tab, _}, Default) -> try Res = ix_read_res(Tab, IxKey,Pos), - set_lock(Tid, Oid, Lock), + set_lock(Tid, Oid, Lock, Default), {granted, Res, [?ALL]} catch _:_ -> {not_granted, {no_exists, Tab, {index, [Pos]}}} end; -grant_lock(Tid, read, Lock, Oid) -> - set_lock(Tid, Oid, Lock), +grant_lock(Tid, read, Lock, Oid, Default) -> + set_lock(Tid, Oid, Lock, Default), {granted, ok}; -grant_lock(Tid, write, Lock, Oid) -> - set_lock(Tid, Oid, Lock), +grant_lock(Tid, write, Lock, Oid, Default) -> + set_lock(Tid, Oid, Lock, Default), granted. %% 1) Impose an ordering on all transactions favour old (low tid) transactions @@ -318,55 +325,40 @@ grant_lock(Tid, write, Lock, Oid) -> %% 3) TabLocks is the problem :-) They should not starve and not deadlock %% handle tablocks in queue as they had locks on unlocked records. -can_lock(Tid, read, {Tab, Key}, AlreadyQ) when Key /= ?ALL -> - %% The key is bound, no need for the other BIF - Oid = {Tab, Key}, - ObjLocks = ?ets_match_object(mnesia_held_locks, {Oid, write, '_'}), - TabLocks = ?ets_match_object(mnesia_held_locks, {{Tab, ?ALL}, write, '_'}), - check_lock(Tid, Oid, ObjLocks, TabLocks, yes, AlreadyQ, read); +can_lock(Tid, read, Oid = {Tab, Key}, AlreadyQ) when Key /= ?ALL -> + ObjLocks = ?ets_lookup(mnesia_held_locks, Oid), + TabLocks = ?ets_lookup(mnesia_held_locks, {Tab, ?ALL}), + {check_lock(Tid, Oid, + filter_write(ObjLocks), + filter_write(TabLocks), + yes, AlreadyQ, read), + ObjLocks}; can_lock(Tid, read, Oid, AlreadyQ) -> % Whole tab Tab = element(1, Oid), ObjLocks = ?ets_match_object(mnesia_held_locks, {{Tab, '_'}, write, '_'}), - check_lock(Tid, Oid, ObjLocks, [], yes, AlreadyQ, read); + {check_lock(Tid, Oid, ObjLocks, [], yes, AlreadyQ, read), undefined}; -can_lock(Tid, write, {Tab, Key}, AlreadyQ) when Key /= ?ALL -> - Oid = {Tab, Key}, +can_lock(Tid, write, Oid = {Tab, Key}, AlreadyQ) when Key /= ?ALL -> ObjLocks = ?ets_lookup(mnesia_held_locks, Oid), TabLocks = ?ets_lookup(mnesia_held_locks, {Tab, ?ALL}), - check_lock(Tid, Oid, ObjLocks, TabLocks, yes, AlreadyQ, write); + {check_lock(Tid, Oid, ObjLocks, TabLocks, yes, AlreadyQ, write), ObjLocks}; can_lock(Tid, write, Oid, AlreadyQ) -> % Whole tab Tab = element(1, Oid), ObjLocks = ?ets_match_object(mnesia_held_locks, ?match_oid_held_locks({Tab, '_'})), - check_lock(Tid, Oid, ObjLocks, [], yes, AlreadyQ, write). + {check_lock(Tid, Oid, ObjLocks, [], yes, AlreadyQ, write), undefined}. + +filter_write([{_, read, _}]) -> []; +filter_write(Res) -> Res. %% Check held locks for conflicting locks -check_lock(Tid, Oid, [Lock | Locks], TabLocks, X, AlreadyQ, Type) -> - case element(3, Lock) of - Tid -> - check_lock(Tid, Oid, Locks, TabLocks, X, AlreadyQ, Type); - WaitForTid -> - Queue = allowed_to_be_queued(WaitForTid,Tid), - if Queue == true -> - check_lock(Tid, Oid, Locks, TabLocks, {queue, WaitForTid}, AlreadyQ, Type); - Tid#tid.pid == WaitForTid#tid.pid -> - dbg_out("Spurious lock conflict ~w ~w: ~w -> ~w~n", - [Oid, Lock, Tid, WaitForTid]), - %% Test.. - {Tab, _Key} = Oid, - HaveQ = (ets:lookup(mnesia_lock_queue, Oid) /= []) - orelse (ets:lookup(mnesia_lock_queue,{Tab,?ALL}) /= []), - if - HaveQ -> - {no, WaitForTid}; - true -> - check_lock(Tid,Oid,Locks,TabLocks,{queue,WaitForTid},AlreadyQ,Type) - end; - %%{no, WaitForTid}; Safe solution - true -> - {no, WaitForTid} - end +check_lock(Tid, Oid, [{_, _, Lock} | Locks], TabLocks, _X, AlreadyQ, Type) -> + case can_queue(Lock, Tid, Oid, _X) of + {no, _} = Res -> + Res; + Res -> + check_lock(Tid, Oid, Locks, TabLocks, Res, AlreadyQ, Type) end; check_lock(_, _, [], [], X, {queue, bad_luck}, _) -> @@ -375,8 +367,7 @@ check_lock(_, _, [], [], X, {queue, bad_luck}, _) -> check_lock(_, _, [], [], X = {queue, _Tid}, _AlreadyQ, _) -> X; -check_lock(Tid, Oid, [], [], X, AlreadyQ, Type) -> - {Tab, Key} = Oid, +check_lock(Tid, Oid = {Tab, Key}, [], [], X, AlreadyQ, Type) -> if Type == write -> check_queue(Tid, Tab, X, AlreadyQ); @@ -403,6 +394,26 @@ check_lock(Tid, Oid, [], [], X, AlreadyQ, Type) -> check_lock(Tid, Oid, [], TabLocks, X, AlreadyQ, Type) -> check_lock(Tid, Oid, TabLocks, [], X, AlreadyQ, Type). +can_queue([{_Op, Tid}|Locks], Tid, Oid, Res) -> + can_queue(Locks, Tid, Oid, Res); +can_queue([{Op, WaitForTid}|Locks], Tid, Oid = {Tab, _}, _) -> + case allowed_to_be_queued(WaitForTid,Tid) of + true when Tid#tid.pid == WaitForTid#tid.pid -> + dbg_out("Spurious lock conflict ~w ~w: ~w -> ~w~n", + [Oid, Op, Tid, WaitForTid]), + HaveQ = (ets:lookup(mnesia_lock_queue, Oid) /= []) + orelse (ets:lookup(mnesia_lock_queue,{Tab,?ALL}) /= []), + case HaveQ of + true -> {no, WaitForTid}; + false -> can_queue(Locks, Tid, Oid, {queue, WaitForTid}) + end; + true -> + can_queue(Locks, Tid, Oid, {queue, WaitForTid}); + false -> + {no, WaitForTid} + end; +can_queue([], _, _, Res) -> Res. + %% True if WaitForTid > Tid -> % Important order allowed_to_be_queued(WaitForTid, Tid) -> case get(pid_sort_order) of @@ -456,14 +467,14 @@ set_read_lock_on_all_keys(Tid, From, Tab, IxKey, Pos) -> Op = {ix_read,IxKey, Pos}, Lock = read, case can_lock(Tid, Lock, Oid, {no, bad_luck}) of - yes -> - Reply = grant_lock(Tid, Op, Lock, Oid), + {yes, Default} -> + Reply = grant_lock(Tid, Op, Lock, Oid, Default), reply(From, Reply); - {no, Lucky} -> + {{no, Lucky},_} -> C = #cyclic{op = Op, lock = Lock, oid = Oid, lucky = Lucky}, ?dbg("Rejected ~p ~p ~p ~p ~n", [Tid, Oid, Lock, Lucky]), reply(From, {not_granted, C}); - {queue, Lucky} -> + {{queue, Lucky},_} -> ?dbg("Queued ~p ~p ~p ~p ~n", [Tid, Oid, Lock, Lucky]), %% Append to queue: Nice place for trace output ?ets_insert(mnesia_lock_queue, @@ -520,14 +531,24 @@ release_locks([]) -> release_lock({Tid, Oid, {queued, _}}) -> ?ets_match_delete(mnesia_lock_queue, #queue{oid=Oid, tid = Tid, op = '_', pid = '_', lucky = '_'}); -release_lock({Tid, Oid, Op}) -> - if - Op == write -> - ?ets_delete(mnesia_held_locks, Oid); - Op == read -> - ets:delete_object(mnesia_held_locks, {Oid, Op, Tid}) +release_lock({_Tid, Oid, write}) -> + ?ets_delete(mnesia_held_locks, Oid); +release_lock({Tid, Oid, read}) -> + case ?ets_lookup(mnesia_held_locks, Oid) of + [{Oid, Prev, Locks0}] -> + case remove_tid(Locks0, Tid, []) of + [] -> ?ets_delete(mnesia_held_locks, Oid); + Locks -> ?ets_insert(mnesia_held_locks, {Oid, Prev, Locks}) + end; + [] -> ok end. +remove_tid([{_Op, Tid}|Ls], Tid, Acc) -> + remove_tid(Ls,Tid, Acc); +remove_tid([Keep|Ls], Tid, Acc) -> + remove_tid(Ls,Tid, [Keep|Acc]); +remove_tid([], _, Acc) -> Acc. + rearrange_queue([{_Tid, {Tab, Key}, _} | Locks]) -> if Key /= ?ALL-> @@ -592,18 +613,18 @@ try_waiter({queue, Oid, Tid, Op, ReplyTo, _}) -> try_waiter(Oid, Op, SimpleOp, Lock, ReplyTo, Tid) -> case can_lock(Tid, Lock, Oid, {queue, bad_luck}) of - yes -> + {yes, Default} -> %% Delete from queue: Nice place for trace output ?ets_match_delete(mnesia_lock_queue, #queue{oid=Oid, tid = Tid, op = Op, pid = ReplyTo, lucky = '_'}), - Reply = grant_lock(Tid, SimpleOp, Lock, Oid), + Reply = grant_lock(Tid, SimpleOp, Lock, Oid, Default), reply(ReplyTo,Reply), locked; - {queue, _Why} -> + {{queue, _Why}, _} -> ?dbg("Keep ~p ~p ~p ~p~n", [Tid, Oid, Lock, _Why]), queued; % Keep waiter in queue - {no, Lucky} -> + {{no, Lucky}, _} -> C = #cyclic{op = SimpleOp, lock = Lock, oid = Oid, lucky = Lucky}, verbose("** WARNING ** Restarted transaction, possible deadlock in lock queue ~w: cyclic = ~w~n", [Tid, C]), @@ -1116,11 +1137,23 @@ rec_requests([], _Oid, _Store) -> get_held_locks() -> ?MODULE ! {get_table, self(), mnesia_held_locks}, - receive {mnesia_held_locks, Locks} -> Locks end. + Locks = receive {mnesia_held_locks, Ls} -> Ls after 5000 -> [] end, + rewrite_locks(Locks, []). + +rewrite_locks([{Oid, _, Ls}|Locks], Acc0) -> + Acc = rewrite_locks(Ls, Oid, Acc0), + rewrite_locks(Locks, Acc); +rewrite_locks([], Acc) -> + lists:reverse(Acc). + +rewrite_locks([{Op, Tid}|Ls], Oid, Acc) -> + rewrite_locks(Ls, Oid, [{Oid, Op, Tid}|Acc]); +rewrite_locks([], _, Acc) -> + Acc. get_lock_queue() -> ?MODULE ! {get_table, self(), mnesia_lock_queue}, - Q = receive {mnesia_lock_queue, Locks} -> Locks end, + Q = receive {mnesia_lock_queue, Locks} -> Locks after 5000 -> [] end, [{Oid, Op, Pid, Tid, WFT} || {queue, Oid, Tid, Op, Pid, WFT} <- Q]. do_stop() -> diff --git a/lib/observer/src/observer_lib.erl b/lib/observer/src/observer_lib.erl index 967baa5c7a..5260861497 100644 --- a/lib/observer/src/observer_lib.erl +++ b/lib/observer/src/observer_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011. All Rights Reserved. +%% Copyright Ericsson AB 2011-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -339,17 +339,37 @@ user_term(Parent, Title, Default) -> ?wxID_OK -> Str = wxTextEntryDialog:getValue(Dialog), wxTextEntryDialog:destroy(Dialog), - parse_string(Str); + parse_string(ensure_last_is_dot(Str)); ?wxID_CANCEL -> - wxTextEntryDialog:destroy(Dialog) + wxTextEntryDialog:destroy(Dialog), + cancel end. parse_string(Str) -> try - {ok, Tokens, _} = erl_scan:string(Str), - erl_parse:parse_term(Tokens) - catch _:{badmatch, {error, {_, _, Err}}} -> - {error, ["Parse error: ", Err]}; - _Err -> + Tokens = case erl_scan:string(Str) of + {ok, Ts, _} -> Ts; + {error, {_SLine, SMod, SError}, _} -> + throw(io_lib:format("~s", [SMod:format_error(SError)])) + end, + case erl_parse:parse_term(Tokens) of + {error, {_PLine, PMod, PError}} -> + throw(io_lib:format("~s", [PMod:format_error(PError)])); + Res -> Res + end + catch + throw:ErrStr -> + {error, ErrStr}; + _:_Err -> {error, ["Syntax error in: ", Str]} end. + +ensure_last_is_dot([]) -> + "."; +ensure_last_is_dot(String) -> + case lists:last(String) =:= $. of + true -> + String; + false -> + String ++ "." + end. diff --git a/lib/observer/src/observer_procinfo.erl b/lib/observer/src/observer_procinfo.erl index a4c5914c49..ec08d3aff1 100644 --- a/lib/observer/src/observer_procinfo.erl +++ b/lib/observer/src/observer_procinfo.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011. All Rights Reserved. +%% Copyright Ericsson AB 2011-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -124,9 +124,14 @@ code_change(_, _, State) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% init_process_page(Panel, Pid) -> - Fields = process_info_fields(Pid), - {FPanel, _, UpFields} = observer_lib:display_info(Panel, Fields), - {FPanel, fun() -> observer_lib:update_info(UpFields, process_info_fields(Pid)) end}. + Fields0 = process_info_fields(Pid), + {FPanel, _, UpFields} = observer_lib:display_info(Panel, Fields0), + {FPanel, fun() -> case process_info_fields(Pid) of + Fields when is_list(Fields) -> + observer_lib:update_info(UpFields, Fields); + _ -> ok + end + end}. init_text_page(Parent) -> Style = ?wxTE_MULTILINE bor ?wxTE_RICH2 bor ?wxTE_READONLY, @@ -144,16 +149,20 @@ init_message_page(Parent, Pid) -> Number+1} end, Update = fun() -> - {messages,RawMessages} = - observer_wx:try_rpc(node(Pid), erlang, process_info, [Pid, messages]), - {Messages,_} = lists:mapfoldl(Format, 1, RawMessages), - Last = wxTextCtrl:getLastPosition(Text), - wxTextCtrl:remove(Text, 0, Last), - case Messages =:= [] of - true -> - wxTextCtrl:writeText(Text, "No messages"); - false -> - wxTextCtrl:writeText(Text, Messages) + case observer_wx:try_rpc(node(Pid), erlang, process_info, + [Pid, messages]) + of + {messages,RawMessages} -> + {Messages,_} = lists:mapfoldl(Format, 1, RawMessages), + Last = wxTextCtrl:getLastPosition(Text), + wxTextCtrl:remove(Text, 0, Last), + case Messages =:= [] of + true -> + wxTextCtrl:writeText(Text, "No messages"); + false -> + wxTextCtrl:writeText(Text, Messages) + end; + _ -> ok end end, Update(), @@ -162,12 +171,15 @@ init_message_page(Parent, Pid) -> init_dict_page(Parent, Pid) -> Text = init_text_page(Parent), Update = fun() -> - {dictionary,RawDict} = - observer_wx:try_rpc(node(Pid), erlang, process_info, [Pid, dictionary]), - Dict = [io_lib:format("~-20.w ~p~n", [K, V]) || {K, V} <- RawDict], - Last = wxTextCtrl:getLastPosition(Text), - wxTextCtrl:remove(Text, 0, Last), - wxTextCtrl:writeText(Text, Dict) + case observer_wx:try_rpc(node(Pid), erlang, process_info, [Pid, dictionary]) + of + {dictionary,RawDict} -> + Dict = [io_lib:format("~-20.w ~p~n", [K, V]) || {K, V} <- RawDict], + Last = wxTextCtrl:getLastPosition(Text), + wxTextCtrl:remove(Text, 0, Last), + wxTextCtrl:writeText(Text, Dict); + _ -> ok + end end, Update(), {Text, Update}. @@ -183,24 +195,29 @@ init_stack_page(Parent, Pid) -> wxListCtrl:setColumnWidth(LCtrl, 1, 300), wxListItem:destroy(Li), Update = fun() -> - {current_stacktrace,RawBt} = - observer_wx:try_rpc(node(Pid), erlang, process_info, - [Pid, current_stacktrace]), - wxListCtrl:deleteAllItems(LCtrl), - wx:foldl(fun({M, F, A, Info}, Row) -> - _Item = wxListCtrl:insertItem(LCtrl, Row, ""), - ?EVEN(Row) andalso - wxListCtrl:setItemBackgroundColour(LCtrl, Row, ?BG_EVEN), - wxListCtrl:setItem(LCtrl, Row, 0, observer_lib:to_str({M,F,A})), - FileLine = case Info of - [{file,File},{line,Line}] -> - io_lib:format("~s:~w", [File,Line]); - _ -> - [] - end, - wxListCtrl:setItem(LCtrl, Row, 1, FileLine), - Row+1 - end, 0, RawBt) + case observer_wx:try_rpc(node(Pid), erlang, process_info, + [Pid, current_stacktrace]) + of + {current_stacktrace,RawBt} -> + observer_wx:try_rpc(node(Pid), erlang, process_info, + [Pid, current_stacktrace]), + wxListCtrl:deleteAllItems(LCtrl), + wx:foldl(fun({M, F, A, Info}, Row) -> + _Item = wxListCtrl:insertItem(LCtrl, Row, ""), + ?EVEN(Row) andalso + wxListCtrl:setItemBackgroundColour(LCtrl, Row, ?BG_EVEN), + wxListCtrl:setItem(LCtrl, Row, 0, observer_lib:to_str({M,F,A})), + FileLine = case Info of + [{file,File},{line,Line}] -> + io_lib:format("~s:~w", [File,Line]); + _ -> + [] + end, + wxListCtrl:setItem(LCtrl, Row, 1, FileLine), + Row+1 + end, 0, RawBt); + _ -> ok + end end, Resize = fun(#wx{event=#wxSize{size={W,_}}},Ev) -> wxEvent:skip(Ev), @@ -216,7 +233,6 @@ create_menus(MenuBar) -> observer_lib:create_menus(Menus, MenuBar, new_window). process_info_fields(Pid) -> - RawInfo = observer_wx:try_rpc(node(Pid), erlang, process_info, [Pid, item_list()]), Struct = [{"Overview", [{"Initial Call", initial_call}, {"Current Function", current_function}, @@ -246,7 +262,12 @@ process_info_fields(Pid) -> {"GC Min Heap Size", {bytes, get_gc_info(min_heap_size)}}, {"GC FullSweep After", get_gc_info(fullsweep_after)} ]}], - observer_lib:fill_info(Struct, RawInfo). + case observer_wx:try_rpc(node(Pid), erlang, process_info, [Pid, item_list()]) of + RawInfo when is_list(RawInfo) -> + observer_lib:fill_info(Struct, RawInfo); + _ -> + ok + end. item_list() -> [ %% backtrace, diff --git a/lib/observer/src/observer_tv_table.erl b/lib/observer/src/observer_tv_table.erl index 31d5f3d632..f432173f57 100644 --- a/lib/observer/src/observer_tv_table.erl +++ b/lib/observer/src/observer_tv_table.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011. All Rights Reserved. +%% Copyright Ericsson AB 2011-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -58,7 +58,7 @@ source, tab, attrs, - timer + timer={false, 30} }). -record(opt, @@ -268,8 +268,8 @@ handle_event(#wx{id=?ID_DELETE}, handle_event(#wx{id=?wxID_CLOSE}, State) -> {stop, normal, State}; -handle_event(Help = #wx{id=?wxID_HELP}, State = #state{parent=Parent}) -> - Parent ! Help, +handle_event(Help = #wx{id=?wxID_HELP}, State) -> + observer ! Help, {noreply, State}; handle_event(#wx{id=?GOTO_ENTRY, event=#wxCommand{cmdString=Str}}, @@ -374,40 +374,51 @@ handle_event(#wx{id=?ID_REFRESH_INTERVAL}, Timer = observer_lib:interval_dialog(Grid, Timer0, 10, 5*60), {noreply, State#state{timer=Timer}}; -handle_event(Event, State) -> - io:format("~p:~p, handle event ~p\n", [?MODULE, ?LINE, Event]), +handle_event(_Event, State) -> + %io:format("~p:~p, handle event ~p\n", [?MODULE, ?LINE, Event]), {noreply, State}. -handle_sync_event(Event, _Obj, _State) -> - io:format("~p:~p, handle sync_event ~p\n", [?MODULE, ?LINE, Event]), +handle_sync_event(_Event, _Obj, _State) -> + %io:format("~p:~p, handle sync_event ~p\n", [?MODULE, ?LINE, Event]), ok. -handle_call(Event, From, State) -> - io:format("~p:~p, handle call (~p) ~p\n", [?MODULE, ?LINE, From, Event]), +handle_call(_Event, _From, State) -> + %io:format("~p:~p, handle call (~p) ~p\n", [?MODULE, ?LINE, From, Event]), {noreply, State}. -handle_cast(Event, State) -> - io:format("~p:~p, handle cast ~p\n", [?MODULE, ?LINE, Event]), +handle_cast(_Event, State) -> + %io:format("~p:~p, handle cast ~p\n", [?MODULE, ?LINE, Event]), {noreply, State}. handle_info({no_rows, N}, State = #state{grid=Grid, status=StatusBar}) -> wxListCtrl:setItemCount(Grid, N), wxStatusBar:setStatusText(StatusBar, io_lib:format("Objects: ~w",[N])), {noreply, State}; + handle_info({new_cols, New}, State = #state{grid=Grid, columns=Cols0}) -> Cols = add_columns(Grid, Cols0, New), {noreply, State#state{columns=Cols}}; + handle_info({refresh, Min, Max}, State = #state{grid=Grid}) -> wxListCtrl:refreshItems(Grid, Min, Max), {noreply, State}; + +handle_info(refresh_interval, State = #state{pid=Pid}) -> + Pid ! refresh, + {noreply, State}; + handle_info({error, Error}, State = #state{frame=Frame}) -> - Dlg = wxMessageDialog:new(Frame, Error), + ErrorStr = + try io_lib:format("~ts", [Error]), Error + catch _:_ -> io_lib:format("~p", [Error]) + end, + Dlg = wxMessageDialog:new(Frame, ErrorStr), wxMessageDialog:showModal(Dlg), wxMessageDialog:destroy(Dlg), {noreply, State}; -handle_info(Event, State) -> - io:format("~p:~p, handle info ~p\n", [?MODULE, ?LINE, Event]), +handle_info(_Event, State) -> + %% io:format("~p:~p, handle info ~p\n", [?MODULE, ?LINE, _Event]), {noreply, State}. terminate(_Event, #state{pid=Pid, attrs=Attrs}) -> @@ -588,19 +599,22 @@ search([Str, Row, Dir0, CaseSens], true -> []; false -> [caseless] end, - {ok, Re} = re:compile(Str, Opt), Dir = case Dir0 of true -> 1; false -> -1 end, - Res = search(Row, Dir, Re, Table), + Res = case re:compile(Str, Opt) of + {ok, Re} -> + search(Row, Dir, Re, Table); + {error, _} -> false + end, Parent ! {self(), Res}, S#holder{search=Res}. search(Row, Dir, Re, Table) -> Res = try lists:nth(Row+1, Table) of Term -> - Str = io_lib:format("~w", [Term]), + Str = format(Term), re:run(Str, Re) catch _:_ -> no_more end, @@ -613,9 +627,9 @@ search(Row, Dir, Re, Table) -> get_row(From, Row, Col, Table) -> case lists:nth(Row+1, Table) of [Object|_] when Col =:= all -> - From ! {self(), io_lib:format("~w", [Object])}; + From ! {self(), format(Object)}; [Object|_] when tuple_size(Object) >= Col -> - From ! {self(), io_lib:format("~w", [element(Col, Object)])}; + From ! {self(), format(element(Col, Object))}; _ -> From ! {self(), ""} end. @@ -724,3 +738,58 @@ key_pos(Node, ets, TabId) -> KeyPos = rpc:call(Node, ets, info, [TabId, keypos]), is_integer(KeyPos) orelse throw(node_or_table_down), KeyPos. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +format(Tuple) when is_tuple(Tuple) -> + [${ |format_tuple(Tuple, 1, tuple_size(Tuple))]; +format(List) when is_list(List) -> + format_list(List); +format(Bin) when is_binary(Bin), byte_size(Bin) > 100 -> + io_lib:format("<<#Bin:~w>>", [byte_size(Bin)]); +format(Float) when is_float(Float) -> + io_lib:format("~.3g", [Float]); +format(Term) -> + io_lib:format("~w", [Term]). + +format_tuple(Tuple, I, Max) when I < Max -> + [format(element(I, Tuple)), $,|format_tuple(Tuple, I+1, Max)]; +format_tuple(Tuple, Max, Max) -> + [format(element(Max, Tuple)), $}]; +format_tuple(_Tuple, 1, 0) -> + [$}]. + +format_list([]) -> "[]"; +format_list(List) -> + case printable_list(List) of + true -> io_lib:format("\"~ts\"", [List]); + false -> [$[ | make_list(List)] + end. + +make_list([Last]) -> + [format(Last), $]]; +make_list([Head|Tail]) -> + [format(Head), $,|make_list(Tail)]. + +%% printable_list([Char]) -> bool() +%% Return true if CharList is a list of printable characters, else +%% false. + +printable_list([C|Cs]) when is_integer(C), C >= $ , C =< 255 -> + printable_list(Cs); +printable_list([$\n|Cs]) -> + printable_list(Cs); +printable_list([$\r|Cs]) -> + printable_list(Cs); +printable_list([$\t|Cs]) -> + printable_list(Cs); +printable_list([$\v|Cs]) -> + printable_list(Cs); +printable_list([$\b|Cs]) -> + printable_list(Cs); +printable_list([$\f|Cs]) -> + printable_list(Cs); +printable_list([$\e|Cs]) -> + printable_list(Cs); +printable_list([]) -> true; +printable_list(_Other) -> false. %Everything else is false diff --git a/lib/observer/src/observer_tv_wx.erl b/lib/observer/src/observer_tv_wx.erl index ad3e8c14ab..b276965f83 100644 --- a/lib/observer/src/observer_tv_wx.erl +++ b/lib/observer/src/observer_tv_wx.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011. All Rights Reserved. +%% Copyright Ericsson AB 2011-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -313,7 +313,7 @@ display_table_info(Parent0, Node, Source, Table) -> list_to_strings([]) -> "None"; list_to_strings([A]) -> integer_to_list(A); -list_to_strings([A,B]) -> +list_to_strings([A|B]) -> integer_to_list(A) ++ " ," ++ list_to_strings(B). handle_error(Foo) -> diff --git a/lib/orber/src/orber_tb.erl b/lib/orber/src/orber_tb.erl index eee67296d7..d3e3a8497d 100644 --- a/lib/orber/src/orber_tb.erl +++ b/lib/orber/src/orber_tb.erl @@ -209,7 +209,7 @@ check_illegal_tcp_options([binary |T], IllegalOpts) -> check_illegal_tcp_options(T,[binary |IllegalOpts]); check_illegal_tcp_options([{reuseaddr, V} |T], IllegalOpts) -> check_illegal_tcp_options(T,[{reuseaddr, V} |IllegalOpts]); -check_illegal_tcp_options([H|T], IllegalOpts) -> +check_illegal_tcp_options([_H|T], IllegalOpts) -> check_illegal_tcp_options(T, IllegalOpts). %%---------------------------------------------------------------------- diff --git a/lib/orber/test/orber_acl_SUITE.erl b/lib/orber/test/orber_acl_SUITE.erl index b43a00be19..49107cde84 100644 --- a/lib/orber/test/orber_acl_SUITE.erl +++ b/lib/orber/test/orber_acl_SUITE.erl @@ -80,7 +80,7 @@ end_per_group(_GroupName, Config) -> %%----------------------------------------------------------------- init_per_suite(Config) -> if - list(Config) -> + is_list(Config) -> Config; true -> exit("Config not a list") diff --git a/lib/os_mon/src/cpu_sup.erl b/lib/os_mon/src/cpu_sup.erl index e414e2c10b..34251178ee 100644 --- a/lib/os_mon/src/cpu_sup.erl +++ b/lib/os_mon/src/cpu_sup.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% Copyright Ericsson AB 1997-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -764,8 +764,7 @@ port_receive_cpu_util_entries(_, _, Data) -> exit({data_mismatch, Data}). start_portprogram() -> - Command = filename:join([code:priv_dir(os_mon), "bin", "cpu_sup"]), - Port = open_port({spawn, Command}, [stream]), + Port = os_mon:open_port("cpu_sup", [stream]), port_command(Port, ?ping), 4711 = port_receive_uint32(Port, 5000), Port. diff --git a/lib/os_mon/src/memsup.erl b/lib/os_mon/src/memsup.erl index ba07a529bc..49533da1f7 100644 --- a/lib/os_mon/src/memsup.erl +++ b/lib/os_mon/src/memsup.erl @@ -802,8 +802,7 @@ port_init() -> port_idle(Port). start_portprogram() -> - Command = filename:join([code:priv_dir(os_mon), "bin", "memsup"]), - open_port({spawn, Command}, [{packet, 1}]). + os_mon:open_port("memsup",[{packet,1}]). %% The connected process loops are a bit awkward (several different %% functions doing almost the same thing) as diff --git a/lib/os_mon/src/os_mon.erl b/lib/os_mon/src/os_mon.erl index ef368571db..3098c38808 100644 --- a/lib/os_mon/src/os_mon.erl +++ b/lib/os_mon/src/os_mon.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2009. All Rights Reserved. +%% Copyright Ericsson AB 1996-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -22,7 +22,7 @@ -behaviour(supervisor). %% API --export([call/2, call/3, get_env/2]). +-export([call/2, call/3, get_env/2, open_port/2]). %% Application callbacks -export([start/2, stop/1]). @@ -79,6 +79,22 @@ get_env(Service, Param) -> Service:param_default(Param) end. +open_port(Name, Opts) -> + PrivDir = code:priv_dir(os_mon), + ReleasedPath = filename:join([PrivDir,"bin",Name]), + %% Check os_mon*/priv/bin/Name + case filelib:is_regular(ReleasedPath) of + true -> + erlang:open_port({spawn, ReleasedPath}, Opts); + false -> + %% Use os_mon*/priv/bin/Arch/Name + ArchPath = + filename:join( + [PrivDir,"bin",erlang:system_info(system_architecture),Name]), + erlang:open_port({spawn, ArchPath}, Opts) + end. + + %%%----------------------------------------------------------------- %%% Application callbacks %%%----------------------------------------------------------------- diff --git a/lib/os_mon/src/os_mon_sysinfo.erl b/lib/os_mon/src/os_mon_sysinfo.erl index 5d12bd95d1..080885d5d6 100644 --- a/lib/os_mon/src/os_mon_sysinfo.erl +++ b/lib/os_mon/src/os_mon_sysinfo.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -108,9 +108,7 @@ code_change(_OldVsn, State, _Extra) -> %%---------------------------------------------------------------------- start_portprogram() -> - Command = - filename:join([code:priv_dir(os_mon),"bin","win32sysinfo.exe"]), - Port = open_port({spawn,Command}, [{packet,1}]), + Port = os_mon:open_port("win32sysinfo.exe", [{packet,1}]), receive {Port, {data, [?OK]}} -> Port; diff --git a/lib/public_key/.gitignore b/lib/public_key/.gitignore index db24906676..d30fe62c9d 100644 --- a/lib/public_key/.gitignore +++ b/lib/public_key/.gitignore @@ -1,7 +1,7 @@ # public_key -/lib/public_key/asn1/*.asn1db -/lib/public_key/asn1/*.erl -/lib/public_key/asn1/*.hrl -/lib/public_key/include/OTP-PUB-KEY.hrl -/lib/public_key/include/PKCS-FRAME.hrl +asn1/*.asn1db +asn1/*.erl +asn1/*.hrl +include/OTP-PUB-KEY.hrl +include/PKCS-FRAME.hrl diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml index 821e7a2300..0b6673e826 100644 --- a/lib/public_key/doc/src/public_key.xml +++ b/lib/public_key/doc/src/public_key.xml @@ -453,7 +453,7 @@ <desc> <p>Encodes a list of ssh file entries (public keys and attributes) to a binary. Possible attributes depends on the file type, see <seealso - marker="ssh_decode"> ssh_decode/2 </seealso></p> + marker="#ssh_decode-2"> ssh_decode/2 </seealso></p> </desc> </func> diff --git a/lib/runtime_tools/c_src/trace_ip_drv.c b/lib/runtime_tools/c_src/trace_ip_drv.c index 5396b8afa9..7ae6c1b329 100644 --- a/lib/runtime_tools/c_src/trace_ip_drv.c +++ b/lib/runtime_tools/c_src/trace_ip_drv.c @@ -212,11 +212,11 @@ static TraceIpData *lookup_data_by_port(int portno); static int set_nonblocking(SOCKET sock); static TraceIpMessage *make_buffer(int datasiz, unsigned char op, unsigned number); -static void enque_message(TraceIpData *data, unsigned char *buff, int bufflen, +static void enque_message(TraceIpData *data, char *buff, int bufflen, int byteswritten); static void clean_que(TraceIpData *data); static void close_client(TraceIpData *data); -static int trywrite(TraceIpData *data, unsigned char *buff, int bufflen); +static int trywrite(TraceIpData *data, char *buff, int bufflen); static SOCKET my_accept(SOCKET sock); static void close_unlink_port(TraceIpData *data); enum MySelectOp { SELECT_ON, SELECT_OFF, SELECT_CLOSE }; @@ -518,7 +518,7 @@ static void trace_ip_ready_output(ErlDrvData handle, ErlDrvEvent fd) tim = data->que[data->questart]; towrite = tim->siz - tim->written; while((res = write_until_done(data->fd, - tim->bin + tim->written, towrite)) + (char *)tim->bin + tim->written, towrite)) == towrite) { driver_free(tim); data->que[data->questart] = NULL; @@ -561,7 +561,7 @@ static ErlDrvSSizeT trace_ip_control(ErlDrvData handle, TraceIpData *data = (TraceIpData *) handle; ErlDrvBinary *b = my_alloc_binary(3); b->orig_bytes[0] = '\0'; /* OK */ - put_be16(data->listen_portno, &(b->orig_bytes[1])); + put_be16(data->listen_portno, (unsigned char *)&(b->orig_bytes[1])); *res = void_ptr = b; return 0; } @@ -696,7 +696,7 @@ static TraceIpMessage *make_buffer(int datasiz, unsigned char op, ** Add message to que, discarding in a politically correct way... ** The FLAG_DROP_OLDEST is currently ingored... */ -static void enque_message(TraceIpData *data, unsigned char *buff, int bufflen, +static void enque_message(TraceIpData *data, char *buff, int bufflen, int byteswritten) { int diff = data->questop - data->questart; @@ -763,13 +763,13 @@ static void close_client(TraceIpData *data) ** Try to write a message from erlang directly (only called when que is empty ** and client is connected) */ -static int trywrite(TraceIpData *data, unsigned char *buff, int bufflen) +static int trywrite(TraceIpData *data, char *buff, int bufflen) { - unsigned char op[5]; + char op[5]; int res; op[0] = OP_BINARY; - put_be32(bufflen, op + 1); + put_be32(bufflen, (unsigned char *)op + 1); if ((res = write_until_done(data->fd, op, 5)) < 0) { close_client(data); @@ -793,7 +793,11 @@ static int trywrite(TraceIpData *data, unsigned char *buff, int bufflen) static SOCKET my_accept(SOCKET sock) { struct sockaddr_in sin; - int sin_size = sizeof(sin); +#ifdef HAVE_SOCKLEN_T + socklen_t sin_size = sizeof(sin); +#else + int sin_size = (int) sizeof(sin); +#endif return accept(sock, (struct sockaddr *) &sin, &sin_size); } diff --git a/lib/sasl/doc/src/appup.xml b/lib/sasl/doc/src/appup.xml index 195f9fe1d3..770b7c2492 100644 --- a/lib/sasl/doc/src/appup.xml +++ b/lib/sasl/doc/src/appup.xml @@ -332,7 +332,7 @@ restart_new_emulator <p>An info report will be written when the upgrade is completed. To programatically find out if the upgrade is complete, - call <seealso marker="release_handler#which_release/0"> + call <seealso marker="release_handler#which_releases/0"> release_handler:which_releases</seealso> and check if the expected release has status <c>current</c>.</p> <p>The new release must still be made permanent after the upgrade diff --git a/lib/sasl/doc/src/systools.xml b/lib/sasl/doc/src/systools.xml index 32c2149a8d..84fed0a25f 100644 --- a/lib/sasl/doc/src/systools.xml +++ b/lib/sasl/doc/src/systools.xml @@ -196,6 +196,10 @@ <p>The applications are sorted according to the dependencies between the applications. Where there are no dependencies, the order in the <c>.rel</c> file is kept.</p> + <p>The function will fail if the mandatory + applications <c>kernel</c> and <c>stdlib</c> are not + included in the <c>.rel</c> file and have start + type <c>permanent</c> (default).</p> <p>If <c>sasl</c> is not included as an application in the <c>.rel</c> file, a warning is emitted because such a release can not be used in an upgrade. To turn off this diff --git a/lib/sasl/src/systools_make.erl b/lib/sasl/src/systools_make.erl index 8fd90c50f9..12ba2a5476 100644 --- a/lib/sasl/src/systools_make.erl +++ b/lib/sasl/src/systools_make.erl @@ -463,30 +463,35 @@ check_appl(Appl) -> end, Appl) of [] -> - {ok,Ws} = mandatory_applications(Appl), - {split_app_incl(Appl),Ws}; + {ApplsNoIncls,Incls} = split_app_incl(Appl), + {ok,Ws} = mandatory_applications(ApplsNoIncls,undefined, + undefined,undefined), + {{ApplsNoIncls,Incls},Ws}; Illegal -> throw({error, {illegal_applications,Illegal}}) end. -mandatory_applications(Appl) -> - AppNames = map(fun(AppT) -> element(1, AppT) end, - Appl), - Mand = mandatory_applications(), - case filter(fun(X) -> member(X, AppNames) end, Mand) of - Mand -> - case member(sasl,AppNames) of - true -> - {ok,[]}; - _ -> - {ok, [{warning,missing_sasl}]} - end; - _ -> - throw({error, {missing_mandatory_app, Mand}}) - end. - -mandatory_applications() -> - [kernel, stdlib]. +mandatory_applications([{kernel,_,Type}|Apps],undefined,Stdlib,Sasl) -> + mandatory_applications(Apps,Type,Stdlib,Sasl); +mandatory_applications([{stdlib,_,Type}|Apps],Kernel,undefined,Sasl) -> + mandatory_applications(Apps,Kernel,Type,Sasl); +mandatory_applications([{sasl,_,Type}|Apps],Kernel,Stdlib,undefined) -> + mandatory_applications(Apps,Kernel,Stdlib,Type); +mandatory_applications([_|Apps],Kernel,Stdlib,Sasl) -> + mandatory_applications(Apps,Kernel,Stdlib,Sasl); +mandatory_applications([],Type,_,_) when Type=/=permanent -> + error_mandatory_application(kernel,Type); +mandatory_applications([],_,Type,_) when Type=/=permanent -> + error_mandatory_application(sasl,Type); +mandatory_applications([],_,_,undefined) -> + {ok, [{warning,missing_sasl}]}; +mandatory_applications([],_,_,_) -> + {ok,[]}. + +error_mandatory_application(App,undefined) -> + throw({error, {missing_mandatory_app, App}}); +error_mandatory_application(App,Type) -> + throw({error, {mandatory_app, App, Type}}). split_app_incl(Appl) -> split_app_incl(Appl, [], []). @@ -1677,6 +1682,7 @@ add_system_files(Tar, RelName, Release, Path1) -> false -> ignore; Relup -> + check_relup(Relup), add_to_tar(Tar, Relup, filename:join(RelVsnDir, "relup")) end, @@ -1684,6 +1690,7 @@ add_system_files(Tar, RelName, Release, Path1) -> false -> ignore; Sys -> + check_sys_config(Sys), add_to_tar(Tar, Sys, filename:join(RelVsnDir, "sys.config")) end, @@ -1700,6 +1707,44 @@ lookup_file(Name, [Dir|Path]) -> lookup_file(_Name, []) -> false. +%% Check that relup can be parsed and has expected format +check_relup(File) -> + case file:consult(File) of + {ok,[{Vsn,UpFrom,DownTo}]} when is_list(Vsn), is_integer(hd(Vsn)), + is_list(UpFrom), is_list(DownTo) -> + ok; + {ok,_} -> + throw({error,{tar_error,{add,"relup",[invalid_format]}}}); + Other -> + throw({error,{tar_error,{add,"relup",[Other]}}}) + end. + +%% Check that sys.config can be parsed and has expected format +check_sys_config(File) -> + case file:consult(File) of + {ok,[SysConfig]} -> + case lists:all(fun({App,KeyVals}) when is_atom(App), + is_list(KeyVals)-> + true; + (OtherConfig) when is_list(OtherConfig), + is_integer(hd(OtherConfig)) -> + true; + (_) -> + false + end, + SysConfig) of + true -> + ok; + false -> + throw({error,{tar_error, + {add,"sys.config",[invalid_format]}}}) + end; + {ok,_} -> + throw({error,{tar_error,{add,"sys.config",[invalid_format]}}}); + Other -> + throw({error,{tar_error,{add,"sys.config",[Other]}}}) + end. + %%______________________________________________________________________ %% Add either a application located under a variable dir or all other %% applications to a tar file. @@ -2187,9 +2232,12 @@ format_error({missing_parameter,Par}) -> format_error({illegal_applications,Names}) -> io_lib:format("Illegal applications in the release file: ~p~n", [Names]); -format_error({missing_mandatory_app,Names}) -> - io_lib:format("Mandatory applications (~p) must be specified in the release file~n", - [Names]); +format_error({missing_mandatory_app,Name}) -> + io_lib:format("Mandatory application ~p must be specified in the release file~n", + [Name]); +format_error({mandatory_app,Name,Type}) -> + io_lib:format("Mandatory application ~p must be of type 'permanent' in the release file. Is '~p'.~n", + [Name,Type]); format_error({duplicate_register,Dups}) -> io_lib:format("Duplicated register names: ~n~s", [map(fun({{Reg,App1,_,_},{Reg,App2,_,_}}) -> diff --git a/lib/sasl/test/systools_SUITE.erl b/lib/sasl/test/systools_SUITE.erl index 43366d8917..4cf7364d74 100644 --- a/lib/sasl/test/systools_SUITE.erl +++ b/lib/sasl/test/systools_SUITE.erl @@ -46,9 +46,11 @@ included_script/1, included_override_script/1, included_fail_script/1, included_bug_script/1, exref_script/1, otp_3065_circular_dependenies/1]). --export([tar_options/1, normal_tar/1, no_mod_vsn_tar/1, variable_tar/1, - src_tests_tar/1, var_tar/1, - exref_tar/1, link_tar/1, otp_9507_path_ebin/1]). +-export([tar_options/1, normal_tar/1, no_mod_vsn_tar/1, system_files_tar/1, + system_files_tar/2, invalid_system_files_tar/1, + invalid_system_files_tar/2, variable_tar/1, + src_tests_tar/1, var_tar/1, exref_tar/1, link_tar/1, + otp_9507_path_ebin/1]). -export([normal_relup/1, restart_relup/1, abnormal_relup/1, no_sasl_relup/1, no_appup_relup/1, bad_appup_relup/1, app_start_type_relup/1, regexp_relup/1]). @@ -80,7 +82,8 @@ groups() -> included_fail_script, included_bug_script, exref_script, otp_3065_circular_dependenies]}, {tar, [], - [tar_options, normal_tar, no_mod_vsn_tar, variable_tar, + [tar_options, normal_tar, no_mod_vsn_tar, system_files_tar, + invalid_system_files_tar, variable_tar, src_tests_tar, var_tar, exref_tar, link_tar, otp_9507_path_ebin]}, {relup, [], [normal_relup, restart_relup, abnormal_relup, no_sasl_relup, @@ -146,7 +149,10 @@ init_per_testcase(_Case, Config) -> Dog = test_server:timetrap(?default_timeout), [{watchdog, Dog}|Config]. -end_per_testcase(_Case, Config) -> +end_per_testcase(Case, Config) -> + try apply(?MODULE,Case,[cleanup,Config]) + catch error:undef -> ok + end, Dog=?config(watchdog, Config), test_server:timetrap_cancel(Dog), case {?config(path,Config),?config(cwd,Config)} of @@ -483,9 +489,17 @@ crazy_script(Config) when is_list(Config) -> ok = file:set_cwd(LatestDir2), error = systools:make_script(LatestName2), - {error, _, {missing_mandatory_app,[kernel,stdlib]}} = + {error, _, {missing_mandatory_app,kernel}} = systools:make_script(LatestName2, [silent,{path,P}]), + %% Run with .rel file with non-permanent kernel + {LatestDir3, LatestName3} = create_script(latest_kernel_start_type, Config), + ok = file:set_cwd(LatestDir3), + + error = systools:make_script(LatestName3), + {error, _, {mandatory_app,kernel,load}} = + systools:make_script(LatestName3, [silent,{path,P}]), + ok = file:set_cwd(OldDir), ok. @@ -756,6 +770,102 @@ no_mod_vsn_tar(Config) when is_list(Config) -> ok = file:set_cwd(OldDir), ok. + +%% make_tar: Check that relup or sys.config are included if they exist +system_files_tar(Config) -> + {ok, OldDir} = file:get_cwd(), + + {LatestDir, LatestName} = create_script(latest,Config), + + DataDir = filename:absname(?copydir), + LibDir = fname([DataDir, d_normal, lib]), + P = [fname([LibDir, 'db-2.1', ebin]), + fname([LibDir, 'fe-3.1', ebin])], + + ok = file:set_cwd(LatestDir), + + %% Add dummy relup and sys.config + ok = file:write_file("sys.config","[].\n"), + ok = file:write_file("relup","{\"LATEST\",[],[]}.\n"), + + {ok, _, _} = systools:make_script(LatestName, [silent, {path, P}]), + ok = systools:make_tar(LatestName, [{path, P}]), + ok = check_tar(fname(["releases","LATEST","sys.config"]), LatestName), + ok = check_tar(fname(["releases","LATEST","relup"]), LatestName), + {ok, _, _} = systools:make_tar(LatestName, [{path, P}, silent]), + ok = check_tar(fname(["releases","LATEST","sys.config"]), LatestName), + ok = check_tar(fname(["releases","LATEST","relup"]), LatestName), + + ok = file:set_cwd(OldDir), + + ok. + +system_files_tar(cleanup,Config) -> + Dir = ?privdir, + file:delete(filename:join(Dir,"sys.config")), + file:delete(filename:join(Dir,"relup")), + ok. + + +%% make_tar: Check that make_tar fails if relup or sys.config exist +%% but do not have valid content +invalid_system_files_tar(Config) -> + {ok, OldDir} = file:get_cwd(), + + {LatestDir, LatestName} = create_script(latest,Config), + + DataDir = filename:absname(?copydir), + LibDir = fname([DataDir, d_normal, lib]), + P = [fname([LibDir, 'db-2.1', ebin]), + fname([LibDir, 'fe-3.1', ebin])], + + ok = file:set_cwd(LatestDir), + + {ok, _, _} = systools:make_script(LatestName, [silent, {path, P}]), + + %% Add dummy relup and sys.config - faulty sys.config + ok = file:write_file("sys.config","[]\n"), %!!! syntax error - missing '.' + ok = file:write_file("relup","{\"LATEST\",[],[]}.\n"), + + error = systools:make_tar(LatestName, [{path, P}]), + {error,_,{tar_error,{add,"sys.config",[{error,_}]}}} = + systools:make_tar(LatestName, [{path, P}, silent]), + + %% Add dummy relup and sys.config - faulty sys.config + ok = file:write_file("sys.config","[x,y].\n"), %!!! faulty format + ok = file:write_file("relup","{\"LATEST\",[],[]}.\n"), + + error = systools:make_tar(LatestName, [{path, P}]), + {error,_,{tar_error,{add,"sys.config",[invalid_format]}}} = + systools:make_tar(LatestName, [{path, P}, silent]), + + %% Add dummy relup and sys.config - faulty relup + ok = file:write_file("sys.config","[]\n"), + ok = file:write_file("relup","{\"LATEST\"\n"), %!!! syntax error - truncated + + error = systools:make_tar(LatestName, [{path, P}]), + {error,_,{tar_error,{add,"relup",[{error,_}]}}} = + systools:make_tar(LatestName, [{path, P}, silent]), + + %% Add dummy relup and sys.config - faulty relup + ok = file:write_file("sys.config","[]\n"), + ok = file:write_file("relup","[].\n"), %!!! faulty format + + error = systools:make_tar(LatestName, [{path, P}]), + {error,_,{tar_error,{add,"relup",[invalid_format]}}} = + systools:make_tar(LatestName, [{path, P}, silent]), + + ok = file:set_cwd(OldDir), + + ok. + +invalid_system_files_tar(cleanup,Config) -> + Dir = ?privdir, + file:delete(filename:join(Dir,"sys.config")), + file:delete(filename:join(Dir,"relup")), + ok. + + %% make_tar: Use variable and create separate tar (included in generated tar). variable_tar(Config) when is_list(Config) -> {ok, OldDir} = file:get_cwd(), @@ -1915,6 +2025,9 @@ create_script(latest_small2,Config) -> create_script(latest_nokernel,Config) -> Apps = [{db,"2.1"},{fe,"3.1"}], do_create_script(latest_nokernel,Config,"4.4",Apps); +create_script(latest_kernel_start_type,Config) -> + Apps = [{kernel,"1.0",load},{db,"2.1"},{fe,"3.1"}], + do_create_script(latest_kernel_start_type,Config,"4.4",Apps); create_script(latest_app_start_type1,Config) -> Apps = core_apps(current), do_create_script(latest_app_start_type1,Config,current,Apps); diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl index 5ea0d98980..73b60057cc 100644 --- a/lib/ssh/test/ssh_basic_SUITE.erl +++ b/lib/ssh/test/ssh_basic_SUITE.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 @@ -41,9 +41,20 @@ init_per_suite(Config) -> case catch crypto:start() of ok -> - Dir = ?config(priv_dir, Config), - {ok, _} = ssh_test_lib:get_id_keys(Dir), - ssh_test_lib:make_dsa_files(Config), + DataDir = ?config(data_dir, Config), + UserDir = ?config(priv_dir, Config), + ssh_test_lib:copyfile(DataDir, UserDir, "id_rsa"), + ssh_test_lib:copyfile(DataDir, UserDir, "id_dsa"), + RSAFile = filename:join(DataDir, "id_rsa.pub"), + DSAFile = filename:join(DataDir, "id_dsa.pub"), + {ok, Ssh1} = file:read_file(RSAFile), + {ok, Ssh2} = file:read_file(DSAFile), + [{RSA, _}] = public_key:ssh_decode(Ssh1,public_key), + [{DSA, _}] = public_key:ssh_decode(Ssh2,public_key), + AuthKeys = public_key:ssh_encode([{RSA, [{comment, "Test"}]}, + {DSA,[{comment, "Test"}]}], auth_keys), + AuthKeysFile = filename:join(UserDir, "authorized_keys"), + file:write_file(AuthKeysFile, AuthKeys), Config; _Else -> {skip, "Crypto could not be started!"} @@ -56,9 +67,7 @@ init_per_suite(Config) -> %% Description: Cleanup after the whole suite %%-------------------------------------------------------------------- end_per_suite(Config) -> - Dir = ?config(priv_dir, Config), crypto:stop(), - ssh_test_lib:remove_id_keys(Dir), ok. %%-------------------------------------------------------------------- @@ -75,7 +84,6 @@ end_per_suite(Config) -> %% Description: Initialization before each test case %%-------------------------------------------------------------------- init_per_testcase(_TestCase, Config) -> - ssh_test_lib:known_hosts(backup), ssh:start(), Config. @@ -87,9 +95,16 @@ init_per_testcase(_TestCase, Config) -> %% A list of key/value pairs, holding the test case configuration. %% Description: Cleanup after each test case %%-------------------------------------------------------------------- -end_per_testcase(_TestCase, _Config) -> + +end_per_testcase(TestCase, Config) when TestCase == server_password_option; + TestCase == server_userpassword_option -> + UserDir = filename:join(?config(priv_dir, Config), nopubkey), + file:del_dir(UserDir), + end_per_testcase(Config); +end_per_testcase(_TestCase, Config) -> + end_per_testcase(Config). +end_per_testcase(Config) -> ssh:stop(), - ssh_test_lib:known_hosts(restore), ok. %%-------------------------------------------------------------------- @@ -101,9 +116,8 @@ end_per_testcase(_TestCase, _Config) -> %% Description: Returns a list of all test cases in this test suite %%-------------------------------------------------------------------- all() -> - [exec, exec_compressed, shell, daemon_already_started, - server_password_option, server_userpassword_option, - known_hosts]. + [exec, exec_compressed, shell, daemon_already_started, + server_password_option, server_userpassword_option, known_hosts]. groups() -> []. @@ -136,10 +150,14 @@ exec(suite) -> exec(Config) when is_list(Config) -> process_flag(trap_exit, true), SystemDir = ?config(data_dir, Config), + UserDir = ?config(priv_dir, Config), + {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, + {user_dir, UserDir}, {failfun, fun ssh_test_lib:failfun/2}]), ConnectionRef = ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, + {user_dir, UserDir}, {user_interaction, false}]), {ok, ChannelId0} = ssh_connection:session_channel(ConnectionRef, infinity), success = ssh_connection:exec(ConnectionRef, ChannelId0, @@ -178,12 +196,15 @@ exec_compressed(suite) -> exec_compressed(Config) when is_list(Config) -> process_flag(trap_exit, true), SystemDir = ?config(data_dir, Config), - {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, + UserDir = ?config(priv_dir, Config), + + {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},{user_dir, UserDir}, {compression, zlib}, {failfun, fun ssh_test_lib:failfun/2}]), ConnectionRef = ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, + {user_dir, UserDir}, {user_interaction, false}]), {ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity), success = ssh_connection:exec(ConnectionRef, ChannelId, @@ -209,12 +230,14 @@ shell(suite) -> shell(Config) when is_list(Config) -> process_flag(trap_exit, true), SystemDir = ?config(data_dir, Config), - {_Pid, _Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, + UserDir = ?config(priv_dir, Config), + + {_Pid, _Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},{user_dir, UserDir}, {failfun, fun ssh_test_lib:failfun/2}]), test_server:sleep(500), IO = ssh_test_lib:start_io_server(), - Shell = ssh_test_lib:start_shell(Port, IO), + Shell = ssh_test_lib:start_shell(Port, IO, UserDir), receive ErlShellStart -> test_server:format("Erlang shell start: ~p~n", [ErlShellStart]) @@ -291,8 +314,9 @@ server_password_option(doc) -> server_password_option(suite) -> []; server_password_option(Config) when is_list(Config) -> - UserDir = ?config(data_dir, Config), % to make sure we don't use - SysDir = ?config(data_dir, Config), % public-key-auth + UserDir = filename:join(?config(priv_dir, Config), nopubkey), % to make sure we don't use public-key-auth + file:make_dir(UserDir), + SysDir = ?config(data_dir, Config), {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir}, {password, "morot"}]), @@ -321,8 +345,9 @@ server_userpassword_option(doc) -> server_userpassword_option(suite) -> []; server_userpassword_option(Config) when is_list(Config) -> - UserDir = ?config(data_dir, Config), % to make sure we don't use - SysDir = ?config(data_dir, Config), % public-key-auth + UserDir = filename:join(?config(priv_dir, Config), nopubkey), % to make sure we don't use public-key-auth + file:make_dir(UserDir), + SysDir = ?config(data_dir, Config), {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir}, {user_passwords, [{"vego", "morot"}]}]), @@ -361,10 +386,10 @@ known_hosts(doc) -> known_hosts(suite) -> []; known_hosts(Config) when is_list(Config) -> - SystemDir = ?config(data_dir, Config), + DataDir = ?config(data_dir, Config), UserDir = ?config(priv_dir, Config), - - {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, + + {Pid, Host, Port} = ssh_test_lib:daemon([{user_dir, UserDir},{system_dir, DataDir}, {failfun, fun ssh_test_lib:failfun/2}]), KnownHosts = filename:join(UserDir, "known_hosts"), diff --git a/lib/ssh/test/ssh_basic_SUITE_data/id_dsa b/lib/ssh/test/ssh_basic_SUITE_data/id_dsa new file mode 100644 index 0000000000..d306f8b26e --- /dev/null +++ b/lib/ssh/test/ssh_basic_SUITE_data/id_dsa @@ -0,0 +1,13 @@ +-----BEGIN DSA PRIVATE KEY----- +MIIBvAIBAAKBgQDfi2flSTZZofwT4yQT0NikX/LGNT7UPeB/XEWe/xovEYCElfaQ +APFixXvEgXwoojmZ5kiQRKzLM39wBP0jPERLbnZXfOOD0PDnw0haMh7dD7XKVMod +/EigVgHf/qBdM2M8yz1s/rRF7n1UpLSypziKjkzCm7JoSQ2zbWIPdmBIXwIVAMgP +kpr7Sq3O7sHdb8D601DRjoExAoGAMOQxDfB2Fd8ouz6G96f/UOzRMI/Kdv8kYYKW +JIGY+pRYrLPyYzUeJznwZreOJgrczAX+luHnKFWJ2Dnk5CyeXk67Wsr7pJ/4MBMD +OKeIS0S8qoSBN8+Krp79fgA+yS3IfqbkJLtLu4EBaCX4mKQIX4++k44d4U5lc8pt ++9hlEI8CgYEAznKxx9kyC6bVo7LUYKaGhofRFt0SYFc5PVmT2VUGRs1R6+6DPD+e +uEO6IhFct7JFSRbP9p0JD4Uk+3zlZF+XX6b2PsZkeV8f/02xlNGUSmEzCSiNg1AX +Cy/WusYhul0MncWCHMcOZB5rIvU/aP5EJJtn3xrRaz6u0SThF6AnT34CFQC63czE +ZU8w8Q+H7z0j+a+70x2iAw== +-----END DSA PRIVATE KEY----- + diff --git a/lib/ssh/test/ssh_basic_SUITE_data/id_dsa.pub b/lib/ssh/test/ssh_basic_SUITE_data/id_dsa.pub new file mode 100644 index 0000000000..9406116777 --- /dev/null +++ b/lib/ssh/test/ssh_basic_SUITE_data/id_dsa.pub @@ -0,0 +1 @@ +ssh-dss AAAAB3NzaC1kc3MAAACBAN+LZ+VJNlmh/BPjJBPQ2KRf8sY1PtQ94H9cRZ7/Gi8RgISV9pAA8WLFe8SBfCiiOZnmSJBErMszf3AE/SM8REtudld844PQ8OfDSFoyHt0PtcpUyh38SKBWAd/+oF0zYzzLPWz+tEXufVSktLKnOIqOTMKbsmhJDbNtYg92YEhfAAAAFQDID5Ka+0qtzu7B3W/A+tNQ0Y6BMQAAAIAw5DEN8HYV3yi7Pob3p/9Q7NEwj8p2/yRhgpYkgZj6lFiss/JjNR4nOfBmt44mCtzMBf6W4ecoVYnYOeTkLJ5eTrtayvukn/gwEwM4p4hLRLyqhIE3z4qunv1+AD7JLch+puQku0u7gQFoJfiYpAhfj76Tjh3hTmVzym372GUQjwAAAIEAznKxx9kyC6bVo7LUYKaGhofRFt0SYFc5PVmT2VUGRs1R6+6DPD+euEO6IhFct7JFSRbP9p0JD4Uk+3zlZF+XX6b2PsZkeV8f/02xlNGUSmEzCSiNg1AXCy/WusYhul0MncWCHMcOZB5rIvU/aP5EJJtn3xrRaz6u0SThF6AnT34= Dsa diff --git a/lib/ssh/test/ssh_basic_SUITE_data/id_rsa b/lib/ssh/test/ssh_basic_SUITE_data/id_rsa new file mode 100644 index 0000000000..79968bdd7d --- /dev/null +++ b/lib/ssh/test/ssh_basic_SUITE_data/id_rsa @@ -0,0 +1,16 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQDCZX+4FBDwZIh9y/Uxee1VJnEXlowpz2yDKwj8semM4q843337 +zbNfxHmladB1lpz2NqyxI175xMIJuDxogyZdsOxGnFAzAnthR4dqL/RWRWzjaxSB +6IAO9SPYVVlrpZ+1hsjLW79fwXK/yc8VdhRuWTeQiRgYY2ek8+OKbOqz4QIDAQAB +AoGANmvJzJO5hkLuvyDZHKfAnGTtpifcR1wtSa9DjdKUyn8vhKF0mIimnbnYQEmW +NUUb3gXCZLi9PvkpRSVRrASDOZwcjoU/Kvww163vBUVb2cOZfFhyn6o2Sk88Tt++ +udH3hdjpf9i7jTtUkUe+QYPsia+wgvvrmn4QrahLAH86+kECQQDx5gFeXTME3cnW +WMpFz3PPumduzjqgqMMWEccX4FtQkMX/gyGa5UC7OHFyh0N/gSWvPbRHa8A6YgIt +n8DO+fh5AkEAzbqX4DOn8NY6xJIi42q7l/2jIA0RkB6P7YugW5NblhqBZ0XDnpA5 +sMt+rz+K07u9XZtxgh1xi7mNfwY6lEAMqQJBAJBEauCKmRj35Z6OyeQku59SPsnY ++SJEREVvSNw2lH9SOKQQ4wPsYlTGbvKtNVZgAcen91L5MmYfeckYE/fdIZECQQCt +64zxsTnM1I8iFxj/gP/OYlJBikrKt8udWmjaghzvLMEw+T2DExJyb9ZNeT53+UMB +m6O+B/4xzU/djvp+0hbhAkAemIt+rA5kTmYlFndhpvzkSSM8a2EXsO4XIPgGWCTT +tQKS/tTly0ADMjN/TVy11+9d6zcqadNVuHXHGtR4W0GR +-----END RSA PRIVATE KEY----- + diff --git a/lib/ssh/test/ssh_basic_SUITE_data/id_rsa.pub b/lib/ssh/test/ssh_basic_SUITE_data/id_rsa.pub new file mode 100644 index 0000000000..95bce6bc61 --- /dev/null +++ b/lib/ssh/test/ssh_basic_SUITE_data/id_rsa.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDCZX+4FBDwZIh9y/Uxee1VJnEXlowpz2yDKwj8semM4q843337zbNfxHmladB1lpz2NqyxI175xMIJuDxogyZdsOxGnFAzAnthR4dqL/RWRWzjaxSB6IAO9SPYVVlrpZ+1hsjLW79fwXK/yc8VdhRuWTeQiRgYY2ek8+OKbOqz4Q== ingela@dain diff --git a/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_dsa_key b/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_dsa_key new file mode 100644 index 0000000000..d306f8b26e --- /dev/null +++ b/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_dsa_key @@ -0,0 +1,13 @@ +-----BEGIN DSA PRIVATE KEY----- +MIIBvAIBAAKBgQDfi2flSTZZofwT4yQT0NikX/LGNT7UPeB/XEWe/xovEYCElfaQ +APFixXvEgXwoojmZ5kiQRKzLM39wBP0jPERLbnZXfOOD0PDnw0haMh7dD7XKVMod +/EigVgHf/qBdM2M8yz1s/rRF7n1UpLSypziKjkzCm7JoSQ2zbWIPdmBIXwIVAMgP +kpr7Sq3O7sHdb8D601DRjoExAoGAMOQxDfB2Fd8ouz6G96f/UOzRMI/Kdv8kYYKW +JIGY+pRYrLPyYzUeJznwZreOJgrczAX+luHnKFWJ2Dnk5CyeXk67Wsr7pJ/4MBMD +OKeIS0S8qoSBN8+Krp79fgA+yS3IfqbkJLtLu4EBaCX4mKQIX4++k44d4U5lc8pt ++9hlEI8CgYEAznKxx9kyC6bVo7LUYKaGhofRFt0SYFc5PVmT2VUGRs1R6+6DPD+e +uEO6IhFct7JFSRbP9p0JD4Uk+3zlZF+XX6b2PsZkeV8f/02xlNGUSmEzCSiNg1AX +Cy/WusYhul0MncWCHMcOZB5rIvU/aP5EJJtn3xrRaz6u0SThF6AnT34CFQC63czE +ZU8w8Q+H7z0j+a+70x2iAw== +-----END DSA PRIVATE KEY----- + diff --git a/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_rsa_key b/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_rsa_key new file mode 100644 index 0000000000..79968bdd7d --- /dev/null +++ b/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_rsa_key @@ -0,0 +1,16 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQDCZX+4FBDwZIh9y/Uxee1VJnEXlowpz2yDKwj8semM4q843337 +zbNfxHmladB1lpz2NqyxI175xMIJuDxogyZdsOxGnFAzAnthR4dqL/RWRWzjaxSB +6IAO9SPYVVlrpZ+1hsjLW79fwXK/yc8VdhRuWTeQiRgYY2ek8+OKbOqz4QIDAQAB +AoGANmvJzJO5hkLuvyDZHKfAnGTtpifcR1wtSa9DjdKUyn8vhKF0mIimnbnYQEmW +NUUb3gXCZLi9PvkpRSVRrASDOZwcjoU/Kvww163vBUVb2cOZfFhyn6o2Sk88Tt++ +udH3hdjpf9i7jTtUkUe+QYPsia+wgvvrmn4QrahLAH86+kECQQDx5gFeXTME3cnW +WMpFz3PPumduzjqgqMMWEccX4FtQkMX/gyGa5UC7OHFyh0N/gSWvPbRHa8A6YgIt +n8DO+fh5AkEAzbqX4DOn8NY6xJIi42q7l/2jIA0RkB6P7YugW5NblhqBZ0XDnpA5 +sMt+rz+K07u9XZtxgh1xi7mNfwY6lEAMqQJBAJBEauCKmRj35Z6OyeQku59SPsnY ++SJEREVvSNw2lH9SOKQQ4wPsYlTGbvKtNVZgAcen91L5MmYfeckYE/fdIZECQQCt +64zxsTnM1I8iFxj/gP/OYlJBikrKt8udWmjaghzvLMEw+T2DExJyb9ZNeT53+UMB +m6O+B/4xzU/djvp+0hbhAkAemIt+rA5kTmYlFndhpvzkSSM8a2EXsO4XIPgGWCTT +tQKS/tTly0ADMjN/TVy11+9d6zcqadNVuHXHGtR4W0GR +-----END RSA PRIVATE KEY----- + diff --git a/lib/ssh/test/ssh_sftp_SUITE.erl b/lib/ssh/test/ssh_sftp_SUITE.erl index c96b6de3ea..a9a568ced6 100644 --- a/lib/ssh/test/ssh_sftp_SUITE.erl +++ b/lib/ssh/test/ssh_sftp_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2011. All Rights Reserved. +%% Copyright Ericsson AB 2005-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -50,7 +50,6 @@ init_per_suite(Config) -> {ok,ok} -> Dir = ?config(priv_dir, Config), {ok, _} = ssh_test_lib:get_id_keys(Dir), - ssh_test_lib:make_dsa_files(Config), Config; {ok,_} -> {skip,"Could not start ssh!"}; @@ -94,13 +93,14 @@ init_per_testcase(_Case, Config) -> SysDir = ?config(data_dir, Config), Host = ssh_test_lib:hostname(), + %% Run test against openssh server if available Sftp = case (catch ssh_sftp:start_channel(Host, [{user_dir, Dir}, {user_interaction, false}, {silently_accept_hosts, true}])) of {ok, ChannelPid, Connection} -> {ChannelPid, Connection}; - _Error -> + _Error -> %% Start own sftp server {_Sftpd, _Host, _Port} = ssh_test_lib:daemon(Host, ?SFPD_PORT, [{system_dir, SysDir}, diff --git a/lib/ssh/test/ssh_sftp_SUITE_data/id_rsa b/lib/ssh/test/ssh_sftp_SUITE_data/id_rsa deleted file mode 100644 index 7e3f885f5d..0000000000 --- a/lib/ssh/test/ssh_sftp_SUITE_data/id_rsa +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIICWwIBAAKBgQDLKYTdRnGzphcN+pF8UuI3sYB7rxZUHbOT87K3vh8XOLkDOsS3 -8VREtNS8Wb3uYXsRtyDoUvrLIDnyllOfJSDupWLr4ibckUZd/nhFAaC6WryVmH6k -GlQLLp9KU+vcn2DwYeo14gbwHYDB3pmv4CWAlnO1m/BkX4aLz1zC314OkQIBIwKB -gD/Z2UzboBPjvhpWEHeHw3CW3zzQoJ4X9pw2peH57IOkHOPCA0/A3/hWFvleCH4e -owWRU3w3ViKVGYbBh/7RJ5rllN+ENUmVn536srJTxLKUtvb5jRGj3W6EWgAGHSUB -hm83Kt9Lb5hprL7dPrNGvSseBm/LQSfBQ4vUUyiVRKGPAkEA/rPxWoLdBBP+FZtE -fGzz9izPM6Fe6o8ZGNZIlRBProOhgEvvIqdgzQWObgLVVrw+M/YApPpiYS3PEmWj -b2b+jwJBAMwyYeL6coKTl8swDu8HvLnshgUFJFTtHhOTXsKtXQNI1b24xhUrB3Sb -X8fmoByyRNRpOfvg4Jdqi3Z6KfIcsN8CQQDEfC83McBw3DkJWoVKCugVrYnmACSm -USH9N5cT6AL0VupNB2C0VTwL37cEaJXyc/V4ipLIaWHV8CNl9qKmZWVJAkEAurG4 -lQI8zyfbPW3EgsU+1d+QeZ5NGnJkpC73jWtNudwxIn0M4CdXRgpmMxwAGjyWs5No -Nr75OfsDKn5SPHIAywJAKrtONlOizgDiG3EvAXZlwFtOb+HkQ7lrFwczrQu9m7yi -brSAcnTrLKI6CrR33b/QJLvb9C/HTEZojFABGq8M7A== ------END RSA PRIVATE KEY----- diff --git a/lib/ssh/test/ssh_sftp_SUITE_data/id_rsa.pub b/lib/ssh/test/ssh_sftp_SUITE_data/id_rsa.pub deleted file mode 100644 index 77f57de4af..0000000000 --- a/lib/ssh/test/ssh_sftp_SUITE_data/id_rsa.pub +++ /dev/null @@ -1 +0,0 @@ -ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAyymE3UZxs6YXDfqRfFLiN7GAe68WVB2zk/Oyt74fFzi5AzrEt/FURLTUvFm97mF7Ebcg6FL6yyA58pZTnyUg7qVi6+Im3JFGXf54RQGgulq8lZh+pBpUCy6fSlPr3J9g8GHqNeIG8B2Awd6Zr+AlgJZztZvwZF+Gi89cwt9eDpE= jakob@balin diff --git a/lib/ssh/test/ssh_sftpd_SUITE.erl b/lib/ssh/test/ssh_sftpd_SUITE.erl index bfe54a3e75..0873348be0 100644 --- a/lib/ssh/test/ssh_sftpd_SUITE.erl +++ b/lib/ssh/test/ssh_sftpd_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2011. All Rights Reserved. +%% Copyright Ericsson AB 2006-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 @@ -53,16 +53,15 @@ %% variable, but should NOT alter/remove any existing entries. %%-------------------------------------------------------------------- init_per_suite(Config) -> - case {catch ssh:stop(),catch crypto:start()} of - {ok,ok} -> - ssh_test_lib:make_dsa_files(Config), + case (catch crypto:start()) of + ok -> + ssh:start(), + DataDir = ?config(data_dir, Config), + UserDir = ?config(priv_dir, Config), + ssh_test_lib:setup_dsa(UserDir, DataDir), Config; - {ok,_} -> - {skip,"Could not start ssh!"}; - {_,ok} -> - {skip,"Could not start crypto!"}; - {_,_} -> - {skip,"Could not start crypto and ssh!"} + _ -> + {skip,"Could not start ssh!"} end. %%-------------------------------------------------------------------- @@ -71,7 +70,10 @@ init_per_suite(Config) -> %% A list of key/value pairs, holding the test case configuration. %% Description: Cleanup after the whole suite %%-------------------------------------------------------------------- -end_per_suite(_Config) -> +end_per_suite(Config) -> + UserDir = ?config(priv_dir, Config), + ssh_test_lib:clean_dsa(UserDir), + ssh:stop(), crypto:stop(), ok. diff --git a/lib/ssh/test/ssh_sftpd_SUITE_data/ssh_host_dsa_key b/lib/ssh/test/ssh_sftpd_SUITE_data/ssh_host_dsa_key new file mode 100644 index 0000000000..51ab6fbd88 --- /dev/null +++ b/lib/ssh/test/ssh_sftpd_SUITE_data/ssh_host_dsa_key @@ -0,0 +1,13 @@ +-----BEGIN DSA PRIVATE KEY----- +MIIBuwIBAAKBgQCClaHzE2ul0gKSUxah5W0W8UiJLy4hXngKEqpaUq9SSdVdY2LK +wVfKH1gt5iuaf1FfzOhsIC9G/GLnjYttXZc92cv/Gfe3gR+s0ni2++MX+T++mE/Q +diltXv/Hp27PybS67SmiFW7I+RWnT2OKlMPtw2oUuKeztCe5UWjaj/y5FQIVAPLA +l9RpiU30Z87NRAHY3NTRaqtrAoGANMRxw8UfdtNVR0CrQj3AgPaXOGE4d+G4Gp4X +skvnCHycSVAjtYxebUkzUzt5Q6f/IabuLUdge3gXrc8BetvrcKbp+XZgM0/Vj2CF +Ymmy3in6kzGZq7Fw1sZaku6AOU8vLa5woBT2vAcHLLT1bLAzj7viL048T6MfjrOP +ef8nHvACgYBhDWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah +/XcF3DeRF+eEoz48wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+U +ykSTXYUbtsfTNRFQGBW2/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0CgIVAN4wtL5W +Lv62jKcdskxNyz2NQoBx +-----END DSA PRIVATE KEY----- + diff --git a/lib/ssh/test/ssh_sftpd_SUITE_data/ssh_host_dsa_key.pub b/lib/ssh/test/ssh_sftpd_SUITE_data/ssh_host_dsa_key.pub new file mode 100644 index 0000000000..4dbb1305b0 --- /dev/null +++ b/lib/ssh/test/ssh_sftpd_SUITE_data/ssh_host_dsa_key.pub @@ -0,0 +1,11 @@ +---- BEGIN SSH2 PUBLIC KEY ---- +AAAAB3NzaC1kc3MAAACBAIKVofMTa6XSApJTFqHlbRbxSIkvLiFeeAoSqlpSr1JJ1V1j +YsrBV8ofWC3mK5p/UV/M6GwgL0b8YueNi21dlz3Zy/8Z97eBH6zSeLb74xf5P76YT9B2 +KW1e/8enbs/JtLrtKaIVbsj5FadPY4qUw+3DahS4p7O0J7lRaNqP/LkVAAAAFQDywJfU +aYlN9GfOzUQB2NzU0WqrawAAAIA0xHHDxR9201VHQKtCPcCA9pc4YTh34bganheyS+cI +fJxJUCO1jF5tSTNTO3lDp/8hpu4tR2B7eBetzwF62+twpun5dmAzT9WPYIViabLeKfqT +MZmrsXDWxlqS7oA5Ty8trnCgFPa8BwcstPVssDOPu+IvTjxPox+Os495/yce8AAAAIBh +DWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah/XcF3DeRF+eEoz48 +wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+UykSTXYUbtsfTNRFQGBW2 +/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0Cg== +---- END SSH2 PUBLIC KEY ---- diff --git a/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl b/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl index 2209af05d5..c63ad7de73 100644 --- a/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl +++ b/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2011. All Rights Reserved. +%% Copyright Ericsson AB 2007-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 @@ -48,13 +48,14 @@ init_per_suite(Config) -> case catch crypto:start() of ok -> DataDir = ?config(data_dir, Config), + UserDir = ?config(priv_dir, Config), FileAlt = filename:join(DataDir, "ssh_sftpd_file_alt.erl"), c:c(FileAlt), FileName = filename:join(DataDir, "test.txt"), {ok, FileInfo} = file:read_file_info(FileName), ok = file:write_file_info(FileName, FileInfo#file_info{mode = 8#400}), - ssh_test_lib:make_dsa_files(Config), + ssh_test_lib:setup_dsa(DataDir, UserDir), Config; _Else -> {skip,"Could not start ssh!"} @@ -66,7 +67,9 @@ init_per_suite(Config) -> %% A list of key/value pairs, holding the test case configuration. %% Description: Cleanup after the whole suite %%-------------------------------------------------------------------- -end_per_suite(_Config) -> +end_per_suite(Config) -> + UserDir = ?config(priv_dir, Config), + ssh_test_lib:clean_dsa(UserDir), crypto:stop(), ok. @@ -85,7 +88,7 @@ end_per_suite(_Config) -> %%-------------------------------------------------------------------- init_per_testcase(TestCase, Config) -> ssh:start(), - DataDir = ?config(data_dir, Config), + PrivDir = ?config(priv_dir, Config), Options = case atom_to_list(TestCase) of @@ -95,8 +98,7 @@ init_per_testcase(TestCase, Config) -> ssh_sftpd_file_alt}]), [{user_passwords,[{?USER, ?PASSWD}]}, {pwdfun, fun(_,_) -> true end}, - {system_dir, DataDir}, - {user_dir, DataDir}, + {system_dir, PrivDir}, {subsystems, [Spec]}]; "root_dir" -> Privdir = ?config(priv_dir, Config), @@ -105,23 +107,20 @@ init_per_testcase(TestCase, Config) -> Spec = ssh_sftpd:subsystem_spec([{root,Root}]), [{user_passwords,[{?USER, ?PASSWD}]}, {pwdfun, fun(_,_) -> true end}, - {system_dir, DataDir}, - {user_dir, DataDir}, + {system_dir, PrivDir}, {subsystems, [Spec]}]; "list_dir_limited" -> Spec = ssh_sftpd:subsystem_spec([{max_files,1}]), [{user_passwords,[{?USER, ?PASSWD}]}, {pwdfun, fun(_,_) -> true end}, - {system_dir, DataDir}, - {user_dir, DataDir}, + {system_dir, PrivDir}, {subsystems, [Spec]}]; _ -> [{user_passwords,[{?USER, ?PASSWD}]}, {pwdfun, fun(_,_) -> true end}, - {user_dir, DataDir}, - {system_dir, DataDir}] + {system_dir, PrivDir}] end, {Sftpd, Host, _Port} = ssh_test_lib:daemon(any, ?SSHD_PORT, Options), @@ -131,8 +130,7 @@ init_per_testcase(TestCase, Config) -> [{silently_accept_hosts, true}, {user, ?USER}, {password, ?PASSWD}, {pwdfun, fun(_,_) -> true end}, - {system_dir, DataDir}, - {user_dir, DataDir}, + {user_dir, PrivDir}, {timeout, 30000}]), TmpConfig = lists:keydelete(sftp, 1, Config), NewConfig = lists:keydelete(sftpd, 1, TmpConfig), diff --git a/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_host_dsa_key b/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_host_dsa_key new file mode 100644 index 0000000000..51ab6fbd88 --- /dev/null +++ b/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_host_dsa_key @@ -0,0 +1,13 @@ +-----BEGIN DSA PRIVATE KEY----- +MIIBuwIBAAKBgQCClaHzE2ul0gKSUxah5W0W8UiJLy4hXngKEqpaUq9SSdVdY2LK +wVfKH1gt5iuaf1FfzOhsIC9G/GLnjYttXZc92cv/Gfe3gR+s0ni2++MX+T++mE/Q +diltXv/Hp27PybS67SmiFW7I+RWnT2OKlMPtw2oUuKeztCe5UWjaj/y5FQIVAPLA +l9RpiU30Z87NRAHY3NTRaqtrAoGANMRxw8UfdtNVR0CrQj3AgPaXOGE4d+G4Gp4X +skvnCHycSVAjtYxebUkzUzt5Q6f/IabuLUdge3gXrc8BetvrcKbp+XZgM0/Vj2CF +Ymmy3in6kzGZq7Fw1sZaku6AOU8vLa5woBT2vAcHLLT1bLAzj7viL048T6MfjrOP +ef8nHvACgYBhDWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah +/XcF3DeRF+eEoz48wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+U +ykSTXYUbtsfTNRFQGBW2/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0CgIVAN4wtL5W +Lv62jKcdskxNyz2NQoBx +-----END DSA PRIVATE KEY----- + diff --git a/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_host_dsa_key.pub b/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_host_dsa_key.pub new file mode 100644 index 0000000000..4dbb1305b0 --- /dev/null +++ b/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_host_dsa_key.pub @@ -0,0 +1,11 @@ +---- BEGIN SSH2 PUBLIC KEY ---- +AAAAB3NzaC1kc3MAAACBAIKVofMTa6XSApJTFqHlbRbxSIkvLiFeeAoSqlpSr1JJ1V1j +YsrBV8ofWC3mK5p/UV/M6GwgL0b8YueNi21dlz3Zy/8Z97eBH6zSeLb74xf5P76YT9B2 +KW1e/8enbs/JtLrtKaIVbsj5FadPY4qUw+3DahS4p7O0J7lRaNqP/LkVAAAAFQDywJfU +aYlN9GfOzUQB2NzU0WqrawAAAIA0xHHDxR9201VHQKtCPcCA9pc4YTh34bganheyS+cI +fJxJUCO1jF5tSTNTO3lDp/8hpu4tR2B7eBetzwF62+twpun5dmAzT9WPYIViabLeKfqT +MZmrsXDWxlqS7oA5Ty8trnCgFPa8BwcstPVssDOPu+IvTjxPox+Os495/yce8AAAAIBh +DWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah/XcF3DeRF+eEoz48 +wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+UykSTXYUbtsfTNRFQGBW2 +/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0Cg== +---- END SSH2 PUBLIC KEY ---- diff --git a/lib/ssh/test/ssh_test_lib.erl b/lib/ssh/test/ssh_test_lib.erl index 425fae22c1..f4e95f9bfb 100644 --- a/lib/ssh/test/ssh_test_lib.erl +++ b/lib/ssh/test/ssh_test_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2011. All Rights Reserved. +%% Copyright Ericsson AB 2004-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -68,15 +68,11 @@ daemon(Host, Port, Options) -> Error end. +start_shell(Port, IOServer, UserDir) -> + spawn_link(?MODULE, init_shell, [Port, IOServer, [{user_dir, UserDir}]]). - - -start_shell(Port, IOServer) -> - spawn_link(?MODULE, init_shell, [Port, IOServer]). - -init_shell(Port, IOServer) -> +init_shell(Port, IOServer, UserDir) -> Host = hostname(), - UserDir = get_user_dir(), Options = [{user_interaction, false}, {silently_accept_hosts, true}] ++ UserDir, group_leader(IOServer, self()), @@ -139,12 +135,18 @@ reply(TestCase, Result) -> receive_exec_result(Msg) -> test_server:format("Expect data! ~p", [Msg]), receive + {ssh_cm,_,{data,_,1, Data}} -> + test_server:format("StdErr: ~p~n", [Data]), + receive_exec_result(Msg); Msg -> test_server:format("1: Collected data ~p", [Msg]), expected; Other -> + test_server:format("Other ~p", [Other]), {unexpected_msg, Other} end. + + receive_exec_end(ConnectionRef, ChannelId) -> Eof = {ssh_cm, ConnectionRef, {eof, ChannelId}}, ExitStatus = {ssh_cm, ConnectionRef, {exit_status, ChannelId, 0}}, @@ -198,9 +200,16 @@ remove_id_keys(Dir) -> file:delete(filename:join(Dir, "id_rsa")), file:delete(filename:join(Dir, "id_dsa")). -copyfile(SrcDir, DstDir, Fn) -> - file:copy(filename:join(SrcDir, Fn), - filename:join(DstDir, Fn)). +copyfile(SrcDir, DstDir, FileName) -> + Dest = filename:join(DstDir, FileName), + Result = file:copy(filename:join(SrcDir, FileName), Dest), + {ok, Pem} = file:read_file(Dest), + case public_key:pem_decode(Pem) of + [{_,_, not_encrypted}] -> + Result; + _ -> + {error, "Has pass phrase can not be used by automated test case"} + end. failfun(_User, {authmethod,none}) -> ok; @@ -222,39 +231,11 @@ known_hosts(BR) -> file:rename(B, KnownHosts) end. - -get_user_dir() -> - case os:type() of - {win32, _} -> - [{user_dir, filename:join([os:getenv("HOME"), ".ssh"])}]; - _ -> - [] - end. - - -make_dsa_cert_files(Config) -> - make_dsa_cert_files("", Config). - -make_dsa_cert_files(RoleStr, Config) -> - - CaInfo = {CaCert, _} = make_cert([{key, dsa}]), - {Cert, CertKey} = make_cert([{key, dsa}, {issuer, CaInfo}]), - CaCertFile = filename:join([?config(data_dir, Config), - RoleStr, "dsa_cacerts.pem"]), - CertFile = filename:join([?config(data_dir, Config), - RoleStr, "dsa_cert.pem"]), - KeyFile = filename:join([?config(data_dir, Config), - RoleStr, "dsa_key.pem"]), - - der_to_pem(CaCertFile, [{'Certificate', CaCert, not_encrypted}]), - der_to_pem(CertFile, [{'Certificate', Cert, not_encrypted}]), - der_to_pem(KeyFile, [CertKey]), - {CaCertFile, CertFile, KeyFile}. - -make_dsa_files(Config) -> - make_dsa_files(Config, rfc4716_public_key). -make_dsa_files(Config, Type) -> - {DSA, EncodedKey} = ssh_test_lib:gen_dsa(128, 20), +setup_dsa(DataDir, UserDir) -> + ssh_test_lib:copyfile(DataDir, UserDir, "ssh_host_dsa_key"), + ssh_test_lib:copyfile(DataDir, UserDir, "ssh_host_dsa_key.pub"), + {ok, Pem} = file:read_file(filename:join(UserDir, "ssh_host_dsa_key")), + DSA = public_key:pem_entry_decode(hd(public_key:pem_decode(Pem))), PKey = DSA#'DSAPrivateKey'.y, P = DSA#'DSAPrivateKey'.p, Q = DSA#'DSAPrivateKey'.q, @@ -263,422 +244,13 @@ make_dsa_files(Config, Type) -> {ok, Hostname} = inet:gethostname(), {ok, {A, B, C, D}} = inet:getaddr(Hostname, inet), IP = lists:concat([A, ".", B, ".", C, ".", D]), - Attributes = [], % Could be [{comment,"user@" ++ Hostname}], HostNames = [{hostnames,[IP, IP]}], - PublicKey = [{{PKey, Dss}, Attributes}], KnownHosts = [{{PKey, Dss}, HostNames}], - KnownHostsEnc = public_key:ssh_encode(KnownHosts, known_hosts), - KnownHosts = public_key:ssh_decode(KnownHostsEnc, known_hosts), - - PublicKeyEnc = public_key:ssh_encode(PublicKey, Type), -% PublicKey = public_key:ssh_decode(PublicKeyEnc, Type), - - SystemTmpDir = ?config(data_dir, Config), - filelib:ensure_dir(SystemTmpDir), - file:make_dir(SystemTmpDir), - - DSAFile = filename:join(SystemTmpDir, "ssh_host_dsa_key.pub"), - file:delete(DSAFile), - - DSAPrivateFile = filename:join(SystemTmpDir, "ssh_host_dsa_key"), - file:delete(DSAPrivateFile), - - KHFile = filename:join(SystemTmpDir, "known_hosts"), - file:delete(KHFile), - - PemBin = public_key:pem_encode([EncodedKey]), - - file:write_file(DSAFile, PublicKeyEnc), - file:write_file(KHFile, KnownHostsEnc), - file:write_file(DSAPrivateFile, PemBin), - ok. - -%%-------------------------------------------------------------------- -%% Create and return a der encoded certificate -%% Option Default -%% ------------------------------------------------------- -%% digest sha1 -%% validity {date(), date() + week()} -%% version 3 -%% subject [] list of the following content -%% {name, Name} -%% {email, Email} -%% {city, City} -%% {state, State} -%% {org, Org} -%% {org_unit, OrgUnit} -%% {country, Country} -%% {serial, Serial} -%% {title, Title} -%% {dnQualifer, DnQ} -%% issuer = {Issuer, IssuerKey} true (i.e. a ca cert is created) -%% (obs IssuerKey migth be {Key, Password} -%% key = KeyFile|KeyBin|rsa|dsa Subject PublicKey rsa or dsa generates key -%% -%% -%% (OBS: The generated keys are for testing only) -%% make_cert([{::atom(), ::term()}]) -> {Cert::binary(), Key::binary()} -%%-------------------------------------------------------------------- -make_cert(Opts) -> - SubjectPrivateKey = get_key(Opts), - {TBSCert, IssuerKey} = make_tbs(SubjectPrivateKey, Opts), - Cert = public_key:pkix_sign(TBSCert, IssuerKey), - true = verify_signature(Cert, IssuerKey, undef), %% verify that the keys where ok - {Cert, encode_key(SubjectPrivateKey)}. - -%%-------------------------------------------------------------------- -%% Writes cert files in Dir with FileName and FileName ++ Suffix -%% write_cert(::string(), ::string(), {Cert,Key}) -> ok -%%-------------------------------------------------------------------- -write_cert(Dir, FileName, Suffix, {Cert, Key = {_,_,not_encrypted}}) when is_binary(Cert) -> - ok = der_to_pem(filename:join(Dir, FileName), - [{'Certificate', Cert, not_encrypted}]), - ok = der_to_pem(filename:join(Dir, FileName ++ Suffix), [Key]). - -%%-------------------------------------------------------------------- -%% Creates a rsa key (OBS: for testing only) -%% the size are in bytes -%% gen_rsa(::integer()) -> {::atom(), ::binary(), ::opaque()} -%%-------------------------------------------------------------------- -gen_rsa(Size) when is_integer(Size) -> - Key = gen_rsa2(Size), - {Key, encode_key(Key)}. - -%%-------------------------------------------------------------------- -%% Creates a dsa key (OBS: for testing only) -%% the sizes are in bytes -%% gen_dsa(::integer()) -> {::atom(), ::binary(), ::opaque()} -%%-------------------------------------------------------------------- -gen_dsa(LSize,NSize) when is_integer(LSize), is_integer(NSize) -> - Key = gen_dsa2(LSize, NSize), - {Key, encode_key(Key)}. - -%%-------------------------------------------------------------------- -%% Verifies cert signatures -%% verify_signature(::binary(), ::tuple()) -> ::boolean() -%%-------------------------------------------------------------------- -verify_signature(DerEncodedCert, DerKey, _KeyParams) -> - Key = decode_key(DerKey), - case Key of - #'RSAPrivateKey'{modulus=Mod, publicExponent=Exp} -> - public_key:pkix_verify(DerEncodedCert, - #'RSAPublicKey'{modulus=Mod, publicExponent=Exp}); - #'DSAPrivateKey'{p=P, q=Q, g=G, y=Y} -> - public_key:pkix_verify(DerEncodedCert, {Y, #'Dss-Parms'{p=P, q=Q, g=G}}) - end. - -%%%%%%%%%%%%%%%%%%%%%%%%% Implementation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -get_key(Opts) -> - case proplists:get_value(key, Opts) of - undefined -> make_key(rsa, Opts); - rsa -> make_key(rsa, Opts); - dsa -> make_key(dsa, Opts); - Key -> - Password = proplists:get_value(password, Opts, no_passwd), - decode_key(Key, Password) - end. - -decode_key({Key, Pw}) -> - decode_key(Key, Pw); -decode_key(Key) -> - decode_key(Key, no_passwd). - - -decode_key(#'RSAPublicKey'{} = Key,_) -> - Key; -decode_key(#'RSAPrivateKey'{} = Key,_) -> - Key; -decode_key(#'DSAPrivateKey'{} = Key,_) -> - Key; -decode_key(PemEntry = {_,_,_}, Pw) -> - public_key:pem_entry_decode(PemEntry, Pw); -decode_key(PemBin, Pw) -> - [KeyInfo] = public_key:pem_decode(PemBin), - decode_key(KeyInfo, Pw). - -encode_key(Key = #'RSAPrivateKey'{}) -> - {ok, Der} = 'OTP-PUB-KEY':encode('RSAPrivateKey', Key), - {'RSAPrivateKey', list_to_binary(Der), not_encrypted}; -encode_key(Key = #'DSAPrivateKey'{}) -> - {ok, Der} = 'OTP-PUB-KEY':encode('DSAPrivateKey', Key), - {'DSAPrivateKey', list_to_binary(Der), not_encrypted}. - -make_tbs(SubjectKey, Opts) -> - Version = list_to_atom("v"++integer_to_list(proplists:get_value(version, Opts, 3))), - - IssuerProp = proplists:get_value(issuer, Opts, true), - {Issuer, IssuerKey} = issuer(IssuerProp, Opts, SubjectKey), - - {Algo, Parameters} = sign_algorithm(IssuerKey, Opts), - - SignAlgo = #'SignatureAlgorithm'{algorithm = Algo, - parameters = Parameters}, - Subject = case IssuerProp of - true -> %% Is a Root Ca - Issuer; - _ -> - subject(proplists:get_value(subject, Opts),false) - end, - - {#'OTPTBSCertificate'{serialNumber = trunc(random:uniform()*100000000)*10000 + 1, - signature = SignAlgo, - issuer = Issuer, - validity = validity(Opts), - subject = Subject, - subjectPublicKeyInfo = publickey(SubjectKey), - version = Version, - extensions = extensions(Opts) - }, IssuerKey}. - -issuer(true, Opts, SubjectKey) -> - %% Self signed - {subject(proplists:get_value(subject, Opts), true), SubjectKey}; -issuer({Issuer, IssuerKey}, _Opts, _SubjectKey) when is_binary(Issuer) -> - {issuer_der(Issuer), decode_key(IssuerKey)}; -issuer({File, IssuerKey}, _Opts, _SubjectKey) when is_list(File) -> - {ok, [{cert, Cert, _}|_]} = pem_to_der(File), - {issuer_der(Cert), decode_key(IssuerKey)}. - -issuer_der(Issuer) -> - Decoded = public_key:pkix_decode_cert(Issuer, otp), - #'OTPCertificate'{tbsCertificate=Tbs} = Decoded, - #'OTPTBSCertificate'{subject=Subject} = Tbs, - Subject. - -subject(undefined, IsRootCA) -> - User = if IsRootCA -> "RootCA"; true -> os:getenv("USER") end, - Opts = [{email, User ++ "@erlang.org"}, - {name, User}, - {city, "Stockholm"}, - {country, "SE"}, - {org, "erlang"}, - {org_unit, "testing dep"}], - subject(Opts); -subject(Opts, _) -> - subject(Opts). - -subject(SubjectOpts) when is_list(SubjectOpts) -> - Encode = fun(Opt) -> - {Type,Value} = subject_enc(Opt), - [#'AttributeTypeAndValue'{type=Type, value=Value}] - end, - {rdnSequence, [Encode(Opt) || Opt <- SubjectOpts]}. - -%% Fill in the blanks -subject_enc({name, Name}) -> {?'id-at-commonName', {printableString, Name}}; -subject_enc({email, Email}) -> {?'id-emailAddress', Email}; -subject_enc({city, City}) -> {?'id-at-localityName', {printableString, City}}; -subject_enc({state, State}) -> {?'id-at-stateOrProvinceName', {printableString, State}}; -subject_enc({org, Org}) -> {?'id-at-organizationName', {printableString, Org}}; -subject_enc({org_unit, OrgUnit}) -> {?'id-at-organizationalUnitName', {printableString, OrgUnit}}; -subject_enc({country, Country}) -> {?'id-at-countryName', Country}; -subject_enc({serial, Serial}) -> {?'id-at-serialNumber', Serial}; -subject_enc({title, Title}) -> {?'id-at-title', {printableString, Title}}; -subject_enc({dnQualifer, DnQ}) -> {?'id-at-dnQualifier', DnQ}; -subject_enc(Other) -> Other. - - -extensions(Opts) -> - case proplists:get_value(extensions, Opts, []) of - false -> - asn1_NOVALUE; - Exts -> - lists:flatten([extension(Ext) || Ext <- default_extensions(Exts)]) - end. - -default_extensions(Exts) -> - Def = [{key_usage,undefined}, - {subject_altname, undefined}, - {issuer_altname, undefined}, - {basic_constraints, default}, - {name_constraints, undefined}, - {policy_constraints, undefined}, - {ext_key_usage, undefined}, - {inhibit_any, undefined}, - {auth_key_id, undefined}, - {subject_key_id, undefined}, - {policy_mapping, undefined}], - Filter = fun({Key, _}, D) -> lists:keydelete(Key, 1, D) end, - Exts ++ lists:foldl(Filter, Def, Exts). - -extension({_, undefined}) -> []; -extension({basic_constraints, Data}) -> - case Data of - default -> - #'Extension'{extnID = ?'id-ce-basicConstraints', - extnValue = #'BasicConstraints'{cA=true}, - critical=true}; - false -> - []; - Len when is_integer(Len) -> - #'Extension'{extnID = ?'id-ce-basicConstraints', - extnValue = #'BasicConstraints'{cA=true, pathLenConstraint=Len}, - critical=true}; - _ -> - #'Extension'{extnID = ?'id-ce-basicConstraints', - extnValue = Data} - end; -extension({Id, Data, Critical}) -> - #'Extension'{extnID = Id, extnValue = Data, critical = Critical}. - - -publickey(#'RSAPrivateKey'{modulus=N, publicExponent=E}) -> - Public = #'RSAPublicKey'{modulus=N, publicExponent=E}, - Algo = #'PublicKeyAlgorithm'{algorithm= ?rsaEncryption, parameters='NULL'}, - #'OTPSubjectPublicKeyInfo'{algorithm = Algo, - subjectPublicKey = Public}; -publickey(#'DSAPrivateKey'{p=P, q=Q, g=G, y=Y}) -> - Algo = #'PublicKeyAlgorithm'{algorithm= ?'id-dsa', - parameters={params, #'Dss-Parms'{p=P, q=Q, g=G}}}, - #'OTPSubjectPublicKeyInfo'{algorithm = Algo, subjectPublicKey = Y}. - -validity(Opts) -> - DefFrom0 = calendar:gregorian_days_to_date(calendar:date_to_gregorian_days(date())-1), - DefTo0 = calendar:gregorian_days_to_date(calendar:date_to_gregorian_days(date())+7), - {DefFrom, DefTo} = proplists:get_value(validity, Opts, {DefFrom0, DefTo0}), - Format = fun({Y,M,D}) -> lists:flatten(io_lib:format("~w~2..0w~2..0w000000Z",[Y,M,D])) end, - #'Validity'{notBefore={generalTime, Format(DefFrom)}, - notAfter ={generalTime, Format(DefTo)}}. - -sign_algorithm(#'RSAPrivateKey'{}, Opts) -> - Type = case proplists:get_value(digest, Opts, sha1) of - sha1 -> ?'sha1WithRSAEncryption'; - sha512 -> ?'sha512WithRSAEncryption'; - sha384 -> ?'sha384WithRSAEncryption'; - sha256 -> ?'sha256WithRSAEncryption'; - md5 -> ?'md5WithRSAEncryption'; - md2 -> ?'md2WithRSAEncryption' - end, - {Type, 'NULL'}; -sign_algorithm(#'DSAPrivateKey'{p=P, q=Q, g=G}, _Opts) -> - {?'id-dsa-with-sha1', {params,#'Dss-Parms'{p=P, q=Q, g=G}}}. - -make_key(rsa, _Opts) -> - %% (OBS: for testing only) - gen_rsa2(64); -make_key(dsa, _Opts) -> - gen_dsa2(128, 20). %% Bytes i.e. {1024, 160} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% RSA key generation (OBS: for testing only) -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - --define(SMALL_PRIMES, [65537,97,89,83,79,73,71,67,61,59,53, - 47,43,41,37,31,29,23,19,17,13,11,7,5,3]). - -gen_rsa2(Size) -> - P = prime(Size), - Q = prime(Size), - N = P*Q, - Tot = (P - 1) * (Q - 1), - [E|_] = lists:dropwhile(fun(Candidate) -> (Tot rem Candidate) == 0 end, ?SMALL_PRIMES), - {D1,D2} = extended_gcd(E, Tot), - D = erlang:max(D1,D2), - case D < E of - true -> - gen_rsa2(Size); - false -> - {Co1,Co2} = extended_gcd(Q, P), - Co = erlang:max(Co1,Co2), - #'RSAPrivateKey'{version = 'two-prime', - modulus = N, - publicExponent = E, - privateExponent = D, - prime1 = P, - prime2 = Q, - exponent1 = D rem (P-1), - exponent2 = D rem (Q-1), - coefficient = Co - } - end. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% DSA key generation (OBS: for testing only) -%% See http://en.wikipedia.org/wiki/Digital_Signature_Algorithm -%% and the fips_186-3.pdf -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -gen_dsa2(LSize, NSize) -> - Q = prime(NSize), %% Choose N-bit prime Q - X0 = prime(LSize), - P0 = prime((LSize div 2) +1), - - %% Choose L-bit prime modulus P such that p-1 is a multiple of q. - case dsa_search(X0 div (2*Q*P0), P0, Q, 1000) of - error -> - gen_dsa2(LSize, NSize); - P -> - G = crypto:mod_exp(2, (P-1) div Q, P), % Choose G a number whose multiplicative order modulo p is q. - %% such that This may be done by setting g = h^(p-1)/q mod p, commonly h=2 is used. - - X = prime(20), %% Choose x by some random method, where 0 < x < q. - Y = crypto:mod_exp(G, X, P), %% Calculate y = g^x mod p. - - #'DSAPrivateKey'{version=0, p=P, q=Q, g=G, y=Y, x=X} - end. - -%% See fips_186-3.pdf -dsa_search(T, P0, Q, Iter) when Iter > 0 -> - P = 2*T*Q*P0 + 1, - case is_prime(crypto:mpint(P), 50) of - true -> P; - false -> dsa_search(T+1, P0, Q, Iter-1) - end; -dsa_search(_,_,_,_) -> - error. - - -%%%%%%% Crypto Math %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -prime(ByteSize) -> - Rand = odd_rand(ByteSize), - crypto:erlint(prime_odd(Rand, 0)). - -prime_odd(Rand, N) -> - case is_prime(Rand, 50) of - true -> - Rand; - false -> - NotPrime = crypto:erlint(Rand), - prime_odd(crypto:mpint(NotPrime+2), N+1) - end. - -%% see http://en.wikipedia.org/wiki/Fermat_primality_test -is_prime(_, 0) -> true; -is_prime(Candidate, Test) -> - CoPrime = odd_rand(<<0,0,0,4, 10000:32>>, Candidate), - case crypto:mod_exp(CoPrime, Candidate, Candidate) of - CoPrime -> is_prime(Candidate, Test-1); - _ -> false - end. - -odd_rand(Size) -> - Min = 1 bsl (Size*8-1), - Max = (1 bsl (Size*8))-1, - odd_rand(crypto:mpint(Min), crypto:mpint(Max)). - -odd_rand(Min,Max) -> - Rand = <<Sz:32, _/binary>> = crypto:rand_uniform(Min,Max), - BitSkip = (Sz+4)*8-1, - case Rand of - Odd = <<_:BitSkip, 1:1>> -> Odd; - Even = <<_:BitSkip, 0:1>> -> - crypto:mpint(crypto:erlint(Even)+1) - end. - -extended_gcd(A, B) -> - case A rem B of - 0 -> - {0, 1}; - N -> - {X, Y} = extended_gcd(B, N), - {Y, X-Y*(A div B)} - end. - -pem_to_der(File) -> - {ok, PemBin} = file:read_file(File), - public_key:pem_decode(PemBin). + KHFile = filename:join(UserDir, "known_hosts"), + file:write_file(KHFile, KnownHostsEnc). -der_to_pem(File, Entries) -> - PemBin = public_key:pem_encode(Entries), - file:write_file(File, PemBin). +clean_dsa(UserDir) -> + file:delete(filename:join(UserDir, "ssh_host_dsa_key")), + file:delete(filename:join(UserDir, "ssh_host_dsa_key.pub")), + file:delete(filename:join(UserDir, "known_hosts")). diff --git a/lib/ssh/test/ssh_to_openssh_SUITE.erl b/lib/ssh/test/ssh_to_openssh_SUITE.erl index f959d50484..53d04620c5 100644 --- a/lib/ssh/test/ssh_to_openssh_SUITE.erl +++ b/lib/ssh/test/ssh_to_openssh_SUITE.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 @@ -42,8 +42,12 @@ init_per_suite(Config) -> case catch crypto:start() of ok -> - ssh_test_lib:make_dsa_files(Config), - Config; + case gen_tcp:connect("localhost", 22, []) of + {error,econnrefused} -> + {skip,"No openssh deamon"}; + _ -> + Config + end; _Else -> {skip,"Could not start crypto!"} end. @@ -100,26 +104,43 @@ all() -> false -> {skip, "openSSH not installed on host"}; _ -> - [erlang_shell_client_openssh_server, - erlang_client_openssh_server_exec, - erlang_client_openssh_server_exec_compressed, - erlang_server_openssh_client_exec, - erlang_server_openssh_client_exec_compressed, - erlang_client_openssh_server_setenv, - erlang_client_openssh_server_publickey_rsa, - erlang_client_openssh_server_publickey_dsa, - erlang_server_openssh_client_pulic_key_dsa, - erlang_client_openssh_server_password] + [{group, erlang_client}, + {group, erlang_server} + ] end. groups() -> - []. - -init_per_group(_GroupName, Config) -> - Config. + [{erlang_client, [], [erlang_shell_client_openssh_server, + erlang_client_openssh_server_exec, + erlang_client_openssh_server_exec_compressed, + erlang_client_openssh_server_setenv, + erlang_client_openssh_server_publickey_rsa, + erlang_client_openssh_server_publickey_dsa, + erlang_client_openssh_server_password]}, + {erlang_server, [], [erlang_server_openssh_client_exec, + erlang_server_openssh_client_exec_compressed, + erlang_server_openssh_client_pulic_key_dsa, + erlang_client_openssh_server_password]} + ]. + +init_per_group(erlang_server, Config) -> + DataDir = ?config(data_dir, Config), + UserDir = ?config(priv_dir, Config), + ssh_test_lib:setup_dsa(DataDir, UserDir), + Config; +init_per_group(_, Config) -> + Dir = ?config(priv_dir, Config), + {ok, _} = ssh_test_lib:get_id_keys(Dir), + Config. -end_per_group(_GroupName, Config) -> - Config. +end_per_group(erlang_server, Config) -> + UserDir = ?config(priv_dir, Config), + ssh_test_lib:clean_dsa(UserDir), + Config; +end_per_group(_, Config) -> + Dir = ?config(priv_dir, Config), + ssh_test_lib:remove_id_keys(Dir), + Config. %% TEST cases starts here. %%-------------------------------------------------------------------- @@ -131,8 +152,9 @@ erlang_shell_client_openssh_server(suite) -> erlang_shell_client_openssh_server(Config) when is_list(Config) -> process_flag(trap_exit, true), + UserDir = ?config(priv_dir, Config), IO = ssh_test_lib:start_io_server(), - Shell = ssh_test_lib:start_shell(?SSH_DEFAULT_PORT, IO), + Shell = ssh_test_lib:start_shell(?SSH_DEFAULT_PORT, IO, UserDir), IO ! {input, self(), "echo Hej\n"}, receive_hej(), IO ! {input, self(), "exit\n"}, @@ -228,7 +250,7 @@ erlang_server_openssh_client_exec(suite) -> []; erlang_server_openssh_client_exec(Config) when is_list(Config) -> - SystemDir = ?config(data_dir, Config), + SystemDir = ?config(priv_dir, Config), {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, {failfun, fun ssh_test_lib:failfun/2}]), @@ -257,7 +279,7 @@ erlang_server_openssh_client_exec_compressed(suite) -> []; erlang_server_openssh_client_exec_compressed(Config) when is_list(Config) -> - SystemDir = ?config(data_dir, Config), + SystemDir = ?config(priv_dir, Config), {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, {compression, zlib}, {failfun, fun ssh_test_lib:failfun/2}]), @@ -346,7 +368,9 @@ erlang_client_openssh_server_publickey_rsa(Config) when is_list(Config) -> ok = ssh:close(ConnectionRef), ok = file:delete(filename:join(UserDir, "id_rsa")); {error, enoent} -> - {skip, "no ~/.ssh/id_rsa"} + {skip, "no ~/.ssh/id_rsa"}; + {error, Reason} -> + {skip, Reason} end. %%-------------------------------------------------------------------- @@ -372,7 +396,9 @@ erlang_client_openssh_server_publickey_dsa(Config) when is_list(Config) -> ok = ssh:close(ConnectionRef), ok = file:delete(filename:join(UserDir, "id_dsa")); {error, enoent} -> - {skip, "no ~/.ssh/id_dsa"} + {skip, "no ~/.ssh/id_dsa"}; + {error, Reason} -> + {skip, Reason} end. %%-------------------------------------------------------------------- @@ -383,7 +409,7 @@ erlang_server_openssh_client_pulic_key_dsa(suite) -> []; erlang_server_openssh_client_pulic_key_dsa(Config) when is_list(Config) -> - SystemDir = ?config(data_dir, Config), + SystemDir = ?config(priv_dir, Config), {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, {public_key_alg, ssh_dsa}, {failfun, fun ssh_test_lib:failfun/2}]), diff --git a/lib/ssh/test/ssh_to_openssh_SUITE_data/ssh_host_dsa_key b/lib/ssh/test/ssh_to_openssh_SUITE_data/ssh_host_dsa_key new file mode 100644 index 0000000000..51ab6fbd88 --- /dev/null +++ b/lib/ssh/test/ssh_to_openssh_SUITE_data/ssh_host_dsa_key @@ -0,0 +1,13 @@ +-----BEGIN DSA PRIVATE KEY----- +MIIBuwIBAAKBgQCClaHzE2ul0gKSUxah5W0W8UiJLy4hXngKEqpaUq9SSdVdY2LK +wVfKH1gt5iuaf1FfzOhsIC9G/GLnjYttXZc92cv/Gfe3gR+s0ni2++MX+T++mE/Q +diltXv/Hp27PybS67SmiFW7I+RWnT2OKlMPtw2oUuKeztCe5UWjaj/y5FQIVAPLA +l9RpiU30Z87NRAHY3NTRaqtrAoGANMRxw8UfdtNVR0CrQj3AgPaXOGE4d+G4Gp4X +skvnCHycSVAjtYxebUkzUzt5Q6f/IabuLUdge3gXrc8BetvrcKbp+XZgM0/Vj2CF +Ymmy3in6kzGZq7Fw1sZaku6AOU8vLa5woBT2vAcHLLT1bLAzj7viL048T6MfjrOP +ef8nHvACgYBhDWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah +/XcF3DeRF+eEoz48wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+U +ykSTXYUbtsfTNRFQGBW2/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0CgIVAN4wtL5W +Lv62jKcdskxNyz2NQoBx +-----END DSA PRIVATE KEY----- + diff --git a/lib/ssh/test/ssh_to_openssh_SUITE_data/ssh_host_dsa_key.pub b/lib/ssh/test/ssh_to_openssh_SUITE_data/ssh_host_dsa_key.pub new file mode 100644 index 0000000000..4dbb1305b0 --- /dev/null +++ b/lib/ssh/test/ssh_to_openssh_SUITE_data/ssh_host_dsa_key.pub @@ -0,0 +1,11 @@ +---- BEGIN SSH2 PUBLIC KEY ---- +AAAAB3NzaC1kc3MAAACBAIKVofMTa6XSApJTFqHlbRbxSIkvLiFeeAoSqlpSr1JJ1V1j +YsrBV8ofWC3mK5p/UV/M6GwgL0b8YueNi21dlz3Zy/8Z97eBH6zSeLb74xf5P76YT9B2 +KW1e/8enbs/JtLrtKaIVbsj5FadPY4qUw+3DahS4p7O0J7lRaNqP/LkVAAAAFQDywJfU +aYlN9GfOzUQB2NzU0WqrawAAAIA0xHHDxR9201VHQKtCPcCA9pc4YTh34bganheyS+cI +fJxJUCO1jF5tSTNTO3lDp/8hpu4tR2B7eBetzwF62+twpun5dmAzT9WPYIViabLeKfqT +MZmrsXDWxlqS7oA5Ty8trnCgFPa8BwcstPVssDOPu+IvTjxPox+Os495/yce8AAAAIBh +DWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah/XcF3DeRF+eEoz48 +wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+UykSTXYUbtsfTNRFQGBW2 +/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0Cg== +---- END SSH2 PUBLIC KEY ---- diff --git a/lib/stdlib/doc/src/io.xml b/lib/stdlib/doc/src/io.xml index 667d758e29..e6d262466c 100644 --- a/lib/stdlib/doc/src/io.xml +++ b/lib/stdlib/doc/src/io.xml @@ -70,7 +70,7 @@ <desc> <p>Either <c>standard_io</c>, <c>standard_error</c>, a registered name, or a pid handling IO protocols (returned from - <seealso marker="file#open/2">file:open/2</seealso>).</p> + <seealso marker="kernel:file#open/2">file:open/2</seealso>).</p> </desc> </datatype> <datatype> diff --git a/lib/stdlib/doc/src/supervisor.xml b/lib/stdlib/doc/src/supervisor.xml index cddb55e5c5..33a7f5bb6a 100644 --- a/lib/stdlib/doc/src/supervisor.xml +++ b/lib/stdlib/doc/src/supervisor.xml @@ -127,25 +127,18 @@ child_spec() = {Id,StartFunc,Restart,Shutdown,Type,Modules} <p><c>StartFunc</c> defines the function call used to start the child process. It should be a module-function-arguments tuple <c>{M,F,A}</c> used as <c>apply(M,F,A)</c>.</p> - <p> <br></br> -</p> <p>The start function <em>must create and link to</em> the child process, and should return <c>{ok,Child}</c> or <c>{ok,Child,Info}</c> where <c>Child</c> is the pid of the child process and <c>Info</c> an arbitrary term which is ignored by the supervisor.</p> - <p> <br></br> -</p> <p>The start function can also return <c>ignore</c> if the child process for some reason cannot be started, in which case - the child specification will be kept by the supervisor but - the non-existing child process will be ignored.</p> - <p> <br></br> -</p> + the child specification will be kept by the supervisor + (unless it is a temporary child) but the non-existing child + process will be ignored.</p> <p>If something goes wrong, the function may also return an error tuple <c>{error,Error}</c>.</p> - <p> <br></br> -</p> <p>Note that the <c>start_link</c> functions of the different behaviour modules fulfill the above requirements.</p> </item> diff --git a/lib/stdlib/src/erl_expand_records.erl b/lib/stdlib/src/erl_expand_records.erl index 20fd247cea..1c69a131f9 100644 --- a/lib/stdlib/src/erl_expand_records.erl +++ b/lib/stdlib/src/erl_expand_records.erl @@ -452,8 +452,10 @@ conj([], _E) -> conj([{{Name,_Rp},L,R,Sz} | AL], E) -> NL = neg_line(L), T1 = {op,NL,'orelse', - {call,NL,{atom,NL,is_record},[R,{atom,NL,Name},{integer,NL,Sz}]}, - {atom,NL,fail}}, + {call,NL, + {remote,NL,{atom,NL,erlang},{atom,NL,is_record}}, + [R,{atom,NL,Name},{integer,NL,Sz}]}, + {atom,NL,fail}}, T2 = case conj(AL, none) of empty -> T1; C -> {op,NL,'and',C,T1} @@ -581,7 +583,9 @@ strict_get_record_field(Line, R, {atom,_,F}=Index, Name, St0) -> ExpRp = erl_lint:modify_line(ExpR, fun(_L) -> 0 end), RA = {{Name,ExpRp},Line,ExpR,length(Fs)+1}, St2 = St1#exprec{strict_ra = [RA | St1#exprec.strict_ra]}, - {{call,Line,{atom,Line,element},[I,ExpR]},St2} + {{call,Line, + {remote,Line,{atom,Line,erlang},{atom,Line,element}}, + [I,ExpR]},St2} end. record_pattern(I, I, Var, Sz, Line, Acc) -> @@ -593,7 +597,9 @@ record_pattern(_, _, _, _, _, Acc) -> reverse(Acc). sloppy_get_record_field(Line, R, Index, Name, St) -> Fs = record_fields(Name, St), I = index_expr(Line, Index, Name, Fs), - expr({call,Line,{atom,Line,element},[I,R]}, St). + expr({call,Line, + {remote,Line,{atom,Line,erlang},{atom,Line,element}}, + [I,R]}, St). strict_record_tests([strict_record_tests | _]) -> true; strict_record_tests([no_strict_record_tests | _]) -> false; @@ -710,7 +716,8 @@ record_setel(R, Name, Fs, Us0) -> {'case',Lr,R, [{clause,Lr,[{tuple,Lr,[{atom,Lr,Name} | Wildcards]}],[], [foldr(fun ({I,Lf,Val}, Acc) -> - {call,Lf,{atom,Lf,setelement},[I,Acc,Val]} end, + {call,Lf,{remote,Lf,{atom,Lf,erlang}, + {atom,Lf,setelement}},[I,Acc,Val]} end, R, Us)]}, {clause,NLr,[{var,NLr,'_'}],[], [call_error(NLr, {tuple,NLr,[{atom,NLr,badrecord},{atom,NLr,Name}]})]}]}. diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl index e5adb84932..cfbcf54d95 100644 --- a/lib/stdlib/src/erl_lint.erl +++ b/lib/stdlib/src/erl_lint.erl @@ -1804,12 +1804,19 @@ guard_test(G, Vt, St0) -> %% Specially handle record type test here. guard_test2({call,Line,{atom,Lr,record},[E,A]}, Vt, St0) -> gexpr({call,Line,{atom,Lr,is_record},[E,A]}, Vt, St0); -guard_test2({call,_Line,{atom,_La,F},As}=G, Vt, St0) -> +guard_test2({call,Line,{atom,_La,F},As}=G, Vt, St0) -> {Asvt,St1} = gexpr_list(As, Vt, St0), %Always check this. A = length(As), case erl_internal:type_test(F, A) of - true when F =/= is_record -> {Asvt,St1}; - _ -> gexpr(G, Vt, St0) + true when F =/= is_record, A =/= 2 -> + case no_guard_bif_clash(St1, {F,A}) of + false -> + {Asvt,add_error(Line, {illegal_guard_local_call,{F,A}}, St1)}; + true -> + {Asvt,St1} + end; + _ -> + gexpr(G, Vt, St0) end; guard_test2(G, Vt, St) -> %% Everything else is a guard expression. @@ -1865,9 +1872,15 @@ gexpr({call,Line,{atom,_Lr,is_record},[E,R]}, Vt, St0) -> gexpr({call,Line,{remote,_Lr,{atom,_Lm,erlang},{atom,Lf,is_record}},[E,A]}, Vt, St0) -> gexpr({call,Line,{atom,Lf,is_record},[E,A]}, Vt, St0); -gexpr({call,_Line,{atom,_Lr,is_record},[E,{atom,_,_Name},{integer,_,_}]}, +gexpr({call,Line,{atom,_Lr,is_record},[E0,{atom,_,_Name},{integer,_,_}]}, Vt, St0) -> - gexpr(E, Vt, St0); + {E,St1} = gexpr(E0, Vt, St0), + case no_guard_bif_clash(St0, {is_record,3}) of + true -> + {E,St1}; + false -> + {E,add_error(Line, {illegal_guard_local_call,{is_record,3}}, St1)} + end; gexpr({call,Line,{atom,_Lr,is_record},[_,_,_]=Asvt0}, Vt, St0) -> {Asvt,St1} = gexpr_list(Asvt0, Vt, St0), {Asvt,add_error(Line, illegal_guard_expr, St1)}; diff --git a/lib/stdlib/src/error_logger_file_h.erl b/lib/stdlib/src/error_logger_file_h.erl index ee4f0b3a51..08f1873803 100644 --- a/lib/stdlib/src/error_logger_file_h.erl +++ b/lib/stdlib/src/error_logger_file_h.erl @@ -104,7 +104,7 @@ code_change(_OldVsn, State, _Extra) -> %%% ------------------------------------------------------ tag_event(Event) -> - {erlang:localtime(), Event}. + {erlang:universaltime(), Event}. write_events(Fd, Events) -> write_events1(Fd, lists:reverse(Events)). @@ -169,23 +169,18 @@ write_event(_, _) -> maybe_utc(Time) -> UTC = case application:get_env(sasl, utc_log) of - {ok, Val} -> - Val; + {ok, Val} -> Val; undefined -> %% Backwards compatible: case application:get_env(stdlib, utc_log) of - {ok, Val} -> - Val; - undefined -> - false + {ok, Val} -> Val; + undefined -> false end end, - if - UTC =:= true -> - {utc, calendar:local_time_to_universal_time(Time)}; - true -> - Time - end. + maybe_utc(Time, UTC). + +maybe_utc(Time, true) -> {utc, Time}; +maybe_utc(Time, _) -> {local, calendar:universal_time_to_local_time(Time)}. format_report(Rep) when is_list(Rep) -> case string_p(Rep) of @@ -238,7 +233,7 @@ write_time(Time) -> write_time(Time, "ERROR REPORT"). write_time({utc,{{Y,Mo,D},{H,Mi,S}}}, Type) -> io_lib:format("~n=~s==== ~p-~s-~p::~s:~s:~s UTC ===~n", [Type,D,month(Mo),Y,t(H),t(Mi),t(S)]); -write_time({{Y,Mo,D},{H,Mi,S}}, Type) -> +write_time({local, {{Y,Mo,D},{H,Mi,S}}}, Type) -> io_lib:format("~n=~s==== ~p-~s-~p::~s:~s:~s ===~n", [Type,D,month(Mo),Y,t(H),t(Mi),t(S)]). diff --git a/lib/stdlib/src/error_logger_tty_h.erl b/lib/stdlib/src/error_logger_tty_h.erl index fa13fbb2bd..48e069a407 100644 --- a/lib/stdlib/src/error_logger_tty_h.erl +++ b/lib/stdlib/src/error_logger_tty_h.erl @@ -97,7 +97,7 @@ set_group_leader() -> end. tag_event(Event) -> - {erlang:localtime(), Event}. + {erlang:universaltime(), Event}. write_events(Events,IOMod) -> write_events1(lists:reverse(Events),IOMod). @@ -162,23 +162,18 @@ write_event({_Time, _Error},_IOMod) -> maybe_utc(Time) -> UTC = case application:get_env(sasl, utc_log) of - {ok, Val} -> - Val; + {ok, Val} -> Val; undefined -> %% Backwards compatible: case application:get_env(stdlib, utc_log) of - {ok, Val} -> - Val; - undefined -> - false + {ok, Val} -> Val; + undefined -> false end end, - if - UTC =:= true -> - {utc, calendar:local_time_to_universal_time(Time)}; - true -> - Time - end. + maybe_utc(Time, UTC). + +maybe_utc(Time, true) -> {utc, Time}; +maybe_utc(Time, _) -> {local, calendar:universal_time_to_local_time(Time)}. format(IOMod, String) -> format(IOMod, String, []). format(io_lib, String, Args) -> io_lib:format(String, Args); @@ -234,7 +229,7 @@ write_time(Time) -> write_time(Time, "ERROR REPORT"). write_time({utc,{{Y,Mo,D},{H,Mi,S}}},Type) -> io_lib:format("~n=~s==== ~p-~s-~p::~s:~s:~s UTC ===~n", [Type,D,month(Mo),Y,t(H),t(Mi),t(S)]); -write_time({{Y,Mo,D},{H,Mi,S}},Type) -> +write_time({local, {{Y,Mo,D},{H,Mi,S}}},Type) -> io_lib:format("~n=~s==== ~p-~s-~p::~s:~s:~s ===~n", [Type,D,month(Mo),Y,t(H),t(Mi),t(S)]). diff --git a/lib/stdlib/src/supervisor.erl b/lib/stdlib/src/supervisor.erl index 42ea42f42e..ac5b078c29 100644 --- a/lib/stdlib/src/supervisor.erl +++ b/lib/stdlib/src/supervisor.erl @@ -270,6 +270,8 @@ start_children(Children, SupName) -> start_children(Children, [], SupName). start_children([Child|Chs], NChildren, SupName) -> case do_start_child(SupName, Child) of + {ok, undefined} when Child#child.restart_type =:= temporary -> + start_children(Chs, NChildren, SupName); {ok, Pid} -> start_children(Chs, [Child#child{pid = Pid}|NChildren], SupName); {ok, Pid, _Extra} -> @@ -325,6 +327,8 @@ handle_call({start_child, EArgs}, _From, State) when ?is_simple(State) -> #child{mfargs = {M, F, A}} = Child, Args = A ++ EArgs, case do_start_child_i(M, F, Args) of + {ok, undefined} when Child#child.restart_type =:= temporary -> + {reply, {ok, undefined}, State}; {ok, Pid} -> NState = save_dynamic_child(Child#child.restart_type, Pid, Args, State), {reply, {ok, Pid}, NState}; @@ -611,12 +615,12 @@ handle_start_child(Child, State) -> case get_child(Child#child.name, State) of false -> case do_start_child(State#state.name, Child) of + {ok, undefined} when Child#child.restart_type =:= temporary -> + {{ok, undefined}, State}; {ok, Pid} -> - {{ok, Pid}, - save_child(Child#child{pid = Pid}, State)}; + {{ok, Pid}, save_child(Child#child{pid = Pid}, State)}; {ok, Pid, Extra} -> - {{ok, Pid, Extra}, - save_child(Child#child{pid = Pid}, State)}; + {{ok, Pid, Extra}, save_child(Child#child{pid = Pid}, State)}; {error, What} -> {{error, {What, Child}}, State} end; diff --git a/lib/stdlib/test/erl_expand_records_SUITE.erl b/lib/stdlib/test/erl_expand_records_SUITE.erl index f8c1ad783c..8b162cfda0 100644 --- a/lib/stdlib/test/erl_expand_records_SUITE.erl +++ b/lib/stdlib/test/erl_expand_records_SUITE.erl @@ -178,6 +178,9 @@ expr(Config) when is_list(Config) -> true -> not_ok end. + + is_record(_, _, _) -> + error(wrong_is_record). ">> ], @@ -366,6 +369,8 @@ strict(Config) when is_list(Config) -> end catch error:_ -> ok end. + element(_, _) -> + error(wrong_element). ">> ], ?line run(Config, Ts1, [strict_record_tests]), @@ -380,6 +385,8 @@ strict(Config) when is_list(Config) -> case foo of _ when A#r2.a =:= 1 -> ok end. + element(_, _) -> + error(wrong_element). ">> ], ?line run(Config, Ts2, [no_strict_record_tests]), @@ -415,6 +422,11 @@ update(Config) when is_list(Config) -> t2() -> R0 = #r{}, #r{_ = R0#r{a = ok}}. + + %% Implicit calls to setelement/3 must go to the BIF, + %% not to this function. + setelement(_, _, _) -> + erlang:error(wrong_setelement_called). ">> ], ?line run(Config, Ts), diff --git a/lib/stdlib/test/erl_lint_SUITE.erl b/lib/stdlib/test/erl_lint_SUITE.erl index 9041adbe5c..4e93f056ad 100644 --- a/lib/stdlib/test/erl_lint_SUITE.erl +++ b/lib/stdlib/test/erl_lint_SUITE.erl @@ -2631,7 +2631,35 @@ bif_clash(Config) when is_list(Config) -> binary_part(A,B,C). ">>, [warn_unused_import], - {warnings,[{2,erl_lint,{redefine_bif_import,{binary_part,3}}}]}} + {warnings,[{2,erl_lint,{redefine_bif_import,{binary_part,3}}}]}}, + %% Don't accept call to a guard BIF if there is a local definition + %% or an import with the same name. Note: is_record/2 is an + %% exception, since it is more of syntatic sugar than a real BIF. + {clash21, + <<"-export([is_list/1]). + -import(x, [is_tuple/1]). + -record(r, {a,b}). + x(T) when is_tuple(T) -> ok; + x(T) when is_list(T) -> ok. + y(T) when is_tuple(T) =:= true -> ok; + y(T) when is_list(T) =:= true -> ok; + y(T) when is_record(T, r, 3) -> ok; + y(T) when is_record(T, r, 3) =:= true -> ok; + y(T) when is_record(T, r) =:= true -> ok. + is_list(_) -> + ok. + is_record(_, _) -> + ok. + is_record(_, _, _) -> + ok. + ">>, + [{no_auto_import,[{is_tuple,1}]}], + {errors,[{4,erl_lint,{illegal_guard_local_call,{is_tuple,1}}}, + {5,erl_lint,{illegal_guard_local_call,{is_list,1}}}, + {6,erl_lint,{illegal_guard_local_call,{is_tuple,1}}}, + {7,erl_lint,{illegal_guard_local_call,{is_list,1}}}, + {8,erl_lint,{illegal_guard_local_call,{is_record,3}}}, + {9,erl_lint,{illegal_guard_local_call,{is_record,3}}}],[]}} ], ?line [] = run(Config, Ts), diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl index 0e8849b5b3..101828fdef 100644 --- a/lib/stdlib/test/ets_SUITE.erl +++ b/lib/stdlib/test/ets_SUITE.erl @@ -74,7 +74,7 @@ -export([bad_table/1, types/1]). -export([otp_9423/1]). --export([init_per_testcase/2]). +-export([init_per_testcase/2, end_per_testcase/2]). %% Convenience for manual testing -export([random_test/0]). @@ -2385,6 +2385,8 @@ setopts_do(Opts) -> ?line {'EXIT',{badarg,_}} = (catch ets:setopts(T,{protection,private,false})), ?line {'EXIT',{badarg,_}} = (catch ets:setopts(T,protection)), ?line ets:delete(T), + unlink(Heir), + exit(Heir, bang), ok. bad_table(doc) -> ["All kinds of operations with bad table argument"]; @@ -5645,7 +5647,8 @@ spawn_logger(Procs) -> true -> exit(Proc, kill); _ -> ok end, - erlang:display(process_info(Proc)), + erlang:display({"Waiting for 'DOWN' from", Proc, + process_info(Proc), pid_status(Proc)}), receive {'DOWN', Mon, _, _, _} -> ok @@ -5656,6 +5659,15 @@ spawn_logger(Procs) -> spawn_logger([From]) end. +pid_status(Pid) -> + try + erts_debug:get_internal_state({process_status, Pid}) + catch + error:undef -> + erts_debug:set_internal_state(available_internal_state, true), + pid_status(Pid) + end. + start_spawn_logger() -> case whereis(ets_test_spawn_logger) of Pid when is_pid(Pid) -> true; diff --git a/lib/stdlib/test/supervisor_SUITE.erl b/lib/stdlib/test/supervisor_SUITE.erl index fa6faa66f2..71b76c093f 100644 --- a/lib/stdlib/test/supervisor_SUITE.erl +++ b/lib/stdlib/test/supervisor_SUITE.erl @@ -34,8 +34,10 @@ %% API tests -export([ sup_start_normal/1, sup_start_ignore_init/1, - sup_start_ignore_child/1, sup_start_error_return/1, - sup_start_fail/1, sup_stop_infinity/1, + sup_start_ignore_child/1, sup_start_ignore_temporary_child/1, + sup_start_ignore_temporary_child_start_child/1, + sup_start_ignore_temporary_child_start_child_simple/1, + sup_start_error_return/1, sup_start_fail/1, sup_stop_infinity/1, sup_stop_timeout/1, sup_stop_brutal_kill/1, child_adm/1, child_adm_simple/1, child_specs/1, extra_return/1]). @@ -85,8 +87,10 @@ all() -> groups() -> [{sup_start, [], [sup_start_normal, sup_start_ignore_init, - sup_start_ignore_child, sup_start_error_return, - sup_start_fail]}, + sup_start_ignore_child, sup_start_ignore_temporary_child, + sup_start_ignore_temporary_child_start_child, + sup_start_ignore_temporary_child_start_child_simple, + sup_start_error_return, sup_start_fail]}, {sup_stop, [], [sup_stop_infinity, sup_stop_timeout, sup_stop_brutal_kill]}, @@ -191,6 +195,59 @@ sup_start_ignore_child(Config) when is_list(Config) -> [2,1,0,2] = get_child_counts(sup_test). %%------------------------------------------------------------------------- +%% Tests what happens if child's init-callback returns ignore for a +%% temporary child when ChildSpec is returned directly from supervisor +%% init callback. +%% Child spec shall NOT be saved!!! +sup_start_ignore_temporary_child(Config) when is_list(Config) -> + process_flag(trap_exit, true), + Child1 = {child1, {supervisor_1, start_child, [ignore]}, + temporary, 1000, worker, []}, + Child2 = {child2, {supervisor_1, start_child, []}, temporary, + 1000, worker, []}, + {ok, _Pid} = start_link({ok, {{one_for_one, 2, 3600}, [Child1,Child2]}}), + + [{child2, CPid2, worker, []}] = supervisor:which_children(sup_test), + true = is_pid(CPid2), + [1,1,0,1] = get_child_counts(sup_test). + +%%------------------------------------------------------------------------- +%% Tests what happens if child's init-callback returns ignore for a +%% temporary child when child is started with start_child/2. +%% Child spec shall NOT be saved!!! +sup_start_ignore_temporary_child_start_child(Config) when is_list(Config) -> + process_flag(trap_exit, true), + {ok, _Pid} = start_link({ok, {{one_for_one, 2, 3600}, []}}), + Child1 = {child1, {supervisor_1, start_child, [ignore]}, + temporary, 1000, worker, []}, + Child2 = {child2, {supervisor_1, start_child, []}, temporary, + 1000, worker, []}, + + {ok, undefined} = supervisor:start_child(sup_test, Child1), + {ok, CPid2} = supervisor:start_child(sup_test, Child2), + + [{child2, CPid2, worker, []}] = supervisor:which_children(sup_test), + [1,1,0,1] = get_child_counts(sup_test). + +%%------------------------------------------------------------------------- +%% Tests what happens if child's init-callback returns ignore for a +%% temporary child when child is started with start_child/2, and the +%% supervisor is simple_one_for_one. +%% Child spec shall NOT be saved!!! +sup_start_ignore_temporary_child_start_child_simple(Config) + when is_list(Config) -> + process_flag(trap_exit, true), + Child1 = {child1, {supervisor_1, start_child, [ignore]}, + temporary, 1000, worker, []}, + {ok, _Pid} = start_link({ok, {{simple_one_for_one, 2, 3600}, [Child1]}}), + + {ok, undefined} = supervisor:start_child(sup_test, []), + {ok, CPid2} = supervisor:start_child(sup_test, []), + + [{undefined, CPid2, worker, []}] = supervisor:which_children(sup_test), + [1,1,0,1] = get_child_counts(sup_test). + +%%------------------------------------------------------------------------- %% Tests what happens if init-callback returns a invalid value. sup_start_error_return(Config) when is_list(Config) -> process_flag(trap_exit, true), diff --git a/lib/stdlib/vsn.mk b/lib/stdlib/vsn.mk index 2f0ecd3863..694d39ce9c 100644 --- a/lib/stdlib/vsn.mk +++ b/lib/stdlib/vsn.mk @@ -1 +1 @@ -STDLIB_VSN = 1.18 +STDLIB_VSN = 1.18.1 diff --git a/lib/syntax_tools/src/Makefile b/lib/syntax_tools/src/Makefile index 50369e633e..bac138e95a 100644 --- a/lib/syntax_tools/src/Makefile +++ b/lib/syntax_tools/src/Makefile @@ -26,7 +26,7 @@ EBIN = ../ebin ifeq ($(NATIVE_LIBS_ENABLED),yes) ERL_COMPILE_FLAGS += +native endif -ERL_COMPILE_FLAGS += +warn_unused_vars +nowarn_shadow_vars +warn_unused_import +warn_missing_spec +warn_untyped_record +ERL_COMPILE_FLAGS += +warn_unused_vars +nowarn_shadow_vars +warn_unused_import # +warn_missing_spec +warn_untyped_record SOURCES=erl_syntax.erl erl_prettypr.erl erl_syntax_lib.erl \ erl_comment_scan.erl erl_recomment.erl erl_tidy.erl \ diff --git a/lib/syntax_tools/src/erl_syntax.erl b/lib/syntax_tools/src/erl_syntax.erl index 7f58fda519..32fd3722d6 100644 --- a/lib/syntax_tools/src/erl_syntax.erl +++ b/lib/syntax_tools/src/erl_syntax.erl @@ -6100,8 +6100,9 @@ implicit_fun_name(Node) -> arity_qualifier( set_pos(atom(Atom), Pos), set_pos(integer(Arity), Pos))); - {'fun', Pos, {function, Module, Atom, Arity}} -> + {'fun', _Pos, {function, Module, Atom, Arity}} -> %% New in R15: fun M:F/A. + %% XXX: Perhaps set position for this as well? module_qualifier(Module, arity_qualifier(Atom, Arity)); Node1 -> data(Node1) diff --git a/lib/tools/c_src/Makefile.in b/lib/tools/c_src/Makefile.in index 604332a91e..b8c4aed6e2 100644 --- a/lib/tools/c_src/Makefile.in +++ b/lib/tools/c_src/Makefile.in @@ -1,19 +1,20 @@ -# ``The contents of this file are subject to the Erlang Public License, +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2009-2012. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in # compliance with the License. You should have received a copy of the # Erlang Public License along with this software. If not, it can be -# retrieved via the world wide web at http://www.erlang.org/. -# +# retrieved online at http://www.erlang.org/. +# # Software distributed under the License is distributed on an "AS IS" # basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See # the License for the specific language governing rights and limitations # under the License. -# -# The Initial Developer of the Original Code is Ericsson Utvecklings AB. -# Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings -# AB. All Rights Reserved.'' -# -# $Id$ +# +# %CopyrightEnd% # include $(ERL_TOP)/make/target.mk @@ -138,15 +139,17 @@ EMEM_LIBS = $(LIBS) \ EMEM_OBJS = $(addprefix $(EMEM_OBJ_DIR)/,$(notdir $(EMEM_SRCS:.c=.o))) +ERTS_LIB = $(ERL_TOP/erts/lib_src/obj/$(TARGET)/$(TYPE)/MADE + # # Misc targets # _create_dirs := $(shell mkdir -p $(CREATE_DIRS)) -all: erts_lib $(PROGS) $(DRIVERS) +all: $(PROGS) $(DRIVERS) -erts_lib: +$(ERTS_LIB): cd $(ERL_TOP)/erts/lib_src && $(MAKE) $(TYPE) @@ -174,7 +177,7 @@ $(EMEM_OBJ_DIR)/%.o: %.c # Program targets # -$(BIN_DIR)/emem$(TYPEMARKER)@EXEEXT@: $(EMEM_OBJS) +$(BIN_DIR)/emem$(TYPEMARKER)@EXEEXT@: $(EMEM_OBJS) $(ERTS_LIB) $(PRE_LD) $(LD) $(EMEM_LDFLAGS) -o $@ $(EMEM_OBJS) $(EMEM_LIBS) # diff --git a/lib/tools/c_src/erl_memory.c b/lib/tools/c_src/erl_memory.c index 872d55e789..5239176d03 100644 --- a/lib/tools/c_src/erl_memory.c +++ b/lib/tools/c_src/erl_memory.c @@ -1224,7 +1224,7 @@ print_main_footer(em_state *state) switch (state->info.stop_reason) { case EMTP_STOP: - p += sprintf(p, stop_str); + p += sprintf(p, "%s", stop_str); break; case EMTP_EXIT: p += sprintf(p, exit_str, state->info.exit_status); @@ -2339,7 +2339,7 @@ usage(char *sw, char *error) if (error) exit(1); else { - char *help_str = + fprintf(filep, "\n" " [] - switch is allowed any number of times\n" " {} - switch is allowed at most one time\n" @@ -2370,8 +2370,7 @@ usage(char *sw, char *error) " " SW_CHAR "o - display operation count values\n" " " SW_CHAR "p <P> - set listen port to <P>\n" " " SW_CHAR "t - display info about total values\n" - " " SW_CHAR "v - verbose output\n"; - fprintf(filep, help_str); + " " SW_CHAR "v - verbose output\n"); exit(0); } diff --git a/lib/wx/doc/src/Makefile b/lib/wx/doc/src/Makefile index c8eb6174c4..03e9f1e1bb 100644 --- a/lib/wx/doc/src/Makefile +++ b/lib/wx/doc/src/Makefile @@ -22,7 +22,7 @@ # ---------------------------------------------------- include ../../vsn.mk include ../../config.mk -APPLICATION=wxErlang +APPLICATION=wx ErlMods = wx.erl wx_object.erl diff --git a/lib/xmerl/doc/src/xmerl_ug.xmlsrc b/lib/xmerl/doc/src/xmerl_ug.xmlsrc index 6ee6707e53..9ef8fbb0b9 100644 --- a/lib/xmerl/doc/src/xmerl_ug.xmlsrc +++ b/lib/xmerl/doc/src/xmerl_ug.xmlsrc @@ -36,9 +36,9 @@ <title>Features</title> <p>The <em>xmerl</em> XML parser is able to parse XML documents according to the XML 1.0 standard. As default it performs - well-formed parsing,(syntax checks and checks of well-formed + well-formed parsing, (syntax checks and checks of well-formed constraints). Optionally one can also use xmerl as a validating - parser,(validate according to referenced DTD and validating + parser, (validate according to referenced DTD and validating constraints). By means of for example the xmerl_xs module it is possible to transform the parsed result to other formats, e.g. text, HTML, XML etc.</p> diff --git a/lib/xmerl/src/xmerl_uri.erl b/lib/xmerl/src/xmerl_uri.erl index a0c6f1c2a7..1864651491 100644 --- a/lib/xmerl/src/xmerl_uri.erl +++ b/lib/xmerl/src/xmerl_uri.erl @@ -358,7 +358,7 @@ scan_host(C0) -> %% Hex3=<?HEX; %% Hex4=<?HEX -> %% {C1,lists:reverse(lists:append(IPv6address))}; - {C1,Hostname,[A|_HostF]} -> + {C1,Hostname,[_A|_HostF]} -> {C1,lists:reverse(lists:append(Hostname))} %% _ -> %% {error,no_host} |