aboutsummaryrefslogtreecommitdiffstats
path: root/res
diff options
context:
space:
mode:
authorqwell <qwell@f38db490-d61c-443f-a65b-d21fe96a405b>2007-11-01 22:10:33 +0000
committerqwell <qwell@f38db490-d61c-443f-a65b-d21fe96a405b>2007-11-01 22:10:33 +0000
commit0468ce965ba8aedffe65713a74f1ec082f269d67 (patch)
tree9ebd302008b72aa900ba72873291520ed651dc4a /res
parent23373716db61af1d1f68ed80ffdad6c6d0819dcf (diff)
Switch res_jabber to use openssl rather than gnutls.
Closes issue #9972, patch by phsultan. Copied from branch at http://svn.digium.com/svn/asterisk/team/phsultan/res_jabber-openssl/ git-svn-id: http://svn.digium.com/svn/asterisk/trunk@88164 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'res')
-rw-r--r--res/res_jabber.c437
1 files changed, 353 insertions, 84 deletions
diff --git a/res/res_jabber.c b/res/res_jabber.c
index 60b6b752e..8e21e1605 100644
--- a/res/res_jabber.c
+++ b/res/res_jabber.c
@@ -23,14 +23,12 @@
* \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);