Example of Erlang crossdomain policy server for Adobe Flash

If you are not familar with erlang sockets you can review my article about Erlang TCP sockets with gen_tcp & sampe echo server it should help to understand Erlang TCP sockets themselves.

Some time ago I had to use sockets from Adobe Flash/Flex, so needed a simple one implemented in Erlang. I do not suggest to use it exactly like it listed below, but you may find some idea for your project there. I hope that you know what I am talking about, if you are reading this article, so do not want to waist your time...

Here is flex code to load policy file from non-standard port:

Security.loadPolicyFile("xmlsocket://localhost:8001");

Here is an example of policy file:

<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM
"http://www.adobe.com/xml/dtds/cross-domain-policy.dtd">

<cross-domain-policy>
 <site-control permitted-cross-domain-policies="all"/> 
 <allow-access-from domain="*" to-ports="8000-8002"/> 
</cross-domain-policy>

And here is erlang server code

-module(policy_server).
-author('Sergiy Dzysyak ').
-behaviour(gen_server).

-export([init/1, handle_call/3, handle_cast/2, handle_info/2,terminate/2, code_change/3]).
-export([start/1, stop/0, accept_loop/1]).

-define(TCP_OPTIONS, [binary, {packet, 0}, {active, false}, {reuseaddr, true}]).

start(Port)->
 gen_server:start({local, ?MODULE}, ?MODULE, [Port], []).

stop()->
 gen_server:cast(?MODULE, {stop}).
 
accept_loop(LSocket) ->
 {ok, Socket} = gen_tcp:accept(LSocket),
    % Let the server spawn a new process and replace this loop
    % with the echo loop, to avoid blocking
    gen_server:cast(?MODULE, {accepted}),
    read(Socket).
    
% To be more robust we should be using spawn_link and trapping exits
accept(LSocket) ->
 spawn_link(?MODULE, accept_loop, [LSocket]),
 LSocket.
    
read(Socket)->
 {ok, _Data} = gen_tcp:recv(Socket, 0),
    {ok, Bin} = file:read_file("/srv/www/crossdomain.xml"),
    gen_tcp:send(Socket, Bin).
 
init([Port]) ->
 % set this so we can catch death of logged in pids:
 %process_flag(trap_exit, true),
 
 case gen_tcp:listen(Port, ?TCP_OPTIONS) of
        {ok, LSocket} ->
         {ok, accept(LSocket)};
        {error, Reason} ->
            {stop, Reason}
    end.
    
handle_cast({accepted}, State) ->
    {noreply, accept(State)};

handle_cast({stop}, State) ->
 {stop, normal, State}.
 
% handle death and cleanup of logged in processes
handle_info(Info, State) ->
 case Info of
 {'EXIT', _Pid, _Why} ->
  {noreply, State};
 Wtf ->
  io:format("Caught unhandled message: ~wn", [Wtf]),
  {noreply, State}
 end.

handle_call(_Msg, _From, State) -> {noreply, State}.

terminate(Reason, State) ->
 io:format("Terminating: ~p~n", [Reason]),
 gen_tcp:close(State),
 ok.

code_change(_OldVsn, State, _Extra) ->
 {ok, State}.

%% Internal functions

Posted by:
Enjoyed this post? Share and Leave a comment below, thanks! :)