[erlang-questions] Erlang-diameter: Issue when trying to add multiple servers to a relay

Arshad Ansari <>
Thu Jul 28 08:35:46 CEST 2016


Hello Chandru,

Thank you for the reply.

Here is what I have done. I'm using the example code given in OTP library
available here at
https://github.com/erlang/otp/tree/master/lib/diameter/examples/code. The
node.erl being common across client.erl, server.erl and relay.erl. However,
I have a seperate version of node.erl for each of these systems. My entire
code is here: https://github.com/arshadansari27/erlang-diameter-eval

The code I'm using the run the client.erl and client_cb.erl is as follows:

-module(runner4).

-export([run/0, one_client/0, stop/0]).

run() ->
        diameter:start(),
        client:start(),
        client:connect(tcp).

stop() ->
        client:stop(),
        diameter:stop().


one_client()  ->
        client:call().


I'm calling runner4:run() first then runner4:one_client() and finally
runner4:stop() so I can see tcp dumps and all after each and every step.
Client connects to Relay and Relay forwards the requests to Server
instances and gets a response from there and returns to the client. So that
part is working. I was even able to do a little hack in pick_peer as shown
below, so I can balance the incoming requests across multiple server
instances. In my case, there are only two instances so I'm just selecting
in a round robin manner and returning that peer.

pick_peer(Peers, _, _SvcName, _State, relayed) ->
        [{_, Peer_counter}] = ets:lookup(mytable_relay, peers),
        Peer_count = other_counter:inc(Peer_counter),
        Index = (Peer_count rem 2) + 1,
        % List = lists:map(fun(N) -> {Xs, _} = N, Xs end, Peers),
        Peer = lists:nth(Index, Peers),
    {ok, Peer}.

With this I'm also able to load balance across different server instances
from relay at exact 50/50 ration. So I was able to solve much of the
original problem I had. The problem that remains is that what I have done
is firstly a hack and secondly inexplicable. And what follows is the
current problem.
When I start relay and then start both the server instances, relay calls
peer up for both the servers and the pick_peer's first argument (local
nodes) has both the servers as peers. Whereas when I start the server
instances first and then relay, then only one time pick_peer is called and
with only one of the server instance. Even the tcp dump on wireshark does
not show the CER exchange between relay and servers, whereas the CER
exchange is there from client to relay. This is what is confusing me. Why
would the order of starting the server/relay allow peers to be added and/or
not as well as why no CER exchange between relay and server instances? They
do have TCP packets exchanged between them, but not the Diameter protocol
CER exchange that is present for Client-relay communication.

 Given below is the code that starts the relay and connects it to both the
server instances that are running on the same machine.
% runner.erl
-module(runner).

-export([run/0]).

run() ->
        diameter:start(),
        relay:start(),
        relay:connect(tcp, 1, true),
        relay:connect(tcp, 2, true),
        relay:listen(tcp).

% relay.erl
-module(relay).

-include_lib("diameter/include/diameter.hrl").
-include_lib("diameter/include/diameter_gen_base_rfc3588.hrl").
-include_lib("diameter/include/diameter_gen_relay.hrl").

-export([start/1,
         start/2,
         listen/2,
         connect/2,
         connect/3,
         stop/1,
         handle_info/2]).

-export([start/0,
         listen/1,
         connect/1,
         stop/0]).

-define(DEF_SVC_NAME, ?MODULE).

%% The service configuration.
-define(SERVICE(Name), [{'Origin-Host', "pcrf.relay.com"},
                        {'Origin-Realm', "relay.com"},
                        {'Vendor-Id', 193},
                        {'Product-Name', "RelayAgent"},
                        {'Auth-Application-Id', [?DIAMETER_APP_ID_RELAY]},
% 16#FFFFFFFF
                        {string_decode, false},
                                                {use_shared_peers, true},
                        {application, [{alias, relay},
                                       {dictionary, ?DIAMETER_DICT_RELAY},
% diameter_gen_relay
                                       {module, relay_cb}]},
                                                {share_peers, true}
                       ]).
                       %% SKIPPING the code that is same as the original
one given on that link..

                      connect(T, SName, Multi) when Multi == true ->
                          node:connect(?DEF_SVC_NAME, T, SName).
% node.erl

%% SKIPPING the code that is same as the original one given on that link..
-define(RELAY_PORT, 3868).
-define(SERVER_PORT1, 3871).
-define(SERVER_PORT2, 3872).

%% connect/2

-spec connect(diameter:service_name(), client_opts())
   -> {ok, diameter:transport_ref()}
    | {error, term()}.

connect(Name, Opts)
  when is_list(Opts) ->
        io:format("Connection Options ~p\n", [{connect, Opts}]),
    diameter:add_transport(Name, {connect, Opts});

connect(Name, {T, Opts}) ->
    connect(Name, Opts ++ client_opts(T));

connect(Name, T) ->
    connect(Name, [{connect_timer, 5000} | client_opts(T)]).

connect(Name, T, SName) ->
    connect(Name, [{connect_timer, 5000} | client_opts({T, SName ,true})]).

client_opts({T, LA, RA, RP})
  when T == all;   %% backwards compatibility
       T == any ->
    [[S, {C,Os}], T] = [client_opts({P, LA, RA, RP}) || P <- [sctp,tcp]],
    [S, {C,Os,2000} | T];

client_opts({T, LA, RA, RP}) ->
    [{transport_module, tmod(T)},
     {transport_config, [{raddr, addr(RA)},
                         {rport, RP},
                         {reuseaddr, true}
                         | ip(LA)]}];

client_opts({T, S_Port, Multi}) when Multi == true ->
        Port = case S_Port of
                1 -> ?SERVER_PORT1;
                2 -> ?SERVER_PORT2
        end,
    client_opts({T, loopback, remotelocal, Port});


client_opts({T, RA, RP}) ->
    client_opts({T, default, RA, RP});

addr(remotelocal) ->
    {172,16,101,146};

ip(remotelocal) ->
    {172,16,101,146};


REALM INFO
------------------

client:
    Origin-Host: first.client.com
    Origin-Realm: client.com

Relay:
    Origin-Host: pcrf.realy.com
    Origin-Realm: realy.com


Server 1:
    Origin-Host: 3671.server.com
    Origin-Realm: server.com

Server 2:
    Origin-Host: 3672.server.com
    Origin-Realm: server.com

I hope that covers everything. Any help or direction is very much
appreciated.

Regards,
Arshad

On 28-Jul-2016 2:56 AM, "Chandru" <>
wrote:

> Hi Arshad,
>
> First, some general advice. I've used the Erlang diameter stack quite
> extensively to build telecom applications and it is pretty rock solid. I
> wouldn't hesitate to recommend using it. There are several mission critical
> services built using this stack running in production at EE (largest mobile
> operator) in the UK.
>
> Re the specific problem you are facing, how are you generating the
> requests on the client side? Some packet captures or the client code would
> be useful to see.
>
> cheers,
> Chandru
>
> On 27 July 2016 at 09:00, Arshad Ansari <> wrote:
>
>> Hello there,
>>
>> Firstly, I've just picked up erlang this week and I'm suppose to evaluate
>> Erlang-Diameter for my company (I'm even new to telecom domain and hence to
>> diameter protocol). So, I'm a complete noob in this area.  I'm using the
>> example provided by OTP in lib/diameter/examples/code folder. I'm using the
>> relay (listening on 3868) code given there to connect to the two instance
>> of server that I have seperately started on 3871 and 3872. When I connect
>> to these two servers, the connection is established with both but the Peer
>> Up in relay_cb.erl is called only for the first server I tried to connect
>> to. Hence forth, all the requests from clients are relayed to this single
>> Peer. I'm trying to load balance the requests and therefore sharing client
>> connections across multiple server. I would like and appreciate some help
>> in that direction. I haven't changed much from the example directory. I'm
>> just listing the params I'm using for connection as shown below:
>>
>> Server uses the following config:
>> Server 1:
>> [{'Origin-Host', "3871.example.com"},
>>                           {'Origin-Realm', "example.com"},
>>                           {'Vendor-Id', 193},
>>                           {'Product-Name', "3871-Server-Erlang"},
>>                           {'Auth-Application-Id', [0]},
>>                           {restrict_connections, false},
>>                           {string_decode, false},
>>                           {application, [{alias, common},
>>                                          {dictionary,
>> diameter_gen_base_rfc6733},
>>                                          {module, server_cb}]}]).
>>
>> Server 2:
>> [{'Origin-Host', "3872.example.com"},
>>                           {'Origin-Realm', "example.com"},
>>                           {'Vendor-Id', 193},
>>                           {'Product-Name', "3872-Server-Erlang"},
>>                           {'Auth-Application-Id', [0]},
>>                           {restrict_connections, false},
>>                           {string_decode, false},
>>                           {application, [{alias, common},
>>                                          {dictionary,
>> diameter_gen_base_rfc6733},
>>                                          {module, server_cb}]}]).
>>
>> Relay:
>> [{'Origin-Host', "arshad.example.com"},
>>                          {'Origin-Realm', "example.com"},
>>                          {'Vendor-Id', 193},
>>                          {'Product-Name', "RelayAgent"},
>>                          {'Auth-Application-Id',
>> [?DIAMETER_APP_ID_RELAY]},
>>                          {string_decode, false},
>>                          {application, [{alias, relay},
>>                                         {dictionary,
>> ?DIAMETER_DICT_RELAY},
>>                                         {module, relay_cb}]}]).
>>
>>
>> _______________________________________________
>> erlang-questions mailing list
>> 
>> http://erlang.org/mailman/listinfo/erlang-questions
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20160728/0e2b78ab/attachment.html>


More information about the erlang-questions mailing list