<div dir="ltr"><div><div><div><div>Hi Anders,<br><br></div>Thanks for your quick responses and detailed comments. I am learning erlang during my spare time and sometimes progress slowly since no enough time to engage into it.<br>
<br></div>Yes, like you mentioned, I started the diameter client configuration (capability exchange) in a separate process and wait for peer up callback (which I think should be same as diameter:subscribe, though I haven't try it yet). Meanwhile I started workers which wait for notifications from the peer up callback via ets table approach to proceed with sending diameter messages. The problem is that if there is a lot of workers, after peer up notifications being received, some of them don't receive diameter answer from the server, instead, they still get no_connection errors from diameter_traffic:send function, and others can get proper diameter answers. Sometimes, all the workers can get the answers after sending requests upon getting notifications from the sole peer up callback. <br>
<br></div>The confusing part is that once the client receives the peer up, it should mean the server is ready to process diameter requests, but why still get no_connection errors. As you mentioned in the previous emails "If you call before the<br>
relevant peer_up callback then the result is {error, no_connection}."<br><br></div>The other question is not diameter related. It is about the erlang BIF function register. I tried to register every process in a loop. However I found through debugger or using whereis function that not all process names can be registered properly. As I check the erlang document, it says <span class="">register(Name, Pid) -> true. It supposes to be always successful unless the process name exists already then get the badarg exception.</span><br>
util:foreach_index(<br> fun(N) -><br> ProcessName = list_to_atom(atom_to_list(test) ++ integer_to_list(N)), <br> register(ProcessName, spawn(executer, execute, []))<br>
end, MyList)<br><div><br></div><div>Do you have any suggestions why register could fail without any warning/error reported?<br><br></div><div>Thanks!<br><br></div><div>Samuel<br></div><div><br></div></div><div class="gmail_extra">
<br><br><div class="gmail_quote">On Tue, Apr 30, 2013 at 5:04 AM, Anders Svensson <span dir="ltr"><<a href="mailto:anders.otp@gmail.com" target="_blank">anders.otp@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Hi Samuel.<br>
<div class="im"><br>
On Tue, Apr 30, 2013 at 4:35 AM, S X <<a href="mailto:erlangprogram@gmail.com">erlangprogram@gmail.com</a>> wrote:<br>
> Hi Anders,<br>
><br>
> Thanks for your explanation. Setting additional options in<br>
> diameter:add_transport and retrieving them with diameter:service_info from<br>
> the peer_up callback work well. And the descriptions about the peer states<br>
> according to RFC3539 and 6733 make a lot of sense.<br>
><br>
> The case I am trying to resolve is:<br>
> Start multiple processes on one pc, each process tries to connect to one<br>
> same server (obviously I will get already_connected warning, but it can keep<br>
> going), in each process, then I try to send a diameter message to the<br>
> server, I used to insert a certain amount of sleep time before I send the<br>
> message after connecting to the server and it works ok. But I wanted to use<br>
> the peer up callback to behave like a handshaking procedure among the client<br>
> and the server, so the server is supposed to be ready when the client<br>
> process sends the message.<br>
><br>
> Now, the fact is that only one peer up callback is invoked for multiple<br>
> processes. Then I tried to notify all the processes in the peer up callback<br>
> when invoked and the processes send out the diameter messages. However, the<br>
> processes don't receive any responses. Or sometimes only part of the<br>
> processes get responses. Why inserting an amount of sleep time always works.<br>
><br>
> This is a little bit confusing me, how peer up should be used properly to<br>
> get the notification done right for multiple processes.<br>
<br>
</div>It's difficult to say what your problem is without seeing code but<br>
here are a few points.<br>
<br>
It's not your client processes that connect to the server. A transport<br>
connection results from someone calling diameter:add_transport/2. Once<br>
diameter establishes the connection, successfully performs<br>
capabilities exchange, and makes peer_up callbacks, that transport<br>
connection is available to any process that wants to send to the peer<br>
in question. In your case, you have multiple processes that want to do<br>
so, but if you're calling diameter:add_transport/2 with the same<br>
config from each of those processes then you're effectively telling<br>
diameter to establish multiple transport connections, only one of<br>
which will succeed by default. If you want to allow multiple transport<br>
connections per peer then you need to configure your service with<br>
{restrict_connections, false}, but the peer need not support this (see<br>
2.1 in RFC 6733) so may reject all but one CER. Without<br>
restrict_connections it's diameter that disallows multiple<br>
connections.<br>
<br>
Given that you want multiple client processes to send from (not wrong,<br>
but why?), I would treat these as workers that have nothing to do with<br>
configuration. That is, call diameter:start_service/2 and<br>
diameter:add_transport/2 from elsewhere and have your workers kick<br>
into action after capabilities exchange.<br>
<br>
Like you said, your workers want to know when the peer becomes<br>
available. There are two ways to get notification: a peer_up callback<br>
or a diameter event. The latter are subscribed to with<br>
diameter:subscribe/1 so one way is for each worker to subscribe to<br>
events and react to them. If you want to use peer_up as a trigger then<br>
you need to code some way for the callback to notify your worker<br>
processes. There are plenty of ways to do this, none of which are<br>
diameter-specific. For example: maintain your worker pids in an ets<br>
table that the callback examines; have workers register with a<br>
registered gen_server that finds out about callbacks; spawn workers as<br>
a result of peer_up. Sleep is never a reliable solution.<br>
<span class="HOEnZb"><font color="#888888"><br>
Anders<br>
</font></span><div class="HOEnZb"><div class="h5"><br>
<br>
><br>
> Thanks for any suggestions!<br>
><br>
> Samuel<br>
><br>
><br>
><br>
><br>
> On Thu, Apr 25, 2013 at 5:40 AM, Anders Svensson <<a href="mailto:anders.otp@gmail.com">anders.otp@gmail.com</a>><br>
> wrote:<br>
>><br>
>> On Wed, Apr 24, 2013 at 5:23 PM, S X <<a href="mailto:erlangprogram@gmail.com">erlangprogram@gmail.com</a>> wrote:<br>
>> > Thanks a lot for your comments.<br>
>> ><br>
>> > The diameter:call function allows to send extra arguments. It works fine<br>
>> > after changing the callback function signatures accordingly. This is<br>
>> > very<br>
>> > useful when I want to notify the other process to do the next thing.<br>
>> ><br>
>> > Before sending a diameter message, we call diameter:add_transport to<br>
>> > connect<br>
>> > to a peer and peform CER/CEA capability information exchange. On the<br>
>> > caller<br>
>> > side, let's say the client callback module, the peer_up will be invoked<br>
>> > when<br>
>> > CER/CEA is completed. Why it doesn't have the similar mechanism like<br>
>> > diameter:call to allow insert additional arguments so we can utilize<br>
>> > them,<br>
>> > for example, notify the others to send diameter messages?<br>
>><br>
>> No particular reason aside from history and that the need hasn't come<br>
>> up. As it is, you can pass arbitrary options to<br>
>> diameter:add_transport/2 (history again) and retrieve these in a<br>
>> callback with diameter:service_info(PeerRef), so that can be used a<br>
>> substitute for extra arguments in this case.<br>
>><br>
>> > diameter:add_transport is a sync call, but it doesn't mean you can send<br>
>><br>
>> add_transport *doesn't* wait for the config it's passed to result in a<br>
>> connection before returning. (It might never happen for one.)<br>
>><br>
>> > diameter messages successfully when the function returns, i.e. it<br>
>> > usually<br>
>> > gets {error, no_connection} or { error, timeout }(this might because of<br>
>> > the<br>
>> > server side) if you call diameter:call right after<br>
>> > diameter:add_transport.<br>
>><br>
>> This is because the peer won't be ready to respond to requests until<br>
>> capabilities exchange has completed (at least). If you call before the<br>
>> relevant peer_up callback then the result is {error, no_connection}.<br>
>> After peer_up the result will be {error, timeout} if the peer doesn't<br>
>> answer. One case in which this is expected is after a connection has<br>
>> been reestablished following an exchange of 3 x DWR/DWA. (ie. RFC 3539<br>
>> DOWN -> REOPEN -> OKAY.) Since both ends of the connection do this,<br>
>> the client can consider the connection to be reestablished before the<br>
>> server. If the client sends a request before the server is done with<br>
>> it's exchange (ie. reached OKAY) then RFC 6733 says it should discard<br>
>> the request, resulting in a timeout on the client end.<br>
>><br>
>> > So is there any reason why not allowing to add additional arguments and<br>
>> > use<br>
>> > them in peer_up callback function? Since it means capability exchange is<br>
>> > done and the peer is ready, at this point it should be safe to send<br>
>> > diameter<br>
>> > messages to the peer.<br>
>><br>
>> See above.<br>
>><br>
>> Anders<br>
>><br>
>><br>
>> ><br>
>> > Any suggestions?<br>
>> ><br>
>> > Thanks!<br>
>> ><br>
>> > Samuel<br>
>> ><br>
>> ><br>
>> > On Tue, Apr 16, 2013 at 7:22 AM, Anders Svensson <<a href="mailto:anders.otp@gmail.com">anders.otp@gmail.com</a>><br>
>> > wrote:<br>
>> >><br>
>> >> On Sun, Apr 14, 2013 at 7:01 PM, S X <<a href="mailto:erlangprogram@gmail.com">erlangprogram@gmail.com</a>> wrote:<br>
>> >> > Hello,<br>
>> >> ><br>
>> >> > Based on the erlang diameter library and the sample code, I want to<br>
>> >> > start<br>
>> >> > multiple diameter client processes in one erlang node(one client IP),<br>
>> >> > and<br>
>> >> > the client needs to define a diameter_app callback module for certain<br>
>> >> > application, for example:<br>
>> >> ><br>
>> >> > -define(SERVICE(Name), [{'Origin-Host', ?L(Name) ++ ".<a href="http://example.com" target="_blank">example.com</a>"},<br>
>> >> > {'Origin-Realm', "<a href="http://example.com" target="_blank">example.com</a>"},<br>
>> >> > {'Vendor-Id', 193},<br>
>> >> > {'Product-Name', "Client"},<br>
>> >> > {'Auth-Application-Id',<br>
>> >> > [?DIAMETER_APP_ID_COMMON,<br>
>> >> > ?DIAMETER_APP_ID_CCRA]},<br>
>> >> > {application, [{alias, ?APP_CCR_ALIAS},<br>
>> >> > {dictionary,<br>
>> >> > ?DIAMETER_DICT_CCRA},<br>
>> >> > {module, client_cb_ccra}]}]).<br>
>> >> ><br>
>> >> ><br>
>> >> > First question:<br>
>> >> > how the diameter library handles this situation? Will all diameter<br>
>> >> > client<br>
>> >> > processes share one single diameter_app callback module<br>
>> >> > "client_cb_ccra"<br>
>> >> > or<br>
>> >> > it will automatically attach different instance of the callback<br>
>> >> > module<br>
>> >> > (process) to the different client process by using spawn_monitor? So<br>
>> >> > from<br>
>> >> > the callback handle_answer in "client_cb_ccra" I can notify the<br>
>> >> > proper<br>
>> >> > client proce by just calling client:notify() something.<br>
>> >><br>
>> >> diameter doesn't know anything about your client process. If you want<br>
>> >> a callback to be able to contact the client process associated with<br>
>> >> the service in question (ie. the service whose name the callback gets<br>
>> >> as an argument) then you need to give the callback the means to do so.<br>
>> >> One way would be to map the service name to your process (eg. it's the<br>
>> >> registered name of your client process), another would be to pass some<br>
>> >> identification as extra arguments to the callbacks. (Eg. {module,<br>
>> >> [client_cb_ccra, X]} in the config above.)<br>
>> >><br>
>> >> > Second question:<br>
>> >> > Notice that diameter:call allows to set extra arguments, so I was<br>
>> >> > wondering<br>
>> >> > I could set some data like:<br>
>> >> > diameter:call(Name, ?APP_CCR_ALIAS, CCR, [{extra, [self()]}]).<br>
>> >> > which sets the client process ID and I hope to deliver to the<br>
>> >> > callback<br>
>> >> > module "client_cb_ccra" and when the callback module knows which<br>
>> >> > client<br>
>> >> > process sends request and response accordingly, for example using the<br>
>> >> > client<br>
>> >> > process ID in the callback function handle_answer.<br>
>> >><br>
>> >> You can do that, but what is it you're trying to accomplish? if it's<br>
>> >> handle_answer that's supposed to communicate something then it already<br>
>> >> does: the return value of handle_answer is returned by diameter:call.<br>
>> >><br>
>> >> > However, I don't want pack the extra arguments into the diameter<br>
>> >> > packet<br>
>> >> > since the diameter server doesn't know what they are and the extra<br>
>> >> > ones<br>
>> >> > are<br>
>> >> > not part of standard diameter packet.<br>
>> >><br>
>> >> Not sure what you mean here. There's no way for your client to send<br>
>> >> the server anything other than a Diameter message.<br>
>> >><br>
>> >> > Now I changed the pick_peer callback signatures to allow extra<br>
>> >> > arguments,<br>
>> >> > pick_peer([Peer | _], _, _SvcName, _State, A)<br>
>> >> ><br>
>> >> > But I got encoding error in the callback prepare_request<br>
>> >> ><br>
>> >> > =ERROR REPORT==== 14-Apr-2013::11:40:41 ===<br>
>> >> > Error in process <0.175.0> with exit value:<br>
>> >> > {undef,[{client_cb_ccra,prepare_request,[{diameter_packet,<br>
>> >><br>
>> >> The arity of your callback probably doesn't agree with the number of<br>
>> >> extra arguments you've specified: prepare_request will also get your<br>
>> >> extra arguments.<br>
>> >><br>
>> >><br>
>> >> ><br>
>> >> > > >{diameter_header,1,undefined,undefined,undefined,3958849953,3958849953,undefined,undefined,undefined,undefined},undefined,{diameter_rfc4006_cc_CCR,["who",";","142745567...<br>
>> >> ><br>
>> >> > {error,encode}<br>
>> >> ><br>
>> >> > In overall, I read the online documents, which have limited<br>
>> >> > information<br>
>> >> > on<br>
>> >> > how to use the extra arguments in the library and don't quite get<br>
>> >> > how<br>
>> >> > to<br>
>> >> > utilize the extra arguments to do something tricky,<br>
>> >> ><br>
>> >> > Are there any suggestions on how to deal with multiple client<br>
>> >> > processes?<br>
>> >><br>
>> >> Not sure I understand what problem it is you're trying to solve.<br>
>> >> Multiple processes invoking diameter:call is nothing strange. You<br>
>> >> typically just return something useful (eg. the answer message from<br>
>> >> the peer) from handle_answer, which diameter:call then returns for the<br>
>> >> caller to deal with.<br>
>> >><br>
>> >> Anders<br>
>> >><br>
>> >><br>
>> >> > Thanks a lot!<br>
>> >> ><br>
>> >> > Samuel<br>
>> >> ><br>
>> ><br>
>> ><br>
><br>
><br>
</div></div></blockquote></div><br></div>