Thursday, October 22, 2015

JabberSend crashes your system if it has no connection with the XMPP server.

JabberSend is quite a useful function.
It lets you send xmpp instant messages, and it can be used for various things such as alert you when a call hits your voice mail or also that someone is calling you.

Here an example dial plan.
[outside_line]
exten =>  s, 1,  Noop(Incoming call is just arrived)
exten =>  s, n,  JabberSend(XMPP_Account,Jid@domain,Incoming call from "${CALLERID(num)}")
exten =>  s, n,  Dial(${GLOBAL(incoming_call_group)},30,${FLAGS_incoming})
exten =>  s, n,  JabberSend(XMPP_Account,Jid@domain,${CALLERID(num)} is leaving VM message)
exten =>  s, n,  VoiceMail(${GLOBAL(incoming_voicemail)}@asterisk)
exten =>  s, n,  Hangup()


Nice feature, but it comes with a big problem: if for any reason the XMPP connection is down, JabberSend crashes your Asterisk system.
This kind of behaviour is obviously not admittable in any kind of production environment.

You can however use it in a production environment making a slight modification to the code source code of res_xmpp.c

In the Asterisk version I'm using, the 11.6, modifying the function xmpp_client_send_message as follow, the result is:
if JabberSend is invoked and there's no connection to the xmpp server it logs a warning message instead of crashing the system.

here the code, the red indicates where I modified the original code:
static int xmpp_client_send_message(struct ast_xmpp_client *client, int group, const char *nick, const char *address, const char *message)
{
        RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
        RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
        int res = 0;
        char from[XMPP_MAX_JIDLEN];
        iks *message_packet;

        if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name)) ||
            !(message_packet = iks_make_msg(group ? IKS_TYPE_GROUPCHAT : IKS_TYPE_CHAT, address, message))) {
                return -1;
        }

        if (!ast_strlen_zero(nick) && ast_test_flag(&clientcfg->flags, XMPP_COMPONENT)) {
                snprintf(from, sizeof(from), "%s@%s/%s", nick, client->jid->full, nick);
        } else {
                snprintf(from, sizeof(from), "%s", client->jid->full);
        }

        iks_insert_attrib(message_packet, "from", from);

        //begin//
        if (client->state == XMPP_STATE_CONNECTED) {
                                                    res = ast_xmpp_client_send(client, message_packet);
                                                   }
                                              else {
                                                    res = -1;
                                                    ast_log(LOG_WARNING, "XMPP: Not connected, unable to send messages to %s\n", client->name);
                                                   }
        //end//


        iks_delete(message_packet);

        return res;
}
I hope this can help.