Home > English, Erlang > Sending and receiving stanzas using EXMPP

Sending and receiving stanzas using EXMPP


A couple of posts ago, I introduced EXMPP, the Erlang library developed by Process One for XMPP.

In that post we used EXMPP to connect an external component to eJabberd server by using the XEP-0114.

This time I will show you how to process streams directed to our component, analyze them and reply to the sender.
First of all I used a gen_server behaviour and put all the code regarding the handshake inside the init([]) method:

init([]) ->
    exmpp:start(),
    Session = exmpp_component:start_link(),
    exmpp_component:auth(Session, ?COMPONENT, ?SECRET),
    _StreamId = exmpp_component:connect(Session, ?SERVER_HOST, ?SERVER_PORT),
    ok = exmpp_component:handshake(Session),
    {ok, #state{session = Session}}

You may notice that I used a set of Erlang macros to identify the variables needed for the connection,
those macros were previously defined in the code as:

-define(COMPONENT, get_conf_value(component)).
-define(SECRET, get_conf_value(secret)).
-define(SERVER_HOST, get_conf_value(server_host)).
-define(SERVER_PORT, get_conf_value(server_port)).

Where get_conf_value(Value) is simply a function I implemented to parse a configuration file.

EXMPP provides to developers a set of records (a record may be thought as a complex data structure and I will write about
them in the future); among these records we need in our code the one representing a received_packet.
It is defined as following:

-record(received_packet,
                   {
                   packet_type, % message, iq, presence
                   type_attr,   % depend on packet. Example: set, get, subscribe, etc
                   from,        % JID
                   id,          % Packet ID
                   queryns,     % IQ only: Namespace of the query
                   raw_packet   % raw exmpp record
}).

After the handshake we can send any kind of stanzas defined in XMPP realm towards the server we are connected to as long as
we have a reference to the session we established before.

A really cool feature of EXMPP is that two different processes spawend by our gen_server can send a stanza at the same time over the same session and the stanzas will not be mixed during their “trip” to the XMPP server.

About incoming stanzas, you must know that all of them will be processed by the gen_server as normal Erlang messages.

I told you before that all the stanzas can be handled by processes spawned by the gen_server, so it seems sensible to spawn
a new process any time a packet is received; this new process will elaborate the stanza and if required will send a reply stanza, then it
terminates.

To do that we add the gen_server something like this:

handle_info(#received_packet{} = Packet, #state{session = Session} = State) ->
            spawn(fun() ->
                          process_received_packet(Session, Packet)
                  end),
{noreply, State};

In practice whenever we receive a Packet we spawn (without linking!) a new process which takes as input the current session and the packet itself.
This process is represented by the following function:

process_received_packet(Session, Packet) ->
       Packet_Type = Packet#received_packet.packet_type,
       case Packet_Type of
          iq ->
               process_received_iq(Session, Packet);
          message ->
               process_received_message(Session, Packet);
          presence ->
               process_received_presence(Session, Packet);
       end.

The previous function is pretty simple: basically it checks the type of the packet and then based on it a different function is called.

Let’s implement process_received_message(Session, Packet) so that whenever a message stanza is received our component sends back the same message:

process_received_message(Session,
                      #received_packet{packet_type=message, raw_packet=Packet}) ->
    %% retrieve recipient jid
    From = exmpp_xml:get_attribute(Packet, from, <<"unknown">>),
    %% retrieve sender jid
    To = exmpp_xml:get_attribute(Packet, to, <<"unknown">>),
    %% set recipient jid
    Pkt1 = exmpp_xml:set_attribute(Packet, from, To),
    %% set sender jid
    Pkt2 = exmpp_xml:set_attribute(Pkt1, to, From),
    %% remove old id
    NewPacket = exmpp_xml:remove_attribute(Pkt2, id),
    %% send new packet
    exmpp_session:send_packet(Session, NewPacket).

Here is the result (captured by using PSI):

Message reply

Let’s  implement process_received_iq(Session, Packet) that sends back a simple message if an iq stanza is received:

process_received_iq(Session,
            #received_packet{packet_type=iq, type_attr=Type, raw_packet=IQ}) ->
    %% get namespace of IQ stanza
    NS = exmpp_xml:get_ns_as_atom(exmpp_iq:get_payload(IQ)),
    %% set text value of IQ stanza
    Reply = exmpp_xml:element(NS, 'response', [],
                                      [{xmlcdata,<<"your iq has been received">>}]);
    %% build result packet
    Result = exmpp_iq:result(IQ, exmpp_xml:element(NS, 'query', [], [Reply]));
    %% sends new packet
    exmpp_component:send_packet(Session, Result).

Ok! For now it is enough…try to read EXMPP specifications and see how you can change slightly this code!

Categories: English, Erlang Tags: , ,
  1. May 20, 2011 at 11:54 am

    Hello,

    How can i retrive body from message packet?

    I receive message, then i try:

    Body = exmpp_xml:get_attribute(Packet, body, <>),

    But i get unknown. How can i get receiving message?

    Thank you.

  2. rk
    September 21, 2011 at 8:38 am

    Hi,

    Thanks for your nice introduction to EXMPP. I am newbie in Exmpp. I would like to use EXMPP and Ejabberd to send and receive message in s2s, c2s and s2c. What reference do thing is good to start with.

    Thanks in advance,

    Regards,
    RK

    • pdincau
      September 21, 2011 at 1:08 pm

      hi,

      thanks for your comment. I haven’t used exmpp very much lately, anyhow i hope i will write again on it soon

      paolo

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: