[erlang-questions] Erlang way for process-as-library?

Emil Hellman <>
Wed Feb 7 12:54:55 CET 2007


> Now, the next question I have is: is there an Erlang way to forbid
> "ordinary users" from calling the server's callback functions
> directly (e.g. init, terminate, and so on), while allowing gen_server
> access to them? The problem is that my exports for my library look
> like this:
>

I'm not sure if this would work, so feel free to criticize.
I believe the code at the end of this email makes sure that only
clients spawned into the 'Allowed' module would get the 'hey_mate'
answere. Running the code:

Eshell V5.5.3  (abort with ^G)
1> server:start(client).
true
2> client:middleman(foo).
<0.32.0>I'm allright!
3> server ! stop.
stop
4> server:start(some_other_module).
true
5> client:middleman(foo).
<0.37.0>Damn your protected function!


I would like to be able to protect the exported functions in a manner
like this without having ot write the custom code. I've been thinking
about doing a parse transform that would check if the module had
something like:
-allowed([ListOfAllowedModules])

and then generate the that would cause these checks to be made.
Alternatively check if the module was started in a specific
application or maybe only protect specific exported funcitons. Would
there be any problems with doing something like that?


%%%
-module(server).
-export([start/1, loop/1, send_msg/1]).

start(Allowed) ->
    register(server, spawn(?MODULE, loop, [Allowed])).

loop(Allowed) ->
    receive
	{_Msg, From} ->
	    case allowed(Allowed, From) of
		true ->
		    From ! hey_mate;
		false ->
		    From ! not_allowed
	    end,
	    loop(Allowed);
	stop ->
	    stop
    end.

send_msg(Msg) ->
    server ! {Msg, self()}.

allowed(Al, P) ->
    PI = process_info(P),
    case lists:keysearch(initial_call, 1, PI) of
	{_,{_,{Al, _, _}}} ->
	    true;
	_ ->
	    false
    end.


%%%
-module(client).
-export([middleman/1, sm/1, client_starter/3]).

middleman(Msg) ->
    spawn(client, client_starter, [?MODULE, sm, [Msg]]).

client_starter(M, F, A) ->
   % io:format("inital_call ~p~n", [process_info(self())]),
    apply(M, F, A).

sm(Msg) ->
    server:send_msg(Msg),
    receive
	stop ->
	    stop;
	hey_mate ->
	    io:format("I'm allright!~n");
	not_allowed ->
	    io:format("Damn your protected function!~n")
    end.



More information about the erlang-questions mailing list