?

Log in

No account? Create an account
socket proxy in erlang - 豬頭'blog [entries|archive|friends|userinfo]
豬頭

[ website | 豬頭基 ]
[ userinfo | livejournal userinfo ]
[ archive | journal archive ]

Links
[Links:| o0o blog myspace deviantart PromoDJ KTK project ]

socket proxy in erlang [Mar. 16th, 2011|10:06 am]
豬頭
[Tags|, , ]

Since I started spitting out some code here, here's another thing I've been playing recently. Erlang. For kicks, I decided to implement a socket proxy/connection bouncer. The erlang socket programming model is slightly different from the ones we used to in python/c/perl/... so here is the piece (docs and original example here:
http://www.erlang.org/doc/man/gen_tcp.html

Interesting things to pay attention on:

you are only going to get data via messages (receive statement) if you use active socket. w/ passive socket you'll have to fetch it with recv.

{packet,0} - means you're getting raw data. it is also possible to request for pre-packaged data (see avail. options at http://www.erlang.org/doc/man/inet.html#setopts-2).

Anyways,
1-2:erl fygrave$ cat socket_proxy.erl
-module(socket_proxy).

-export([
	 start/4,
	 server/3,
	 process/1,
         loop/2
]).
%
% once compiled, start it like socket_proxy:start(20, 1222, "somehost", 22).
%
start(Num,LPort, Host, DPort) ->
    case gen_tcp:listen(LPort,[{active, true},{packet,0}]) of
        {ok, ListenSock} ->
            start_servers(Num,ListenSock, Host, DPort),
            {ok, Port} = inet:port(ListenSock),
            Port;
        {error,Reason} ->
            {error,Reason}
    end.
start_servers(0,_, _, _) ->
    ok;
start_servers(Num,LS, Host, DPort) ->
    spawn(?MODULE,server,[LS, Host, DPort]),
    start_servers(Num-1,LS, Host, DPort).
server(LS, Host, DPort) ->
    io:format("Server started ~n"),
    case gen_tcp:accept(LS) of
        {ok,S} ->
            io:format("Got connect ~n"),
            case gen_tcp:connect(Host, DPort,
				 [binary, 
		     {packet,0},
		     {active, true}
                    ]
				) of
		{ok, Socket} ->
		    loop(S,Socket),
		    server(LS,Host, DPort);
		E ->
		    io:format("Error:Connect failed!~n"),
		    E
		end,
		ok;
        Other ->
            io:format("Error: accept returned ~w - finita!~n",[Other]),
            ok
    end.
loop(S,Socket) ->
    inet:setopts(S,[{active,once}]),
    receive
        {tcp,S,Data} ->
	    io:format("Received tcp ~p ~n",[Data]),
            Ret = process(Data), % you can poke around with the data
            gen_tcp:send(Socket,Ret),
            loop(S, Socket); % erlang awesomeness. no loops ;)
        {tcp,Socket,Data} ->
            io:format("Received tcp(S) ~p ~n", [Data]),
            Ret = process(Data),
            gen_tcp:send(S, Ret),
            loop(S,Socket);
        {tcp_closed,S} ->
            gen_tcp:close(Socket),
            io:format("Socket ~w closed [~w]~n",[S,self()]),
            ok;
        {tcp_closed, Socket}->
            gen_tcp:close(S),
            io:format("Socket (S) ~w closed [~w]~n",[S,self()]),
            ok
	
    end.

process(Data) ->
    io:format("Process data: ~p ~n", [ Data]),
    Data.



blah. time for stress-test ;)
LinkReply