Using OTP

Pupeno <>
Sat Jan 14 17:44:09 CET 2006


Hello,
I've been trying for days to start working in a project of mine in Erlang not 
being able to see how it should be coded according to OTP.
I've read the OTP Designs and principles, but that didn't really told me all I 
needed.
What I am doing is a library to make servers[1], it is supposed to make 
abstractions over protocols like DNS, SMTP, POP3, etc leaving you only to 
worry about data handling.
I'll show you what I want with a trivial example: the echo protocol[2].
Someone wants to write a echo server, so it would write this:

-module(echo).
-export([start/0, init/1, echo/1]).
-behaviour(gen_echo).

start() ->
    gen_echo:start(?MODULE, [], []).

init(_Args) ->
    {10007, 10007}.

echo(Data) ->
    string:concat("You said: ", Data).

where start/0 would start the server, init/1 replies with the TCP and UDP 
ports to use (false or something like that in any of them would mean "don't 
use that transport, tcp or udp").
The function echo/1 is the real worker here. In the DNS example (one in which 
I worked on HaServers[1]), it would be query/1 and it would get a big record 
containing the data sent by the client. echo/1 replies another string which 
will be sent to the ip client (either by tcp, or udp, the good thing is that 
echo/1 doesn't worry about that). As you can see, this is a non-compliant 
echo server where the smart developer is doing some experimentation. In the 
DNS example, query/1 would return a record containing the a packet to be sent 
back.
Another callback function possible for DNS would be transfer/N, which is 
triggered for transferring actions. Other protocols (smtp, pop3, imap4, which 
are my priorities after dns, in that order) would have other set of 
callbacks.

Now, my gen_echo.erl looks like this:

-module(gen_echo).
-export([behaviour_info/1]).
-export([start/3]).
-export([tcpLoop/2, tcpHandler/1]).

behaviour_info(callbacks) ->
    [{echo, 1}];
behaviour_info(_Args) ->
    undefined.

start(Mod, Args, Options) ->
    {TCPPort, _UDPPort} = Mod:init(Args),
    {_, TCPLSocket} = gen_tcp:listen(TCPPort, [{active, once}, {packet, 0}]),
    spawn(?MODULE, tcpLoop, [Mod, TCPLSocket]).

tcpLoop(Mod, TCPLSocket) ->
    {_, Socket} = gen_tcp:accept(TCPLSocket),
    TcpHandler = spawn(?MODULE, tcpHandler, [Mod]),
    gen_tcp:controlling_process(Socket, TcpHandler),
    tcpLoop(Mod, TCPLSocket).

tcpHandler(Mod) ->
    receive
	{tcp, Socket, Data} ->
	    gen_tcp:send(Socket, Mod:echo(Data)),
	    inet:setopts(Socket, [{active, once}]),
	    tcpHandler(Mod);
	{tcp_closed, Socket} ->
	    io:format("~w closed.~n", [Socket]);
	Unknown ->
	    io:format("Received unknow message ~w.~n", [Unknown])
    end.

I want to rewrite this as Erlangish and OTPish as possible, what do you 
recommend ? what should I do ? Some questions I have are:
- Should gen_echo, gen_PROTOCOL, be a gen_server ? or another gen_X ?
- Should gen_echo, gen_PROTOCOL, use gen (gen:start, etc, I see that 
gen_server uses it) ?
- Should I write supervisors ?
- Should all this be an application (ErServers, the temporary name for this 
will only be a library, it shouldn't provide any runable program except a 
couple of examples, any developed server should be packaged and developed 
separately) ?
Any other tips and hints are welcome, I feel very lost here.
-- 
Pupeno <> (http://pupeno.com)
Vendemos: Kit del guitarrista: http://pupeno.com/vendo/#kit

[1] For those of you that understand Haskell, I started working on Haskell and 
the result was HaServers http://software.pupeno.com/HaServers/

[2] RFC862.

PS: All this will be free software.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20060114/6c0e228a/attachment.bin>


More information about the erlang-questions mailing list