aboutsummaryrefslogblamecommitdiffstats
path: root/lib/diameter/src/app/diameter_peer.erl
blob: 6b8971b8ea1015137752517798d5de9815c8994d (plain) (tree)





































































































































































































































                                                                               
%%
%% %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(diameter_peer).

-behaviour(gen_server).

%% Interface towards transport modules ...
-export([recv/2,
         up/1,
         up/2]).

%% ... and the stack.
-export([start/3,
         send/2,
         close/1,
         abort/1,
         notify/2]).

%% Server start.
-export([start_link/0]).

%% gen_server callbacks
-export([init/1,
         terminate/2,
         handle_call/3,
         handle_cast/2,
         handle_info/2,
         code_change/3]).

%% debug
-export([state/0,
         uptime/0]).

-include_lib("diameter/include/diameter.hrl").
-include("diameter_internal.hrl").

%% Registered name of the server.
-define(SERVER, ?MODULE).

%% Server state.
-record(state, {id = now()}).

%%% ---------------------------------------------------------------------------
%%% # notify/2
%%% ---------------------------------------------------------------------------

notify(SvcName, T) ->
    rpc:abcast(nodes(), ?SERVER, {notify, SvcName, T}).

%%% ---------------------------------------------------------------------------
%%% # start/3
%%% ---------------------------------------------------------------------------

start(T, Opts, #diameter_service{} = Svc) ->
    {Mod, Cfg} = split_transport(Opts),
    apply(Mod, start, [T, Svc, Cfg]).

%%% ---------------------------------------------------------------------------
%%% # up/[12]
%%% ---------------------------------------------------------------------------

up(Pid) ->  %% accepting transport
    ifc_send(Pid, {self(), connected}).

up(Pid, Remote) ->  %% connecting transport
    ifc_send(Pid, {self(), connected, Remote}).

%%% ---------------------------------------------------------------------------
%%% # recv/2
%%% ---------------------------------------------------------------------------

recv(Pid, Pkt) ->
    ifc_send(Pid, {recv, Pkt}).

%%% ---------------------------------------------------------------------------
%%% # send/2
%%% ---------------------------------------------------------------------------

send(Pid, #diameter_packet{transport_data = undefined,
			   bin = Bin}) ->
    send(Pid, Bin);

send(Pid, Pkt) ->
    ifc_send(Pid, {send, Pkt}).

%%% ---------------------------------------------------------------------------
%%% # close/1
%%% ---------------------------------------------------------------------------

close(Pid) ->
    ifc_send(Pid, {close, self()}).

%%% ---------------------------------------------------------------------------
%%% # abort/1
%%% ---------------------------------------------------------------------------

abort(Pid) ->
    exit(Pid, shutdown).

%% ---------------------------------------------------------------------------
%% ---------------------------------------------------------------------------

start_link() ->
    ServerName = {local, ?SERVER},
    Module     = ?MODULE,
    Args       = [],
    Options    = [{spawn_opt, diameter_lib:spawn_opts(server, [])}],
    gen_server:start_link(ServerName, Module, Args, Options).

state() ->
    call(state).

uptime() ->
    call(uptime).

%%% ----------------------------------------------------------
%%% # init(Role)
%%% ----------------------------------------------------------

init([]) ->
    {ok, #state{}}.

%%% ----------------------------------------------------------
%%% # handle_call(Request, From, State)
%%% ----------------------------------------------------------

handle_call(state, _, State) ->
    {reply, State, State};

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]),
    {reply, nok, State}.

%%% ----------------------------------------------------------
%%% # handle_cast(Request, State)
%%% ----------------------------------------------------------

handle_cast(Msg, State) ->
    warning_msg("received unexpected message:~n~w", [Msg]),
    {noreply, State}.

%%% ----------------------------------------------------------
%%% # handle_info(Request, State)
%%% ----------------------------------------------------------

%% Remote service is distributing a message.
handle_info({notify, SvcName, T}, S) ->
    bang(diameter_service:whois(SvcName), T),
    {noreply, S};

handle_info(Info, State) ->
    warning_msg("received unexpected info:~n~w", [Info]),
    {noreply, State}.

%% ----------------------------------------------------------
%% terminate(Reason, State)
%% ----------------------------------------------------------

terminate(_Reason, _State) ->
    ok.

%% ----------------------------------------------------------
%% code_change(OldVsn, State, Extra)
%% ----------------------------------------------------------

code_change(_OldVsn, State, _Extra) ->
    {ok, State}.

%% ---------------------------------------------------------
%% INTERNAL FUNCTIONS
%% ---------------------------------------------------------

%% ifc_send/2
%%
%% Send something over the transport interface.

ifc_send(Pid, T) ->
    Pid ! {diameter, T}.

%% bang/2

bang(undefined = No, _) ->
    No;
bang(Pid, T) ->
    Pid ! T.

%% split_transport/1
%%
%% Split options into transport module, transport config and
%% remaining options.

split_transport(Opts) ->
    {[M,C], _} = proplists:split(Opts, [transport_module,
                                        transport_config]),
    {value(M, diameter_tcp), value(C, [])}.

value([{_,V}], _) ->
    V;
value([], V) ->
    V.

%% call/1

call(Request) ->
    gen_server:call(?SERVER, Request, infinity).

%% warning_msg/2

warning_msg(F, A) ->
    ?diameter_warning("~p: " ++ F, [?MODULE | A]).