Switch res_jabber to use openssl rather than gnutls.
authorJason Parker <jparker@digium.com>
Thu, 1 Nov 2007 22:10:33 +0000 (22:10 +0000)
committerJason Parker <jparker@digium.com>
Thu, 1 Nov 2007 22:10:33 +0000 (22:10 +0000)
Closes issue #9972, patch by phsultan.  Copied from branch at http://svn.digium.com/svn/asterisk/team/phsultan/res_jabber-openssl/

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@88164 65c4cc65-6c06-0410-ace0-fbb531ad65f3

include/asterisk/jabber.h
res/res_jabber.c

index 83ba0b1..89fdd1a 100644 (file)
 #ifndef _ASTERISK_JABBER_H
 #define _ASTERISK_JABBER_H
 
+#ifdef HAVE_OPENSSL
+
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#define TRY_SECURE 2
+#define SECURE 4
+/* file is read by blocks with this size */
+#define NET_IO_BUF_SIZE 4096
+/* Return value for timeout connection expiration */
+#define IKS_NET_EXPIRED 12
+
+#endif /* HAVE_OPENSSL */
+
 #include <iksemel.h>
 #include "asterisk/astobj.h"
 #include "asterisk/linkedlists.h"
@@ -132,12 +145,19 @@ struct aji_client {
        char user[AJI_MAX_JIDLEN];
        char serverhost[AJI_MAX_RESJIDLEN];
        char statusmessage[256];
+       char name_space[256];
        char sid[10]; /* Session ID */
        char mid[6]; /* Message ID */
        iksid *jid;
        iksparser *p;
        iksfilter *f;
        ikstack *stack;
+#ifdef HAVE_OPENSSL
+       SSL_CTX *ssl_context;
+       SSL *ssl_session;
+       SSL_METHOD *ssl_method;
+       unsigned int stream_flags;
+#endif /* HAVE_OPENSSL */
        enum aji_state state;
        int port;
        int debug;
index 60b6b75..8e21e16 100644 (file)
  * \extref Iksemel http://iksemel.jabberstudio.org/
  *
  * \todo If you unload this module, chan_gtalk/jingle will be dead. How do we handle that?
- * \todo If you have TLS, you can't unload this module. See bug #9738. This needs to be fixed,
- *       but the bug is in the unmantained Iksemel library
  *
  */
 
 /*** MODULEINFO
        <depend>iksemel</depend>
-       <use>gnutls</use>
+       <use>openssl</use>
  ***/
 
 #include "asterisk.h"
@@ -71,13 +69,21 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #endif
 
 /*-- Forward declarations */
-static int aji_start_sasl(iksparser *prs, enum ikssasltype type, char *username, char *pass);
 static int aji_highest_bit(int number);
 static void aji_buddy_destroy(struct aji_buddy *obj);
 static void aji_client_destroy(struct aji_client *obj);
 static int aji_send_exec(struct ast_channel *chan, void *data);
 static int aji_status_exec(struct ast_channel *chan, void *data);
+static int aji_is_secure(struct aji_client *client);
+static int aji_start_tls(struct aji_client *client);
+static int aji_tls_handshake(struct aji_client *client);
+static int aji_io_recv(struct aji_client *client, char *buffer, size_t buf_len, int timeout);
+static int aji_recv(struct aji_client *client, int timeout);
+static int aji_send_header(struct aji_client *client, const char *to);
+static int aji_send(struct aji_client *client, iks *x);
+static int aji_send_raw(struct aji_client *client, const char *xmlstr);
 static void aji_log_hook(void *data, const char *xmpp, size_t size, int is_incoming);
+static int aji_start_sasl(struct aji_client *client, enum ikssasltype type, char *username, char *pass);
 static int aji_act_hook(void *data, int type, iks *node);
 static void aji_handle_iq(struct aji_client *client, iks *node);
 static void aji_handle_message(struct aji_client *client, ikspak *pak);
@@ -150,7 +156,6 @@ struct aji_capabilities *capabilities = NULL;
 
 /*! \brief Global flags, initialized to default values */
 static struct ast_flags globalflags = { AJI_AUTOPRUNE | AJI_AUTOREGISTER };
-static int tls_initialized = FALSE;
 
 /*!
  * \brief Deletes the aji_client data structure.
@@ -501,6 +506,252 @@ static int aji_send_exec(struct ast_channel *chan, void *data)
        return 0;
 }
 
+/*! 
+ * \brief Tests whether the connection is secured or not
+ * \return 0 if the connection is not secured
+ */
+static int aji_is_secure(struct aji_client *client)
+{
+#ifdef HAVE_OPENSSL
+       return client->stream_flags & SECURE;
+#else
+       return 0;
+#endif
+}
+
+
+/*!
+ * \brief Starts the TLS procedure
+ * \param client the configured XMPP client we use to connect to a XMPP server
+ * \return IKS_OK on success, an error code if sending failed, IKS_NET_TLSFAIL
+ * if OpenSSL is not installed
+ */
+static int aji_start_tls(struct aji_client *client)
+{
+       int ret;
+#ifndef HAVE_OPENSSL
+       return IKS_NET_TLSFAIL;
+#endif 
+       /* This is sent not encrypted */
+       ret = iks_send_raw(client->p, "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>");
+       if (ret)
+               return ret;
+       client->stream_flags |= TRY_SECURE;
+
+       return IKS_OK;
+}
+
+/*! 
+ * \brief TLS handshake, OpenSSL initialization
+ * \param client the configured XMPP client we use to connect to a XMPP server
+ * \return IKS_OK on success, IKS_NET_TLSFAIL on failure 
+ */
+static int aji_tls_handshake(struct aji_client *client)
+{
+       int ret;
+       int sock;
+
+#ifndef HAVE_OPENSSL
+       return IKS_NET_TLSFAIL;
+#endif
+       
+       ast_debug(1, "Starting TLS handshake\n"); 
+
+       /* Load encryption, hashing algorithms and error strings */
+       SSL_library_init();
+       SSL_load_error_strings();
+
+       /* Choose an SSL/TLS protocol version, create SSL_CTX */
+       client->ssl_method = SSLv3_method();
+       client->ssl_context = SSL_CTX_new(client->ssl_method);                
+       if (!client->ssl_context)
+               return IKS_NET_TLSFAIL;
+
+       /* Create new SSL session */
+       client->ssl_session = SSL_new(client->ssl_context);
+       if (!client->ssl_session)
+               return IKS_NET_TLSFAIL;
+
+       /* Enforce TLS on our XMPP connection */
+       sock = iks_fd(client->p);
+       ret = SSL_set_fd(client->ssl_session, sock);
+       if (!ret)
+               return IKS_NET_TLSFAIL;
+
+       /* Perform SSL handshake */
+       ret = SSL_connect(client->ssl_session);
+       if (!ret)
+               return IKS_NET_TLSFAIL;
+
+       client->stream_flags &= (~TRY_SECURE);
+       client->stream_flags |= SECURE;
+
+       /* Sent over the established TLS connection */
+       ret = aji_send_header(client, client->jid->server);
+       if (ret != IKS_OK)
+               return IKS_NET_TLSFAIL;
+
+       ast_debug(1, "TLS started with server\n"); 
+
+       return IKS_OK;
+}
+
+/*! 
+ * \brief Secured or unsecured IO socket receiving function
+ * \param client the configured XMPP client we use to connect to a XMPP server
+ * \param buffer the reception buffer
+ * \param buf_len the size of the buffer
+ * \param timeout the select timer
+ * \return the number of read bytes on success, 0 on timeout expiration, 
+ * -1 on  error
+ */
+static int aji_io_recv(struct aji_client *client, char *buffer, size_t buf_len, int timeout)
+{
+       int sock;
+       fd_set fds;
+       struct timeval tv, *tvptr = NULL;
+       int len, res;
+
+#ifdef HAVE_OPENSSL
+       if (aji_is_secure(client)) {
+               sock = SSL_get_fd(client->ssl_session);
+               if (sock < 0)
+                       return -1;              
+       } else
+#endif /* HAVE_OPENSSL */
+               sock = iks_fd(client->p);       
+
+       memset(&tv, 0, sizeof(struct timeval));
+       FD_ZERO(&fds);
+       FD_SET(sock, &fds);
+       tv.tv_sec = timeout;
+
+       /* NULL value for tvptr makes ast_select wait indefinitely */
+       tvptr = (timeout != -1) ? &tv : NULL;
+
+       /* ast_select emulates linux behaviour in terms of timeout handling */
+       res = ast_select(sock + 1, &fds, NULL, NULL, tvptr);
+       if (res > 0) {
+#ifdef HAVE_OPENSSL
+               if (aji_is_secure(client)) {
+                       len = SSL_read(client->ssl_session, buffer, buf_len);
+               } else
+#endif /* HAVE_OPENSSL */
+                       len = recv(sock, buffer, buf_len, 0);
+
+               if (len > 0) {
+                       return len;
+               } else if (len <= 0) {
+                       return -1;
+               }
+       }
+       return res;
+}
+
+/*! 
+ * \brief Tries to receive data from the Jabber server
+ * \param client the configured XMPP client we use to connect to a XMPP server
+ * \param timeout the timeout value
+ * This function receives (encrypted or unencrypted) data from the XMPP server,
+ * and passes it to the parser.
+ * \return IKS_OK on success, IKS_NET_RWERR on IO error, IKS_NET_NOCONN, if no
+ * connection available, IKS_NET_EXPIRED on timeout expiration
+ */
+static int aji_recv (struct aji_client *client, int timeout)
+{
+       int len, ret;
+       char buf[NET_IO_BUF_SIZE -1];
+
+       memset(buf, 0, sizeof(buf));
+
+       while (1) {
+               len = aji_io_recv(client, buf, NET_IO_BUF_SIZE - 1, timeout);
+               if (len < 0) return IKS_NET_RWERR;
+               if (len == 0) return IKS_NET_EXPIRED;
+               buf[len] = '\0';
+               
+               /* Log the message here, because iksemel's logHook is 
+                  unaccessible */
+               aji_log_hook(client, buf, len, 1);
+               
+               ret = iks_parse(client->p, buf, len, 0);
+               if (ret != IKS_OK) {
+                       return ret;
+               }
+       }
+       return IKS_OK;
+}
+
+/*! 
+ * \brief Sends XMPP header to the server
+ * \param client the configured XMPP client we use to connect to a XMPP server
+ * \param to the target XMPP server
+ * \return IKS_OK on success, any other value on failure
+ */
+static int aji_send_header(struct aji_client *client, const char *to)
+{
+       char *msg;
+       int len, err;
+
+       len = 91 + strlen(client->name_space) + 6 + strlen(to) + 16 + 1;
+       msg = iks_malloc(len);
+       if (!msg)
+               return IKS_NOMEM;
+       sprintf(msg, "<?xml version='1.0'?>"
+               "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='"
+               "%s' to='%s' version='1.0'>", client->name_space, to);
+       err = aji_send_raw(client, msg);
+       iks_free(msg);
+       if (err != IKS_OK)
+               return err;
+
+       return IKS_OK;
+}
+
+/*! 
+ * \brief Wraps raw sending
+ * \param client the configured XMPP client we use to connect to a XMPP server
+ * \param x the XMPP packet to send
+ * \return IKS_OK on success, any other value on failure
+ */
+static int aji_send(struct aji_client *client, iks *x)
+{
+       return aji_send_raw(client, iks_string(iks_stack(x), x));
+}
+
+/*! 
+ * \brief Sends an XML string over an XMPP connection
+ * \param client the configured XMPP client we use to connect to a XMPP server
+ * \param xmlstr the XML string to send
+ * The XML data is sent whether the connection is secured or not. In the 
+ * latter case, we just call iks_send_raw().
+ * \return IKS_OK on success, any other value on failure
+ */
+static int aji_send_raw(struct aji_client *client, const char *xmlstr)
+{
+       int ret;
+#ifdef HAVE_OPENSSL
+       int len = strlen(xmlstr);
+
+       if (aji_is_secure(client)) {
+               ret = SSL_write(client->ssl_session, xmlstr, len);
+               if (ret) {
+                       /* Log the message here, because iksemel's logHook is 
+                          unaccessible */
+                       aji_log_hook(client, xmlstr, len, 0);
+                       return IKS_OK;
+               }
+       }
+#endif
+       /* If needed, data will be sent unencrypted, and logHook will 
+          be called inside iks_send_raw */
+       ret = iks_send_raw(client->p, xmlstr);
+       if (ret != IKS_OK)
+               return ret;     
+
+       return IKS_OK;
+}
+
 /*!
  * \brief the debug loop.
  * \param data void
@@ -532,7 +783,7 @@ static void aji_log_hook(void *data, const char *xmpp, size_t size, int is_incom
 
 /*!
  * \brief A wrapper function for iks_start_sasl
- * \param prs the XML parser
+ * \param client the configured XMPP client we use to connect to a XMPP server
  * \param type the SASL authentication type. Supported types are PLAIN and MD5
  * \param username
  * \param pass password.
@@ -543,7 +794,7 @@ static void aji_log_hook(void *data, const char *xmpp, size_t size, int is_incom
  * computed with iks_start_sasl().
  * \return IKS_OK on success, IKSNET_NOTSUPP on failure.
  */
-static int aji_start_sasl(iksparser *prs, enum ikssasltype type, char *username, char *pass)
+static int aji_start_sasl(struct aji_client *client, enum ikssasltype type, char *username, char *pass)
 {
        iks *x = NULL;
        int len;
@@ -551,7 +802,7 @@ static int aji_start_sasl(iksparser *prs, enum ikssasltype type, char *username,
        char *base64;
 
        if (type == IKS_STREAM_SASL_MD5)
-               return iks_start_sasl(prs, IKS_SASL_DIGEST_MD5, username, pass);
+               return iks_start_sasl(client->p, IKS_SASL_DIGEST_MD5, username, pass);
 
        x = iks_new("auth"); 
        if (!x) {
@@ -567,7 +818,7 @@ static int aji_start_sasl(iksparser *prs, enum ikssasltype type, char *username,
        snprintf(s, len, "%c%s%c%s", 0, username, 0, pass);
        ast_base64encode(base64, (const unsigned char *) s, len, (len + 2) * 4 / 3);
        iks_insert_cdata(x, base64, 0);
-       iks_send(prs, x);
+       aji_send(client, x);
        iks_delete(x);
 
        return IKS_OK;
@@ -603,12 +854,13 @@ static int aji_act_hook(void *data, int type, iks *node)
        if (!client->component) { /*client */
                switch (type) {
                case IKS_NODE_START:
-                       if (client->usetls && !iks_is_secure(client->p)) {
-                               if (iks_has_tls()) {
-                                       iks_start_tls(client->p);
-                                       tls_initialized = TRUE;
-                               } else
-                                       ast_log(LOG_ERROR, "gnuTLS not installed. You need to recompile the Iksemel library with gnuTLS support\n");
+                       if (client->usetls && !aji_is_secure(client)) {
+                               if (aji_start_tls(client) == IKS_NET_TLSFAIL) {
+                                       ast_log(LOG_ERROR, "OpenSSL not installed. You need to install OpenSSL on this system\n");
+                                       ASTOBJ_UNREF(client, aji_client_destroy);
+                                       return IKS_HOOK;                
+                               }
+
                                break;
                        }
                        if (!client->usesasl) {
@@ -618,7 +870,7 @@ static int aji_act_hook(void *data, int type, iks *node)
                                        iks_insert_attrib(auth, "id", client->mid);
                                        iks_insert_attrib(auth, "to", client->jid->server);
                                        ast_aji_increment_mid(client->mid);
-                                       iks_send(client->p, auth);
+                                       aji_send(client, auth);
                                        iks_delete(auth);
                                } else
                                        ast_log(LOG_ERROR, "Out of memory.\n");
@@ -626,19 +878,25 @@ static int aji_act_hook(void *data, int type, iks *node)
                        break;
 
                case IKS_NODE_NORMAL:
+                       if (client->stream_flags & TRY_SECURE) {
+                               if (!strcmp("proceed", iks_name(node))) {
+                                       return aji_tls_handshake(client);
+                               }
+                       }
+
                        if (!strcmp("stream:features", iks_name(node))) {
                                features = iks_stream_features(node);
                                if (client->usesasl) {
-                                       if (client->usetls && !iks_is_secure(client->p))
+                                       if (client->usetls && !aji_is_secure(client))
                                                break;
                                        if (client->authorized) {
                                                if (features & IKS_STREAM_BIND) {
-                                                       iks_filter_add_rule (client->f, aji_client_connect, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_DONE);
+                                                       iks_filter_add_rule(client->f, aji_client_connect, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_DONE);
                                                        auth = iks_make_resource_bind(client->jid);
                                                        if (auth) {
                                                                iks_insert_attrib(auth, "id", client->mid);
                                                                ast_aji_increment_mid(client->mid);
-                                                               iks_send(client->p, auth);
+                                                               aji_send(client, auth);
                                                                iks_delete(auth);
                                                        } else {
                                                                ast_log(LOG_ERROR, "Out of memory.\n");
@@ -651,7 +909,7 @@ static int aji_act_hook(void *data, int type, iks *node)
                                                        if (auth) {
                                                                iks_insert_attrib(auth, "id", "auth");
                                                                ast_aji_increment_mid(client->mid);
-                                                               iks_send(client->p, auth);
+                                                               aji_send(client, auth);
                                                                iks_delete(auth);
                                                        } else {
                                                                ast_log(LOG_ERROR, "Out of memory.\n");
@@ -664,7 +922,7 @@ static int aji_act_hook(void *data, int type, iks *node)
                                                        break;
                                                }
                                                features = aji_highest_bit(features);
-                                               ret = aji_start_sasl(client->p, features, client->jid->user, client->password);
+                                               ret = aji_start_sasl(client, features, client->jid->user, client->password);
                                                if (ret != IKS_OK) {
                                                        ASTOBJ_UNREF(client, aji_client_destroy);
                                                        return IKS_HOOK;
@@ -676,7 +934,7 @@ static int aji_act_hook(void *data, int type, iks *node)
                                ast_log(LOG_ERROR, "JABBER: encryption failure. possible bad password.\n");
                        } else if (!strcmp("success", iks_name(node))) {
                                client->authorized = 1;
-                               iks_send_header(client->p, client->jid->server);
+                               aji_send_header(client, client->jid->server);
                        }
                        break;
                case IKS_NODE_ERROR: 
@@ -701,12 +959,12 @@ static int aji_act_hook(void *data, int type, iks *node)
                                handshake = NULL;
                                asprintf(&handshake, "<handshake>%s</handshake>", shasum);
                                if (handshake) {
-                                       iks_send_raw(client->p, handshake);
+                                       aji_send_raw(client, handshake);
                                        ast_free(handshake);
                                        handshake = NULL;
                                }
                                client->state = AJI_CONNECTING;
-                               if (iks_recv(client->p, 1) == 2) /*XXX proper result for iksemel library on iks_recv of <handshake/> XXX*/
+                               if(aji_recv(client, 1) == 2) /*XXX proper result for iksemel library on iks_recv of <handshake/> XXX*/
                                        client->state = AJI_CONNECTED;
                                else
                                        ast_log(LOG_WARNING, "Jabber didn't seem to handshake, failed to authenticate.\n");
@@ -782,7 +1040,7 @@ static int aji_register_approve_handler(void *data, ikspak *pak)
                        iks_insert_attrib(iq, "to", pak->from->full);
                        iks_insert_attrib(iq, "id", pak->id);
                        iks_insert_attrib(iq, "type", "result");
-                       iks_send(client->p, iq);
+                       aji_send(client, iq);
 
                        iks_insert_attrib(presence, "from", client->jid->full);
                        iks_insert_attrib(presence, "to", pak->from->partial);
@@ -791,7 +1049,7 @@ static int aji_register_approve_handler(void *data, ikspak *pak)
                        iks_insert_attrib(presence, "type", "subscribe");
                        iks_insert_attrib(x, "xmlns", "vcard-temp:x:update");
                        iks_insert_node(presence, x);
-                       iks_send(client->p, presence); 
+                       aji_send(client, presence); 
                }
        } else {
                ast_log(LOG_ERROR, "Out of memory.\n");
@@ -841,7 +1099,7 @@ static int aji_register_query_handler(void *data, ikspak *pak)
                        iks_insert_node(iq, query);
                        iks_insert_node(iq, error);
                        iks_insert_node(error, notacceptable);
-                       iks_send(client->p, iq);
+                       aji_send(client, iq);
                } else {
                        ast_log(LOG_ERROR, "Out of memory.\n");
                }
@@ -868,7 +1126,7 @@ static int aji_register_query_handler(void *data, ikspak *pak)
                        iks_insert_cdata(instructions, explain, 0);
                        iks_insert_node(iq, query);
                        iks_insert_node(query, instructions);
-                       iks_send(client->p, iq);
+                       aji_send(client, iq);
                } else {
                        ast_log(LOG_ERROR, "Out of memory.\n");
                }
@@ -912,7 +1170,7 @@ static int aji_ditems_handler(void *data, ikspak *pak)
 
                        iks_insert_node(iq, query);
                        iks_insert_node(query, item);
-                       iks_send(client->p, iq);
+                       aji_send(client, iq);
                } else {
                        ast_log(LOG_ERROR, "Out of memory.\n");
                }
@@ -941,7 +1199,7 @@ static int aji_ditems_handler(void *data, ikspak *pak)
 
                        iks_insert_node(iq, query);
                        iks_insert_node(query, confirm);
-                       iks_send(client->p, iq);
+                       aji_send(client, iq);
                } else {
                        ast_log(LOG_ERROR, "Out of memory.\n");
                }
@@ -968,7 +1226,7 @@ static int aji_ditems_handler(void *data, ikspak *pak)
                        iks_insert_attrib(feature, "var", "http://jabber.org/protocol/commands");
                        iks_insert_node(iq, query);
                        iks_insert_node(query, feature);
-                       iks_send(client->p, iq);
+                       aji_send(client, iq);
                } else {
                        ast_log(LOG_ERROR, "Out of memory.\n");
                }
@@ -1029,7 +1287,7 @@ static int aji_client_info_handler(void *data, ikspak *pak)
                        iks_insert_node(query, ident);
                        iks_insert_node(query, google);
                        iks_insert_node(query, disco);
-                       iks_send(client->p, iq);
+                       aji_send(client, iq);
                } else
                        ast_log(LOG_ERROR, "Out of Memory.\n");
                if (iq)
@@ -1116,7 +1374,7 @@ static int aji_dinfo_handler(void *data, ikspak *pak)
                        iks_insert_node(query, version);
                        iks_insert_node(query, vcard);
                        iks_insert_node(query, search);
-                       iks_send(client->p, iq);
+                       aji_send(client, iq);
                } else {
                        ast_log(LOG_ERROR, "Out of memory.\n");
                }
@@ -1160,7 +1418,7 @@ static int aji_dinfo_handler(void *data, ikspak *pak)
                        iks_insert_attrib(confirm, "jid", client->user);
                        iks_insert_node(iq, query);
                        iks_insert_node(query, confirm);
-                       iks_send(client->p, iq);
+                       aji_send(client, iq);
                } else {
                        ast_log(LOG_ERROR, "Out of memory.\n");
                }
@@ -1187,7 +1445,7 @@ static int aji_dinfo_handler(void *data, ikspak *pak)
                        iks_insert_attrib(feature, "var", "http://jabber.org/protocol/commands");
                        iks_insert_node(iq, query);
                        iks_insert_node(query, feature);
-                       iks_send(client->p, iq);
+                       aji_send(client, iq);
                } else {
                        ast_log(LOG_ERROR, "Out of memory.\n");
                }
@@ -1205,7 +1463,7 @@ static int aji_dinfo_handler(void *data, ikspak *pak)
 
 /*!
  * \brief Handles \verbatim <iq> \endverbatim tags.
- * \param client aji_client
+ * \param client the configured XMPP client we use to connect to a XMPP server
  * \param node iks 
  * \return void.
  */
@@ -1216,7 +1474,7 @@ static void aji_handle_iq(struct aji_client *client, iks *node)
 
 /*!
  * \brief Handles presence packets.
- * \param client aji_client
+ * \param client the configured XMPP client we use to connect to a XMPP server
  * \param pak ikspak the node
  */
 static void aji_handle_message(struct aji_client *client, ikspak *pak)
@@ -1256,7 +1514,7 @@ static void aji_handle_message(struct aji_client *client, ikspak *pak)
 }
 /*!
  * \brief Check the presence info
- * \param client aji_client
+ * \param client the configured XMPP client we use to connect to a XMPP server
  * \param pak ikspak
 */
 static void aji_handle_presence(struct aji_client *client, ikspak *pak)
@@ -1428,7 +1686,7 @@ static void aji_handle_presence(struct aji_client *client, ikspak *pak)
                                ast_aji_increment_mid(client->mid);
                                iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
                                iks_insert_node(iq, query);
-                               iks_send(client->p, iq);
+                               aji_send(client, iq);
                                
                        } else
                                ast_log(LOG_ERROR, "Out of memory.\n");
@@ -1474,7 +1732,7 @@ static void aji_handle_presence(struct aji_client *client, ikspak *pak)
 
 /*!
  * \brief handles subscription requests.
- * \param client aji_client
+ * \param client the configured XMPP client we use to connect to a XMPP server
  * \param pak ikspak iksemel packet.
  * \return void.
  */
@@ -1492,7 +1750,7 @@ static void aji_handle_subscribe(struct aji_client *client, ikspak *pak)
                                iks_insert_attrib(presence, "id", pak->id);
                        iks_insert_cdata(status, "Asterisk has approved subscription", 0);
                        iks_insert_node(presence, status);
-                       iks_send(client->p, presence);
+                       aji_send(client, presence);
                } else
                        ast_log(LOG_ERROR, "Unable to allocate nodes\n");
                if (presence)
@@ -1524,7 +1782,7 @@ static void aji_handle_subscribe(struct aji_client *client, ikspak *pak)
 
 /*!
  * \brief sends messages.
- * \param client aji_client 
+ * \param client the configured XMPP client we use to connect to a XMPP server
  * \param address
  * \param message
  * \return 1.
@@ -1537,7 +1795,7 @@ int ast_aji_send(struct aji_client *client, const char *address, const char *mes
                message_packet = iks_make_msg(IKS_TYPE_CHAT, address, message);
                if (message_packet) {
                        iks_insert_attrib(message_packet, "from", client->jid->full);
-                       res = iks_send(client->p, message_packet);
+                       res = aji_send(client, message_packet);
                } else {
                        ast_log(LOG_ERROR, "Out of memory.\n");
                }
@@ -1550,7 +1808,7 @@ int ast_aji_send(struct aji_client *client, const char *address, const char *mes
 
 /*!
  * \brief create a chatroom.
- * \param client aji_client
+ * \param client the configured XMPP client we use to connect to a XMPP server
  * \param room name of room
  * \param server name of server
  * \param topic topic for the room.
@@ -1566,7 +1824,7 @@ int ast_aji_create_chat(struct aji_client *client, char *room, char *server, cha
                iks_insert_attrib(iq, "to", server);
                iks_insert_attrib(iq, "id", client->mid);
                ast_aji_increment_mid(client->mid);
-               iks_send(client->p, iq);
+               aji_send(client, iq);
        } else 
                ast_log(LOG_ERROR, "Out of memory.\n");
        return res;
@@ -1574,7 +1832,7 @@ int ast_aji_create_chat(struct aji_client *client, char *room, char *server, cha
 
 /*!
  * \brief join a chatroom.
- * \param client aji_client 
+ * \param client the configured XMPP client we use to connect to a XMPP server
  * \param room room to join
  * \return res.
  */
@@ -1588,10 +1846,10 @@ int ast_aji_join_chat(struct aji_client *client, char *room)
                iks_insert_cdata(priority, "0", 1);
                iks_insert_attrib(presence, "to", room);
                iks_insert_node(presence, priority);
-               res = iks_send(client->p, presence);
+               res = aji_send(client, presence);
                iks_insert_cdata(priority, "5", 1);
                iks_insert_attrib(presence, "to", room);
-               res = iks_send(client->p, presence);
+               res = aji_send(client, presence);
        } else 
                ast_log(LOG_ERROR, "Out of memory.\n");
        if (presence)
@@ -1603,7 +1861,7 @@ int ast_aji_join_chat(struct aji_client *client, char *room)
 
 /*!
  * \brief invite to a chatroom.
- * \param client aji_client
+ * \param client the configured XMPP client we use to connect to a XMPP server
  * \param user 
  * \param room
  * \param message
@@ -1626,7 +1884,7 @@ int ast_aji_invite_chat(struct aji_client *client, char *user, char *room, char
                iks_insert_attrib(namespace, "jid", room);
                iks_insert_node(invite, body);
                iks_insert_node(invite, namespace);
-               res = iks_send(client->p, invite);
+               res = aji_send(client, invite);
        } else 
                ast_log(LOG_ERROR, "Out of memory.\n");
        if (body)
@@ -1648,8 +1906,16 @@ static void *aji_recv_loop(void *data)
 {
        struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
        int res = IKS_HOOK;
+
+       while(res != IKS_OK) {
+               if(option_verbose > 3)
+                       ast_verbose("JABBER: Connecting.\n");
+               res = aji_reconnect(client);
+               sleep(4);
+       }
+
        do {
-               if (res != IKS_OK) {
+               if (res == IKS_NET_RWERR || client->timeout == 0) {
                        while(res != IKS_OK) {
                                ast_verb(4, "JABBER: reconnecting.\n");
                                res = aji_reconnect(client);
@@ -1657,19 +1923,23 @@ static void *aji_recv_loop(void *data)
                        }
                }
 
-               res = iks_recv(client->p, 1);
-
+               res = aji_recv(client, 1);
+               
                if (client->state == AJI_DISCONNECTING) {
                        ast_debug(2, "Ending our Jabber client's thread due to a disconnect\n");
                        pthread_exit(NULL);
                }
-               client->timeout--;
+
+               /* Decrease timeout if no data received */
+               if (res == IKS_NET_EXPIRED)
+                       client->timeout--;
+
                if (res == IKS_HOOK) 
                        ast_log(LOG_WARNING, "JABBER: Got hook event.\n");
                else if (res == IKS_NET_TLSFAIL)
                        ast_log(LOG_WARNING, "JABBER:  Failure in TLS.\n");
                else if (client->timeout == 0 && client->state == AJI_CONNECTED) {
-                       res = iks_send_raw(client->p, " ");
+                       res = aji_send_raw(client, " ");
                        if(res == IKS_OK)
                                client->timeout = 50;
                        else
@@ -1727,7 +1997,7 @@ static int aji_register_transport(void *data, ikspak *pak)
                iks_insert_attrib(send, "id", client->mid);
                ast_aji_increment_mid(client->mid);
                iks_insert_attrib(send, "from", client->user);
-               res = iks_send(client->p, send);
+               res = aji_send(client, send);
        } else 
                ast_log(LOG_ERROR, "Out of memory.\n");
 
@@ -1772,7 +2042,7 @@ static int aji_register_transport2(void *data, ikspak *pak)
                iks_insert_node(regiq, regquery);
                iks_insert_node(regquery, reguser);
                iks_insert_node(regquery, regpass);
-               res = iks_send(client->p, regiq);
+               res = aji_send(client, regiq);
        } else
                ast_log(LOG_ERROR, "Out of memory.\n");
        if (regiq)
@@ -1790,7 +2060,7 @@ static int aji_register_transport2(void *data, ikspak *pak)
 
 /*!
  * \brief goes through roster and prunes users not needed in list, or adds them accordingly.
- * \param client aji_client
+ * \param client the configured XMPP client we use to connect to a XMPP server
  * \return void.
  */
 static void aji_pruneregister(struct aji_client *client)
@@ -1809,10 +2079,10 @@ static void aji_pruneregister(struct aji_client *client)
                        /* For an aji_buddy, both AUTOPRUNE and AUTOREGISTER will never
                         * be called at the same time */
                        if (ast_test_flag(iterator, AJI_AUTOPRUNE)) {
-                               res = iks_send(client->p, iks_make_s10n(IKS_TYPE_UNSUBSCRIBE, iterator->name,
+                               res = aji_send(client, iks_make_s10n(IKS_TYPE_UNSUBSCRIBE, iterator->name,
                                                "GoodBye your status is no longer needed by Asterisk the Open Source PBX"
                                                " so I am no longer subscribing to your presence.\n"));
-                               res = iks_send(client->p, iks_make_s10n(IKS_TYPE_UNSUBSCRIBED, iterator->name,
+                               res = aji_send(client, iks_make_s10n(IKS_TYPE_UNSUBSCRIBED, iterator->name,
                                                "GoodBye you are no longer in the asterisk config file so I am removing"
                                                " your access to my presence.\n"));
                                iks_insert_attrib(removeiq, "from", client->jid->full); 
@@ -1820,9 +2090,9 @@ static void aji_pruneregister(struct aji_client *client)
                                iks_insert_attrib(removequery, "xmlns", "jabber:iq:roster");
                                iks_insert_attrib(removeitem, "jid", iterator->name);
                                iks_insert_attrib(removeitem, "subscription", "remove");
-                               res = iks_send(client->p, removeiq);
+                               res = aji_send(client, removeiq);
                        } else if (ast_test_flag(iterator, AJI_AUTOREGISTER)) {
-                               res = iks_send(client->p, iks_make_s10n(IKS_TYPE_SUBSCRIBE, iterator->name, 
+                               res = aji_send(client, iks_make_s10n(IKS_TYPE_SUBSCRIBE, iterator->name, 
                                                "Greetings I am the Asterisk Open Source PBX and I want to subscribe to your presence\n"));
                                ast_clear_flag(iterator, AJI_AUTOREGISTER);
                        }
@@ -1919,7 +2189,7 @@ static int aji_filter_roster(void *data, ikspak *pak)
 }
 /*!
  * \brief reconnect to jabber server
- * \param client aji_client
+ * \param client the configured XMPP client we use to connect to a XMPP server
  * \return res.
 */
 static int aji_reconnect(struct aji_client *client)
@@ -1940,7 +2210,7 @@ static int aji_reconnect(struct aji_client *client)
 }
 /*!
  * \brief Get the roster of jabber users
- * \param client aji_client
+ * \param client the configured XMPP client we use to connect to a XMPP server
  * \return 1.
 */
 static int aji_get_roster(struct aji_client *client)
@@ -1950,7 +2220,7 @@ static int aji_get_roster(struct aji_client *client)
        if(roster) {
                iks_insert_attrib(roster, "id", "roster");
                aji_set_presence(client, NULL, client->jid->full, client->status, client->statusmessage);
-               iks_send(client->p, roster);
+               aji_send(client, roster);
        }
        if (roster)
                iks_delete(roster);
@@ -1986,7 +2256,7 @@ static int aji_client_connect(void *data, ikspak *pak)
 
 /*!
  * \brief prepares client for connect.
- * \param client aji_client
+ * \param client the configured XMPP client we use to connect to a XMPP server
  * \return 1.
  */
 static int aji_initialize(struct aji_client *client)
@@ -2000,20 +2270,27 @@ static int aji_initialize(struct aji_client *client)
        } else  if (connected == IKS_NET_NODNS) {
                ast_log(LOG_ERROR, "JABBER ERROR: No DNS %s for client to  %s\n", client->name, S_OR(client->serverhost, client->jid->server));
                return IKS_HOOK;
-       } else /* if (!connected) phsultan: check if this is needed! */
-               iks_recv(client->p, 30);
+       }
+
        return IKS_OK;
 }
 
 /*!
  * \brief disconnect from jabber server.
- * \param client aji_client
+ * \param client the configured XMPP client we use to connect to a XMPP server
  * \return 1.
  */
 int ast_aji_disconnect(struct aji_client *client)
 {
        if (client) {
                ast_verb(4, "JABBER: Disconnecting\n");
+#ifdef HAVE_OPENSSL
+               if (client->stream_flags & SECURE) {
+                       SSL_shutdown(client->ssl_session);
+                       SSL_CTX_free(client->ssl_context);
+                       SSL_free(client->ssl_session);
+               }
+#endif
                iks_disconnect(client->p);
                iks_parser_delete(client->p);
                ASTOBJ_UNREF(client, aji_client_destroy);
@@ -2024,7 +2301,7 @@ int ast_aji_disconnect(struct aji_client *client)
 
 /*!
  * \brief set presence of client.
- * \param client aji_client
+ * \param client the configured XMPP client we use to connect to a XMPP server
  * \param to user send it to
  * \param from user it came from
  * \param level
@@ -2052,7 +2329,7 @@ static void aji_set_presence(struct aji_client *client, char *to, char *from, in
                iks_insert_attrib(cnode, "ext", "voice-v1");
                iks_insert_attrib(cnode, "xmlns", "http://jabber.org/protocol/caps");
                iks_insert_node(presence, cnode);
-               res = iks_send(client->p, presence);
+               res = aji_send(client, presence);
        } else
                ast_log(LOG_ERROR, "Out of memory.\n");
        if (cnode)
@@ -2422,7 +2699,9 @@ static int aji_create_client(char *label, struct ast_variable *var, int debug)
                ASTOBJ_UNREF(client, aji_client_destroy);
                return 1;
        }
-       client->p = iks_stream_new(((client->component) ? "jabber:component:accept" : "jabber:client"), client, aji_act_hook);
+
+       ast_copy_string(client->name_space, (client->component) ? "jabber:component:accept" : "jabber:client", sizeof(client->name_space));
+       client->p = iks_stream_new(client->name_space, client, aji_act_hook);
        if (!client->p) {
                ast_log(LOG_ERROR, "Failed to create stream for client '%s'!\n", client->name);
                return 0;
@@ -2523,7 +2802,7 @@ static int aji_create_transport(char *label, struct aji_client *client)
 /*!
  * \brief creates buddy.
  * \param label char.
- * \param client aji_client buddy to dump it into. 
+ * \param client the configured XMPP client we use to connect to a XMPP server 
  * \return 1 on success, 0 on failure.
  */
 static int aji_create_buddy(char *label, struct aji_client *client)
@@ -2695,16 +2974,6 @@ static int aji_reload(int reload)
 static int unload_module(void)
 {
 
-       /* Check if TLS is initialized. If that's the case, we can't unload this
-          module due to a bug in the iksemel library that will cause a crash or
-          a deadlock. We're trying to find a way to handle this, but in the meantime
-          we will simply refuse to die... 
-        */
-       if (tls_initialized) {
-               ast_log(LOG_ERROR, "Module can't be unloaded due to a bug in the Iksemel library when using TLS.\n");
-               return 1;       /* You need a forced unload to get rid of this module */
-       }
-
        ast_cli_unregister_multiple(aji_cli, sizeof(aji_cli) / sizeof(struct ast_cli_entry));
        ast_unregister_application(app_ajisend);
        ast_unregister_application(app_ajistatus);
@@ -2713,7 +2982,7 @@ static int unload_module(void)
        
        ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
                ASTOBJ_RDLOCK(iterator);
-               ast_debug(3, "JABBER: Releasing and disconneing client: %s\n", iterator->name);
+               ast_debug(3, "JABBER: Releasing and disconnecting client: %s\n", iterator->name);
                iterator->state = AJI_DISCONNECTING;
                ast_aji_disconnect(iterator);
                pthread_join(iterator->thread, NULL);