aboutsummaryrefslogtreecommitdiffstats
path: root/lib/diameter/src
diff options
context:
space:
mode:
Diffstat (limited to 'lib/diameter/src')
-rw-r--r--lib/diameter/src/app/Makefile27
-rw-r--r--lib/diameter/src/app/diameter.app.src2
-rw-r--r--lib/diameter/src/app/diameter.appup.src22
-rw-r--r--lib/diameter/src/app/diameter_callback.erl8
-rw-r--r--lib/diameter/src/app/diameter_codec.erl22
-rw-r--r--lib/diameter/src/app/diameter_config.erl11
-rw-r--r--lib/diameter/src/app/diameter_dbg.erl147
-rw-r--r--lib/diameter/src/app/diameter_internal.hrl25
-rw-r--r--lib/diameter/src/app/diameter_lib.erl40
-rw-r--r--lib/diameter/src/app/diameter_peer.erl11
-rw-r--r--lib/diameter/src/app/diameter_reg.erl12
-rw-r--r--lib/diameter/src/app/diameter_service.erl200
-rw-r--r--lib/diameter/src/app/diameter_stats.erl11
-rw-r--r--lib/diameter/src/app/diameter_sync.erl35
-rw-r--r--lib/diameter/src/app/modules.mk12
-rw-r--r--lib/diameter/src/compiler/Makefile10
-rw-r--r--lib/diameter/src/compiler/diameter_codegen.erl79
-rw-r--r--lib/diameter/src/compiler/diameter_spec_util.erl50
-rw-r--r--lib/diameter/src/transport/diameter_sctp.erl19
19 files changed, 363 insertions, 380 deletions
diff --git a/lib/diameter/src/app/Makefile b/lib/diameter/src/app/Makefile
index 6de220d282..a75c70d71c 100644
--- a/lib/diameter/src/app/Makefile
+++ b/lib/diameter/src/app/Makefile
@@ -52,18 +52,29 @@ INCDIR = ../../include
include modules.mk
+SPEC_MODULES = \
+ $(SPEC_FILES:%.dia=%)
+
SPEC_ERL_FILES = \
$(SPEC_FILES:%.dia=%.erl)
SPEC_HRL_FILES = \
$(SPEC_FILES:%.dia=%.hrl)
+MODULES = \
+ $(RUNTIME_MODULES) \
+ $(HELP_MODULES)
+
APP_MODULES = \
- $(MODULES) \
- $(SPEC_FILES:%.dia=%)
+ $(RUNTIME_MODULES) \
+ $(SPEC_MODULES)
+
+TARGET_MODULES = \
+ $(APP_MODULES) \
+ $(HELP_MODULES)
TARGET_FILES = \
- $(APP_MODULES:%=$(EBIN)/%.$(EMULATOR)) \
+ $(TARGET_MODULES:%=$(EBIN)/%.$(EMULATOR)) \
$(APP_TARGET) \
$(APPUP_TARGET)
@@ -125,17 +136,15 @@ info:
# ----------------------------------------------------
# Generate the app file and then modules into in. This shouldn't know
-# about ../{compiler,transport} but good enough for now.
+# about ../transport but good enough for now.
$(APP_TARGET): $(APP_SRC) \
../../vsn.mk \
modules.mk \
- ../compiler/modules.mk \
../transport/modules.mk
sed -e 's;%VSN%;$(VSN);' $< > $@
M=`echo $(APP_MODULES) | sed -e 's/^ *//' -e 's/ *$$//' -e 'y/ /,/'`; \
echo "/%APP_MODULES%/s//$$M/;w;q" | tr ';' '\n' \
| ed -s $@
- $(MAKE) -C ../compiler $(APP_TARGET) APP_TARGET=$(APP_TARGET)
$(MAKE) -C ../transport $(APP_TARGET) APP_TARGET=$(APP_TARGET)
$(APPUP_TARGET): $(APPUP_SRC) ../../vsn.mk
@@ -150,7 +159,6 @@ app: $(APP_TARGET) $(APPUP_TARGET)
diameter_gen_%.erl diameter_gen_%.hrl: diameter_gen_%.dia
../../bin/diameterc -i $(EBIN) -o $(@D) $<
-
# ----------------------------------------------------
# Release Target
# ----------------------------------------------------
@@ -181,6 +189,11 @@ release_docs_spec:
# Dependencies
# ----------------------------------------------------
+$(SPEC_MODULES:%=$(EBIN)/%.$(EMULATOR)): \
+ $(EBIN)/diameter_exprecs.$(EMULATOR) \
+ $(DIAMETER_TOP)/include/diameter.hrl \
+ $(DIAMETER_TOP)/include/diameter_gen.hrl
+
depend: depend.mk
# Generate dependencies makefile. It's assumed that the compile target
diff --git a/lib/diameter/src/app/diameter.app.src b/lib/diameter/src/app/diameter.app.src
index 119997953e..a806b5c78a 100644
--- a/lib/diameter/src/app/diameter.app.src
+++ b/lib/diameter/src/app/diameter.app.src
@@ -20,7 +20,7 @@
{application, diameter,
[{description, "Diameter protocol"},
{vsn, "%VSN%"},
- {modules, [%APP_MODULES%,%COMPILER_MODULES%,%TRANSPORT_MODULES%]},
+ {modules, [%APP_MODULES%,%TRANSPORT_MODULES%]},
{registered, []},
{applications, [stdlib, kernel]},
{env, []},
diff --git a/lib/diameter/src/app/diameter.appup.src b/lib/diameter/src/app/diameter.appup.src
index 2b96153575..6d8ceadb92 100644
--- a/lib/diameter/src/app/diameter.appup.src
+++ b/lib/diameter/src/app/diameter.appup.src
@@ -20,8 +20,28 @@
{"%VSN%",
[
+ {"0.9",
+ [
+ {load_module, diameter, soft_purge, soft_purge, []},
+ {load_module, diameter_capx, soft_purge, soft_purge, []},
+ {load_module, diameter_codec, soft_purge, soft_purge, [diameter_lib]},
+ {load_module, diameter_lib, soft_purge, soft_purge, []},
+ {load_module, diameter_types, soft_purge, soft_purge, []},
+ {load_module, diameter_gen_base_accounting, soft_purge, soft_purge, []},
+ {load_module, diameter_gen_base_rfc3588, soft_purge, soft_purge, []},
+ {load_module, diameter_gen_relay, soft_purge, soft_purge, []},
+ {update, diameter_service, soft, soft_purge, soft_purge, [diameter_lib]},
+ {update, diameter_config, soft, soft_purge, soft_purge, []},
+ {update, diameter_peer, soft, soft_purge, soft_purge, []},
+ {update, diameter_peer_fsm, soft, soft_purge, soft_purge, [diameter_lib]},
+ {update, diameter_reg, soft, soft_purge, soft_purge, []},
+ {update, diameter_sctp, soft, soft_purge, soft_purge, []},
+ {update, diameter_stats, soft, soft_purge, soft_purge, []},
+ {update, diameter_sync, soft, soft_purge, soft_purge, []},
+ {update, diameter_watchdog, soft, soft_purge, soft_purge, [diameter_lib]}
+ ]
+ }
],
[
]
}.
-
diff --git a/lib/diameter/src/app/diameter_callback.erl b/lib/diameter/src/app/diameter_callback.erl
index fcf9a8fc1e..6d5c8cdca1 100644
--- a/lib/diameter/src/app/diameter_callback.erl
+++ b/lib/diameter/src/app/diameter_callback.erl
@@ -60,28 +60,28 @@ pick_peer([Peer|_], _, _SvcName, _State) ->
%%% ----------------------------------------------------------
prepare_request(Pkt, _SvcName, _Peer) ->
- Pkt.
+ {send, Pkt}.
%%% ----------------------------------------------------------
%%% # prepare_retransmit/3
%%% ----------------------------------------------------------
prepare_retransmit(Pkt, _SvcName, _Peer) ->
- Pkt.
+ {send, Pkt}.
%%% ----------------------------------------------------------
%%% # handle_request/3
%%% ----------------------------------------------------------
handle_request(_Pkt, _SvcName, _Peer) ->
- discard.
+ {protocol_error, 3001}. %% DIAMETER_COMMAND_UNSUPPORTED
%%% ----------------------------------------------------------
%%% # handle_answer/4
%%% ----------------------------------------------------------
handle_answer(#diameter_packet{msg = Ans}, _Req, _SvcName, _Peer) ->
- {ok, Ans}.
+ Ans.
%%% ---------------------------------------------------------------------------
%%% # handle_error/4
diff --git a/lib/diameter/src/app/diameter_codec.erl b/lib/diameter/src/app/diameter_codec.erl
index f6cbde5446..d88f42fb7c 100644
--- a/lib/diameter/src/app/diameter_codec.erl
+++ b/lib/diameter/src/app/diameter_codec.erl
@@ -140,10 +140,10 @@ make_flags(Flags0, #diameter_header{is_request = R,
mf(undefined, F, _) ->
F;
mf(B, F, N) -> %% reset the affected bit
- (F bxor (F band (1 bsl N))) bor (bit(B) bsl N).
+ (F bxor (F band (1 bsl N))) bor bit(B, N).
-bit(true) -> 1;
-bit(false) -> 0.
+bit(true, N) -> 1 bsl N;
+bit(false, _) -> 0.
%% values/1
@@ -199,25 +199,16 @@ msg_header(Mod, MsgName, Header) ->
p(Flags, #diameter_header{is_request = true,
is_proxiable = P}) ->
- Flags bor choose(P, 2#01000000, 0);
+ Flags band (2#10110000 bor choose(P, 2#01000000, 0));
p(Flags, _) ->
Flags.
-%% The header below is that of the incoming request being answered,
-%% not of the answer (which hasn't been encoded yet).
-
h(Mod, 'answer-message' = MsgName, Header) ->
?BASE = Mod,
- #diameter_header{is_request = true,
- cmd_code = Code}
- = Header,
+ #diameter_header{cmd_code = Code} = Header,
{_, Flags, ApplId} = ?BASE:msg_header(MsgName),
{Code, Flags, ApplId};
-h(Mod, MsgName, #diameter_header{is_request = true,
- cmd_code = Code}) ->
- {Code, _, _} = Mod:msg_header(MsgName); %% ensure Code
-
h(Mod, MsgName, _) ->
Mod:msg_header(MsgName).
@@ -290,7 +281,8 @@ decode_avps(MsgName, Mod, Pkt, {Bs, Avps}) -> %% invalid avp bits ...
decode_avps('', Mod, Pkt, Avps) -> %% unknown message ...
?LOG(unknown, {Mod, Pkt#diameter_packet.header}),
- Pkt#diameter_packet{errors = lists:reverse(Avps)};
+ Pkt#diameter_packet{avps = lists:reverse(Avps),
+ errors = [3001]}; %% DIAMETER_COMMAND_UNSUPPORTED
%% msg = undefined identifies this case.
decode_avps(MsgName, Mod, Pkt, Avps) -> %% ... or not
diff --git a/lib/diameter/src/app/diameter_config.erl b/lib/diameter/src/app/diameter_config.erl
index 42c70890b3..a6b48fe65b 100644
--- a/lib/diameter/src/app/diameter_config.erl
+++ b/lib/diameter/src/app/diameter_config.erl
@@ -267,7 +267,7 @@ handle_call(uptime, _, #state{id = Time} = State) ->
{reply, diameter_lib:now_diff(Time), State};
handle_call(Req, From, State) ->
- warning_msg("received unexpected request from ~p:~n~w", [From, Req]),
+ ?UNEXPECTED([Req, From]),
Reply = {error, {bad_request, Req}},
{reply, Reply, State}.
@@ -276,7 +276,7 @@ handle_call(Req, From, State) ->
%%% ----------------------------------------------------------
handle_cast(Msg, State) ->
- warning_msg("received unexpected message:~n~w", [Msg]),
+ ?UNEXPECTED([Msg]),
{noreply, State}.
%%% ----------------------------------------------------------
@@ -309,7 +309,7 @@ handle_info(restart, State) ->
{noreply, State};
handle_info(Info, State) ->
- warning_msg("received unknown info:~n~w", [Info]),
+ ?UNEXPECTED([Info]),
{noreply, State}.
%%--------------------------------------------------------------------
@@ -674,8 +674,3 @@ cb(M,F) ->
call(Request) ->
gen_server:call(?SERVER, Request, infinity).
-
-%% warning_msg/2
-
-warning_msg(F, A) ->
- ?diameter_warning("~p: " ++ F, [?MODULE | A]).
diff --git a/lib/diameter/src/app/diameter_dbg.erl b/lib/diameter/src/app/diameter_dbg.erl
index b18f34e13d..5b0ac3a3b6 100644
--- a/lib/diameter/src/app/diameter_dbg.erl
+++ b/lib/diameter/src/app/diameter_dbg.erl
@@ -68,12 +68,6 @@
-define(VALUES(Rec), tl(tuple_to_list(Rec))).
-%%% ----------------------------------------------------------
-%%% # log/4
-%%%
-%%% Called to have something to trace on for happenings of interest.
-%%% ----------------------------------------------------------
-
log(_Slogan, _Mod, _Line, _Details) ->
ok.
@@ -82,9 +76,6 @@ log(_Slogan, _Mod, _Line, _Details) ->
%%% ----------------------------------------------------------
help() ->
- ?INFO:usage(usage()).
-
-usage() ->
not_yet_implemented.
%%% ----------------------------------------------------------
@@ -99,30 +90,23 @@ table(T)
when (T == diameter_peer) orelse (T == diameter_reg) ->
?INFO:format(collect(T), fields(T), fun ?INFO:split/2);
-table(diameter_service = T) ->
- Fs = [name, started] ++ fields(T) ++ [peerT,
- connT,
- share_peers,
- use_shared_peers,
- shared_peers,
- local_peers,
- monitor],
- ?INFO:format(T,
- fun(R) ->
- [I,N,S|Vs] = ?VALUES(R),
- {Fs, [N,I] ++ ?VALUES(S) ++ Vs}
- end,
- fun ?INFO:split/2);
-
table(Table)
when is_atom(Table) ->
case fields(Table) of
undefined = No ->
No;
Fields ->
- ?INFO:format(Table, Fields, fun ?INFO:split/2)
+ ?INFO:format(Table, Fields, fun split/2)
end.
+split([started, name | Fs], [S, N | Vs]) ->
+ {name, [started | Fs], N, [S | Vs]};
+split([[F|FT]|Fs], [Rec|Vs]) ->
+ [_, V | VT] = tuple_to_list(Rec),
+ {F, FT ++ Fs, V, VT ++ Vs};
+split([F|Fs], [V|Vs]) ->
+ {F, Fs, V, Vs}.
+
%%% ----------------------------------------------------------
%%% # TableName()
%%% ----------------------------------------------------------
@@ -146,14 +130,14 @@ table(Table)
%%% ----------------------------------------------------------
tables() ->
- format_all(fun ?INFO:split/3).
-
-format_all(SplitFun) ->
- ?INFO:format(field(?LOCAL), SplitFun, fun collect/1).
+ ?INFO:format(field(?LOCAL), fun split/3, fun collect/1).
field(Tables) ->
lists:map(fun(T) -> {T, fields(T)} end, lists:sort(Tables)).
+split(_, Fs, Vs) ->
+ split(Fs, Vs).
+
%%% ----------------------------------------------------------
%%% # modules()
%%% ----------------------------------------------------------
@@ -396,76 +380,24 @@ stop() ->
%% tp/1
tpl(T) ->
- dbg(tpl, dbg(T)).
+ dbg(tpl, T).
tp(T) ->
- dbg(tp, dbg(T)).
-
-%% dbg/1
-
-dbg(x) ->
- [{M, x, []} || M <- [diameter_tcp,
- diameter_etcp,
- diameter_sctp,
- diameter_peer_fsm,
- diameter_watchdog]];
-
-dbg(log) ->
- {?MODULE, log, 4};
-
-dbg({log = F, Mods})
- when is_list(Mods) ->
- {?MODULE, F, [{['_','$1','_','_'],
- [?ORCOND([{'==', '$1', M} || M <- Mods])],
- []}]};
-
-dbg({log = F, Mod}) ->
- dbg({F, [Mod]});
-
-dbg(send) ->
- {diameter_peer, send, 2};
-
-dbg(recv) ->
- {diameter_peer, recv, 2};
-
-dbg(sendrecv) ->
- [{diameter_peer, send, 2},
- {diameter_peer, recv, 2}];
-
-dbg(decode) ->
- [{diameter_codec,decode,2}];
-
-dbg(encode) ->
- [{diameter_codec,encode,2,[]},
- {diameter_codec,encode,3,[]},
- {diameter_codec,encode,4}];
-
-dbg(transition = T) ->
- [{?MODULE, log, [{[T,M,'_','_'],[],[]}]}
- || M <- [diameter_watchdog, diameter_peer_fsm]];
-
-dbg(T) ->
- T.
+ dbg(tp, T).
%% dbg/2
-dbg(TF, L)
+dbg(F, L)
when is_list(L) ->
- {ok, lists:foldl(fun(T,A) -> {ok, X} = dbg(TF, T), [X|A] end, [], L)};
+ [dbg(F, X) || X <- L];
dbg(F, M)
when is_atom(M) ->
- dbg(F, {M});
+ apply(dbg, F, [M, x]);
dbg(F, T)
when is_tuple(T) ->
- [_|_] = A = tuple_to_list(T),
- {ok,_} = apply(dbg, F, case is_list(lists:last(A)) of
- false ->
- A ++ [[{'_',[],[{exception_trace}]}]];
- true ->
- A
- end).
+ apply(dbg, F, tuple_to_list(T)).
%% ===========================================================================
%% ===========================================================================
@@ -493,15 +425,19 @@ peers(Name) ->
peers(_, undefined) ->
[];
-peers(Name, {Cs,As}) ->
- mk_peer(Name, connector, Cs) ++ mk_peer(Name, acceptor, As).
-
-mk_peer(Name, T, Ts) ->
- [[Name | mk_peer(T,Vs)] || Vs <- Ts].
-
-mk_peer(Type, Vs) ->
- [Ref, State, Opts, WPid, TPid, SApps, Caps]
- = get_values(Vs, [ref, state, options, watchdog, peer, apps, caps]),
+peers(Name, Ts) ->
+ lists:flatmap(fun(T) -> mk_peers(Name, T) end, Ts).
+
+mk_peers(Name, [_, {type, connect} | _] = Ts) ->
+ [[Name | mk_peer(Ts)]];
+mk_peers(Name, [R, {type, listen}, O, {accept = A, As}]) ->
+ [[Name | mk_peer([R, {type, A}, O | Ts])] || Ts <- As].
+%% This is a bit lame: service_info works to build this list and out
+%% of something like what we want here and then we take it apart.
+
+mk_peer(Vs) ->
+ [Type, Ref, State, Opts, WPid, TPid, SApps, Caps]
+ = get_values(Vs, [type,ref,state,options,watchdog,peer,apps,caps]),
[Ref, State, [{type, Type} | Opts], s(WPid), s(TPid), SApps, Caps].
get_values(Vs, Ks) ->
@@ -509,9 +445,13 @@ get_values(Vs, Ks) ->
s(undefined = T) ->
T;
+s({Pid, _Started, _State}) ->
+ state(Pid);
+s({Pid, _Started}) ->
+ state(Pid).
%% Collect states from watchdog/transport pids.
-s(Pid) ->
+state(Pid) ->
MRef = erlang:monitor(process, Pid),
Pid ! {state, self()},
receive
@@ -541,7 +481,18 @@ fields(diameter_stats) ->
[]
end;
-?FIELDS(diameter_service);
+fields(diameter_service) ->
+ [started,
+ name,
+ record_info(fields, diameter_service),
+ peerT,
+ connT,
+ share_peers,
+ use_shared_peers,
+ shared_peers,
+ local_peers,
+ monitor];
+
?FIELDS(diameter_event);
?FIELDS(diameter_uri);
?FIELDS(diameter_avp);
diff --git a/lib/diameter/src/app/diameter_internal.hrl b/lib/diameter/src/app/diameter_internal.hrl
index 9de3914830..63b35550a8 100644
--- a/lib/diameter/src/app/diameter_internal.hrl
+++ b/lib/diameter/src/app/diameter_internal.hrl
@@ -37,13 +37,14 @@
%% Failure reports always get a stack trace.
-define(STACK, erlang:get_stacktrace()).
-%% Info report for anything unexpected.
--define(REPORT(Reason, Func, Args),
- diameter_lib:report(Reason, {?MODULE, Func, Args})).
+%% Warning report for unexpected messages in various processes.
+-define(UNEXPECTED(F,A),
+ diameter_lib:warning_report(unexpected, {?MODULE, F, A})).
+-define(UNEXPECTED(A), ?UNEXPECTED(?FUNC, A)).
%% Something to trace on.
-define(LOG(Slogan, Details),
- diameter_dbg:log(Slogan, ?MODULE, ?LINE, Details)).
+ diameter_lib:log(Slogan, ?MODULE, ?LINE, Details)).
-define(LOGC(Bool, Slogan, Details), ((Bool) andalso ?LOG(Slogan, Details))).
%% Compensate for no builtin ?FUNC for use in log reports.
@@ -77,19 +78,3 @@
server_id,
is_dynamic,
expiration}).
-
-%%%----------------------------------------------------------------------
-%%% Error/warning/info message macro(s)
-%%%----------------------------------------------------------------------
-
--define(diameter_info(F, A),
- (catch error_logger:info_msg("[ ~w : ~w : ~p ] ~n" ++ F ++ "~n",
- [?APPLICATION, ?MODULE, self()|A]))).
-
--define(diameter_warning(F, A),
- (catch error_logger:warning_msg("[ ~w : ~w : ~p ] ~n" ++ F ++ "~n",
- [?APPLICATION, ?MODULE, self()|A]))).
-
--define(diameter_error(F, A),
- (catch error_logger:error_msg("[ ~w : ~w : ~p ] ~n" ++ F ++ "~n",
- [?APPLICATION, ?MODULE, self()|A]))).
diff --git a/lib/diameter/src/app/diameter_lib.erl b/lib/diameter/src/app/diameter_lib.erl
index b5c0e1bf6a..362d593b24 100644
--- a/lib/diameter/src/app/diameter_lib.erl
+++ b/lib/diameter/src/app/diameter_lib.erl
@@ -30,7 +30,8 @@
ipaddr/1,
spawn_opts/2,
wait/1,
- fold_tuple/3]).
+ fold_tuple/3,
+ log/4]).
-include("diameter_internal.hrl").
@@ -46,14 +47,9 @@
report(Reason, MFA) ->
info_report(Reason, MFA).
-info_report(Reason, {M,F,A}) ->
- error_logger:info_report(" Reason: ~p~n"
- " Pid: ~p~n"
- " Node: ~p~n"
- " Module: ~p~n"
- " Function: ~p~n"
- "Arguments: ~p~n",
- [Reason, self(), node(), M, F, A]).
+info_report(Reason, MFA) ->
+ report(fun error_logger:info_report/1, Reason, MFA),
+ true.
%%% ---------------------------------------------------------------------------
%%% # error_report(Reason, MFA)
@@ -69,7 +65,7 @@ warning_report(Reason, MFA) ->
report(fun error_logger:warning_report/1, Reason, MFA).
report(Fun, Reason, MFA) ->
- Fun([{reason, Reason}, {who, self()}, {where, node()}, {what, MFA}]),
+ Fun([{why, Reason}, {who, self()}, {what, MFA}]),
false.
%%% ---------------------------------------------------------------------------
@@ -255,12 +251,22 @@ w(L) ->
fold_tuple(_, T, undefined) ->
T;
-fold_tuple(N, T0, T) ->
- element(2, lists:foldl(fun(X, {M,_} = A) -> {M+1, ft(X, A)} end,
- {N, T0},
- lists:nthtail(N-1, tuple_to_list(T)))).
+fold_tuple(N, T0, T1) ->
+ {_, T} = lists:foldl(fun(V, {I,_} = IT) -> {I+1, ft(V, IT)} end,
+ {N, T0},
+ lists:nthtail(N-1, tuple_to_list(T1))),
+ T.
-ft(undefined, T) ->
+ft(undefined, {_, T}) ->
T;
-ft(X, {N, T}) ->
- setelement(N, T, X).
+ft(Value, {Idx, T}) ->
+ setelement(Idx, T, Value).
+
+%%% ----------------------------------------------------------
+%%% # log(Slogan, Mod, Line, Details)
+%%%
+%%% Called to have something to trace on for happenings of interest.
+%%% ----------------------------------------------------------
+
+log(_, _, _, _) ->
+ ok.
diff --git a/lib/diameter/src/app/diameter_peer.erl b/lib/diameter/src/app/diameter_peer.erl
index 6b8971b8ea..3e78c4caef 100644
--- a/lib/diameter/src/app/diameter_peer.erl
+++ b/lib/diameter/src/app/diameter_peer.erl
@@ -148,7 +148,7 @@ handle_call(uptime, _, #state{id = Time} = State) ->
{reply, diameter_lib:now_diff(Time), State};
handle_call(Req, From, State) ->
- warning_msg("received unexpected request from ~p:~n~w", [From, Req]),
+ ?UNEXPECTED([Req, From]),
{reply, nok, State}.
%%% ----------------------------------------------------------
@@ -156,7 +156,7 @@ handle_call(Req, From, State) ->
%%% ----------------------------------------------------------
handle_cast(Msg, State) ->
- warning_msg("received unexpected message:~n~w", [Msg]),
+ ?UNEXPECTED([Msg]),
{noreply, State}.
%%% ----------------------------------------------------------
@@ -169,7 +169,7 @@ handle_info({notify, SvcName, T}, S) ->
{noreply, S};
handle_info(Info, State) ->
- warning_msg("received unexpected info:~n~w", [Info]),
+ ?UNEXPECTED([Info]),
{noreply, State}.
%% ----------------------------------------------------------
@@ -223,8 +223,3 @@ value([], V) ->
call(Request) ->
gen_server:call(?SERVER, Request, infinity).
-
-%% warning_msg/2
-
-warning_msg(F, A) ->
- ?diameter_warning("~p: " ++ F, [?MODULE | A]).
diff --git a/lib/diameter/src/app/diameter_reg.erl b/lib/diameter/src/app/diameter_reg.erl
index 8e5f34c2c3..882b9da238 100644
--- a/lib/diameter/src/app/diameter_reg.erl
+++ b/lib/diameter/src/app/diameter_reg.erl
@@ -243,7 +243,8 @@ handle_call(state, _, State) ->
handle_call(uptime, _, #state{id = Time} = State) ->
{reply, diameter_lib:now_diff(Time), State};
-handle_call(_Req, _From, State) ->
+handle_call(Req, From, State) ->
+ ?UNEXPECTED([Req, From]),
{reply, nok, State}.
%%% ----------------------------------------------------------
@@ -251,7 +252,7 @@ handle_call(_Req, _From, State) ->
%%% ----------------------------------------------------------
handle_cast(Msg, State)->
- warning_msg("received unexpected message:~n~w", [Msg]),
+ ?UNEXPECTED([Msg]),
{noreply, State}.
%%% ----------------------------------------------------------
@@ -264,7 +265,7 @@ handle_info({'DOWN', MRef, process, Pid, _}, State) ->
{noreply, State};
handle_info(Info, State) ->
- warning_msg("received unknown info:~n~w", [Info]),
+ ?UNEXPECTED([Info]),
{noreply, State}.
%%% ----------------------------------------------------------
@@ -324,8 +325,3 @@ repl([], _, _) ->
call(Request) ->
gen_server:call(?SERVER, Request, infinity).
-
-%% warning_msg/2
-
-warning_msg(F, A) ->
- ?diameter_warning("~p: " ++ F, [?MODULE | A]).
diff --git a/lib/diameter/src/app/diameter_service.erl b/lib/diameter/src/app/diameter_service.erl
index 63b0649dc4..421e36ccf5 100644
--- a/lib/diameter/src/app/diameter_service.erl
+++ b/lib/diameter/src/app/diameter_service.erl
@@ -463,7 +463,7 @@ handle_call(stop, _From, S) ->
%% stating a monitor that waits for DOWN before returning.
handle_call(Req, From, S) ->
- ?REPORT(unknown_request, ?FUNC, [Req, From]),
+ unexpected(handle_call, [Req, From], S),
{reply, nok, S}.
%%% ---------------------------------------------------------------------------
@@ -471,7 +471,7 @@ handle_call(Req, From, S) ->
%%% ---------------------------------------------------------------------------
handle_cast(Req, S) ->
- ?REPORT(unknown_request, ?FUNC, [Req]),
+ unexpected(handle_cast, [Req], S),
{noreply, S}.
%%% ---------------------------------------------------------------------------
@@ -553,8 +553,8 @@ transition({failover, TRef, Seqs}, S) ->
failover(TRef, Seqs, S),
ok;
-transition(Req, _) ->
- ?REPORT(unknown_request, ?FUNC, [Req]),
+transition(Req, S) ->
+ unexpected(handle_info, [Req], S),
ok.
%%% ---------------------------------------------------------------------------
@@ -591,6 +591,9 @@ code_change(FromVsn, SvcName, Extra, #diameter_app{alias = Alias} = A) ->
%% ===========================================================================
%% ===========================================================================
+unexpected(F, A, #state{service_name = Name}) ->
+ ?UNEXPECTED(F, A ++ [Name]).
+
cb([_|_] = M, F, A) ->
eval(M, F, A);
cb(Rec, F, A) ->
@@ -1398,15 +1401,15 @@ recv_answer(Timeout,
%% is, from the last peer to which we've transmitted.
receive
- {answer = A, Ref, Rq, Pkt} -> %% Answer from peer.
+ {answer = A, Ref, Rq, Pkt} -> %% Answer from peer
{A, Rq, Pkt};
- {timeout = Reason, TRef, _} -> %% No timely reply
+ {timeout = Reason, TRef, _} -> %% No timely reply
{error, Req, Reason};
- {failover = Reason, TRef, false} -> %% No alternative peer.
+ {failover = Reason, TRef, false} -> %% No alternate peer
{error, Req, Reason};
- {failover, TRef, Transport} -> %% Resend to alternate peer.
+ {failover, TRef, Transport} -> %% Resend to alternate peer
try_retransmit(Timeout, SvcName, Req, Transport);
- {failover, TRef} -> %% May have missed failover notification.
+ {failover, TRef} -> %% May have missed failover notification
Seqs = diameter_codec:sequence_numbers(RPkt),
Pid = whois(SvcName),
is_pid(Pid) andalso (Pid ! {failover, TRef, Seqs}),
@@ -1685,9 +1688,9 @@ recv_request({Id, Alias}, T, TPid, Apps, Caps, Pkt) ->
%% DIAMETER_APPLICATION_UNSUPPORTED 3007
%% A request was sent for an application that is not supported.
-recv_request(false, {_, OH, OR}, TPid, _, _, Pkt) ->
- ?LOG({error, application}, Pkt),
- reply(answer_message({OH, OR, 3007}, collect_avps(Pkt)), ?BASE, TPid, Pkt).
+recv_request(false, T, TPid, _, _, Pkt) ->
+ As = collect_avps(Pkt),
+ protocol_error(3007, T, TPid, Pkt#diameter_packet{avps = As}).
collect_avps(Pkt) ->
case diameter_codec:collect_avps(Pkt) of
@@ -1706,13 +1709,9 @@ collect_avps(Pkt) ->
%% set to an unrecognized value, or that is inconsistent with the
%% AVP's definition.
%%
-recv_request({_, OH, OR}, {TPid, _}, _, #diameter_packet{errors = [Bs | _],
- bin = Bin,
- avps = Avps}
- = Pkt)
+recv_request(T, {TPid, _}, _, #diameter_packet{errors = [Bs | _]} = Pkt)
when is_bitstring(Bs) ->
- ?LOG({error, invalid_avp_bits}, Bin),
- reply(answer_message({OH, OR, 3009}, Avps), ?BASE, TPid, Pkt);
+ protocol_error(3009, T, TPid, Pkt);
%% Either we support this application but don't recognize the command
%% or we're a relay and the command isn't proxiable.
@@ -1722,18 +1721,15 @@ recv_request({_, OH, OR}, {TPid, _}, _, #diameter_packet{errors = [Bs | _],
%% recognize or support. This MUST be used when a Diameter node
%% receives an experimental command that it does not understand.
%%
-recv_request({_, OH, OR},
+recv_request(T,
{TPid, _},
#diameter_app{id = Id},
#diameter_packet{header = #diameter_header{is_proxiable = P},
- msg = M,
- avps = Avps,
- bin = Bin}
+ msg = M}
= Pkt)
when ?APP_ID_RELAY /= Id, undefined == M;
?APP_ID_RELAY == Id, not P ->
- ?LOG({error, command_unsupported}, Bin),
- reply(answer_message({OH, OR, 3001}, Avps), ?BASE, TPid, Pkt);
+ protocol_error(3001, T, TPid, Pkt);
%% Error bit was set on a request.
%%
@@ -1742,15 +1738,12 @@ recv_request({_, OH, OR},
%% either set to an invalid combination, or to a value that is
%% inconsistent with the command code's definition.
%%
-recv_request({_, OH, OR},
+recv_request(T,
{TPid, _},
_,
- #diameter_packet{header = #diameter_header{is_error = true},
- avps = Avps,
- bin = Bin}
+ #diameter_packet{header = #diameter_header{is_error = true}}
= Pkt) ->
- ?LOG({error, error_bit}, Bin),
- reply(answer_message({OH, OR, 3008}, Avps), ?BASE, TPid, Pkt);
+ protocol_error(3008, T, TPid, Pkt);
%% A message in a locally supported application or a proxiable message
%% in the relay application. Don't distinguish between the two since
@@ -1878,7 +1871,7 @@ resend(true, _, _, T, {TPid, _}, Pkt) -> %% Route-Record loop
resend(false,
Opts,
App,
- {SvcName, _, _},
+ {SvcName, _, _} = T,
{TPid, #diameter_caps{origin_host = {_, OH}}},
#diameter_packet{header = Hdr0,
avps = Avps}
@@ -1887,46 +1880,41 @@ resend(false,
Seq = diameter_session:sequence(),
Hdr = Hdr0#diameter_header{hop_by_hop_id = Seq},
Msg = [Hdr, Route | Avps],
- %% Filter sender as ineligible receiver.
- reply(call(SvcName, App, Msg, [{filter, {neg, {host, OH}}} | Opts]),
- TPid,
- Pkt).
+ resend(call(SvcName, App, Msg, Opts), T, TPid, Pkt).
%% The incoming request is relayed with the addition of a
-%% Route-Record. Note the requirement on the return from call/4.
-%% This places a requirement on the values returned by the
-%% handle_answer and handle_error callbacks of the application module
-%% in question.
+%% Route-Record. Note the requirement on the return from call/4 below,
+%% which places a requirement on the value returned by the
+%% handle_answer callback of the application module in question.
+%%
+%% Note that there's nothing stopping the request from being relayed
+%% back to the sender. A pick_peer callback may want to avoid this but
+%% a smart peer might recognize the potential loop and choose another
+%% route. A less smart one will probably just relay the request back
+%% again and force us to detect the loop. A pick_peer that wants to
+%% avoid this can specify filter to avoid the possibility.
+%% Eg. {neg, {host, OH} where #diameter_caps{origin_host = {OH, _}}.
%%
%% RFC 6.3 says that a relay agent does not modify Origin-Host but
%% says nothing about a proxy. Assume it should behave the same way.
-%% reply/3
+%% resend/4
%%
%% Relay a reply to a relayed request.
%% Answer from the peer: reset the hop by hop identifier and send.
-reply(#diameter_packet{bin = B}
- = Pkt,
- TPid,
- #diameter_packet{header = #diameter_header{hop_by_hop_id = Id},
- transport_data = TD}) ->
+resend(#diameter_packet{bin = B}
+ = Pkt,
+ _,
+ TPid,
+ #diameter_packet{header = #diameter_header{hop_by_hop_id = Id},
+ transport_data = TD}) ->
send(TPid, Pkt#diameter_packet{bin = diameter_codec:hop_by_hop_id(Id, B),
transport_data = TD});
%% TODO: counters
-%% Not. Ignoring the error feels harsh but there is no appropriate
-%% Result-Code for a protocol error (which this isn't really anyway)
-%% and the RFC doesn't provide any guidance how to act. A weakness
-%% here is that we don't deal well with a decode error: the request
-%% will simply timeout on the peer's end. Better would be to just send
-%% the answer (with modified hop by hop identifier) on regardless, at
-%% least in the relay case in which there's no examination of the
-%% answer. In the proxy case it's not clear that the callback won't
-%% examine the answer. Just be quiet here since a decode error causes
-%% the request process to crash (or not depending on the error and
-%% config and/or handle_answer callback).
-reply(_, _, _) ->
- ok.
+%% Or not: DIAMETER_UNABLE_TO_DELIVER.
+resend(_, T, TPid, Pkt) ->
+ protocol_error(3002, T, TPid, Pkt).
%% is_loop/4
%%
@@ -1971,24 +1959,20 @@ reply(Msg, Dict, TPid, #diameter_packet{errors = [H|_] = Es} = Pkt) ->
%% make_reply_packet/2
+%% Binaries and header/avp lists are sent as-is.
make_reply_packet(Bin, _)
when is_binary(Bin) ->
#diameter_packet{bin = Bin};
-
make_reply_packet([#diameter_header{} | _] = Msg, _) ->
#diameter_packet{msg = Msg};
+%% Otherwise a reply message clears the R and T flags and retains the
+%% P flag. The E flag will be set at encode.
make_reply_packet(Msg, #diameter_packet{header = ReqHdr}) ->
- #diameter_header{end_to_end_id = EId,
- hop_by_hop_id = Hid,
- is_proxiable = P}
- = ReqHdr,
-
- Hdr = #diameter_header{version = ?DIAMETER_VERSION,
- end_to_end_id = EId,
- hop_by_hop_id = Hid,
- is_proxiable = P,
- is_retransmitted = false},
+ Hdr = ReqHdr#diameter_header{version = ?DIAMETER_VERSION,
+ is_request = false,
+ is_error = undefined,
+ is_retransmitted = false},
#diameter_packet{header = Hdr,
msg = Msg}.
@@ -2126,16 +2110,6 @@ answer_message({OH, OR, RC}, Avps) ->
session_id(Code, Vid, Avps)
when is_list(Avps) ->
try
- {value, #diameter_avp{} = Avp} = find_avp(Code, Vid, Avps),
- Avp
- catch
- error: _ ->
- []
- end;
-
-session_id(Code, Vid, Avps)
- when is_list(Avps) ->
- try
{value, #diameter_avp{data = D}} = find_avp(Code, Vid, Avps),
[{'Session-Id', [?BASE:avp(decode, D, 'Session-Id')]}]
catch
@@ -2482,6 +2456,7 @@ rpd(Pid, Alias, PDict) ->
%%%
%%% Output: {TransportPid, #diameter_caps{}, #diameter_app{}}
%%% | false
+%%% | {error, Reason}
%%% ---------------------------------------------------------------------------
%% Initial call, from an arbitrary process.
@@ -2540,28 +2515,18 @@ get_destination(Msg, Dict) ->
[str(get_avp_value(Dict, 'Destination-Realm', Msg)),
str(get_avp_value(Dict, 'Destination-Host', Msg))].
-%% TODO:
-%%
-%% Should add some way of specifying destination directly so that the
-%% only requirement is that the prepare_request callback returns
-%% something specific. (eg. {host, DH}; that is, let the caller specify.)
-%%
-%% Also, there is no longer any need to call get_destination at all in
-%% the default case.
-
-str(T)
- when T == undefined;
- T == [] ->
+%% This is not entirely correct. The avp could have an arity 1, in
+%% which case an empty list is a DiameterIdentity of length 0 rather
+%% than the list of no values we treat it as by mapping to undefined.
+%% This behaviour is documented.
+str([]) ->
undefined;
-str([X])
- when is_list(X) ->
- X;
str(T) ->
T.
%% get_avp_value/3
%%
-%% Support outgoing messages in one of three forms:
+%% Find an AVP in a message of one of three forms:
%%
%% - a message record (as generated from a .dia spec) or
%% - a list of an atom message name followed by 2-tuple, avp name/value pairs.
@@ -2593,8 +2558,9 @@ get_avp_value(_, Name, [_MsgName | Avps]) ->
undefined
end;
-get_avp_value(Dict, Name, Rec)
- when is_tuple(Rec) ->
+%% Message is typically a record but not necessarily: diameter:call/4
+%% can be passed an arbitrary term.
+get_avp_value(Dict, Name, Rec) ->
try
Dict:'#get-'(Name, Rec)
catch
@@ -2690,7 +2656,8 @@ peers(Alias, RH, Filter, Peers) ->
end.
%% Place a peer whose Destination-Host/Realm matches those of the
-%% request at the front of the result list.
+%% request at the front of the result list. Could add some sort of
+%% 'sort' option to allow more control.
ps([], _, _, {Ys, Ns}) ->
lists:reverse(Ys, Ns);
@@ -2700,11 +2667,11 @@ ps([{_TPid, #diameter_caps{} = Caps} = TC | Rest], RH, Filter, Acc) ->
TC,
Acc)).
-pacc(true, true, TC, {Ts, Fs}) ->
- {[TC|Ts], Fs};
-pacc(true, false, TC, {Ts, Fs}) ->
- {Ts, [TC|Fs]};
-pacc(false, _, _, Acc) ->
+pacc(true, true, Peer, {Ts, Fs}) ->
+ {[Peer|Ts], Fs};
+pacc(true, false, Peer, {Ts, Fs}) ->
+ {Ts, [Peer|Fs]};
+pacc(_, _, _, Acc) ->
Acc.
%% caps_filter/3
@@ -2712,17 +2679,19 @@ pacc(false, _, _, Acc) ->
caps_filter(C, RH, {neg, F}) ->
not caps_filter(C, RH, F);
-caps_filter(C, RH, {all, L}) ->
+caps_filter(C, RH, {all, L})
+ when is_list(L) ->
lists:all(fun(F) -> caps_filter(C, RH, F) end, L);
-caps_filter(C, RH, {any, L}) ->
+caps_filter(C, RH, {any, L})
+ when is_list(L) ->
lists:any(fun(F) -> caps_filter(C, RH, F) end, L);
-caps_filter(#diameter_caps{origin_host = {_,H}}, [_,DH], host) ->
- eq(undefined, DH, H);
+caps_filter(#diameter_caps{origin_host = {_,OH}}, [_,DH], host) ->
+ eq(undefined, DH, OH);
-caps_filter(#diameter_caps{origin_realm = {_,R}}, [DR,_], realm) ->
- eq(undefined, DR, R);
+caps_filter(#diameter_caps{origin_realm = {_,OR}}, [DR,_], realm) ->
+ eq(undefined, DR, OR);
caps_filter(C, _, Filter) ->
caps_filter(C, Filter).
@@ -2738,6 +2707,9 @@ caps_filter(#diameter_caps{origin_host = {_,OH}}, {host, H}) ->
caps_filter(#diameter_caps{origin_realm = {_,OR}}, {realm, R}) ->
eq(any, R, OR);
+%% Anything else is expected to be an eval filter. Filter failure is
+%% documented as being equivalent to a non-matching filter.
+
caps_filter(C, T) ->
try
{eval, F} = T,
@@ -2746,8 +2718,14 @@ caps_filter(C, T) ->
_:_ -> false
end.
-eq(X, A, B) ->
- X == A orelse A == B.
+eq(Any, Id, PeerId) ->
+ Any == Id orelse try
+ iolist_to_binary(Id) == iolist_to_binary(PeerId)
+ catch
+ _:_ -> false
+ end.
+%% OctetString() can be specified as an iolist() so test for string
+%% rather then term equality.
%% transports/1
diff --git a/lib/diameter/src/app/diameter_stats.erl b/lib/diameter/src/app/diameter_stats.erl
index b52d4cdcfb..71479afa95 100644
--- a/lib/diameter/src/app/diameter_stats.erl
+++ b/lib/diameter/src/app/diameter_stats.erl
@@ -207,7 +207,7 @@ handle_call({flush, Contrib}, _From, State) ->
{reply, fetch(Contrib), State};
handle_call(Req, From, State) ->
- warning_msg("received unexpected request from ~p:~n~w", [From, Req]),
+ ?UNEXPECTED([Req, From]),
{reply, nok, State}.
%% ----------------------------------------------------------
@@ -219,7 +219,7 @@ handle_cast({incr, Rec}, State) ->
{noreply, State};
handle_cast(Msg, State) ->
- warning_msg("received unexpected message:~n~w", [Msg]),
+ ?UNEXPECTED([Msg]),
{noreply, State}.
%% ----------------------------------------------------------
@@ -231,7 +231,7 @@ handle_info({'DOWN', _MRef, process, Pid, _}, State) ->
{noreply, State};
handle_info(Info, State) ->
- warning_msg("received unknown info:~n~w", [Info]),
+ ?UNEXPECTED([Info]),
{noreply, State}.
%% ----------------------------------------------------------
@@ -340,8 +340,3 @@ cast(Msg) ->
call(Request) ->
gen_server:call(?SERVER, Request, infinity).
-
-%% warning_msg/2
-
-warning_msg(F, A) ->
- ?diameter_warning("~p: " ++ F, [?MODULE | A]).
diff --git a/lib/diameter/src/app/diameter_sync.erl b/lib/diameter/src/app/diameter_sync.erl
index f7777ae809..ce2db4b3a2 100644
--- a/lib/diameter/src/app/diameter_sync.erl
+++ b/lib/diameter/src/app/diameter_sync.erl
@@ -204,37 +204,37 @@ handle_call(?REQUEST(Type, Name, Req, Max, Timeout),
T = find(Name, QD),
nq(queued(T) =< Max, T, {Type, From}, Name, Req, Timeout, State);
-handle_call(Request, _From, State) ->
- {reply, call(Request, State), State}.
+handle_call(Request, From, State) ->
+ {reply, call(Request, From, State), State}.
-%% call/2
+%% call/3
-call(?CARP(Name), #state{queue = QD}) ->
+call(?CARP(Name), _, #state{queue = QD}) ->
pcar(find(Name, QD));
-call(state, State) ->
+call(state, _, State) ->
State;
-call(uptime, #state{time = T}) ->
+call(uptime, _, #state{time = T}) ->
diameter_lib:now_diff(T);
-call({flush, Name}, #state{queue = QD}) ->
+call({flush, Name}, _, #state{queue = QD}) ->
cancel(find(Name, QD));
-call(pending, #state{pending = N}) ->
+call(pending, _, #state{pending = N}) ->
N;
-call({pending, Name}, #state{queue = QD}) ->
+call({pending, Name}, _, #state{queue = QD}) ->
queued(find(Name, QD));
-call(queues, #state{queue = QD}) ->
+call(queues, _, #state{queue = QD}) ->
fetch_keys(QD);
-call({pids, Name}, #state{queue = QD}) ->
+call({pids, Name}, _, #state{queue = QD}) ->
plist(find(Name, QD));
-call(Req, _State) -> %% ignore
- warning_msg("received unexpected request:~n~w", [Req]),
+call(Req, From, _State) -> %% ignore
+ ?UNEXPECTED(handle_call, [Req, From]),
nok.
%%% ----------------------------------------------------------
@@ -242,7 +242,7 @@ call(Req, _State) -> %% ignore
%%% ----------------------------------------------------------
handle_cast(Msg, State) ->
- warning_msg("received unexpected message:~n~w", [Msg]),
+ ?UNEXPECTED([Msg]),
{noreply, State}.
%%% ----------------------------------------------------------
@@ -267,7 +267,7 @@ info({'DOWN', MRef, process, Pid, Info},
queue = dq(fetch(Name, QD), Pid, Info, Name, QD)};
info(Info, State) ->
- warning_msg("received unknown info:~n~w", [Info]),
+ ?UNEXPECTED(handle_info, [Info]),
State.
reply({call, From}, T) ->
@@ -548,8 +548,3 @@ gen_call(Server, Req, Timeout) ->
exit: _ ->
timeout
end.
-
-%% warning_msg/2
-
-warning_msg(F, A) ->
- ?diameter_warning("~p: " ++ F, [?MODULE | A]).
diff --git a/lib/diameter/src/app/modules.mk b/lib/diameter/src/app/modules.mk
index a7a78b1a9d..c133e6f64e 100644
--- a/lib/diameter/src/app/modules.mk
+++ b/lib/diameter/src/app/modules.mk
@@ -22,17 +22,13 @@ SPEC_FILES = \
diameter_gen_base_accounting.dia \
diameter_gen_relay.dia
-MODULES = \
+RUNTIME_MODULES = \
diameter \
diameter_app \
- diameter_callback \
diameter_capx \
diameter_config \
- diameter_dbg \
diameter_codec \
diameter_dict \
- diameter_exprecs \
- diameter_info \
diameter_lib \
diameter_misc_sup \
diameter_peer \
@@ -49,6 +45,12 @@ MODULES = \
diameter_watchdog \
diameter_watchdog_sup
+HELP_MODULES = \
+ diameter_callback \
+ diameter_exprecs \
+ diameter_dbg \
+ diameter_info
+
INTERNAL_HRL_FILES = \
diameter_internal.hrl \
diameter_types.hrl
diff --git a/lib/diameter/src/compiler/Makefile b/lib/diameter/src/compiler/Makefile
index 3ab76064ac..779013bfbc 100644
--- a/lib/diameter/src/compiler/Makefile
+++ b/lib/diameter/src/compiler/Makefile
@@ -94,16 +94,6 @@ info:
@echo ""
# ----------------------------------------------------
-# Special Build Targets
-# ----------------------------------------------------
-
-# Invoked from ../app to add modules to the app file.
-$(APP_TARGET): force
- M=`echo $(MODULES) | sed -e 's/^ *//' -e 's/ *$$//' -e 'y/ /,/'`; \
- echo "/%COMPILER_MODULES%/s//$$M/;w;q" | tr ';' '\n' \
- | ed -s $@
-
-# ----------------------------------------------------
# Release Target
# ----------------------------------------------------
ifneq ($(ERL_TOP),)
diff --git a/lib/diameter/src/compiler/diameter_codegen.erl b/lib/diameter/src/compiler/diameter_codegen.erl
index 213ba0d22c..a33b07a3d3 100644
--- a/lib/diameter/src/compiler/diameter_codegen.erl
+++ b/lib/diameter/src/compiler/diameter_codegen.erl
@@ -37,7 +37,6 @@
file/2,
file/3]).
--include_lib("diameter/src/app/diameter_internal.hrl").
-include("diameter_forms.hrl").
%% Generated functions that could have no generated clauses will have
@@ -250,9 +249,14 @@ f_name(Name) ->
%%% ------------------------------------------------------------------------
f_id(Spec) ->
- Id = orddict:fetch(id, Spec),
{?function, id, 0,
- [{?clause, [], [], [?INTEGER(Id)]}]}.
+ [c_id(orddict:find(id, Spec))]}.
+
+c_id({ok, Id}) ->
+ {?clause, [], [], [?INTEGER(Id)]};
+
+c_id(error) ->
+ ?UNEXPECTED(0).
%%% ------------------------------------------------------------------------
%%% # vendor_id/0
@@ -454,9 +458,10 @@ avp(Spec) ->
Native = get_value(avp_types, Spec),
Custom = get_value(custom_types, Spec),
Imported = get_value(import_avps, Spec),
- avp([{N,T} || {N,_,T,_,_} <- Native], Imported, Custom).
+ Enums = get_value(enums, Spec),
+ avp([{N,T} || {N,_,T,_,_} <- Native], Imported, Custom, Enums).
-avp(Native, Imported, Custom) ->
+avp(Native, Imported, Custom, Enums) ->
Dict = orddict:from_list(Native),
report(native, Dict),
@@ -470,8 +475,8 @@ avp(Native, Imported, Custom) ->
false == lists:member(N, CustomNames)
end,
Native))
- ++ lists:flatmap(fun c_imported_avp/1, Imported)
- ++ lists:flatmap(fun(C) -> c_custom_avp(C, Dict) end, Custom).
+ ++ lists:flatmap(fun(I) -> cs_imported_avp(I, Enums) end, Imported)
+ ++ lists:flatmap(fun(C) -> cs_custom_avp(C, Dict) end, Custom).
c_base_avp({AvpName, T}) ->
{?clause, [?VAR('T'), ?VAR('Data'), ?ATOM(AvpName)],
@@ -487,23 +492,35 @@ base_avp(AvpName, 'Grouped') ->
base_avp(_, Type) ->
?APPLY(diameter_types, Type, [?VAR('T'), ?VAR('Data')]).
-c_imported_avp({Mod, Avps}) ->
- lists:map(fun(A) -> imported_avp(Mod, A) end, Avps).
+cs_imported_avp({Mod, Avps}, Enums) ->
+ lists:map(fun(A) -> imported_avp(Mod, A, Enums) end, Avps).
-imported_avp(_Mod, {AvpName, _, 'Grouped' = T, _, _}) ->
+imported_avp(_Mod, {AvpName, _, 'Grouped' = T, _, _}, _) ->
c_base_avp({AvpName, T});
-imported_avp(Mod, {AvpName, _, _, _, _}) ->
+imported_avp(Mod, {AvpName, _, 'Enumerated' = T, _, _}, Enums) ->
+ case lists:keymember(AvpName, 1, Enums) of
+ true ->
+ c_base_avp({AvpName, T});
+ false ->
+ c_imported_avp(Mod, AvpName)
+ end;
+
+imported_avp(Mod, {AvpName, _, _, _, _}, _) ->
+ c_imported_avp(Mod, AvpName).
+
+c_imported_avp(Mod, AvpName) ->
{?clause, [?VAR('T'), ?VAR('Data'), ?ATOM(AvpName)],
[],
[?APPLY(Mod, avp, [?VAR('T'),
?VAR('Data'),
?ATOM(AvpName)])]}.
-c_custom_avp({Mod, Avps}, Dict) ->
- lists:map(fun(N) -> custom_avp(Mod, N, orddict:fetch(N, Dict)) end, Avps).
+cs_custom_avp({Mod, Avps}, Dict) ->
+ lists:map(fun(N) -> c_custom_avp(Mod, N, orddict:fetch(N, Dict)) end,
+ Avps).
-custom_avp(Mod, AvpName, Type) ->
+c_custom_avp(Mod, AvpName, Type) ->
{?clause, [?VAR('T'), ?VAR('Data'), ?ATOM(AvpName)],
[],
[?APPLY(Mod, AvpName, [?VAR('T'), ?ATOM(Type), ?VAR('Data')])]}.
@@ -516,9 +533,25 @@ f_enumerated_avp(Spec) ->
{?function, enumerated_avp, 3, enumerated_avp(Spec) ++ [?UNEXPECTED(3)]}.
enumerated_avp(Spec) ->
- lists:flatmap(fun c_enumerated_avp/1, get_value(enums, Spec)).
+ Enums = get_value(enums, Spec),
+ lists:flatmap(fun cs_enumerated_avp/1, Enums)
+ ++ lists:flatmap(fun({M,Es}) -> enumerated_avp(M, Es, Enums) end,
+ get_value(import_enums, Spec)).
+
+enumerated_avp(Mod, Es, Enums) ->
+ lists:flatmap(fun({N,_}) ->
+ cs_enumerated_avp(lists:keymember(N, 1, Enums),
+ Mod,
+ N)
+ end,
+ Es).
-c_enumerated_avp({AvpName, Values}) ->
+cs_enumerated_avp(true, Mod, Name) ->
+ [c_imported_avp(Mod, Name)];
+cs_enumerated_avp(false, _, _) ->
+ [].
+
+cs_enumerated_avp({AvpName, Values}) ->
lists:flatmap(fun(V) -> c_enumerated_avp(AvpName, V) end, Values).
c_enumerated_avp(AvpName, {I,_}) ->
@@ -537,10 +570,14 @@ f_msg_header(Spec) ->
{?function, msg_header, 1, msg_header(Spec) ++ [?UNEXPECTED(1)]}.
msg_header(Spec) ->
+ msg_header(get_value(messages, Spec), Spec).
+
+msg_header([], _) ->
+ [];
+msg_header(Msgs, Spec) ->
ApplId = orddict:fetch(id, Spec),
- lists:map(fun({M,C,F,_,_}) -> c_msg_header(M, C, F, ApplId) end,
- get_value(messages, Spec)).
+ lists:map(fun({M,C,F,_,_}) -> c_msg_header(M, C, F, ApplId) end, Msgs).
%% Note that any application id in the message header spec is ignored.
@@ -616,10 +653,12 @@ f_empty_value(Spec) ->
{?function, empty_value, 1, empty_value(Spec)}.
empty_value(Spec) ->
+ Imported = lists:flatmap(fun avps/1, get_value(import_enums, Spec)),
Groups = get_value(grouped, Spec)
++ lists:flatmap(fun avps/1, get_value(import_groups, Spec)),
- Enums = get_value(enums, Spec)
- ++ lists:flatmap(fun avps/1, get_value(import_enums, Spec)),
+ Enums = [T || {N,_} = T <- get_value(enums, Spec),
+ not lists:keymember(N, 1, Imported)]
+ ++ Imported,
lists:map(fun c_empty_value/1, Groups ++ Enums)
++ [{?clause, [?VAR('Name')], [], [?CALL(empty, [?VAR('Name')])]}].
diff --git a/lib/diameter/src/compiler/diameter_spec_util.erl b/lib/diameter/src/compiler/diameter_spec_util.erl
index 322d53a199..b60886b678 100644
--- a/lib/diameter/src/compiler/diameter_spec_util.erl
+++ b/lib/diameter/src/compiler/diameter_spec_util.erl
@@ -39,11 +39,11 @@ parse(Path, Options) ->
{ok, B} = file:read_file(Path),
Chunks = chunk(B),
Spec = make_spec(Chunks),
- true = enums_defined(Spec), %% sanity checks
- true = groups_defined(Spec), %%
+ true = groups_defined(Spec), %% sanity checks
true = customs_defined(Spec), %%
Full = import_enums(import_groups(import_avps(insert_codes(Spec),
Options))),
+ true = enums_defined(Full), %% sanity checks
true = v_flags_set(Spec),
Full.
@@ -243,35 +243,48 @@ get_value(Key, Spec) ->
%% with an appropriate type.
enums_defined(Spec) ->
- is_defined(Spec, 'Enumerated', enums).
+ Avps = get_value(avp_types, Spec),
+ Import = get_value(import_enums, Spec),
+ lists:all(fun({N,_}) ->
+ true = enum_defined(N, Avps, Import)
+ end,
+ get_value(enums, Spec)).
-groups_defined(Spec) ->
- is_defined(Spec, 'Grouped', grouped).
+enum_defined(Name, Avps, Import) ->
+ case lists:keyfind(Name, 1, Avps) of
+ {Name, _, 'Enumerated', _, _} ->
+ true;
+ {Name, _, T, _, _} ->
+ ?ERROR({avp_has_wrong_type, Name, 'Enumerated', T});
+ false ->
+ lists:any(fun({_,Is}) -> lists:keymember(Name, 1, Is) end, Import)
+ orelse ?ERROR({avp_not_defined, Name, 'Enumerated'})
+ end.
+%% Note that an AVP is imported only if referenced by a message or
+%% grouped AVP, so the final branch will fail if an enum definition is
+%% extended without this being the case.
-is_defined(Spec, Type, Key) ->
+groups_defined(Spec) ->
Avps = get_value(avp_types, Spec),
- lists:all(fun(T) -> true = is_local(name(Key, T), Type, Avps) end,
- get_value(Key, Spec)).
+ lists:all(fun({N,_,_,_}) -> true = group_defined(N, Avps) end,
+ get_value(grouped, Spec)).
-name(enums, {N,_}) -> N;
-name(grouped, {N,_,_,_}) -> N.
-
-is_local(Name, Type, Avps) ->
+group_defined(Name, Avps) ->
case lists:keyfind(Name, 1, Avps) of
- {Name, _, Type, _, _} ->
+ {Name, _, 'Grouped', _, _} ->
true;
{Name, _, T, _, _} ->
- ?ERROR({avp_has_wrong_type, Name, Type, T});
+ ?ERROR({avp_has_wrong_type, Name, 'Grouped', T});
false ->
- ?ERROR({avp_not_defined, Name, Type})
+ ?ERROR({avp_not_defined, Name, 'Grouped'})
end.
customs_defined(Spec) ->
Avps = get_value(avp_types, Spec),
- lists:all(fun(A) -> true = is_local(A, Avps) end,
+ lists:all(fun(A) -> true = custom_defined(A, Avps) end,
lists:flatmap(fun last/1, get_value(custom_types, Spec))).
-is_local(Name, Avps) ->
+custom_defined(Name, Avps) ->
case lists:keyfind(Name, 1, Avps) of
{Name, _, T, _, _} when T == 'Grouped';
T == 'Enumerated' ->
@@ -510,6 +523,9 @@ choose(false, _, X) -> X.
%% ------------------------------------------------------------------------
%% import_groups/1
%% import_enums/1
+%%
+%% For each inherited module, store the content of imported AVP's of
+%% type grouped/enumerated in a new key.
import_groups(Spec) ->
orddict:store(import_groups, import(grouped, Spec), Spec).
diff --git a/lib/diameter/src/transport/diameter_sctp.erl b/lib/diameter/src/transport/diameter_sctp.erl
index 92aa8488a0..46473e7bf1 100644
--- a/lib/diameter/src/transport/diameter_sctp.erl
+++ b/lib/diameter/src/transport/diameter_sctp.erl
@@ -525,7 +525,22 @@ recv({[#sctp_sndrcvinfo{stream = Id}], Bin}, #transport{parent = Pid})
recv({[], #sctp_shutdown_event{assoc_id = Id}},
#transport{assoc_id = Id}) ->
- stop.
+ stop;
+
+%% Note that diameter_sctp(3) documents that sctp_events cannot be
+%% specified in the list of options passed to gen_sctp and that
+%% gen_opts/1 guards against this. This is to ensure that we know what
+%% events to expect and also to ensure that we receive
+%% #sctp_sndrcvinfo{} with each incoming message (data_io_event =
+%% true). Adaptation layer events (ie. #sctp_adaptation_event{}) are
+%% disabled by default so don't handle it. We could simply disable
+%% events we don't react to but don't.
+
+recv({[], #sctp_paddr_change{}}, _) ->
+ ok;
+
+recv({[], #sctp_pdapi_event{}}, _) ->
+ ok.
%% up/1
@@ -591,7 +606,7 @@ f([], _, _) ->
%% assoc_id/1
-assoc_id(#sctp_shutdown_event{assoc_id = Id}) -> %% undocumented
+assoc_id(#sctp_shutdown_event{assoc_id = Id}) ->
Id;
assoc_id(#sctp_assoc_change{assoc_id = Id}) ->
Id;