Instant Messaging using erlang and XMPP — Part 3

Sep 9, 2021

Note: When I started writing this, I was using customized mongooseim version 3.7.1, now latest updates using TOML config and such have come up as on July 2021. So, if you want to refer to the latest documentation, feel free to read it here .

XMPP Jargon

Client to Server (C2S)

The client can be any medium such as mobile, web or any application that knows to talk in XMPP protocol

Server to Server (S2S)

Any other XMPP Server that knows how to connect to an XMPP based Server.

Federation

Inter-connecting different XMPP servers, such as a.chat.com can be federated to talk to b.chatty.org. Note, the difference in domain chat.com and chatty.org.

XML Namespace (xmlns)

A specific set of resource or route or functions, that are identified by the namespaces

Jid or Jabber ID

A Jabber ID is a unique ID given to each user in a Jabber Server / XMPP Server to identify the users.

Understanding XMPP

XMPP is not a technology or a language, instead a protocol using structured XML to instruct the server to put or get data. The XML queries are called Stanzas. There are three basic stanzas, that we’ll use to satisfy most of our needs:

IQ stanza Sample

<!-- (IQ Stanza sent to Server) -->
<iq from='user@example.com/mobile' to='user@example.com' id='x13' type='get'>
  <query xmlns='http://jabber.org/protocol/disco#info'/>
</iq>
<!-- (IQ Stanza received from Server) -->
<iq from='juliet@capulet.lit' to='juliet@capulet.lit/balcony' id='disco1' type='result'>
  <query xmlns='http://jabber.org/protocol/disco#info'>
    <identity category='account' type='registered'/>
    <feature var='urn:xmpp:push:0'/>
    ...
  </query>
</iq>

In the above example, all we’re trying to do is query the supported features from the server. If you examine closely, you might be wondering what is from, to, id, type, etc., . Those who are familiar with XML, know it as attributes.

There are 4 types of IQ stanzas:

How a stanza is represented in MongooseIM:

Before we dive into it, I’m using MongooseIM to demonstrate, as ejabberd uses a different library for parsing xml files. So, there are going to be subtle differences in a very major way.

MongooseIM uses a library called exml and some old modules might be referring to xml to parse to actual xml stanzas from erlang records. Here, we have a common erlang record to define xml stanzas.

If you’re familiar with erlang, you are probably already aware of RECORDS. To put it simply, erlang record is equivalent to a C struct. For more detailed description, you can check here .

The stanza as an erlang record is represented as Follows:

#xmlel{
  name = <<"message">>,
  attrs = [
    {<<"xmlns">>, <<"jabber:client">>},
    {<<"id">>, <<"43a6d6be-de78-47d7-a283-e391ae7b2d83">>}, 
    {<<"from">>, <<"test@jabber.fr">>}, 
    {<<"to">>, <<"friend@jabber.fr">>}
  ],
  children = [
    #xmlel{
      name = <<"body">>,
      children = [
        #xmlcdata{ content = <<"Hello, world!">> }
      ]
    }
  ]
}

%% The above record when you convert to XML String will be as follows:
<message xmlns='jabber:client' id='43a6d6be-de78-47d7-a283-e391ae7b2d83' from='test@jabber.fr' to='friend@jabber.fr'>
  <body>Hello, world!</body>
</message>

Any Stanzas that reach the server will go through a series of steps and then get converted to the xmlel record and that is what will be passed around most of the time. It is very much essential to get an understanding how to read, manipulate the stanzas in order to be working with them.

I’m assuming that you’d set up mongooseim in your machine already using docker or else please read my Part 1 and Part 2 .

Note: You will see a lot of logs being printed out as a part of boot up process.

Now this gets interesting, in the shell:

(mongooseim@localhost)2> A = <<"<message xmlns='jabber:client' id='43a6d6be-de78-47d7-a283-e391ae7b2d83' from='test@jabber.fr' to='friend@jabber.fr'>
(mongooseim@localhost)2>   <body>Hello, world!</body>
(mongooseim@localhost)2> </message>">>.
<<"<message xmlns='jabber:client' id='43a6d6be-de78-47d7-a283-e391ae7b2d83' from='test@jabber.fr' to='friend@jabber.fr'"...>>
(mongooseim@localhost)5> {ok, B} = exml:parse(A).   
{ok,{xmlel,<<"message">>,
           [{<<"xmlns">>,<<"jabber:client">>},
            {<<"id">>,<<"43a6d6be-de78-47d7-a283-e391ae7b2d83">>},
            {<<"from">>,<<"test@jabber.fr">>},
            {<<"to">>,<<"friend@jabber.fr">>}],
           [{xmlel,<<"body">>,[],[{xmlcdata,<<"Hello, world!">>}]}]}}
(mongooseim@localhost)6> exml:to_pretty_iolist(B).
<<"<message xmlns='jabber:client' id='43a6d6be-de78-47d7-a283-e391ae7b2d83' from='test@jabber.fr' to='friend@jabber.fr'"...>>

In the illustration above, I have shown how to encode and decode XML stanzas from String to Erlang Records and Vice Versa.

Important thing to remember, most of the XML elements or components are represented as Erlang Records in MongooseIM, for example, Jabber ID/Jid is a record and so on.

With this, I’ll be wrapping us this part and continue with more information in the next part…


   erlang (8) , mongooseim (4) , ejabberd (4) , xmpp (4) , instant-messaging (4)