One might ask why bother with a relay in the first place. Fair enough. Here's why:
Before trying to write an ejabberd module that demuxes multiple connections, it would be nice to know that this is in any way possible. By creating a relay, I can test that, if I don't mess up the data, a program such as that works. At the next step, when I start mulxing and demuxing traffic, if things do not work I can be assured that the basic concept is sound that that I have done something to mess up the data being sent back and forth.
OK, so just acting as a relay is proving mighty annoying. The erlang program I wrote is able to accept connections and forward data from the client to the server, but when I listen to the server I get a an error. First I get {error, einval} on the gen_tcp:recv call, and thereafter I get {error, closed}.
After a bit of googling I discovered that erlang uses "active mode" by default when doing TCP. Basically this means that the erlang process receives messages from the TCP stack when data arrives and specifically that calling recv on the port will result in the observed error. At least I'm not the only one that feel prey to this.
Once I changed over the code to use "passive mode" things worked as well as they did before; which is to say sort of. Pidgin still does not work with the thing and neither does JWChat via the proxy; but the NXB side still displays lots-o-data in a manner that suggests that it at least thinks things are going OK.
Here is the relay program:
-module(relay).
-export([start/0, start/1]).
start(Port) ->
io:format("server listening on port ~p~n", [Port]),
{ok, Sock} = gen_tcp:listen(Port, [binary, {packet, 0}, {active, false}]),
listen(Sock).
start() ->
start(8222).
%%
%% the system consists of two process: one that waits for messages from the client
%% to the server, and one that waits for messages from the server to the client.
%% There is no easy way that I am aware of in which to wait on two sockets simultaneously
%% as one would with the select function in C; hence the need for two processes.
%%
listen(Socket) ->
{ok, ClientSocket} = gen_tcp:accept(Socket),
{ok, ServerSocket} = gen_tcp:connect("localhost", 5222, [binary, {packet, 0}, {active, false}]),
spawn(fun() -> relay(ClientSocket, ServerSocket) end),
spawn(fun() -> relay(ServerSocket, ClientSocket) end),
listen(Socket).
%%
%% Loop forever, getting a packet from the one socket and relaying it onto the other
%% socket.
%%
relay(ClientSocket, ServerSocket) ->
case gen_tcp:recv(ClientSocket, 0) of
{ok, Data} ->
io:format("Relaying data from ~p to ~p~n", [ClientSocket, ServerSocket]),
case gen_tcp:send(ServerSocket, Data) of
ok -> relay(ClientSocket, ServerSocket);
Other ->
io:format("got unexpected result when trying to send data to port~n port: ~p, result: ~p~n", [ServerSocket, Other])
end;
Other ->
io:format("got unexpected result while listening to socket ~p, result = ~p~n", [ClientSocket, Other])
end.
No comments:
Post a Comment