diff options
author | Anders Svensson <[email protected]> | 2011-12-20 14:51:56 +0100 |
---|---|---|
committer | Anders Svensson <[email protected]> | 2011-12-20 14:51:56 +0100 |
commit | 58336ee5c613de56f6d69562cd59b651eef734f0 (patch) | |
tree | 5a593244269992c86b9157229a2cb6d0242bbb79 /lib/diameter/examples/code | |
parent | e986108d71a71d835c241d22cdb08f97584958c5 (diff) | |
parent | 84873533d8caf176a710135d15e3578168350eab (diff) | |
download | otp-58336ee5c613de56f6d69562cd59b651eef734f0.tar.gz otp-58336ee5c613de56f6d69562cd59b651eef734f0.tar.bz2 otp-58336ee5c613de56f6d69562cd59b651eef734f0.zip |
Merge branch 'anders/diameter/testsuites/OTP-9829' into maint
* anders/diameter/testsuites/OTP-9829: (21 commits)
Install example dictionaries
Move example code to examples/code
Move example dictionaries to examples/dict
Set name/prefix at compilation, not in dictionaries
Add RFC 4004 (MIP) dictionary
Add RFC 4740 (SIP) dictionary
Add RFC 4072 (EAP) dictionary
Add RFC 4006 (CC) dictionary
Add RFC 4005 (NAS) dictionary
Add standards testcase to compiler suite
Remove {init,end}_per_group workaround
Use new syntax for specifying ct group properties
Increase timetrap in compiler suite
Minor capx suite tweaks
Minor makefile tweak
Remove trailing whitespace
Update skip condition in gen_sctp suite
Reintroduce gen_sctp suite
Remove delay from connect in transport suite
Add codec testcase for decode of unknown AVPs
...
Diffstat (limited to 'lib/diameter/examples/code')
-rw-r--r-- | lib/diameter/examples/code/GNUmakefile | 35 | ||||
-rw-r--r-- | lib/diameter/examples/code/client.erl | 125 | ||||
-rw-r--r-- | lib/diameter/examples/code/client_cb.erl | 103 | ||||
-rw-r--r-- | lib/diameter/examples/code/peer.erl | 139 | ||||
-rw-r--r-- | lib/diameter/examples/code/redirect.erl | 70 | ||||
-rw-r--r-- | lib/diameter/examples/code/redirect_cb.erl | 63 | ||||
-rw-r--r-- | lib/diameter/examples/code/relay.erl | 92 | ||||
-rw-r--r-- | lib/diameter/examples/code/relay_cb.erl | 69 | ||||
-rw-r--r-- | lib/diameter/examples/code/sctp.erl | 131 | ||||
-rw-r--r-- | lib/diameter/examples/code/server.erl | 88 | ||||
-rw-r--r-- | lib/diameter/examples/code/server_cb.erl | 115 |
11 files changed, 1030 insertions, 0 deletions
diff --git a/lib/diameter/examples/code/GNUmakefile b/lib/diameter/examples/code/GNUmakefile new file mode 100644 index 0000000000..a0669119d2 --- /dev/null +++ b/lib/diameter/examples/code/GNUmakefile @@ -0,0 +1,35 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2010-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +EXAMPLES = client server relay # redirect proxy + +CALLBACKS = $(EXAMPLES:%=%_cb) +MODULES = peer $(EXAMPLES) $(EXAMPLES:%=%_cb) + +BEAM = $(MODULES:%=%.beam) + +%.beam: %.erl + erlc -W $< + +all: $(BEAM) + +clean: + rm -f $(BEAM) + +.PHONY: all clean diff --git a/lib/diameter/examples/code/client.erl b/lib/diameter/examples/code/client.erl new file mode 100644 index 0000000000..9e65f98de0 --- /dev/null +++ b/lib/diameter/examples/code/client.erl @@ -0,0 +1,125 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% An example Diameter client that can sends base protocol RAR +%% requests to a connected peer. +%% +%% The simplest usage is as follows this to connect to a server +%% listening on the default port on the local host, assuming diameter +%% is already started (eg. diameter:start()). +%% +%% client:start(). +%% client:connect(tcp). +%% client:call(). +%% +%% The first call starts the a service with the default name of +%% ?MODULE, the second defines a connecting transport that results in +%% a connection to the peer (if it's listening), the third sends it a +%% RAR and returns the answer. +%% + +-module(client). + +-include_lib("diameter/include/diameter.hrl"). +-include_lib("diameter/src/app/diameter_gen_base_rfc3588.hrl"). + +-export([start/1, %% start a service + connect/2, %% add a connecting transport + call/1, %% send using the record encoding + cast/1, %% send using the list encoding and detached + stop/1]). %% stop a service +%% A real application would typically choose an encoding and whether +%% they want the call to return the answer or not. Sending with +%% both the record and list encoding here, one detached and one not, +%% is just for demonstration purposes. + +%% Convenience functions using the default service name, ?SVC_NAME. +-export([start/0, + connect/1, + stop/0, + call/0, + cast/0]). + +-define(SVC_NAME, ?MODULE). +-define(APP_ALIAS, ?MODULE). +-define(CALLBACK_MOD, client_cb). + +-define(L, atom_to_list). + +%% The service configuration. As in the server example, a client +%% supporting multiple Diameter applications may or may not want to +%% configure a common callback module on all applications. +-define(SERVICE(Name), [{'Origin-Host', ?L(Name) ++ ".example.com"}, + {'Origin-Realm', "example.com"}, + {'Vendor-Id', 0}, + {'Product-Name', "Client"}, + {'Auth-Application-Id', [?DIAMETER_APP_ID_COMMON]}, + {application, [{alias, ?APP_ALIAS}, + {dictionary, ?DIAMETER_DICT_COMMON}, + {module, ?CALLBACK_MOD}]}]). + +%% start/1 + +start(Name) + when is_atom(Name) -> + peer:start(Name, ?SERVICE(Name)). + +start() -> + start(?SVC_NAME). + +%% connect/2 + +connect(Name, T) -> + peer:connect(Name, T). + +connect(T) -> + connect(?SVC_NAME, T). + +%% call/1 + +call(Name) -> + SId = diameter:session_id(?L(Name)), + RAR = #diameter_base_RAR{'Session-Id' = SId, + 'Auth-Application-Id' = 0, + 'Re-Auth-Request-Type' = 0}, + diameter:call(Name, ?APP_ALIAS, RAR, []). + +call() -> + call(?SVC_NAME). + +%% cast/1 + +cast(Name) -> + SId = diameter:session_id(?L(Name)), + RAR = ['RAR', {'Session-Id', SId}, + {'Auth-Application-Id', 0}, + {'Re-Auth-Request-Type', 1}], + diameter:call(Name, ?APP_ALIAS, RAR, [detach]). + +cast() -> + cast(?SVC_NAME). + +%% stop/1 + +stop(Name) -> + peer:stop(Name). + +stop() -> + stop(?SVC_NAME). diff --git a/lib/diameter/examples/code/client_cb.erl b/lib/diameter/examples/code/client_cb.erl new file mode 100644 index 0000000000..524a8f94a1 --- /dev/null +++ b/lib/diameter/examples/code/client_cb.erl @@ -0,0 +1,103 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(client_cb). + +-include_lib("diameter/include/diameter.hrl"). +-include_lib("diameter/src/app/diameter_gen_base_rfc3588.hrl"). + +%% diameter callbacks +-export([peer_up/3, + peer_down/3, + pick_peer/4, + prepare_request/3, + prepare_retransmit/3, + handle_answer/4, + handle_error/4, + handle_request/3]). + +%% peer_up/3 + +peer_up(_SvcName, _Peer, State) -> + State. + +%% peer_down/3 + +peer_down(_SvcName, _Peer, State) -> + State. + +%% pick_peer/4 + +pick_peer([Peer | _], _, _SvcName, _State) -> + {ok, Peer}. + +%% prepare_request/3 + +prepare_request(#diameter_packet{msg = ['RAR' = T | Avps]}, _, {_, Caps}) -> + #diameter_caps{origin_host = {OH, DH}, + origin_realm = {OR, DR}} + = Caps, + + {send, [T, {'Origin-Host', OH}, + {'Origin-Realm', OR}, + {'Destination-Host', DH}, + {'Destination-Realm', DR} + | Avps]}; + +prepare_request(#diameter_packet{msg = Rec}, _, {_, Caps}) -> + #diameter_caps{origin_host = {OH, DH}, + origin_realm = {OR, DR}} + = Caps, + + {send, Rec#diameter_base_RAR{'Origin-Host' = OH, + 'Origin-Realm' = OR, + 'Destination-Host' = DH, + 'Destination-Realm' = DR}}. + +%% prepare_retransmit/3 + +prepare_retransmit(Packet, SvcName, Peer) -> + prepare_request(Packet, SvcName, Peer). + +%% handle_answer/4 + +%% Since client.erl has detached the call when using the list +%% encoding and not otherwise, output to the terminal in the +%% the former case, return in the latter. + +handle_answer(#diameter_packet{msg = Msg}, Request, _SvcName, _Peer) + when is_list(Request) -> + io:format("answer: ~p~n", [Msg]); + +handle_answer(#diameter_packet{msg = Msg}, _Request, _SvcName, _Peer) -> + {ok, Msg}. + +%% handle_error/4 + +handle_error(Reason, Request, _SvcName, _Peer) + when is_list(Request) -> + io:format("error: ~p~n", [Reason]); + +handle_error(Reason, _Request, _SvcName, _Peer) -> + {error, Reason}. + +%% handle_request/3 + +handle_request(_Packet, _SvcName, _Peer) -> + erlang:error({unexpected, ?MODULE, ?LINE}). diff --git a/lib/diameter/examples/code/peer.erl b/lib/diameter/examples/code/peer.erl new file mode 100644 index 0000000000..89203e15c3 --- /dev/null +++ b/lib/diameter/examples/code/peer.erl @@ -0,0 +1,139 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% A library module that factors out commonality in the example +%% Diameter peers. +%% + +-module(peer). + +-include_lib("diameter/include/diameter.hrl"). +-include_lib("diameter/src/app/diameter_gen_base_rfc3588.hrl"). + +-export([start/2, + listen/2, + connect/2, + stop/1]). + +-type service_name() + :: term(). + +-type protocol() + :: tcp | sctp. + +-type ip_address() + :: default + | inet:ip_address(). + +-type server_config() + :: protocol() + | {protocol(), ip_address(), non_neg_integer()}. + +-type client_config() + :: protocol() + | {protocol(), ip_address(), non_neg_integer()} + | {protocol(), ip_address(), ip_address(), non_neg_integer()}. + +-define(DEFAULT_ADDR, {127,0,0,1}). +-define(DEFAULT_PORT, 3868). + +%% --------------------------------------------------------------------------- +%% Interface functions +%% --------------------------------------------------------------------------- + +%% start/2 + +-spec start(service_name(), list()) + -> ok + | {error, term()}. + +start(Name, Opts) + when is_atom(Name), is_list(Opts) -> + diameter:start_service(Name, Opts). + +%% connect/2 + +-spec connect(service_name(), client_config()) + -> {ok, reference()} + | {error, term()}. + +connect(Name, T) -> + diameter:add_transport(Name, {connect, [{reconnect_timer, 5000} + | client(T)]}). + +%% listen/2 + +-spec listen(service_name(), server_config()) + -> {ok, reference()} + | {error, term()}. + +listen(Name, T) -> + diameter:add_transport(Name, {listen, server(T)}). + +%% stop/1 + +-spec stop(service_name()) + -> ok + | {error, term()}. + +stop(Name) -> + diameter:stop_service(Name). + +%% --------------------------------------------------------------------------- +%% Internal functions +%% --------------------------------------------------------------------------- + +%% server/1 +%% +%% Return config for a listening transport. + +server({T, Addr, Port}) -> + [{transport_module, tmod(T)}, + {transport_config, [{reuseaddr, true}, + {ip, addr(Addr)}, + {port, Port}]}]; + +server(T) -> + server({T, ?DEFAULT_ADDR, ?DEFAULT_PORT}). + +%% client/1 +%% +%% Return config for a connecting transport. + +client({T, LA, RA, RP}) -> + [{transport_module, tmod(T)}, + {transport_config, [{ip, addr(LA)}, + {raddr, addr(RA)}, + {rport, RP}, + {reuseaddr, true}]}]; + +client({T, LA, RP}) -> + client({T, LA, LA, RP}); + +client(T) -> + client({T, ?DEFAULT_ADDR, ?DEFAULT_ADDR, ?DEFAULT_PORT}). + +tmod(tcp) -> diameter_tcp; +tmod(sctp) -> diameter_sctp. + +addr(default) -> + ?DEFAULT_ADDR; +addr(A) -> + A. diff --git a/lib/diameter/examples/code/redirect.erl b/lib/diameter/examples/code/redirect.erl new file mode 100644 index 0000000000..b54701243f --- /dev/null +++ b/lib/diameter/examples/code/redirect.erl @@ -0,0 +1,70 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(redirect). + +-include_lib("diameter/include/diameter.hrl"). +-include_lib("diameter/src/app/diameter_gen_base_rfc3588.hrl"). + +-export([start/1, + listen/2, + stop/1]). + +-export([start/0, + listen/1, + stop/0]). + +-define(APP_ALIAS, ?MODULE). +-define(SVC_NAME, ?MODULE). +-define(CALLBACK_MOD, redirect_mod). + +%% The service configuration. +-define(SERVICE(Name), [{'Origin-Host', atom_to_list(Name) ++ ".example.com"}, + {'Origin-Realm', "example.com"}, + {'Vendor-Id', 193}, + {'Product-Name', "RedirectAgent"}, + {'Auth-Application-Id', [?DIAMETER_APP_ID_RELAY]}, + {application, [{alias, ?APP_ALIAS}, + {dictionary, ?DIAMETER_DICT_RELAY}, + {module, ?CALLBACK_MOD}]}]). + +%% start/1 + +start(Name) + when is_atom(Name) -> + peer:start(Name, ?SERVICE(Name)). + +start() -> + start(?SVC_NAME). + +%% listen/2 + +listen(Name, T) -> + peer:listen(Name, T). + +listen(T) -> + listen(?SVC_NAME, T). + +%% stop/1 + +stop(Name) -> + peer:stop(Name). + +stop() -> + stop(?SVC_NAME). diff --git a/lib/diameter/examples/code/redirect_cb.erl b/lib/diameter/examples/code/redirect_cb.erl new file mode 100644 index 0000000000..ea7ad38749 --- /dev/null +++ b/lib/diameter/examples/code/redirect_cb.erl @@ -0,0 +1,63 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(redirect_cb). + +-include_lib("diameter/include/diameter.hrl"). +-include_lib("diameter/src/app/diameter_gen_base_rfc3588.hrl"). + +%% diameter callbacks +-export([peer_up/3, + peer_down/3, + pick_peer/4, + prepare_request/3, + prepare_retransmit/3, + handle_answer/4, + handle_error/4, + handle_request/3]). + +-define(UNEXPECTED, erlang:error({unexpected, ?MODULE, ?LINE})). + +peer_up(_SvcName, {PeerRef, _}, State) -> + io:format("up: ~p~n", [PeerRef]), + State. + +peer_down(_SvcName, {PeerRef, _}, State) -> + io:format("down: ~p~n", [PeerRef]), + State. + +pick_peer(_, _, _SvcName, _State) -> + ?UNEXPECTED. + +prepare_request(_, _SvcName, _Peer) -> + ?UNEXPECTED. + +prepare_retransmit(_Packet, _SvcName, _Peer) -> + ?UNEXPECTED. + +handle_answer(_Packet, _Request, _SvcName, _Peer) -> + ?UNEXPECTED. + +handle_error(_Reason, _Request, _SvcName, _Peer) -> + ?UNEXPECTED. + +handle_request(#diameter_packet{msg = _, errors = []}, _SvcName, {_, Caps}) -> + #diameter_caps{} + = Caps, + discard. %% TODO diff --git a/lib/diameter/examples/code/relay.erl b/lib/diameter/examples/code/relay.erl new file mode 100644 index 0000000000..deecb1cfc0 --- /dev/null +++ b/lib/diameter/examples/code/relay.erl @@ -0,0 +1,92 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% An example Diameter relay agent. +%% +%% Usage to connect to a server listening on the default port over TCP +%% and to listen on the default port over SCTP is as follows, assuming +%% diameter is already started (eg. diameter:start()). +%% +%% Eg. relay:start(). +%% relay:connect(tcp). +%% relay:listen(sctp). +%% + +-module(relay). + +-include_lib("diameter/include/diameter.hrl"). +-include_lib("diameter/src/app/diameter_gen_base_rfc3588.hrl"). + +-export([start/1, + listen/2, + connect/2, + stop/1]). + +-export([start/0, + listen/1, + connect/1, + stop/0]). + +-define(APP_ALIAS, ?MODULE). +-define(SVC_NAME, ?MODULE). +-define(CALLBACK_MOD, relay_cb). + +%% The service configuration. +-define(SERVICE(Name), [{'Origin-Host', atom_to_list(Name) ++ ".example.com"}, + {'Origin-Realm', "example.com"}, + {'Vendor-Id', 193}, + {'Product-Name', "RelayAgent"}, + {'Auth-Application-Id', [?DIAMETER_APP_ID_RELAY]}, + {application, [{alias, ?MODULE}, + {dictionary, ?DIAMETER_DICT_RELAY}, + {module, ?CALLBACK_MOD}]}]). + +%% start/1 + +start(Name) + when is_atom(Name) -> + peer:start(Name, ?SERVICE(Name)). + +start() -> + start(?SVC_NAME). + +%% listen/2 + +listen(Name, T) -> + peer:listen(Name, T). + +listen(T) -> + listen(?SVC_NAME, T). + +%% connect/2 + +connect(Name, T) -> + peer:connect(Name, T). + +connect(T) -> + connect(?SVC_NAME, T). + +%% stop/1 + +stop(Name) -> + peer:stop(Name). + +stop() -> + stop(?SVC_NAME). diff --git a/lib/diameter/examples/code/relay_cb.erl b/lib/diameter/examples/code/relay_cb.erl new file mode 100644 index 0000000000..9ed6517d5c --- /dev/null +++ b/lib/diameter/examples/code/relay_cb.erl @@ -0,0 +1,69 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(relay_cb). + +-include_lib("diameter/include/diameter.hrl"). +-include_lib("diameter/src/app/diameter_gen_base_rfc3588.hrl"). + +%% diameter callbacks +-export([peer_up/3, + peer_down/3, + pick_peer/5, + prepare_request/4, + prepare_retransmit/4, + handle_answer/5, + handle_error/5, + handle_request/3]). + +peer_up(_SvcName, {PeerRef, _}, State) -> + io:format("up: ~p~n", [PeerRef]), + State. + +peer_down(_SvcName, {PeerRef, _}, State) -> + io:format("down: ~p~n", [PeerRef]), + State. + +%% Returning 'relay' from handle_request causes diameter to resend the +%% incoming request, which leads to pick_peer and prepare_request +%% callbacks as if sending explicitly. The 'extra' argument is +%% appended to the argument list for callbacks following from +%% resending of the request. + +handle_request(_Pkt, _SvcName, _Peer) -> + {relay, [{timeout, 1000}, {extra, [relayed]}]}. + +%% diameter will filter the sender in the Peers list. +pick_peer([Peer | _], _, _SvcName, _State, relayed) -> + {ok, Peer}. + +prepare_request(Pkt, _SvcName, _Peer, relayed) -> + {send, Pkt}. + +prepare_retransmit(Pkt, _SvcName, _Peer, relayed) -> + {send, Pkt}. + +%% diameter expects handle_answer to return the diameter_packet record +%% containing the answer when called for a relayed request. + +handle_answer(Pkt, _Request, _SvcName, _Peer, relayed) -> + Pkt. + +handle_error(Reason, _Request, _SvcName, _Peer, relayed) -> + {error, Reason}. diff --git a/lib/diameter/examples/code/sctp.erl b/lib/diameter/examples/code/sctp.erl new file mode 100644 index 0000000000..08de023571 --- /dev/null +++ b/lib/diameter/examples/code/sctp.erl @@ -0,0 +1,131 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(sctp). + +%% +%% A small example demonstrating the establishment of an SCTP +%% association with gen_sctp. +%% + +-export([assoc/0, + dbg/0]). + +-include_lib("kernel/include/inet_sctp.hrl"). + +-define(ADDR, {127,0,0,1}). +-define(SERVER_PORT, 3868). +-define(CONNECT_TIMEOUT, 2000). +-define(REQUEST, <<0:64>>). +-define(REPLY, <<1:64>>). + +-record(server, {client, + socket, + assoc}). + +-record(client, {socket, + assoc}). + +%% assoc/0 +%% +%% Return on a successfully established association, raise an +%% exception otherwise. + +assoc() -> + {_, MRef} = spawn_monitor(fun server/0), + receive {'DOWN', MRef, process, _, Info} -> Info end. + +%% dbg/0 + +dbg() -> + dbg:tracer(), + dbg:p(all,c), + dbg:tpl(?MODULE, [{'_',[],[{exception_trace}]}]), + dbg:tp(gen_sctp, [{'_',[],[{exception_trace}]}]), + ok. + +%% server/0 + +server() -> + {ok, Sock} = gen_sctp:open([binary, + {reuseaddr, true}, + {active, true}, + {ip, ?ADDR}, + {port, ?SERVER_PORT}]), + ok = gen_sctp:listen(Sock, true), + {_Pid, MRef} = spawn_monitor(fun client/0), + s(#server{client = MRef, socket = Sock}), + gen_sctp:close(Sock). + +%% s/1 + +s(#server{} = S) -> + s(s(receive T -> T end, S)); +s(T) -> + T. + +%% s/2 + +s({sctp, Sock, _RA, _RP, {[], #sctp_assoc_change{state = comm_up, + assoc_id = Id}}}, + #server{socket = Sock, assoc = undefined} + = S) -> + S#server{assoc = Id}; + +s({sctp, Sock, _RA, _RP, {[#sctp_sndrcvinfo{assoc_id = AId, + stream = SId}], + ?REQUEST}}, + #server{socket = Sock, assoc = AId} + = S) -> + ok = gen_sctp:send(Sock, AId, SId, ?REPLY), + S; + +s({'DOWN', MRef, process, _, normal} = T, #server{client = MRef}) -> + T. + +%% client/0 + +client() -> + {ok, Sock} = gen_sctp:open([binary, + {reuseaddr, true}, + {active, true}, + {ip, ?ADDR}, + {port, 0}]), + ok = gen_sctp:connect_init(Sock, ?ADDR, ?SERVER_PORT, []), + c(#client{socket = Sock}), + gen_sctp:close(Sock). + + +%% c/1 + +c(#client{} = S) -> + c(c(receive T -> T end, S)); +c(T) -> + T. + +c({sctp, Sock, _RA, _RP, {[], #sctp_assoc_change{state = comm_up, + assoc_id = Id}}}, + #client{socket = Sock, assoc = undefined} + = S) -> + ok = gen_sctp:send(Sock, Id, 0, ?REQUEST), + S#client{assoc = Id}; + +c({sctp, Sock, _RA, _RP, {[#sctp_sndrcvinfo{assoc_id = AId}], ?REPLY}}, + #client{socket = Sock, assoc = AId}) -> + ok. diff --git a/lib/diameter/examples/code/server.erl b/lib/diameter/examples/code/server.erl new file mode 100644 index 0000000000..ebb408e501 --- /dev/null +++ b/lib/diameter/examples/code/server.erl @@ -0,0 +1,88 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% An example Diameter server that can respond to the base protocol +%% RAR sent by the client example. +%% +%% The simplest example to start a server listening on the loopback +%% address (which will serve the example usage given in client.erl) is +%% like this assuming diameter is already started (eg. diameter:start()): +%% +%% server:start(). +%% server:listen(tcp). +%% +%% The first call starts a service, the second adds a transport listening +%% on the default port. +%% + +-module(server). + +-include_lib("diameter/include/diameter.hrl"). +-include_lib("diameter/src/app/diameter_gen_base_rfc3588.hrl"). + +-export([start/1, %% start a service + listen/2, %% add a listening transport + stop/1]). %% stop a service + +%% Convenience functions using the default service name, ?SVC_NAME. +-export([start/0, + listen/1, + stop/0]). + +-define(SVC_NAME, ?MODULE). +-define(APP_ALIAS, ?MODULE). +-define(CALLBACK_MOD, server_cb). + +%% The service configuration. In a server supporting multiple Diameter +%% applications each application may have its own, although they could all +%% be configured with a common callback module. +-define(SERVICE(Name), [{'Origin-Host', atom_to_list(Name) ++ ".example.com"}, + {'Origin-Realm', "example.com"}, + {'Vendor-Id', 193}, + {'Product-Name', "Server"}, + {'Auth-Application-Id', [?DIAMETER_APP_ID_COMMON]}, + {application, [{alias, ?APP_ALIAS}, + {dictionary, ?DIAMETER_DICT_COMMON}, + {module, ?CALLBACK_MOD}]}]). + +%% start/1 + +start(Name) + when is_atom(Name) -> + peer:start(Name, ?SERVICE(Name)). + +start() -> + start(?SVC_NAME). + +%% listen/2 + +listen(Name, T) -> + peer:listen(Name, T). + +listen(T) -> + listen(?SVC_NAME, T). + +%% stop/1 + +stop(Name) -> + peer:stop(Name). + +stop() -> + stop(?SVC_NAME). diff --git a/lib/diameter/examples/code/server_cb.erl b/lib/diameter/examples/code/server_cb.erl new file mode 100644 index 0000000000..43b8e24b5c --- /dev/null +++ b/lib/diameter/examples/code/server_cb.erl @@ -0,0 +1,115 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% The diameter application callback module configured by server.erl. +%% + +-module(server_cb). + +-include_lib("diameter/include/diameter.hrl"). +-include_lib("diameter/src/app/diameter_gen_base_rfc3588.hrl"). + +%% diameter callbacks +-export([peer_up/3, + peer_down/3, + pick_peer/4, + prepare_request/3, + prepare_retransmit/3, + handle_answer/4, + handle_error/4, + handle_request/3]). + +-define(UNEXPECTED, erlang:error({unexpected, ?MODULE, ?LINE})). + +peer_up(_SvcName, {PeerRef, _}, State) -> + io:format("up: ~p~n", [PeerRef]), + State. + +peer_down(_SvcName, {PeerRef, _}, State) -> + io:format("down: ~p~n", [PeerRef]), + State. + +pick_peer(_, _, _SvcName, _State) -> + ?UNEXPECTED. + +prepare_request(_, _SvcName, _Peer) -> + ?UNEXPECTED. + +prepare_retransmit(_Packet, _SvcName, _Peer) -> + ?UNEXPECTED. + +handle_answer(_Packet, _Request, _SvcName, _Peer) -> + ?UNEXPECTED. + +handle_error(_Reason, _Request, _SvcName, _Peer) -> + ?UNEXPECTED. + +%% A request whose decode was successful ... +handle_request(#diameter_packet{msg = Req, errors = []}, _SvcName, {_, Caps}) + when is_record(Req, diameter_base_RAR) -> + #diameter_caps{origin_host = {OH,_}, + origin_realm = {OR,_}} + = Caps, + #diameter_base_RAR{'Session-Id' = Id, + 'Re-Auth-Request-Type' = RT} + = Req, + + {reply, answer(RT, Id, OH, OR)}; + +%% ... or one that wasn't. 3xxx errors are answered by diameter itself +%% but these are 5xxx errors for which we must contruct a reply. +%% diameter will set Result-Code and Failed-AVP's. +handle_request(#diameter_packet{msg = Req} = Pkt, _SvcName, {_, Caps}) + when is_record(Req, diameter_base_RAR) -> + #diameter_caps{origin_host = {OH,_}, + origin_realm = {OR,_}} + = Caps, + #diameter_base_RAR{'Session-Id' = Id} + = Req, + + Ans = #diameter_base_RAA{'Origin-Host' = OH, + 'Origin-Realm' = OR, + 'Session-Id' = Id}, + + {reply, Ans}; + +%% Should really reply to other base messages that we don't support +%% but simply discard them instead. +handle_request(#diameter_packet{}, _SvcName, {_,_}) -> + discard. + +%% --------------------------------------------------------------------------- + +%% Answer using the record or list encoding depending on +%% Re-Auth-Request-Type. This is just as an example. You would +%% typically just choose one, and this has nothing to do with the how +%% client.erl sends. + +answer(0, Id, OH, OR) -> + #diameter_base_RAA{'Result-Code' = 2001, %% DIAMETER_SUCCESS + 'Origin-Host' = OH, + 'Origin-Realm' = OR, + 'Session-Id' = Id}; + +answer(_, Id, OH, OR) -> + ['RAA', {'Result-Code', 5012}, %% DIAMETER_UNABLE_TO_COMPLY + {'Origin-Host', OH}, + {'Origin-Realm', OR}, + {'Session-Id', Id}]. |