Archive

Posts Tagged ‘external component’

How to handle presence stanzas using EXMPP

August 10, 2010 Leave a comment

I have written many posts this year about EXMPP and XMPP; we discussed about message stanzas and IQ stanzas therefore I would like to tell you something about presence handling today, so that you would be able to start some implementation by yourselves.

Presence in XMPP is used to communicate to other users our status (e.g “online”, “do not disturb”, “away”, etc etc); let’s see how we can improve our component by exploiting this kind of stanzas.

In a previous post we saw how to handle user subscription, anyhow we didn’t take in consideration the fact that many times one user can be connected to the server with a status different than “online”…we don’t want our bot to become a spamming machine, users should receive notifications only if they are using an “online” status.

How can we achieve this?

Ok, first of all our bot should subscribe to user’s presence during the registration process, this way we could understand whether to send the notifications or not; we can do this by using the following functions:

subscribe_to_presence(JID) ->
    CompAddr = ?XMLCDATA(<>),
    Presence = ?XMLEL4(?NS_USER_NICKNAME, 'nick', [], [CompAddr]),
    exmpp_xml:append_child(make_presence(JID, <<"subscribe">>), Presence).

make_presence(JID, Type) ->
    From = ?XMLATTR('from', ?COMPONENT_ADDRESS),
    PresenceType = ?XMLATTR('type', Type),
    Presence = ?XMLEL4(?NS_COMPONENT_ACCEPT, 'presence', [PresenceType, From], []),
    exmpp_stanza:set_recipient(Presence, JID).

so that we can send to the user the following stanzas:

<presence from="mod_xxxxx.localhost" 
  type="subscribe" to="user@localhost" 
  id="Component-985548963" >
<nick xmlns="http://jabber.org/protocol/nick">mod_xxxxx.localhost</nick>
</presence>

If you are using PSI, you will receive this:

Component asks for presence subscription

Component asks for presence subscription

 

In the previous code, ?COMPONENT_ADDRESS is nothing more than the address of our component (e.g. mod_xxxxx.domain), it is just the address to which the user should send his status updates; at this point if the user sends back a presence stanza with the attribute type set to “subscribed” the process is successful, and in you PSI your user will have a new Agents/Transports contact in his roster.

Component in now in user's roster

Component in now in user's roster

 

Now one can say: “Hey! Wait a second! What are ?XMLCDATA, ?XMLEL4, ?XMLATTR and ?NS_USER_NICKNAME?”, well let’s say that in previous posts I didn’t tell you all the truth: if you include in your module the library exmpp_xml.hrl with:

-include_lib("exmpp/include/exmpp_xml.hrl").

you will be able to build xml elements and xmlcdata with this easier sintax 🙂 , I suggest you to take a look at that file, so that you will see all the other functions provided.

Another smart thing to do is to include the library exmpp_nss.hrl:

-include_lib("exmpp/include/exmpp_nss.hrl").

this way you will be able to use a set of macros for the different namespaces, instead of declaring them by yourselves.

Now what? Well, we should process the presence stanzas as we did for messages and IQs; as I told you before I want to send notifications only to user whose status is set to “online”, thus we should upgrade our mnesia user_table whenever a presence stanza is received, we can do it using the following code:

process_received_presence(_Session,
	                  #received_packet{packet_type=presence,
                          type_attr=_Type, raw_packet=Presence}) ->
    Status = exmpp_presence:get_show(Presence),
    From = exmpp_jid:parse(exmpp_stanza:get_sender(Presence)),
    BareFrom = binary_to_list(exmpp_jid:prep_bare_to_binary(From)),

    case get_subscription(BareFrom) of
	{subscribed, UId, Pwd} ->
	    mnesia:dirty_write({user_table, BareFrom, Status, UId, Pwd});
	_ ->
	    nothing
    end.

And this is done! Now we can select all the users whose status in online using:

mnesia:dirty_index_read(user_table, online, presence).

We can use this function because we set the field presence as a secondary index while creating the Mnesia scheme.

And for today this is all!

Advertisements

Testing your XMPP external component using Tsung and ejabberd part 2

August 1, 2010 5 comments

In the previous post we discussed ow to enable anonymous authentication in ejabberd in order to use Tsung for our testing purposes.

Tsung (a.k.a. Tsunami) is a shell testing tool fairly easy to use when dealing with XMPP, it is mainly used to simulate thousands of users for testing the scalability and performances of IP based client/server applications.

For XMPP test purposes it allows:

  • Authentication (plain-text, digest and sip-digest)
  • presence and register messages
  • Chat messages to online or offline users
  • MUC: join room, send message in room, change nickname
  • Roster set and get requests
  • Global users' synchronization  set on specific actions
  • raw XML messages
  • PubSub
  • Multiple vhost instances support

First thing first: install Tsung! Download the source from http://tsung.erlang-projects.org and just follow the common procedure configure, make, make install (you may need sudo).

You may check whether the installation was successful by typing:

paolo@blog $ tsung -h
Usage: tsung  start|stop|debug|status
Options:
    -f   set configuration file (default is ~/.tsung/tsung.xml)
    -l   set log file (default is ~/.tsung/log/tsung.log)
    -i   set controller id (default is empty)
    -r   set remote connector (default is ssh)
    -F   use long names (FQDN) for erlang nodes
    -v   print version information and exit
    -h   display this help and exit

When you start Tsung (we will see how) it executes a set of operation based on an xml file (tsung.xml) that you easily configure by using a text editor. This file is inside the directory  ~/.tsung but sometimes it is not present so I suggest you to copy one of the examples you can find in the directory “examples” of the installation package, copy it there and rename it.

The Great Wave Of Kanagawa

Let’s take a look at tsung.xml.

Scenarios start with clients (Tsung cluster) and server definitions, so for a non-distributed load, you can use a basic setup like:

<clients>
    <client host="client-ip" use_controller_vm="true"/>
</clients>

<servers>
    <server host="server-ip" port="80" type="tcp"></server>
</servers>

You can put more than one client or one server in you tsung.xml, using either a string or an ip-addres to identificate them. In case of multiple servers, a round robin algorithm will be used to chose a server.

Let’s define now a load progression by specifing a set of  arrival phases to the server:

<load>
  <arrivalphase phase="1" duration="1" unit="hour">
    <users interarrival="6" unit="second"></users>
  </arrivalphase>

  <arrivalphase phase="2" duration="40" unit="minute">
    <users interarrival="1" unit="second"></users>
  </arrivalphase>

  <arrivalphase phase="3" duration="5" unit="minute">
    <users interarrival="0.1" unit="second"></users>
  </arrivalphase>
</load>

Above we specified 3 phases:

  1. duration 1 hour, 1 user each 6 seconds will start a session
  2. duration 40 minutes, 1 user every 1 second
  3. duration 5 minutes, 1 user every 0.1 seconds

The phases will happen one after the other and the test will finish when all users have ended their session. Notice that duration of the test can be much longer than the duration of arrival phases, therefore if you want to stop the test after a threshold duration (even if phases are not finished or if some sessions are still active), you can do by setting a duration attribute to load:

<load duration="4" unit="hour">
 .......
</load>

You can then edit the options as follows:

<options>
  <option type="ts_jabber" name="global_number" value="5"></option>
  <option type="ts_jabber" name="userid_max" value="1000"></option>
  <option type="ts_jabber" name="domain" value="yourdomain"></option>
  <option type="ts_jabber" name="username" value="yourusername"></option>
  <option type="ts_jabber" name="passwd" value="yourpwd"></option>
</options>

In the next post (the final part of this tutorial on Tsung) we will see how to deal with sessions and how to run a test and evaluate its results.

Categories: English, Erlang Tags: , ,

Testing your XMPP external component using Tsung and ejabberd part 1

July 21, 2010 Leave a comment

In many previous posts, I gave you some ideas on how to build an external component for XMPP servers; now it is time to test your work!

Tsung is a stress testing tool written in Erlang that you can use to test HTTP, WebDAV, LDAP, MySQL, PostgreSQL, SOAP and XMPP servers; it can simulate hundreds of simultaneous users on a single system in a single server or in a clustered environment therefore Tsung is the right tool to test our XMPP services.

First of all: when you use Tsung, you simulate few or many users….the problem is that you need to authenticate these users against the server, so you have two solutions: the first one is to create all the users…the second one (the smartest) is to enable anonymous authentication in your XMPP server.

Anonymous authentication is a standard login using classical login and password mechanisms, but where password is accepted or preconfigured for all anonymous users. This login is compliant with sasl authentication, password and digest non-sasl authentication. For more information see this.

On ejabberd, to provide anonymous authenticatio to users you have to tune your configuration file as follows:

1) set up two virtual hosts on the server, one public (any user can login) and one private (login only with valid credentials):

{hosts, ["private.yourdomain", "public.yourdomain"]}.

2) set the global authentication method that you will use. In our case we will  authenticate against ejabberd internal database, but alternative solutions can be MySQL, PostgreSQL, LDAP and so on:

{auth_method, internal}.

3) At the end override the host_config options to provide anonymous login to public host’s clients:

{host_config, "public.yourdomain", [{auth_method, anonymous},
                                     {anonymous_protocol, login_anon}]}.

Just start/restart your ejabberd from this point you can connect to the virtual host “public.yourdomain” with any pair (JID, pwd) but you will be able to authenticate against  “private.yourdomain” only with a valid pair.

Ok, now you have anonymous authentication enabled in you XMPP server!

This week I’m really busy 😦 , so I will teach you how to use Tsung and how to configure it for our purposes in the next post.

How to provide In-Band Registration to users

June 15, 2010 Leave a comment

As you should already know, I am currently working (when I have some free time) to an External Component for Jabber servers which is supposed to be a sort of interface to some Twitter functionalities that I’m not going to explain within this post.

We saw a couple of posts ago, that some information are mandatory in order to exploits Twitter APIs, so we implemented by using Mnesia and Erlang two functions for storing Twitter username and password of our customers; those data should be provided to our component by the user using In-Band Registration, the XEP-0077 of XMPP Protocol).

In few lines we can say that XEP-0077 is a method for in-band registration with instant messaging servers and associated services. In-band registration allows an entity to register with a host, cancel an existing registration with a host, or change a password with a host where the host can be either a server or service.

I strongly suggest you to read the extension’s specs on the web page; I’m not going to write them here since brevity is the soul of wit, and tediousness the limbs and outward flourishes”.

Even though I’m not writing the specs, I will post here the code I wrote for my robot (or at least a snippet of it) 😀

First of all when we receive an IQ with the namespace jabber:iq:register we reply one of the following ways: a form with the parameters to be filled in with the user’s data or the IQ containing the element <registered/>, followed by the data already provided in the previous registration.

Here is a code example:

handle_form_request(Session, IQ, NS) ->
    From = exmpp_jid:parse(exmpp_stanza:get_sender(IQ)),
    BareFrom = binary_to_list(exmpp_jid:prep_bare_to_binary(From)),

    case get_subscribtion(BareFrom) of
	notsubscribed ->
	    send_registration_fields(Session, IQ, NS);
	{subscribed, UId, _Pwd} ->
	    send_registration_form(UId, Session, IQ)
    end.

Where:

send_registration_form(UId, Session, IQ) ->
    Registered = exmpp_xml:element(?NS_INBAND_REGISTER, 'registered', [], []),
    Username = exmpp_xml:element(?NS_INBAND_REGISTER, 'username', [],
				 [{xmlcdata, list_to_binary(UId)}]),
    Password = exmpp_xml:element(?NS_INBAND_REGISTER, 'password', [],
				 [{xmlcdata, "empty due to security"}]),
    Result = exmpp_iq:result(IQ, exmpp_xml:element(?NS_INBAND_REGISTER,
                                         'query', [],
                                         [Registered, Username, Password])),
    exmpp_component:send_packet(Session, Result).

And:

send_registration_fields(Session, IQ, NS) ->
    Instructions = exmpp_xml:element(NS, 'instructions', [], [{xmlcdata,
                <<"Choose a username and password for use with this service.">>}]),
    Pwd = exmpp_xml:element(NS, 'password', [], []),
    User = exmpp_xml:element(NS, 'username', [], []),
    Result = exmpp_iq:result(IQ, exmpp_xml:element(NS, 'query', [],
                                        [Instructions, User, Pwd])),
    exmpp_component:send_packet(Session, Result).

Here is a screenshot of the service working:

In-Band registration process

In-Band registration process


All the other functionalities provided by In-Band Registration can be implemented with really little effort.
If you have any kind of problem or if you want to point out something feel free to contact me!

Connecting an XMPP external component via Erlang and EXMPP

February 23, 2010 10 comments

Here I am again. Sorry for the time it took me to write a new blog entry, but I was preparing the speech for my bachelor thesis..so as you could understand that took all of my free time.
My thesis explained how social networking could be integrated in an XMPP environment, and I have to say that during the time it took me to design and write the code I became an XMPP nuts. XMPP is a protocol aimed to real-time messaging and presence, but it allows developers to use many extensions to implement different kind of services.
For my thesis I used as XMPP server the software Tigase and since it is developed in Java, I wrote all of my code in the same language, but I was aware of the fact that a XMPP server developed in Erlang and called eJabberd exists so I decided to port all of my code in Erlang.
In this post I will teach you how enable an external component in eJabberd and how to code it using Erlang and EXMPP a library provided by Process One. First of all we have to enable the external component in the eJabberd configuration file; by default you can find it in /etc/ejabberd, so:
bellerofonte@pegaso:~$ cd /etc/ejabberd/
belleforonte@pegaso:/etc/ejabberd$ ls
ejabberd.cfg  ejabberdctl.cfg  inetrc

At this point let’s edit ejabberd.cfg (you may be asked to do it with the sudo option).

bellerofonte@pegaso:~$ sudo nano ejabberd.cfg

Now you have to find the part of the configuration file that starts with:

%% ejabberd_service: Interact with external components (transports...)

And add the following lines to add two different external components:

  {8888, ejabberd_service, [
                          {access, all},
                          {shaper_rule, fast},
                          {ip, {127, 0, 0, 1}},
                          {hosts, ["weather.localhost", "weather.trentino.com"],
                           [{password, "weather"}]
                          }
                         ]},

  {8888, ejabberd_service, [
                          {access, all},
                          {shaper_rule, fast},
                          {ip, {127, 0, 0, 1}},
                          {hosts, ["news.localhost", "news.trentino.com"],
                           [{password, "news"}]
                          }
                         ]},

If you don’t know about XMPP and external component I can just tell you that the names I specified in the list after hosts represent the names that will be used to identify this component in the XMPP network, while the value of password is just the password used by the component to perform the handshake with the server. For more info you can read this.

At this point save the configuration file and restart eJabberd.

Now let’s use EXMPP to connect from the Erlang shell to eJabberd as if we were one of the two components.

bellerofonte@pegaso:/etc/ejabberd$ erl
Erlang R13B03 (erts-5.7.4) 

Eshell V5.7.4  (abort with ^G)
1> exmpp:start().
ok
2> Session = exmpp_component:start_link().
<0.59.0>
3> exmpp_component:auth(Session, "weather", "weather").
ok
4> _StreamId = exmpp_component:connect(Session, "localhost", 8888).
"1627139564"
5>  ok = exmpp_component:handshake(Session).
ok

In the code above, I first started  the exmpp application, then I created a Session for the XMPP component and made the authorization stream by passing to the function exmpp_component the session, the name used by the component and the password needed  for the handshake.

Then I connected it to the eJabberd server by using the function connect, which needs the session, the name of the server and the port on which it is listening to.

After that just connect the component by using the function handshake.

Now, you can log in to the server with one test account of yours and perform a service discovery, the result should be something like:

PSI: Service Discovery

Ok, I know this post was kinda short, but I promise that next one will be much better, and in it I will teach you how to receive and send XMPP stanzas from our component!

Categories: English, Erlang Tags: , ,