From c9ca7f7e836dc6a4fe91fd4d7103af6d4db76f0e Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Mon, 11 Feb 2013 00:04:37 +0100 Subject: Add application_opt() request_errors Configuring the value 'callback' all errors detected in incoming requests to result in a handle_request callback. The default value 'answer_3xxx' is the previous behaviour in which diameter answers protocol errors without a callback. --- lib/diameter/doc/src/diameter.xml | 28 +++- lib/diameter/include/diameter.hrl | 4 +- lib/diameter/src/base/diameter.erl | 3 +- lib/diameter/src/base/diameter_config.erl | 11 +- lib/diameter/src/base/diameter_traffic.erl | 205 +++++++++++++++-------------- 5 files changed, 142 insertions(+), 109 deletions(-) diff --git a/lib/diameter/doc/src/diameter.xml b/lib/diameter/doc/src/diameter.xml index ba9225da8b..accf21cf98 100644 --- a/lib/diameter/doc/src/diameter.xml +++ b/lib/diameter/doc/src/diameter.xml @@ -16,7 +16,7 @@
-20112012 +20112013 Ericsson AB. All Rights Reserved. @@ -206,11 +206,13 @@ probably avoid it.

Determines the manner in which incoming answer messages containing -decode errors are handled. +decode errors are handled.

+ +

If callback then errors result in a &app_handle_answer; callback in the same fashion as for &app_handle_request;, with errors communicated in the errors field of the -#diameter_packet{} record passed to the callback. +#diameter_packet{} passed to the callback. If report then an answer containing errors is discarded without a callback and a warning report is written to the log. If discard then an answer containing errors is silently @@ -224,6 +226,24 @@ question is as if a callback had taken place and returned Defaults to report if unspecified.

+{request_errors, answer_3xxx|callback} + +

+Determines the manner in which incoming requests are handled when an +error other than 3007, DIAMETER_APPLICATION_UNSUPPORTED. (With which no +application callback module can be associated.)

+ +

+If answer_3xxx then the request is answered by diameter +without a &app_handle_request; callback taking place if a 3xxx series +error (protocol errors) is detected. +If callback then even 3xxx errors result in an application +&app_handle_request; callback.

+ +

+Defaults to answer_3xxx if unspecified.

+
+ @@ -534,7 +554,7 @@ Pkt = #diameter_packet{} The RFC 3539 watchdog state machine has transitioned into (up) or out of (down) the OKAY state. -If a #diameter_packet{} record is present in an up event +If a #diameter_packet{} is present in an up event then there has been a capabilties exchange on a newly established transport connection and the record contains the received CER or CEA. Otherwise a connection has reestablished without the loss or diff --git a/lib/diameter/include/diameter.hrl b/lib/diameter/include/diameter.hrl index 5ee898c3dd..513665cec1 100644 --- a/lib/diameter/include/diameter.hrl +++ b/lib/diameter/include/diameter.hrl @@ -143,6 +143,6 @@ init_state, %% option 'state', initial callback state id, %% 32-bit unsigned application identifier = Dict:id() mutable = false, %% boolean(), do traffic callbacks modify state? - options = [{answer_errors, report}]}). %% | callback | discard - + options = [{answer_errors, report}, %% | callback | discard + {request_errors, answer_3xxx}]}). %% | callback -endif. %% -ifdef(diameter_hrl). diff --git a/lib/diameter/src/base/diameter.erl b/lib/diameter/src/base/diameter.erl index f563d244f6..7359688404 100644 --- a/lib/diameter/src/base/diameter.erl +++ b/lib/diameter/src/base/diameter.erl @@ -306,7 +306,8 @@ call(SvcName, App, Message) -> | {module, app_module()} | {state, any()} | {call_mutates_state, boolean()} - | {answer_errors, callback|report|discard}. + | {answer_errors, callback|report|discard} + | {request_errors, callback|answer_3xxx}. -type app_alias() :: any(). diff --git a/lib/diameter/src/base/diameter_config.erl b/lib/diameter/src/base/diameter_config.erl index 1486071573..889c75e3da 100644 --- a/lib/diameter/src/base/diameter_config.erl +++ b/lib/diameter/src/base/diameter_config.erl @@ -672,13 +672,15 @@ app_acc({application, Opts}, Acc) -> ModS = get_opt(state, Opts, Alias), M = get_opt(call_mutates_state, Opts, false), A = get_opt(answer_errors, Opts, report), + R = get_opt(request_errors, Opts, answer_3xxx), [#diameter_app{alias = Alias, dictionary = Dict, id = cb(Dict, id), module = init_mod(Mod), init_state = ModS, mutable = init_mutable(M), - options = [{answer_errors, init_answers(A)}]} + options = [{answer_errors, init_answers(A)}, + {request_errors, init_request_errors(R)}]} | Acc]; app_acc(_, Acc) -> Acc. @@ -722,6 +724,13 @@ init_answers(A) init_answers(A) -> ?THROW({answer_errors, A}). +init_request_errors(P) + when callback == P; + answer_3xxx == P -> + P; +init_request_errors(P) -> + ?THROW({request_errors, P}). + %% Get a single value at the specified key. get_opt(Keys, List) when is_list(Keys) -> diff --git a/lib/diameter/src/base/diameter_traffic.erl b/lib/diameter/src/base/diameter_traffic.erl index 0de3825943..c3b9c195fb 100644 --- a/lib/diameter/src/base/diameter_traffic.erl +++ b/lib/diameter/src/base/diameter_traffic.erl @@ -205,16 +205,25 @@ recv_request({#diameter_app{id = Id, dictionary = Dict} = App, Caps}, Caps, Dict0, RecvData, - diameter_codec:decode(Id, Dict, Pkt)); + errors(Id, diameter_codec:decode(Id, Dict, Pkt))); %% Note that the decode is different depending on whether or not Id is %% ?APP_ID_RELAY. %% DIAMETER_APPLICATION_UNSUPPORTED 3007 %% A request was sent for an application that is not supported. -recv_request(#diameter_caps{} = Caps, TPid, Pkt, Dict0, _) -> - As = collect_avps(Pkt), - protocol_error(3007, TPid, Caps, Dict0, Pkt#diameter_packet{avps = As}); +recv_request(#diameter_caps{} + = Caps, + TPid, + #diameter_packet{errors = Es} + = Pkt, + Dict0, + _) -> + protocol_error(TPid, + Caps, + Dict0, + Pkt#diameter_packet{avps = collect_avps(Pkt), + errors = [3007 | Es]}); recv_request(false, _, _, _, _) -> %% transport has gone down ok. @@ -229,75 +238,25 @@ collect_avps(Pkt) -> %% recv_R/6 -%% Wrong number of bits somewhere in the message: reply. -%% -%% DIAMETER_INVALID_AVP_BITS 3009 -%% A request was received that included an AVP whose flag bits are -%% set to an unrecognized value, or that is inconsistent with the -%% AVP's definition. -%% -recv_R(_App, +%% Answer 3xxx errors ourselves ... +recv_R(#diameter_app{options = [_, {request_errors, answer_3xxx} | _]}, TPid, Caps, Dict0, _RecvData, - #diameter_packet{errors = [Bs | _]} = Pkt) - when is_bitstring(Bs) -> - protocol_error(3009, TPid, Caps, Dict0, Pkt); + #diameter_packet{errors = [RC|_]} = Pkt) + when 3 == RC div 1000 -> + protocol_error(TPid, Caps, Dict0, Pkt); -%% Either we support this application but don't recognize the command -%% or we're a relay and the command isn't proxiable. -%% -%% DIAMETER_COMMAND_UNSUPPORTED 3001 -%% The Request contained a Command-Code that the receiver did not -%% recognize or support. This MUST be used when a Diameter node -%% receives an experimental command that it does not understand. -%% -recv_R(#diameter_app{id = Id}, +%% ... or make a handle_request callback. Note that +%% Pkt#diameter_packet.msg = undefined in the 3001 case. +recv_R(App, TPid, Caps, Dict0, - _RecvData, - #diameter_packet{header = #diameter_header{is_proxiable = P}, - msg = M} - = Pkt) - when ?APP_ID_RELAY /= Id, undefined == M; - ?APP_ID_RELAY == Id, not P -> - protocol_error(3001, TPid, Caps, Dict0, Pkt); - -%% Error bit was set on a request. -%% -%% DIAMETER_INVALID_HDR_BITS 3008 -%% A request was received whose bits in the Diameter header were -%% either set to an invalid combination, or to a value that is -%% inconsistent with the command code's definition. -%% -recv_R(_App, - TPid, - Caps, - Dict0, - _RecvData, - #diameter_packet{header = #diameter_header{is_error = true}} - = Pkt) -> - protocol_error(3008, TPid, Caps, Dict0, Pkt); - -%% A message in a locally supported application or a proxiable message -%% in the relay application. Don't distinguish between the two since -%% each application has its own callback config. That is, the user can -%% easily distinguish between the two cases. -recv_R(App, TPid, Caps, Dict0, RecvData, Pkt) -> - request_cb(App, TPid, Caps, Dict0, RecvData, examine(Pkt)). - -%% Note that there may still be errors but these aren't protocol -%% (3xxx) errors that lead to an answer-message. - -request_cb(App, - TPid, - Caps, - Dict0, - #recvdata{service_name = SvcName} - = RecvData, - Pkt) -> + #recvdata{service_name = SvcName} + = RecvData, + Pkt) -> request_cb(cb(App, handle_request, [Pkt, SvcName, {TPid, Caps}]), App, TPid, @@ -307,20 +266,21 @@ request_cb(App, [], Pkt). -%% examine/1 +%% errors/1 %% -%% Look for errors in a decoded message. It's odd/unfortunate that -%% 501[15] aren't protocol errors. +%% Look for errors in a decoded message, prepending the errors field +%% with the first detected error. It's odd/unfortunate that 5011 isn't +%% a protocol error. %% DIAMETER_INVALID_MESSAGE_LENGTH 5015 %% %% This error is returned when a request is received with an invalid %% message length. -examine(#diameter_packet{header = #diameter_header{length = Len}, - bin = Bin, - errors = Es} - = Pkt) +errors(_, #diameter_packet{header = #diameter_header{length = Len}, + bin = Bin, + errors = Es} + = Pkt) when Len < 20; 0 /= Len rem 4; 8*Len /= bit_size(Bin) -> @@ -330,13 +290,47 @@ examine(#diameter_packet{header = #diameter_header{length = Len}, %% This error is returned when a request was received, whose version %% number is unsupported. -examine(#diameter_packet{header = #diameter_header{version = V}, - errors = Es} - = Pkt) +errors(_, #diameter_packet{header = #diameter_header{version = V}, + errors = Es} + = Pkt) when V /= ?DIAMETER_VERSION -> Pkt#diameter_packet{errors = [5011 | Es]}; -examine(Pkt) -> +%% DIAMETER_INVALID_AVP_BITS 3009 +%% A request was received that included an AVP whose flag bits are +%% set to an unrecognized value, or that is inconsistent with the +%% AVP's definition. + +errors(_, #diameter_packet{errors = [Bs | Es]} = Pkt) + when is_bitstring(Bs) -> + Pkt#diameter_packet{errors = [3009 | Es]}; + +%% DIAMETER_COMMAND_UNSUPPORTED 3001 +%% The Request contained a Command-Code that the receiver did not +%% recognize or support. This MUST be used when a Diameter node +%% receives an experimental command that it does not understand. + +errors(Id, #diameter_packet{header = #diameter_header{is_proxiable = P}, + msg = M, + errors = Es} + = Pkt) + when ?APP_ID_RELAY /= Id, undefined == M; %% don't know the command + ?APP_ID_RELAY == Id, not P -> %% command isn't proxiable + Pkt#diameter_packet{errors = [3001 | Es]}; + +%% DIAMETER_INVALID_HDR_BITS 3008 +%% A request was received whose bits in the Diameter header were +%% either set to an invalid combination, or to a value that is +%% inconsistent with the command code's definition. + +errors(_, #diameter_packet{header = #diameter_header{is_request = true, + is_error = true}, + errors = Es} + = Pkt) -> + Pkt#diameter_packet{errors = [3008 | Es]}; + +%% Green. +errors(_, Pkt) -> Pkt. %% request_cb/8 @@ -365,7 +359,7 @@ request_cb({protocol_error, RC}, _RecvData, Fs, Pkt) - when 3000 =< RC, RC < 4000 -> + when 3 == RC div 1000 -> protocol_error(RC, TPid, Caps, Dict0, Fs, Pkt); %% RFC 3588 says we must reply 3001 to anything unrecognized or @@ -447,28 +441,36 @@ dict(Dict, Dict0, Rec) -> error:_ -> Dict end. -%% protocol_error/6 - -protocol_error(RC, TPid, Caps, Dict0, Fs, Pkt) -> - #diameter_caps{origin_host = {OH,_}, - origin_realm = {OR,_}} - = Caps, - #diameter_packet{avps = Avps, errors = Es} - = Pkt, +%% protocol_error/5 +protocol_error(TPid, + #diameter_caps{origin_host = {OH,_}, + origin_realm = {OR,_}}, + Dict0, + Fs, + #diameter_packet{avps = Avps, + errors = [RC|_]} + = Pkt) -> ?LOG({error, RC}, Pkt), - reply(answer_message({OH, OR, RC}, Dict0, Avps), - Dict0, - TPid, - Fs, - Pkt#diameter_packet{errors = [RC | Es]}). + reply(answer_message({OH, OR, RC}, Dict0, Avps), Dict0, TPid, Fs, Pkt). %% Note that reply/5 may set the result code once more. It's set in %% answer_message/3 in case reply/5 doesn't. -%% protocol_error/5 +protocol_error(TPid, Caps, Dict0, Pkt) -> + protocol_error(TPid, Caps, Dict0, [], Pkt). -protocol_error(RC, TPid, Caps, Dict0, Pkt) -> - protocol_error(RC, TPid, Caps, Dict0, [], Pkt). +protocol_error(RC, + TPid, + Caps, + Dict0, + Fs, + #diameter_packet{errors = Es} + = Pkt) -> + protocol_error(TPid, + Caps, + Dict0, + Fs, + Pkt#diameter_packet{errors = [RC | Es]}). %% resend/7 %% @@ -661,15 +663,15 @@ rc(RC) -> %% rc/4 -rc(#diameter_packet{msg = Rec} = Pkt, RC, Failed, DictT) -> - Pkt#diameter_packet{msg = rc(Rec, RC, Failed, DictT)}; +rc(#diameter_packet{msg = Rec} = Pkt, RC, Failed, Dict) -> + Pkt#diameter_packet{msg = rc(Rec, RC, Failed, Dict)}; -rc(Rec, RC, Failed, DictT) +rc(Rec, RC, Failed, Dict) when is_integer(RC) -> set(Rec, - lists:append([rc(Rec, {'Result-Code', RC}, DictT), - failed_avp(Rec, Failed, DictT)]), - DictT). + lists:append([rc(Rec, {'Result-Code', RC}, Dict), + failed_avp(Rec, Failed, Dict)]), + Dict). %% Reply as name and tuple list ... set([_|_] = Ans, Avps, _) -> @@ -1268,11 +1270,12 @@ handle_answer(SvcName, App, {error, Req, Reason}) -> handle_error(App, Req, Reason, SvcName); handle_answer(SvcName, - #diameter_app{dictionary = Dict} + #diameter_app{dictionary = Dict, + id = Id} = App, {answer, Req, Dict0, Pkt}) -> Mod = dict(Dict, Dict0, Pkt), - answer(examine(diameter_codec:decode(Mod, Pkt)), + answer(errors(Id, diameter_codec:decode(Mod, Pkt)), SvcName, Mod, App, -- cgit v1.2.3 From 60e5862b7c162a7b392eb2e2e77121b6333a862b Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Tue, 12 Feb 2013 00:13:05 +0100 Subject: Minor suite simplification --- lib/diameter/test/diameter_failover_SUITE.erl | 6 ++-- lib/diameter/test/diameter_length_SUITE.erl | 43 ++++++++++++++------------- lib/diameter/test/diameter_relay_SUITE.erl | 2 +- lib/diameter/test/diameter_tls_SUITE.erl | 2 +- lib/diameter/test/diameter_traffic_SUITE.erl | 28 ++++++++--------- 5 files changed, 41 insertions(+), 40 deletions(-) diff --git a/lib/diameter/test/diameter_failover_SUITE.erl b/lib/diameter/test/diameter_failover_SUITE.erl index bb820a8bf2..0ea8ae2d4e 100644 --- a/lib/diameter/test/diameter_failover_SUITE.erl +++ b/lib/diameter/test/diameter_failover_SUITE.erl @@ -103,9 +103,9 @@ -define(SUCCESS, 2001). %% Value of Termination-Cause determines client/server behaviour. --define(LOGOUT, ?'DIAMETER_BASE_TERMINATION-CAUSE_DIAMETER_LOGOUT'). --define(MOVED, ?'DIAMETER_BASE_TERMINATION-CAUSE_DIAMETER_USER_MOVED'). --define(TIMEOUT, ?'DIAMETER_BASE_TERMINATION-CAUSE_DIAMETER_SESSION_TIMEOUT'). +-define(LOGOUT, ?'DIAMETER_BASE_TERMINATION-CAUSE_LOGOUT'). +-define(MOVED, ?'DIAMETER_BASE_TERMINATION-CAUSE_USER_MOVED'). +-define(TIMEOUT, ?'DIAMETER_BASE_TERMINATION-CAUSE_SESSION_TIMEOUT'). %% =========================================================================== diff --git a/lib/diameter/test/diameter_length_SUITE.erl b/lib/diameter/test/diameter_length_SUITE.erl index 4e413e6a42..ffb19d2288 100644 --- a/lib/diameter/test/diameter_length_SUITE.erl +++ b/lib/diameter/test/diameter_length_SUITE.erl @@ -41,10 +41,10 @@ %% diameter callbacks -export([peer_up/3, peer_down/3, - pick_peer/6, - prepare_request/5, - handle_answer/6, - handle_error/6, + pick_peer/5, + prepare_request/4, + handle_answer/5, + handle_error/5, handle_request/3]). -include("diameter.hrl"). @@ -73,14 +73,14 @@ {answer_errors, callback}]}]). -define(SUCCESS, - ?'DIAMETER_BASE_RESULT-CODE_DIAMETER_SUCCESS'). + ?'DIAMETER_BASE_RESULT-CODE_SUCCESS'). -define(MISSING_AVP, - ?'DIAMETER_BASE_RESULT-CODE_DIAMETER_MISSING_AVP'). + ?'DIAMETER_BASE_RESULT-CODE_MISSING_AVP'). -define(INVALID_MESSAGE_LENGTH, - ?'DIAMETER_BASE_RESULT-CODE_DIAMETER_INVALID_MESSAGE_LENGTH'). + ?'DIAMETER_BASE_RESULT-CODE_INVALID_MESSAGE_LENGTH'). -define(LOGOUT, - ?'DIAMETER_BASE_TERMINATION-CAUSE_DIAMETER_LOGOUT'). + ?'DIAMETER_BASE_TERMINATION-CAUSE_LOGOUT'). -define(GROUPS, [exit, handle, discard]). @@ -196,21 +196,18 @@ send(discard) -> = call(0); send(Config) -> - Group = proplists:get_value(group, Config), - put({?MODULE, group}, Group), - send(Group). + send(proplists:get_value(group, Config)). %% =========================================================================== call(Delta) -> - Group = get({?MODULE, group}), diameter:call(?CLIENT, ?DICT, #diameter_base_STR {'Termination-Cause' = ?LOGOUT, 'Auth-Application-Id' = ?DIAMETER_APP_ID_COMMON, 'Origin-State-Id' = [7]}, - [{extra, [Group, Delta]}]). + [{extra, [Delta]}]). %% =========================================================================== %% diameter callbacks @@ -225,14 +222,14 @@ peer_up(_SvcName, _Peer, State) -> peer_down(_SvcName, _Peer, State) -> State. -%% pick_peer/6 +%% pick_peer/5 -pick_peer([Peer], _, ?CLIENT, _State, _Group, _Delta) -> +pick_peer([Peer], _, ?CLIENT, _State, _Delta) -> {ok, Peer}. -%% prepare_request/5 +%% prepare_request/4 -prepare_request(Pkt, ?CLIENT, {_Ref, Caps}, _Group, Delta) -> +prepare_request(Pkt, ?CLIENT, {_Ref, Caps}, Delta) -> {send, resize(Delta, prepare(Pkt, Caps))}. prepare(#diameter_packet{msg = Req0} = Pkt, Caps) -> @@ -253,14 +250,14 @@ resize(Delta, #diameter_packet{bin = Bin} = Pkt) -> resize(Delta, <>) -> <>. -%% handle_answer/6 +%% handle_answer/5 -handle_answer(Pkt, _Req, ?CLIENT, _Peer, _Group, _Delta) -> +handle_answer(Pkt, _Req, ?CLIENT, _Peer, _Delta) -> Pkt#diameter_packet.msg. -%% handle_error/6 +%% handle_error/5 -handle_error(Reason, _Req, ?CLIENT, _Peer, _Group, _Delta) -> +handle_error(Reason, _Req, ?CLIENT, _Peer, _Delta) -> {error, Reason}. %% handle_request/3 @@ -280,8 +277,12 @@ handle_request(Pkt, ?SERVER, {_Ref, Caps}) -> answer(Group, #diameter_packet{errors = Es}, Ans) -> answer(Group, Es, Ans); +%% No errors: just answer. answer(_, [], Ans) -> {reply, Ans}; + +%% Otherwise an invalid length should only reach the callback if +%% length_errors = handle. answer(Group, [RC|_], Ans) when RC == ?INVALID_MESSAGE_LENGTH, Group == handle; RC /= ?INVALID_MESSAGE_LENGTH -> diff --git a/lib/diameter/test/diameter_relay_SUITE.erl b/lib/diameter/test/diameter_relay_SUITE.erl index f10d82bdf8..614eb4d4ca 100644 --- a/lib/diameter/test/diameter_relay_SUITE.erl +++ b/lib/diameter/test/diameter_relay_SUITE.erl @@ -107,7 +107,7 @@ -define(LOOP_DETECTED, 3005). -define(UNABLE_TO_DELIVER, 3002). --define(LOGOUT, ?'DIAMETER_BASE_TERMINATION-CAUSE_DIAMETER_LOGOUT'). +-define(LOGOUT, ?'DIAMETER_BASE_TERMINATION-CAUSE_LOGOUT'). -define(AUTHORIZE_ONLY, ?'DIAMETER_BASE_RE-AUTH-REQUEST-TYPE_AUTHORIZE_ONLY'). %% =========================================================================== diff --git a/lib/diameter/test/diameter_tls_SUITE.erl b/lib/diameter/test/diameter_tls_SUITE.erl index 6cc34b20c5..92a1113758 100644 --- a/lib/diameter/test/diameter_tls_SUITE.erl +++ b/lib/diameter/test/diameter_tls_SUITE.erl @@ -122,7 +122,7 @@ {capabilities, Caps}]}). -define(SUCCESS, 2001). --define(LOGOUT, ?'DIAMETER_BASE_TERMINATION-CAUSE_DIAMETER_LOGOUT'). +-define(LOGOUT, ?'DIAMETER_BASE_TERMINATION-CAUSE_LOGOUT'). %% =========================================================================== diff --git a/lib/diameter/test/diameter_traffic_SUITE.erl b/lib/diameter/test/diameter_traffic_SUITE.erl index 6727e88b66..d3d6fff705 100644 --- a/lib/diameter/test/diameter_traffic_SUITE.erl +++ b/lib/diameter/test/diameter_traffic_SUITE.erl @@ -178,27 +178,27 @@ diameter_gen_acct_rfc6733]]]). -define(SUCCESS, - ?'DIAMETER_BASE_RESULT-CODE_DIAMETER_SUCCESS'). + ?'DIAMETER_BASE_RESULT-CODE_SUCCESS'). -define(COMMAND_UNSUPPORTED, - ?'DIAMETER_BASE_RESULT-CODE_DIAMETER_COMMAND_UNSUPPORTED'). + ?'DIAMETER_BASE_RESULT-CODE_COMMAND_UNSUPPORTED'). -define(TOO_BUSY, - ?'DIAMETER_BASE_RESULT-CODE_DIAMETER_TOO_BUSY'). + ?'DIAMETER_BASE_RESULT-CODE_TOO_BUSY'). -define(APPLICATION_UNSUPPORTED, - ?'DIAMETER_BASE_RESULT-CODE_DIAMETER_APPLICATION_UNSUPPORTED'). + ?'DIAMETER_BASE_RESULT-CODE_APPLICATION_UNSUPPORTED'). -define(INVALID_HDR_BITS, - ?'DIAMETER_BASE_RESULT-CODE_DIAMETER_INVALID_HDR_BITS'). + ?'DIAMETER_BASE_RESULT-CODE_INVALID_HDR_BITS'). -define(INVALID_AVP_BITS, - ?'DIAMETER_BASE_RESULT-CODE_DIAMETER_INVALID_AVP_BITS'). + ?'DIAMETER_BASE_RESULT-CODE_INVALID_AVP_BITS'). -define(AVP_UNSUPPORTED, - ?'DIAMETER_BASE_RESULT-CODE_DIAMETER_AVP_UNSUPPORTED'). + ?'DIAMETER_BASE_RESULT-CODE_AVP_UNSUPPORTED'). -define(UNSUPPORTED_VERSION, - ?'DIAMETER_BASE_RESULT-CODE_DIAMETER_UNSUPPORTED_VERSION'). + ?'DIAMETER_BASE_RESULT-CODE_UNSUPPORTED_VERSION'). -define(REALM_NOT_SERVED, - ?'DIAMETER_BASE_RESULT-CODE_DIAMETER_REALM_NOT_SERVED'). + ?'DIAMETER_BASE_RESULT-CODE_REALM_NOT_SERVED'). -define(UNABLE_TO_DELIVER, - ?'DIAMETER_BASE_RESULT-CODE_DIAMETER_UNABLE_TO_DELIVER'). + ?'DIAMETER_BASE_RESULT-CODE_UNABLE_TO_DELIVER'). -define(INVALID_AVP_LENGTH, - ?'DIAMETER_BASE_RESULT-CODE_DIAMETER_INVALID_AVP_LENGTH'). + ?'DIAMETER_BASE_RESULT-CODE_INVALID_AVP_LENGTH'). -define(EVENT_RECORD, ?'DIAMETER_BASE_ACCOUNTING-RECORD-TYPE_EVENT_RECORD'). @@ -208,11 +208,11 @@ ?'DIAMETER_BASE_RE-AUTH-REQUEST-TYPE_AUTHORIZE_AUTHENTICATE'). -define(LOGOUT, - ?'DIAMETER_BASE_TERMINATION-CAUSE_DIAMETER_LOGOUT'). + ?'DIAMETER_BASE_TERMINATION-CAUSE_LOGOUT'). -define(BAD_ANSWER, - ?'DIAMETER_BASE_TERMINATION-CAUSE_DIAMETER_BAD_ANSWER'). + ?'DIAMETER_BASE_TERMINATION-CAUSE_BAD_ANSWER'). -define(USER_MOVED, - ?'DIAMETER_BASE_TERMINATION-CAUSE_DIAMETER_USER_MOVED'). + ?'DIAMETER_BASE_TERMINATION-CAUSE_USER_MOVED'). %% =========================================================================== -- cgit v1.2.3 From df2189c22f7ca7660496e46322d8b825e9f28ba3 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Mon, 11 Feb 2013 19:35:19 +0100 Subject: Add 3xxx suite for testing application_opt() request_errors --- lib/diameter/test/diameter_3xxx_SUITE.erl | 214 ++++++++++++++++++++++++++++++ lib/diameter/test/modules.mk | 3 +- 2 files changed, 216 insertions(+), 1 deletion(-) create mode 100644 lib/diameter/test/diameter_3xxx_SUITE.erl diff --git a/lib/diameter/test/diameter_3xxx_SUITE.erl b/lib/diameter/test/diameter_3xxx_SUITE.erl new file mode 100644 index 0000000000..a87d5347db --- /dev/null +++ b/lib/diameter/test/diameter_3xxx_SUITE.erl @@ -0,0 +1,214 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2013. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% 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% +%% + +%% +%% Tests of application_opt() request_errors. +%% + +-module(diameter_3xxx_SUITE). + +-export([suite/0, + all/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]). + +%% testcases +-export([start/1, + send/1, + stop/1]). + +%% diameter callbacks +-export([peer_up/3, + peer_down/3, + pick_peer/4, + prepare_request/3, + handle_answer/4, + handle_error/4, + handle_request/3]). + +-include("diameter.hrl"). +-include("diameter_gen_base_rfc6733.hrl"). + +%% =========================================================================== + +-define(util, diameter_util). + +-define(CLIENT, "CLIENT"). +-define(SERVER, "SERVER"). +-define(REALM, "erlang.org"). +-define(HOST(Host, Realm), Host ++ [$.|Realm]). +-define(DICT, diameter_gen_base_rfc6733). + +%% Config for diameter:start_service/2. +-define(SERVICE(Name, RequestErrors), + [{'Origin-Host', Name ++ "." ++ ?REALM}, + {'Origin-Realm', ?REALM}, + {'Host-IP-Address', [{127,0,0,1}]}, + {'Vendor-Id', 12345}, + {'Product-Name', "OTP/diameter"}, + {'Auth-Application-Id', [?DIAMETER_APP_ID_COMMON]}, + {application, [{dictionary, ?DICT}, + {module, ?MODULE}, + {answer_errors, callback}, + {request_errors, RequestErrors}]}]). + +-define(SUCCESS, ?'DIAMETER_BASE_RESULT-CODE_SUCCESS'). +-define(UNSUPPORTED, ?'DIAMETER_BASE_RESULT-CODE_COMMAND_UNSUPPORTED'). + +-define(LOGOUT, ?'DIAMETER_BASE_TERMINATION-CAUSE_LOGOUT'). + +-define(GROUPS, [answer_3xxx, callback]). +-define(L, atom_to_list). + +%% =========================================================================== + +suite() -> + [{timetrap, {seconds, 60}}]. + +all() -> + [{group, G} || G <- ?GROUPS]. + +groups() -> + [{G, [], [start, send, stop]} || G <- ?GROUPS]. + +init_per_suite(Config) -> + ok = diameter:start(), + Config. + +end_per_suite(_Config) -> + ok = diameter:stop(). + +init_per_group(Group, Config) -> + [{group, Group} | Config]. + +end_per_group(_, _) -> + ok. + +init_per_testcase(_Name, Config) -> + Config. + +end_per_testcase(_, _) -> + ok. + +origin(answer_3xxx) -> 0; +origin(callback) -> 1; + +origin(0) -> answer_3xxx; +origin(1) -> callback. + +%% =========================================================================== + +%% start/1 + +start(Config) -> + Group = proplists:get_value(group, Config), + ok = diameter:start_service(?SERVER, ?SERVICE(?L(Group), Group)), + ok = diameter:start_service(?CLIENT, ?SERVICE(?CLIENT, callback)), + LRef = ?util:listen(?SERVER, tcp), + ?util:connect(?CLIENT, + tcp, + LRef, + [{capabilities, [{'Origin-State-Id', origin(Group)}]}]). + +%% stop/1 + +stop(_Config) -> + ok = diameter:remove_transport(?CLIENT, true), + ok = diameter:remove_transport(?SERVER, true), + ok = diameter:stop_service(?SERVER), + ok = diameter:stop_service(?CLIENT). + +%% send/1 +%% +%% Send a unknown command and expect a different result depending on +%% whether or not the server gets a handle_request callback. + +%% Server handle_request discards the request. +send(callback) -> + {error, timeout} = call(); + +%% No handle_request, diameter answers. +send(answer_3xxx) -> + #'diameter_base_answer-message'{'Result-Code' = ?UNSUPPORTED} = call(); + +send(Config) -> + send(proplists:get_value(group, Config)). + +%% =========================================================================== + +call() -> + diameter:call(?CLIENT, + ?DICT, + #diameter_base_STR + {'Termination-Cause' = ?LOGOUT, + 'Auth-Application-Id' = ?DIAMETER_APP_ID_COMMON}). + +%% =========================================================================== +%% diameter callbacks + +%% peer_up/3 + +peer_up(_SvcName, _Peer, State) -> + State. + +%% peer_down/3 + +peer_down(_SvcName, _Peer, State) -> + State. + +%% pick_peer/4 + +pick_peer([Peer], _, ?CLIENT, _State) -> + {ok, Peer}. + +%% prepare_request/3 + +prepare_request(#diameter_packet{msg = Req0} = Pkt0, ?CLIENT, {_Ref, Caps}) -> + #diameter_caps{origin_host = {OH, _}, + origin_realm = {OR, DR}} + = Caps, + Req = Req0#diameter_base_STR{'Session-Id' = diameter:session_id(OH), + 'Origin-Host' = OH, + 'Origin-Realm' = OR, + 'Destination-Realm' = DR}, + #diameter_packet{bin = <>} + = Pkt + = diameter_codec:encode(?DICT, Pkt0#diameter_packet{msg = Req}), + + {send, Pkt#diameter_packet{bin = <>}}. + +%% handle_answer/4 + +handle_answer(Pkt, _Req, ?CLIENT, _Peer) -> + Pkt#diameter_packet.msg. + +%% handle_error/4 + +handle_error(Reason, _Req, ?CLIENT, _Peer) -> + {error, Reason}. + +%% handle_request/3 + +handle_request(_, ?SERVER, _) -> + discard. diff --git a/lib/diameter/test/modules.mk b/lib/diameter/test/modules.mk index f575085843..32e5fb4613 100644 --- a/lib/diameter/test/modules.mk +++ b/lib/diameter/test/modules.mk @@ -42,7 +42,8 @@ MODULES = \ diameter_failover_SUITE \ diameter_dpr_SUITE \ diameter_event_SUITE \ - diameter_length_SUITE + diameter_length_SUITE \ + diameter_3xxx_SUITE HRL_FILES = \ diameter_ct.hrl -- cgit v1.2.3