1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2010-2019. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20
21-module(diameter).
22
23%% Configuration.
24-export([start_service/2,
25         stop_service/1,
26         add_transport/2,
27         remove_transport/2,
28         subscribe/1,
29         unsubscribe/1]).
30
31%% Traffic.
32-export([session_id/1,
33         origin_state_id/0,
34         call/3,
35         call/4]).
36
37%% Information.
38-export([services/0,
39         peer_info/1,
40         peer_find/1,
41         service_info/2]).
42
43%% Start/stop the application. In a "real" application this should
44%% typically be a consequence of a release file rather than by calling
45%% start/stop explicitly.
46-export([start/0,
47         stop/0]).
48
49-export_type([eval/0,
50              evaluable/0,  %% deprecated
51              decode_format/0,
52              strict_arities/0,
53              restriction/0,
54              message_length/0,
55              remotes/0,
56              sequence/0,
57              app_alias/0,
58              service_name/0,
59              capability/0,
60              peer_filter/0,
61              peer_ref/0,
62              service_opt/0,
63              application_opt/0,
64              app_module/0,
65              transport_ref/0,
66              transport_opt/0,
67              transport_pred/0,
68              call_opt/0]).
69
70-export_type(['OctetString'/0,
71              'Integer32'/0,
72              'Integer64'/0,
73              'Unsigned32'/0,
74              'Unsigned64'/0,
75              'Float32'/0,
76              'Float64'/0,
77              'Grouped'/0,
78              'Address'/0,
79              'Time'/0,
80              'UTF8String'/0,
81              'DiameterIdentity'/0,
82              'DiameterURI'/0,
83              'Enumerated'/0,
84              'IPFilterRule'/0,
85              'QoSFilterRule'/0]).
86
87-include_lib("diameter/include/diameter.hrl").
88-include("diameter_internal.hrl").
89
90%% ---------------------------------------------------------------------------
91%% start/0
92%% ---------------------------------------------------------------------------
93
94-spec start()
95   -> ok
96    | {error, term()}.
97
98start() ->
99    application:start(?APPLICATION).
100
101%% ---------------------------------------------------------------------------
102%% stop/0
103%% ---------------------------------------------------------------------------
104
105-spec stop()
106   -> ok
107    | {error, term()}.
108
109stop() ->
110    application:stop(?APPLICATION).
111
112%% ---------------------------------------------------------------------------
113%% start_service/2
114%% ---------------------------------------------------------------------------
115
116-spec start_service(service_name(), [service_opt()])
117   -> ok
118    | {error, term()}.
119
120start_service(SvcName, Opts)
121  when is_list(Opts) ->
122    diameter_config:start_service(SvcName, Opts).
123
124%% ---------------------------------------------------------------------------
125%% stop_service/1
126%% ---------------------------------------------------------------------------
127
128-spec stop_service(service_name())
129   -> ok
130    | {error, term()}.
131
132stop_service(SvcName) ->
133    diameter_config:stop_service(SvcName).
134
135%% ---------------------------------------------------------------------------
136%% services/0
137%% ---------------------------------------------------------------------------
138
139-spec services()
140   -> [service_name()].
141
142services() ->
143    [Name || {Name, _} <- diameter_service:services()].
144
145%% ---------------------------------------------------------------------------
146%% service_info/2
147%% ---------------------------------------------------------------------------
148
149-spec service_info(service_name(), atom() | [atom()])
150   -> any().
151
152service_info(SvcName, Option) ->
153    diameter_service:info(SvcName, Option).
154
155%% ---------------------------------------------------------------------------
156%% peer_info/2
157%% ---------------------------------------------------------------------------
158
159-spec peer_info(peer_ref())
160   -> [tuple()].
161
162peer_info(PeerRef) ->
163    diameter_service:peer_info(PeerRef).
164
165%% ---------------------------------------------------------------------------
166%% peer_find/1
167%% ---------------------------------------------------------------------------
168
169-spec peer_find(peer_ref() | pid())
170   -> {peer_ref(), pid()}
171    | false.
172
173peer_find(Pid) ->
174    diameter_peer_fsm:find(Pid).
175
176%% ---------------------------------------------------------------------------
177%% add_transport/3
178%% ---------------------------------------------------------------------------
179
180-spec add_transport(service_name(), {listen|connect, [transport_opt()]})
181   -> {ok, transport_ref()}
182    | {error, term()}.
183
184add_transport(SvcName, {T, Opts} = Cfg)
185  when is_list(Opts), (T == connect orelse T == listen) ->
186    diameter_config:add_transport(SvcName, Cfg).
187
188%% ---------------------------------------------------------------------------
189%% remove_transport/2
190%% ---------------------------------------------------------------------------
191
192-spec remove_transport(service_name(), transport_pred())
193   -> ok | {error, term()}.
194
195remove_transport(SvcName, Pred) ->
196    diameter_config:remove_transport(SvcName, Pred).
197
198%% ---------------------------------------------------------------------------
199%% subscribe/1
200%% ---------------------------------------------------------------------------
201
202-spec subscribe(service_name())
203   -> true.
204
205subscribe(SvcName) ->
206    diameter_service:subscribe(SvcName).
207
208%% ---------------------------------------------------------------------------
209%% unsubscribe/1
210%% ---------------------------------------------------------------------------
211
212-spec unsubscribe(service_name())
213   -> true.
214
215unsubscribe(SvcName) ->
216    diameter_service:unsubscribe(SvcName).
217
218%% ---------------------------------------------------------------------------
219%% session_id/1
220%% ---------------------------------------------------------------------------
221
222-spec session_id('DiameterIdentity'())
223   -> 'OctetString'().
224
225session_id(Ident) ->
226    diameter_session:session_id(Ident).
227
228%% ---------------------------------------------------------------------------
229%% origin_state_id/0
230%% ---------------------------------------------------------------------------
231
232-spec origin_state_id()
233   -> 'Unsigned32'().
234
235origin_state_id() ->
236    diameter_session:origin_state_id().
237
238%% ---------------------------------------------------------------------------
239%% call/3,4
240%% ---------------------------------------------------------------------------
241
242-spec call(service_name(), app_alias(), any(), [call_opt()])
243   -> any().
244
245call(SvcName, App, Message, Options) ->
246    diameter_traffic:send_request(SvcName, {alias, App}, Message, Options).
247
248call(SvcName, App, Message) ->
249    call(SvcName, App, Message, []).
250
251%% ===========================================================================
252
253%% Diameter basic types
254
255-type 'OctetString'() :: iolist().
256-type 'Integer32'()   :: -2147483647..2147483647.
257-type 'Integer64'()   :: -9223372036854775807..9223372036854775807.
258-type 'Unsigned32'()  :: 0..4294967295.
259-type 'Unsigned64'()  :: 0..18446744073709551615.
260-type 'Float32'()     :: '-infinity' | float() | infinity.
261-type 'Float64'()     :: '-infinity' | float() | infinity.
262-type 'Grouped'()     :: list() | tuple().
263
264%% Diameter derived types
265
266-type 'Address'()
267   :: inet:ip_address()
268    | string().
269
270-type 'Time'()             :: {{integer(), 1..12, 1..31},
271                               {0..23, 0..59, 0..59}}.
272-type 'UTF8String'()       :: iolist().
273-type 'DiameterIdentity'() :: 'OctetString'().
274-type 'DiameterURI'()      :: 'OctetString'().
275-type 'Enumerated'()       :: 'Integer32'().
276-type 'IPFilterRule'()     :: 'OctetString'().
277-type 'QoSFilterRule'()    :: 'OctetString'().
278
279%% The handle to a service.
280
281-type service_name()
282   :: any().
283
284%% Capabilities options/avps on start_service/2 and/or add_transport/2
285
286-type capability()
287   :: {'Origin-Host',                    'DiameterIdentity'()}
288    | {'Origin-Realm',                   'DiameterIdentity'()}
289    | {'Host-IP-Address',                ['Address'()]}
290    | {'Vendor-Id',                      'Unsigned32'()}
291    | {'Product-Name',                   'UTF8String'()}
292    | {'Supported-Vendor-Id',            ['Unsigned32'()]}
293    | {'Auth-Application-Id',            ['Unsigned32'()]}
294    | {'Vendor-Specific-Application-Id', ['Grouped'()]}
295    | {'Firmware-Revision',              'Unsigned32'()}.
296
297%% Filters for call/4
298
299-type peer_filter()
300   :: none
301    | host
302    | realm
303    | {host,  any|'DiameterIdentity'()}
304    | {realm, any|'DiameterIdentity'()}
305    | {eval, eval()}
306    | {neg, peer_filter()}
307    | {all, [peer_filter()]}
308    | {any, [peer_filter()]}.
309
310-opaque peer_ref()
311   :: pid().
312
313-type eval()
314   :: {module(), atom(), list()}
315    | fun()
316    | maybe_improper_list(eval(), list()).
317
318-type evaluable()
319   :: eval().
320
321-type sequence()
322   :: {'Unsigned32'(), 0..32}.
323
324-type restriction()
325   :: false
326    | node
327    | nodes
328    | [node()]
329    | eval().
330
331-type remotes()
332   :: boolean()
333    | [node()]
334    | eval().
335
336-type message_length()
337   :: 0..16#FFFFFF.
338
339-type decode_format()
340   :: record
341    | list
342    | map
343    | none
344    | record_from_map.
345
346-type strict_arities()
347   :: false
348    | encode
349    | decode.
350
351%% Options common to both start_service/2 and add_transport/2.
352
353-type common_opt()
354   :: {pool_size, pos_integer()}
355    | {capabilities_cb, eval()}
356    | {capx_timeout, 'Unsigned32'()}
357    | {strict_capx, boolean()}
358    | {strict_mbit, boolean()}
359    | {avp_dictionaries, [module()]}
360    | {disconnect_cb, eval()}
361    | {dpr_timeout, 'Unsigned32'()}
362    | {dpa_timeout, 'Unsigned32'()}
363    | {incoming_maxlen, message_length()}
364    | {length_errors, exit | handle | discard}
365    | {connect_timer, 'Unsigned32'()}
366    | {watchdog_timer, 'Unsigned32'() | {module(), atom(), list()}}
367    | {watchdog_config, [{okay|suspect, non_neg_integer()}]}
368    | {spawn_opt, list() | mfa()}.
369
370%% Options passed to start_service/2
371
372-type service_opt()
373   :: capability()
374    | {application, [application_opt()]}
375    | {restrict_connections, restriction()}
376    | {sequence, sequence() | eval()}
377    | {share_peers, remotes()}
378    | {decode_format, decode_format()}
379    | {traffic_counters, boolean()}
380    | {string_decode, boolean()}
381    | {strict_arities, true | strict_arities()}
382    | {use_shared_peers, remotes()}
383    | common_opt().
384
385-type application_opt()
386   :: {alias, app_alias()}
387    | {dictionary, module()}
388    | {module, app_module()}
389    | {state, any()}
390    | {call_mutates_state, boolean()}
391    | {answer_errors, callback|report|discard}
392    | {request_errors, answer_3xxx|answer|callback}.
393
394-type app_alias()
395   :: any().
396
397-type app_module()
398   :: module()
399    | maybe_improper_list(module(), list())
400    | #diameter_callback{}.
401
402%% Identifier returned by add_transport/2
403
404-type transport_ref()
405   :: reference().
406
407%% Options passed to add_transport/2
408
409-type transport_opt()
410   :: {transport_module, atom()}
411    | {transport_config, any()}
412    | {transport_config, any(), 'Unsigned32'() | infinity}
413    | {applications, [app_alias()]}
414    | {capabilities, [capability()]}
415    | common_opt()
416    | {private, any()}.
417
418%% Predicate passed to remove_transport/2
419
420-type transport_pred()
421   :: fun((transport_ref(), connect|listen, list()) -> boolean())
422    | fun((transport_ref(), list()) -> boolean())
423    | fun((list()) -> boolean())
424    | transport_ref()
425    | boolean()
426    | list()
427    | {connect|listen, transport_pred()}
428    | {atom(), atom(), list()}.
429
430%% Options passed to call/4
431
432-type call_opt()
433   :: {extra, list()}
434    | {filter, peer_filter()}
435    | {timeout, 'Unsigned32'()}
436    | {peer, peer_ref()}
437    | detach.
438