diff options
Diffstat (limited to 'lib/diameter')
-rw-r--r-- | lib/diameter/doc/src/diameter_make.xml | 2 | ||||
-rw-r--r-- | lib/diameter/doc/src/notes.xml | 8 | ||||
-rw-r--r-- | lib/diameter/include/diameter_gen.hrl | 123 | ||||
-rw-r--r-- | lib/diameter/src/Makefile | 19 | ||||
-rw-r--r-- | lib/diameter/src/base/diameter_service.erl | 2 | ||||
-rw-r--r-- | lib/diameter/src/diameter.app.src | 19 | ||||
-rw-r--r-- | lib/diameter/src/info/diameter_dbg.erl (renamed from lib/diameter/src/base/diameter_dbg.erl) | 15 | ||||
-rw-r--r-- | lib/diameter/src/info/diameter_info.erl (renamed from lib/diameter/src/base/diameter_info.erl) | 14 | ||||
-rw-r--r-- | lib/diameter/src/modules.mk | 12 | ||||
-rw-r--r-- | lib/diameter/src/transport/diameter_sctp.erl | 23 | ||||
-rw-r--r-- | lib/diameter/test/diameter_codec_test.erl | 3 |
11 files changed, 186 insertions, 54 deletions
diff --git a/lib/diameter/doc/src/diameter_make.xml b/lib/diameter/doc/src/diameter_make.xml index 13ec5bbfc1..0c7e6b794d 100644 --- a/lib/diameter/doc/src/diameter_make.xml +++ b/lib/diameter/doc/src/diameter_make.xml @@ -52,7 +52,7 @@ under the License. <p> The function &codec; is used to compile a diameter &dictionary; into Erlang source. -The resulting source implements the interface diameter required +The resulting source implements the interface diameter requires to encode and decode the dictionary's messages and AVPs.</p> <p> diff --git a/lib/diameter/doc/src/notes.xml b/lib/diameter/doc/src/notes.xml index cd14195e78..e2390df37c 100644 --- a/lib/diameter/doc/src/notes.xml +++ b/lib/diameter/doc/src/notes.xml @@ -11,7 +11,7 @@ <header> <copyright> <year>2011</year> -<year>2013</year> +<year>2014</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -73,12 +73,6 @@ first.</p> <p> Own Id: OTP-11361</p> </item> - <item> - <p> - Fix silent make rules (Thanks to Anthony Ramine)</p> - <p> - Own Id: OTP-11514</p> - </item> </list> </section> diff --git a/lib/diameter/include/diameter_gen.hrl b/lib/diameter/include/diameter_gen.hrl index 55aae3a243..c8f706dc3e 100644 --- a/lib/diameter/include/diameter_gen.hrl +++ b/lib/diameter/include/diameter_gen.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2013. All Rights Reserved. +%% Copyright Ericsson AB 2010-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -25,6 +25,11 @@ -define(THROW(T), throw({?MODULE, T})). +%% Key to a value in the process dictionary that determines whether or +%% not an unrecognized AVP setting the M-bit should be regarded as an +%% error or not. See is_strict/0. +-define(STRICT_KEY, strict). + -type parent_name() :: atom(). %% parent = Message or AVP -type parent_record() :: tuple(). %% -type avp_name() :: atom(). @@ -35,6 +40,18 @@ -type grouped_avp() :: nonempty_improper_list(#diameter_avp{}, [avp()]). -type avp() :: non_grouped_avp() | grouped_avp(). +%% Use a (hopefully) unique key when manipulating the process +%% dictionary. + +putr(K,V) -> + put({?MODULE, K}, V). + +getr(K) -> + get({?MODULE, K}). + +eraser(K) -> + erase({?MODULE, K}). + %% --------------------------------------------------------------------------- %% # encode_avps/2 %% --------------------------------------------------------------------------- @@ -212,12 +229,61 @@ decode(Name, #diameter_avp{code = Code, vendor_id = Vid} = Avp, Acc) -> %% decode/4 +%% AVP is defined in the dictionary ... decode(Name, {AvpName, Type}, Avp, Acc) -> d(Name, Avp#diameter_avp{name = AvpName, type = Type}, Acc); +%% ... or not. decode(Name, 'AVP', Avp, Acc) -> decode_AVP(Name, Avp, Acc). +%% 6733, 4.4: +%% +%% Receivers of a Grouped AVP that does not have the 'M' (mandatory) +%% bit set and one or more of the encapsulated AVPs within the group +%% has the 'M' (mandatory) bit set MAY simply be ignored if the +%% Grouped AVP itself is unrecognized. The rule applies even if the +%% encapsulated AVP with its 'M' (mandatory) bit set is further +%% encapsulated within other sub-groups, i.e., other Grouped AVPs +%% embedded within the Grouped AVP. +%% +%% The first sentence is slightly mangled, but take it to mean this: +%% +%% An unrecognized AVP of type Grouped that does not set the 'M' bit +%% MAY be ignored even if one of its encapsulated AVPs sets the 'M' +%% bit. +%% +%% The text above is a change from RFC 3588, which instead says this: +%% +%% Further, if any of the AVPs encapsulated within a Grouped AVP has +%% the 'M' (mandatory) bit set, the Grouped AVP itself MUST also +%% include the 'M' bit set. +%% +%% Both of these texts have problems. If the AVP is unknown then its +%% type is unknown since the type isn't sent over the wire, so the +%% 6733 text becomes a non-statement: don't know that the AVP not +%% setting the M-bit is of type Grouped, therefore can't know that its +%% data consists of encapsulated AVPs, therefore can't but ignore that +%% one of these might set the M-bit. It should be no worse if we know +%% the AVP to have type Grouped. +%% +%% Similarly, for the 3588 text: if we receive an AVP that doesn't set +%% the M-bit and don't know that the AVP has type Grouped then we +%% can't realize that its data contains an AVP that sets the M-bit, so +%% can't regard the AVP as erroneous on this account. Again, it should +%% be no worse if the type is known to be Grouped, but in this case +%% the RFC forces us to regard the AVP as erroneous. This is +%% inconsistent, and the 3588 text has never been enforced. +%% +%% So, if an AVP doesn't set the M-bit then we're free to ignore it, +%% regardless of the AVP's type. If we know the type to be Grouped +%% then we must ignore the M-bit on an encapsulated AVP. That means +%% packing such an encapsulated AVP into an 'AVP' field if need be, +%% not regarding the lack of a specific field as an error as is +%% otherwise the case. (The lack of an AVP-specific field being how we +%% defined the RFC's "unrecognized", which is slightly stronger than +%% "not defined".) + %% d/3 %% Don't try to decode the value of a Failed-AVP component since it @@ -230,9 +296,19 @@ d('Failed-AVP' = Name, Avp, Acc) -> %% Or try to decode. d(Name, Avp, {Avps, Acc}) -> #diameter_avp{name = AvpName, - data = Data} + data = Data, + type = Type, + is_mandatory = M} = Avp, + %% Use the process dictionary is to keep track of whether or not + %% to ignore an M-bit on an encapsulated AVP. Not ideal, but the + %% alternative requires widespread changes to be able to pass the + %% value around through the entire decode. The solution here is + %% simple in comparison, both to implement and to understand. + + Reset = relax(Type, M), + try avp(decode, Data, AvpName) of V -> {H, A} = ungroup(V, Avp), @@ -250,8 +326,32 @@ d(Name, Avp, {Avps, Acc}) -> {Reason, Avp, erlang:get_stacktrace()}), {Rec, Failed} = Acc, {[Avp|Avps], {Rec, [rc(Reason, Avp) | Failed]}} + after + relax(Reset) end. +%% Set false in the process dictionary as soon as we see a Grouped AVP +%% that doesn't set the M-bit, so that is_strict() can say whether or +%% not to ignore the M-bit on an encapsulated AVP. +relax('Grouped', M) -> + V = getr(?STRICT_KEY), + if V == undefined andalso not M -> + putr(?STRICT_KEY, M); + true -> + false + end; +relax(_, _) -> + false. + +%% Reset strictness. +relax(undefined) -> + eraser(?STRICT_KEY); +relax(false) -> + ok. + +is_strict() -> + false /= getr(?STRICT_KEY). + %% decode_AVP/3 %% %% Don't know this AVP: see if it can be packed in an 'AVP' field @@ -310,15 +410,8 @@ pack_avp(_, Arity, Avp, Acc) -> %% pack_AVP/3 -%% Give Failed-AVP special treatment since it'll contain any -%% unrecognized mandatory AVP's. -pack_AVP(Name, #diameter_avp{is_mandatory = true} = Avp, Acc) - when Name /= 'Failed-AVP' -> - {Rec, Failed} = Acc, - {Rec, [{5001, Avp} | Failed]}; - pack_AVP(Name, #diameter_avp{is_mandatory = M} = Avp, Acc) -> - case avp_arity(Name, 'AVP') of + case pack_arity(Name, M) of 0 -> {Rec, Failed} = Acc, {Rec, [{if M -> 5001; true -> 5008 end, Avp} | Failed]}; @@ -326,6 +419,16 @@ pack_AVP(Name, #diameter_avp{is_mandatory = M} = Avp, Acc) -> pack(Arity, 'AVP', Avp, Acc) end. +%% Give Failed-AVP special treatment since it'll contain any +%% unrecognized mandatory AVP's. +pack_arity(Name, M) -> + case Name /= 'Failed-AVP' andalso M andalso is_strict() of + true -> + 0; + false -> + avp_arity(Name, 'AVP') + end. + %% 3588: %% %% DIAMETER_AVP_UNSUPPORTED 5001 diff --git a/lib/diameter/src/Makefile b/lib/diameter/src/Makefile index 578bbaee2e..127406ae23 100644 --- a/lib/diameter/src/Makefile +++ b/lib/diameter/src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2010-2013. All Rights Reserved. +# Copyright Ericsson AB 2010-2014. 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,7 +41,7 @@ INCDIR = ../include ABS_EBIN := $(shell cd $(EBIN) && pwd) # Where make should look for dependencies. -VPATH = .:base:compiler:transport:gen +VPATH = .:base:compiler:transport:gen:info # ---------------------------------------------------- # Target specs @@ -55,13 +55,13 @@ DICT_ERLS = $(DICT_MODULES:%=%.erl) DICT_HRLS = $(DICT_MODULES:%=%.hrl) # Modules to build before compiling dictionaries. -COMPILER_MODULES = $(notdir $(filter compiler/%, $(CT_MODULES))) \ - $(DICT_YRL) +COMPILER_MODULES = $(notdir $(CT_MODULES)) $(DICT_YRL) # All handwritten modules from which a depend.mk is generated. MODULES = \ $(RT_MODULES) \ - $(CT_MODULES) + $(CT_MODULES) \ + $(INFO_MODULES) # Modules whose names are inserted into the app file. APP_MODULES = \ @@ -72,6 +72,7 @@ APP_MODULES = \ TARGET_MODULES = \ $(APP_MODULES) \ $(CT_MODULES) \ + $(INFO_MODULES) \ $(DICT_YRL:%=gen/%) # What to build for the 'opt' target. @@ -150,9 +151,13 @@ gen/$(DICT_YRL).erl: compiler/$(DICT_YRL).yrl $(APP_TARGET): $(APP_SRC) ../vsn.mk modules.mk $(gen_verbose) \ M=`echo $(notdir $(APP_MODULES)) | tr ' ' ,`; \ + C=`echo $(COMPILER_MODULES) | tr ' ' ,`; \ + I=`echo $(notdir $(INFO_MODULES)) | tr ' ' ,`; \ R=`echo $(REGISTERED) | tr ' ' ,`; \ sed -e 's;%VSN%;$(VSN);' \ -e "s;%MODULES%;$$M;" \ + -e "s;%COMPILER%;$$C;" \ + -e "s;%INFO%;$$I;" \ -e "s;%REGISTERED%;$$R;" \ $< > $@ @@ -177,6 +182,8 @@ info: @echo @$(call list,CT_MODULES) @echo + @$(call list,INFO_MODULES) + @echo @$(call list,TARGET_MODULES) @echo @$(call list,TARGET_DIRS) @@ -216,7 +223,7 @@ dialyze: opt $(PLT) -Wno_improper_lists \ $(EBIN)/diameter_gen_base_rfc3588.$(EMULATOR) \ $(patsubst %, $(EBIN)/%.$(EMULATOR), \ - $(notdir $(RT_MODULES) $(CT_MODULES))) + $(notdir $(RT_MODULES) $(CT_MODULES) $(INFO_MODULES))) # Omit all but the common dictionary module since these # (diameter_gen_relay in particular) generate warning depending on how # much of the included diameter_gen.hrl they use. diff --git a/lib/diameter/src/base/diameter_service.erl b/lib/diameter/src/base/diameter_service.erl index 1274e0fc48..8914992f17 100644 --- a/lib/diameter/src/base/diameter_service.erl +++ b/lib/diameter/src/base/diameter_service.erl @@ -1389,6 +1389,8 @@ pick_peer(Local, Remote, Pid, _SvcName, #diameter_app{mutable = true} = App) case call_service(Pid, {pick_peer, Local, Remote, App}) of {TPid, _} = T when is_pid(TPid) -> T; + false = No -> + No; {error, _} -> false end; diff --git a/lib/diameter/src/diameter.app.src b/lib/diameter/src/diameter.app.src index ceefb9b398..d2290aeccc 100644 --- a/lib/diameter/src/diameter.app.src +++ b/lib/diameter/src/diameter.app.src @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2013. All Rights Reserved. +%% Copyright Ericsson AB 2010-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -20,9 +20,20 @@ {application, diameter, [{description, "Diameter protocol"}, {vsn, "%VSN%"}, - {modules, [%MODULES%]}, + {modules, [ + %MODULES% + %,%COMPILER% + %,%INFO% + ]}, {registered, [%REGISTERED%]}, - {applications, [stdlib, kernel]}, + {applications, [ + stdlib, kernel + %, syntax_tools + %, runtime_tools + %, ssl + ]}, {env, []}, - {mod, {diameter_app, []}} + {mod, {diameter_app, []}}, + {runtime_dependencies, ["syntax_tools-1.6.14","stdlib-2.0","ssl-5.3.4", + "runtime_tools-1.8.14","kernel-3.0","erts-6.0"]} ]}. diff --git a/lib/diameter/src/base/diameter_dbg.erl b/lib/diameter/src/info/diameter_dbg.erl index 5b0ac3a3b6..1237007a75 100644 --- a/lib/diameter/src/base/diameter_dbg.erl +++ b/lib/diameter/src/info/diameter_dbg.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% Copyright Ericsson AB 2010-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -17,6 +17,10 @@ %% %CopyrightEnd% %% +%% +%% Information and debug functions. +%% + -module(diameter_dbg). -export([table/1, @@ -29,8 +33,7 @@ compiled/0, procs/0, latest/0, - nl/0, - log/4]). + nl/0]). -export([diameter_config/0, diameter_peer/0, @@ -52,9 +55,8 @@ tp/1]). -include_lib("diameter/include/diameter.hrl"). --include("diameter_internal.hrl"). - +-define(APPLICATION, diameter). -define(INFO, diameter_info). -define(SEP(), ?INFO:sep()). @@ -68,9 +70,6 @@ -define(VALUES(Rec), tl(tuple_to_list(Rec))). -log(_Slogan, _Mod, _Line, _Details) -> - ok. - %%% ---------------------------------------------------------- %%% # help() %%% ---------------------------------------------------------- diff --git a/lib/diameter/src/base/diameter_info.erl b/lib/diameter/src/info/diameter_info.erl index 39d32d07cd..10972f3231 100644 --- a/lib/diameter/src/base/diameter_info.erl +++ b/lib/diameter/src/info/diameter_info.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% Copyright Ericsson AB 2010-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -17,6 +17,11 @@ %% %CopyrightEnd% %% +%% +%% Generic functions for formatting table listings and more. Used by +%% diameter_dbg. +%% + -module(diameter_info). -export([usage/1, @@ -573,12 +578,7 @@ sys_info() -> {A,V}. os_info() -> - {os:version(), case os:type() of - {_Fam, _Name} = T -> - T; - Fam -> - {Fam, ""} - end}. + {os:version(), os:type()}. chomp(S) -> string:strip(S, right, $\n). diff --git a/lib/diameter/src/modules.mk b/lib/diameter/src/modules.mk index f8d3cf1d6f..a2a7a51892 100644 --- a/lib/diameter/src/modules.mk +++ b/lib/diameter/src/modules.mk @@ -1,8 +1,7 @@ -#-*-makefile-*- ; force emacs to enter makefile-mode # %CopyrightBegin% # -# Copyright Ericsson AB 2010-2013. All Rights Reserved. +# Copyright Ericsson AB 2010-2014. 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 @@ -64,16 +63,19 @@ RT_MODULES = \ transport/diameter_transport \ transport/diameter_transport_sup -# Handwritten (compile time) modules not included in the app file. +# Handwritten compiler modules not included in the app file. CT_MODULES = \ - base/diameter_dbg \ - base/diameter_info \ compiler/diameter_codegen \ compiler/diameter_exprecs \ compiler/diameter_dict_scanner \ compiler/diameter_dict_util \ compiler/diameter_make +# Info/debug modules, also not included in the app file. +INFO_MODULES = \ + info/diameter_dbg \ + info/diameter_info + # Released hrl files in ../include intended for public consumption. EXTERNAL_HRLS = \ diameter.hrl \ diff --git a/lib/diameter/src/transport/diameter_sctp.erl b/lib/diameter/src/transport/diameter_sctp.erl index f5275e66b5..d0a01351f3 100644 --- a/lib/diameter/src/transport/diameter_sctp.erl +++ b/lib/diameter/src/transport/diameter_sctp.erl @@ -171,18 +171,33 @@ start_link(T) -> info({gen_sctp, Sock}) -> lists:flatmap(fun(K) -> info(K, Sock) end, - [{socket, sockname}, - {peer, peername}, + [{socket, socknames}, + {peer, peernames}, {statistics, getstat}]). info({K,F}, Sock) -> case inet:F(Sock) of {ok, V} -> - [{K,V}]; + [{K, map(F,V)}]; _ -> [] end. +%% inet:{sock,peer}names/1 returns [{Addr, Port}] but the port number +%% should be the same in each tuple. Map to a {[Addr], Port} tuple if +%% so. +map(K, [{_, Port} | _] = APs) + when K == socknames; + K == peernames -> + try [A || {A,P} <- APs, P == Port orelse throw(?MODULE)] of + As -> {As, Port} + catch + ?MODULE -> APs + end; + +map(_, V) -> + V. + %% --------------------------------------------------------------------------- %% # init/1 %% --------------------------------------------------------------------------- @@ -549,7 +564,7 @@ accept_peer(_, []) -> ok; accept_peer(Sock, Matches) -> - {RAddrs, _} = ok(inet:peername(Sock)), + RAddrs = [A || {A,_} <- ok(inet:peernames(Sock))], diameter_peer:match(RAddrs, Matches) orelse x({accept, RAddrs, Matches}), ok. diff --git a/lib/diameter/test/diameter_codec_test.erl b/lib/diameter/test/diameter_codec_test.erl index 0b4568a9e5..90536dcf2b 100644 --- a/lib/diameter/test/diameter_codec_test.erl +++ b/lib/diameter/test/diameter_codec_test.erl @@ -1,8 +1,7 @@ -%% coding: utf-8 %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2013. All Rights Reserved. +%% Copyright Ericsson AB 2010-2014. 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 |