- I decided to try a simple pass-through.
- I got a simple pass-through to work.
- I made progress with a simple BOSH pass-through.
After a bit more work, I got the BOSH pass-through to work. Here it is:
-export([start/2, stop/1, start_module/2, data_loop/1]).
-behavior(gen_mod).
-include("ejabberd.hrl").
start(Host, [Port]) ->
spawn(?MODULE, start_module, [Host, Port]).
stop(_Host) -> ok.
start_module(Host, Port) ->
{ok, Socket} = gen_tcp:listen(Port, [binary, {active, false}]),
?DEBUG("~p is now listening on ~p:~p", [?MODULE, Host, Port]),
module_loop(Socket).
module_loop(Socket) ->
{ok, Client} = gen_tcp:accept(Socket),
?DEBUG("Got connection", []),
PID = spawn(?MODULE, data_loop, [Client]),
gen_tcp:controlling_process(Client, PID),
module_loop(Socket).
data_loop(Socket) ->
case gen_tcp:recv(Socket, 0) of
{ error, closed } ->
?DEBUG("connection closed", []);
{ ok, Data } ->
StrData = binary_to_list(Data),
?DEBUG("received ~p", [StrData]),
{ _ResponseCode, _Headers, Response} =
ejabberd_http_bind:process_request(Data, {{127, 0, 0, 1}, 1234}),
?DEBUG("response ~p", [Response]),
gen_tcp:send(Socket, Response),
data_loop(Socket)
end.
The module receives control from ejabberd via the start function. It immediately calls start_module to fire up something that will hang around and listen for connections. start_module starts up a gen_tcp listener then goes into module_loop to accept individual connections.
The module is intended to work with a nodejs part that connects to it. In this, the single-connection version, the nodejs part serves no useful purpose but I am including it because the multi-connection part will need it.
Getting back to the erlang code, when a new connection comes in, the module_loop function starts up a new process (data_loop) and then goes back to waiting for more connections.
data_loop expects to receive the body of a BOSH message which it passes on to ejabberd_http_bind process_request. For whatever reason, process_request wants an IP address along with the data, so I give it 127.0.0.1:1234 process_request responds with a response code, a set of HTTP headers and the body of the response. data_loop ignores everything but the body of the response, which it forwards on to the nodejs program.
Not sure whether or not the response code needs to be returned or if the response headers are needed. For now the values are discarded, but in the future I may modify the megaphone "protocol" to include them.
Here is the nodejs program:
var util = require('util'),
net = require('net'),
config = require('./config.js').data,
http = require('http');
var clientPort = 8280;
var ejabberdPort = 7280;
var response = null;
var serverSocket = net.createConnection(ejabberdPort, "localhost");
console.log("connected to server");
serverSocket.on("data", function(data) {
if (response != null)
{
var headers = {
'content-type' : 'text/xml; charset=utf-8',
'content-length' : data.length
};
response.writeHead(200, headers);
response.end(data);
}
});
var server = http.createServer(function (req, resp) {
req.on("data", function (data) {
serverSocket.write(data);
});
response = resp;
});
server.listen(clientPort);
console.log("listening on port " + clientPort);
The program is much simpler than the multi-connection version because, well, it only has to deal with a single connection. I like not having to deal with headers and CRLF sequences, so I may end up using the httpserver approach with the multi-connection version; especially since the multi-connection version does not work at this point.
Next time: trying to apply these results to the multi-connection version.
No comments:
Post a Comment