erlang: mochiweb + BOSH
I’ve been playing with mochiweb for a while and I found it a nice way to improve my Erlang knowledge. For making things more interesting I want to use mochiweb to implement a BOSH manager. If you are not tempted to read the spec documentation about BOSH I can give you this excerpt:
BOSH, the technology defined in this specification, essentially provides a “drop-in” alternative to a long-lived, bidirectional TCP connection …
For applications that require both “push” and “pull” semantics, BOSH is significantly more bandwidth-efficient and responsive than most other bidirectional HTTP-based transport protocols and the techniques now commonly known as “Ajax”…
That is, BOSH is quite similar to WebSockets
So, at this point is where mochiweb comes in. It will provide the framework for handling the HTTP requests where the BOSH requests themselves are wrapped. But before going any further lets explain how mochiweb works, with a picture:
What do we have here?
- An HTTP request comes in, to the address and port mochiweb is configured.
- If it’s a valid HTTP request, a mochiweb_request “object” is created and the handler function at the callback module (which is provided when mochiweb starts) is invoked with this mochiweb_request as a parameter. Give a look to this and this to get a grasp at parameterized modules if you wish to know more about “objects” on Erlang.
Easy, huh?
And what is all that about a BOSH manager? The BOSH manager handles the connection between the resource-client (for example a browser) and the resource-owner (for example a server). It has to keep HTTP connections opened to fake this bidirectional comunication. That is, the client ask for something about the resource and so it sends a request to the BOSH manager, the BOSH manager sends this same request to the server and waits for a reply. If a reply arrives, then it’s forwarded to the client. But aside from this, which is no more than plain-old AJAX, BOSH offers PUSH technologies. If any event happens at the server and the client has to be notified, the BOSH manager forwards the event to the client. That’s why it has to keep HTTP connections opened, it must have a valid path.
In Erlang, creating and destroying processes is extremely cheap, so what I wanted was to spawn a new process for each single BOSH session (between one client and one or multiple servers). Lets give another picture:
On the picture above, there are two separate BOSH managers (each of them is a Erlang process) BM1 and BM2 which handler connections from one client to one server (BM1 ) and from another different client to two servers (BM2)
To complete the setup I used, I have to talk about StropheJS which is a library for writing xmpp clients (BOSH is an xmpp extension).
Well, once I have explained more or less what I’m doing with mochiweb and BOSH, lets got to the details.
First, lets talk about my callback module for mochiweb. It’s not a ver big one nor a complicated one, not because I don’t know how to move on but was the error I’ll talk later which didn’t allow me to progress. So ladys and gentleman here is my litle callback module:
-module(mochibosh).
-export([start/0, start/1, stop/0]).
-export([handler/1]).
-export([init/0]).
-record(mochibosh_state,{procs, xml_models}).
handler(Req) ->
io:format("CALLBACK. Petition on port ~p ~n", [inet:port(Req:get(socket))]),
mochibosh ! Req,
ok.
start() ->
erlang:register(mochibosh, spawn_link(?MODULE, init, [])),
start([{ip,"192.168.1.110"}, {port, 8888}]).
start(Options) ->
Options2 = [{loop, {?MODULE, handler}} | Options],
mochiweb_http:start(Options2).
stop() ->
mochibosh ! exit,
mochiweb_http:stop().
% Internal API
init() ->
Models = init_xml_models(),
loop(#mochibosh_state{procs = dict:new(), xml_models = Models}).
loop(State = #mochibosh_state{procs = Procs, xml_models = Models}) ->
receive
Request ->
io:format("SPAWNED PROCESS. Request received on port ~p ~n", [inet:port(Request:get(socket))]),
loop(State)
end.
init_xml_models()->
[{bosh_init, init_xml_model("bosh_init.xsd")}].
init_xml_model(Xsdfile) ->
{ok, Model} = erlsom:compile_xsd_file(Xsdfile),
Model.
It very easy. If want to use it, you cant fire a Erlang terminal and type mochibosh:start() and it will be up and running. The loop
option in the tuple that is passed to mochiweb_http:start is used to provide the callback module. In this case is the mochibosh module itself (?MODULE)
So what would happen if we try it….
In one terminal we fire the Erlang shell (erl) and start mochibosh:
20:38:25 mochibosh $ erl
Erlang R14A (erts-5.8) [source] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V5.8 (abort with ^G)
1> mochibosh:start().
{ok,<0.34.0>}
In another terminal we issue a simple request with curl…
20:40:19 mochibosh $ curl -v http://192.168.1.110:8888 * About to connect() to 192.168.1.110 port 8888 (#0) * Trying 192.168.1.110... connected * Connected to 192.168.1.110 (192.168.1.110) port 8888 (#0) > GET / HTTP/1.1 > User-Agent: curl/7.21.0 (i386-apple-darwin10.2.0) libcurl/7.21.0 OpenSSL/1.0.0a zlib/1.2.5 libidn/1.19 > Host: 192.168.1.110:8888 > Accept: */* > ^C
And meanwhile in the Erlang shell..
{ok,<0.34.0>}
CALLBACK. Petition on port {ok,8888}
SPAWNED PROCESS. Request received on port {ok,8888}
2>
GREAT!! Everything seems to work. So now, I decided to move on and begin to develop my BOSH manager.
As I sayed, I’ll be using StropheJS for the browser/client side. For testing purpouses I began using one of the examples shipped with the library: echobot.js .This example will issue a request for starting a BOSH session (among other things) and that is perfect for my testing pourposes. So lets, try.
(Imagin that the request is sent from echobot to the BOSH manager)
And I expecto to get the same reply from my callback module as when I tryed it with curl. Lets see:
CALLBACK. Petition on port {ok,8888}
SPAWNED PROCESS. Request received on port {error,einval}
WTF!!!!! What’s that of {error, einval}. Well, I can see that’s an error, but why? As this post is getting really big, I’ll leave the explanation for another one.
Category: erlang, programacion Comment »

