Who called my gen_server?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Who called my gen_server?

Frank Muller
Hi guys,

I've two connected nodes: N1, N2.

N1 is mine and I've a gen_server running on it.
N2 is external and doesn't belong to me.

A process on N2 is calling my gen_server (on N1) via an rpc:call.

Is there a way to know the Pid of that process?
Or, can I log all rpc_call(s) calling my gen_server?

/Frank

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Who called my gen_server?

Mikael Pettersson-5
Frank Muller writes:
 > Hi guys,
 >
 > I've two connected nodes: N1, N2.
 >
 > N1 is mine and I've a gen_server running on it.
 > N2 is external and doesn't belong to me.
 >
 > A process on N2 is calling my gen_server (on N1) via an rpc:call.
 >
 > Is there a way to know the Pid of that process?

Based on a half hour study of lib/kernel/src/rpc.erl in OTP-19.3 I didn't
think so, but now I think I may have found a way.

On the callee node, rpc has a gen_server (rex) which handles incoming calls.
When it calls the {Mod,Fun,Args} from the rpc:call, it does so asynchronously
via a temporary process (see handle_call_call/6).  There is a mapping from
that process' Pid to the From passed to rex' handle_call (called 'To' in the code)
in rex' state, which you could dig out using sys:get_state or :get_status.

But on the caller node, rpc:call also uses a temporary process when doing the
gen_server:call to the callee node (see do_call/3), and the only association
between that process and the application process doing the rpc:call is buried
in the local variables of do_call/3 and the temporary process.  (So if you do
the sys:get_state on the callee node, you'd end up with the Pid of the temporary
process on the caller node.)

... but now it struck me that the temporary process is monitored by the process
doing the rpc:call, which erlang:process_info(Pid, monitored_by) should be able
to retrieve.  So a reverse rpc:call to the caller node to do that could work.

Not tested, will break if the rpc implementation changes, etc.

Why do you need this anyway?

 > Or, can I log all rpc_call(s) calling my gen_server?

rex doesn't have that built-in, but you could modify it to do so (it's on the
node you control)

/Mikael
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Who called my gen_server?

Frank Muller
Hi Mikael,

Thank you for the hint about rpc module. I'll try to read it to understand its behaviour

I'm still considering myself an Erlang newbie.

The idea here is to log all calls to my gen_server for debugging purposes: who called me, from where, when, with which arguments ...

For "handle_call", it's more or less easy. Not so for "handle_cast" and "handle_info".

Finally, I would like to generalize this idea to more than one gen_server. It'll be very tedious if I've to add log calls to every gen_server in my app. Maybe there's a better way. 

Thanks again for your time Mikael.

/Frank

<[hidden email]> wrote :
Frank Muller writes:
 > Hi guys,
 >
 > I've two connected nodes: N1, N2.
 >
 > N1 is mine and I've a gen_server running on it.
 > N2 is external and doesn't belong to me.
 >
 > A process on N2 is calling my gen_server (on N1) via an rpc:call.
 >
 > Is there a way to know the Pid of that process?

Based on a half hour study of lib/kernel/src/rpc.erl in OTP-19.3 I didn't
think so, but now I think I may have found a way.

On the callee node, rpc has a gen_server (rex) which handles incoming calls.
When it calls the {Mod,Fun,Args} from the rpc:call, it does so asynchronously
via a temporary process (see handle_call_call/6).  There is a mapping from
that process' Pid to the From passed to rex' handle_call (called 'To' in the code)
in rex' state, which you could dig out using sys:get_state or :get_status.

But on the caller node, rpc:call also uses a temporary process when doing the
gen_server:call to the callee node (see do_call/3), and the only association
between that process and the application process doing the rpc:call is buried
in the local variables of do_call/3 and the temporary process.  (So if you do
the sys:get_state on the callee node, you'd end up with the Pid of the temporary
process on the caller node.)

... but now it struck me that the temporary process is monitored by the process
doing the rpc:call, which erlang:process_info(Pid, monitored_by) should be able
to retrieve.  So a reverse rpc:call to the caller node to do that could work.

Not tested, will break if the rpc implementation changes, etc.

Why do you need this anyway?

 > Or, can I log all rpc_call(s) calling my gen_server?

rex doesn't have that built-in, but you could modify it to do so (it's on the
node you control)

/Mikael

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Who called my gen_server?

Andreas Schultz
In reply to this post by Frank Muller
Hi,

----- On Apr 24, 2017, at 5:43 PM, Frank Muller <[hidden email]> wrote:
Hi guys,

I've two connected nodes: N1, N2.

N1 is mine and I've a gen_server running on it.
N2 is external and doesn't belong to me.

A process on N2 is calling my gen_server (on N1) via an rpc:call.

You do know that the rpc server is exactly one process per Erlang
node. Pushing to many calls through it will degrade performance.

If you have any influence on the design of node N2, change it to call
your N1 gen_server directly without the intermediate rpc process.

You could either register your server with a global name, use another
global registry (e.g. gproc), or a myriad of other ways to reach your
gen_server without the rpc module.

That way, `From` in the handle_call method will contain the PID of
the caller.

Andreas

Is there a way to know the Pid of that process?
Or, can I log all rpc_call(s) calling my gen_server?

/Frank

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Who called my gen_server?

Frank Muller
Hi Andreas,

No I didn't know that issue with "rpc".

But is switching to a different solution as you mentioned (gproc, etc.) will help me solve "the who's calling me"?

/Frank

Schultz<[hidden email]> wrote :
Hi,

----- On Apr 24, 2017, at 5:43 PM, Frank Muller <[hidden email]> wrote:
Hi guys,

I've two connected nodes: N1, N2.

N1 is mine and I've a gen_server running on it.
N2 is external and doesn't belong to me.

A process on N2 is calling my gen_server (on N1) via an rpc:call.

You do know that the rpc server is exactly one process per Erlang
node. Pushing to many calls through it will degrade performance.

If you have any influence on the design of node N2, change it to call
your N1 gen_server directly without the intermediate rpc process.

You could either register your server with a global name, use another
global registry (e.g. gproc), or a myriad of other ways to reach your
gen_server without the rpc module.

That way, `From` in the handle_call method will contain the PID of
the caller.

Andreas

Is there a way to know the Pid of that process?
Or, can I log all rpc_call(s) calling my gen_server?

/Frank

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Who called my gen_server?

Andreas Schultz
Hi Frank,

----- On Apr 27, 2017, at 9:49 AM, Frank Muller <[hidden email]> wrote:
Hi Andreas,

No I didn't know that issue with "rpc".

But is switching to a different solution as you mentioned (gproc, etc.) will help me solve "the who's calling me"?

Only for handle_call case. handle_cast and handle_info won't get that information. You have to include
the source in the actual message you are sending.

Andreas

/Frank

Schultz<[hidden email]> wrote :
Hi,

----- On Apr 24, 2017, at 5:43 PM, Frank Muller <[hidden email]> wrote:
Hi guys,

I've two connected nodes: N1, N2.

N1 is mine and I've a gen_server running on it.
N2 is external and doesn't belong to me.

A process on N2 is calling my gen_server (on N1) via an rpc:call.

You do know that the rpc server is exactly one process per Erlang
node. Pushing to many calls through it will degrade performance.

If you have any influence on the design of node N2, change it to call
your N1 gen_server directly without the intermediate rpc process.

You could either register your server with a global name, use another
global registry (e.g. gproc), or a myriad of other ways to reach your
gen_server without the rpc module.

That way, `From` in the handle_call method will contain the PID of
the caller.

Andreas

Is there a way to know the Pid of that process?
Or, can I log all rpc_call(s) calling my gen_server?

/Frank

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions


_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Who called my gen_server?

Valentin Micic-2
In reply to this post by Frank Muller
Or, can I log all rpc_call(s) calling my gen_server?

/Frank

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions


General comments about appropriateness of rpc notwithstanding….

Consider following statements (you may run them from the shell):

(tcap2@macbookv)225> f(REX), REX=whereis(rex).  
<0.12.0>
(tcap2@macbookv)226> unregister( rex ).         
true
(tcap2@macbookv)227> catch register( rex, self() ).      
true

Then, you could go to the remote node's shell and run, say:

(tcap3@macbookv)3> rpc:call( tcap2@macbookv, erlang, now, [], 1000 ).

(NOTE 1: the caller wil timeout after one second)

At this point, your first node will receive a message, such that:

(tcap2@macbookv)228> flush().
Shell got {'$gen_call',{<7155.38.0>,#Ref<7155.0.0.59>},
                       {call,erlang,now,[],<7155.31.0>}}
ok

(NOTE 2:  <<7155.38.0>> is pid() of the process that issued the call)
(NOTE 3:  <<7155.31.0>> is pid() of the group leader)

Thus, you could exploit this in order to write your own logger, which would front rex:

Consider below for incorporation in your code:


...
-export( [init/1, logger/0] ).
...
-record( state, {rex, logger} ).
...
init( _ )
->
...
  % ---------------
  % Redirecting REX
  % ---------------
  OldREX = whereis( REX ),
  unregister( rex ),
  register( rex, self() ),
  main_loop( #state{rex=OldREX, logger=spawn(?MODULE, logger, []} )
.

main_loop( S=#state{} )
->
    NewS = receive
        Request -> fwd_request(Request, S)
    end,
    main_loop( NewS )
;
main_loop( {shutdown, #state{rex=OldREX, logger=LPID}} )
->
   % ---------------
   % Exit gracefully
   % ---------------
   unregister( rex ),
   register( rex, OldRex ),
   LPID ! shutdown,
   exit( normal )
.

fwd_request( Request={'$gen_call',{CallerPID,CallerRef}, {call,Mod,Func,Args,_CallerGroupLeader}}, S=#state{rex=OldRex, logger=LPID} )
->
   OldRex ! Request, 
   LPID   ! {log, CallerPid, CallerRef, Mod, Func, Args},
   S
;
fwd_request( shutdown, S ) -> {shutdown, S};
fwd_request( _, S )        -> S.

% ------
% LOGGER
% ------
logger()
->
   receive
      {log, CallerPid, CallerRef, Mod, Func, Args}
      ->
          ... Do some logging stuff ...
      ;
      shutdown -> exit( normal );
      _        -> void 
   end,
   logger()
.

Kind regards

V/

PS
Just want to state the obvious: I did not compile this code. It could contain bugs, but it illustrates the point.




_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Who called my gen_server?

Frank Muller
Hi Valentin,

I clearly see your idea. I'll play with it and let you know. 

To everyone: thanks guys. I've learnt a lot today. 

/Frank

Valentin Micic <[hidden email]> wrote  :
Or, can I log all rpc_call(s) calling my gen_server?

/Frank

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions


General comments about appropriateness of rpc notwithstanding….

Consider following statements (you may run them from the shell):

(tcap2@macbookv)225> f(REX), REX=whereis(rex).  
<0.12.0>
(tcap2@macbookv)226> unregister( rex ).         
true
(tcap2@macbookv)227> catch register( rex, self() ).      
true

Then, you could go to the remote node's shell and run, say:

(tcap3@macbookv)3> rpc:call( tcap2@macbookv, erlang, now, [], 1000 ).

(NOTE 1: the caller wil timeout after one second)

At this point, your first node will receive a message, such that:

(tcap2@macbookv)228> flush().
Shell got {'$gen_call',{<7155.38.0>,#Ref<7155.0.0.59>},
                       {call,erlang,now,[],<7155.31.0>}}
ok

(NOTE 2:  <<7155.38.0>> is pid() of the process that issued the call)
(NOTE 3:  <<7155.31.0>> is pid() of the group leader)

Thus, you could exploit this in order to write your own logger, which would front rex:

Consider below for incorporation in your code:


...
-export( [init/1, logger/0] ).
...
-record( state, {rex, logger} ).
...
init( _ )
->
...
  % ---------------
  % Redirecting REX
  % ---------------
  OldREX = whereis( REX ),
  unregister( rex ),
  register( rex, self() ),
  main_loop( #state{rex=OldREX, logger=spawn(?MODULE, logger, []} )
.

main_loop( S=#state{} )
->
    NewS = receive
        Request -> fwd_request(Request, S)
    end,
    main_loop( NewS )
;
main_loop( {shutdown, #state{rex=OldREX, logger=LPID}} )
->
   % ---------------
   % Exit gracefully
   % ---------------
   unregister( rex ),
   register( rex, OldRex ),
   LPID ! shutdown,
   exit( normal )
.

fwd_request( Request={'$gen_call',{CallerPID,CallerRef}, {call,Mod,Func,Args,_CallerGroupLeader}}, S=#state{rex=OldRex, logger=LPID} )
->
   OldRex ! Request, 
   LPID   ! {log, CallerPid, CallerRef, Mod, Func, Args},
   S
;
fwd_request( shutdown, S ) -> {shutdown, S};
fwd_request( _, S )        -> S.

% ------
% LOGGER
% ------
logger()
->
   receive
      {log, CallerPid, CallerRef, Mod, Func, Args}
      ->
          ... Do some logging stuff ...
      ;
      shutdown -> exit( normal );
      _        -> void 
   end,
   logger()
.

Kind regards

V/

PS
Just want to state the obvious: I did not compile this code. It could contain bugs, but it illustrates the point.




_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

DDDS/DNS oriented project considerations

RDlab
In reply to this post by Frank Muller
Gentlemen,

We would like to check if our understanding is correct.
We consider deploying and documenting an user oriented set of
distributed local IoT/internet OS independent services/applications.
We wish to test the concept through a DDDs proposition (the DNS is a
DDDS) oriented towards local DNS and Named Data Networking as a fork of BIND.

We understand that an Erlang/Elixir Beam based solution could be a
alternative and that OTP could provide a full communictions library
for such a project. However, we have no knowledge in your area, and
therefore before heavily investing into learnng it, we would be
rather interested in knowing your opinions:

- would such a project make sense from your experience
- would there be some existing projects/solution that could be of
interest to us.

We are a young non-profit Lab in Montpellier, South of France.
Thank you for you help.
JFC Morfin

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Loading...