[erlang-questions] Stateful gen_servers

Ulf Wiger <>
Sun Oct 7 13:41:00 CEST 2007


2007/10/7, David King <>:
> >>> I would like to use gen_server to develop a stateful server
> >> You could have each client do something like: [...]
> > Thanks David for the tip. I think I can use session-id to track
> > state and have the client pass it with each request. Though, I
> > would liked it if somehow that session-id is implicitly passed.
>
> You could have the session implicitly passed by storing it in the
> process dictionary, like this:
>
> -module(my_server).
> -behaviour(gen_server).
>
> [gen_server stuff...]
>
> login() ->
>    Session=gen_server:call(?MODULE,login),
>    put(my_server_session_id,session),
>    Session.

I tend to want the server to keep track of client pids, rather than
having the client pass an identifier in each call. Not that it
matters much in terms of security (since there is no way to
prevent spoofing anyway), but it _feels_ better.  (:

The server will verify that the client pid is logged in, and will send
the reply only to that pid.

Another trick, which is more of a therapeutic one (again, since we
have no real security), is to verify that the caller has actually entered
through one of the exported interface functions:

call(Server, Request) ->
   MRef = erlang:monitor(process, Server),
   Server ! {call, self(), MRef, Request},
   my_await_reply(MRef).

my_await_reply(MRef) ->
   receive
      {MRef, Reply} -> Reply;
      ...
   end.

and then, on the server side:

server_loop(St) ->
   receive
      {From, Ref, Request} ->
         case valid_request(From) andalso logged_in(From, St) of
             true ->
                {Reply, St1} = handle_request(Ref, Request),
                From ! {Ref, Reply},
                server_loop(St1);
             false ->
                %% ignore, or possibly send an error reply
                 server_loop(St)
         end;
       ...
   end.

valid_request(Pid) ->
   case process_info(Pid, current_function) of
      {current_function, {?MODULE,my_await_reply,1}} ->
         true;
      _ ->
         false
   end.

(assuming that my_await_reply/1 is not exported, and a few other things,
this is a cheap way of preventing someone from faking a request, by
just sending a message).

BR,
Ulf W



More information about the erlang-questions mailing list