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 ;) |