[asterisk-commits] qwell: trunk r88164 - in /trunk: ./ include/asterisk/jabber.h res/res_jabber.c

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Thu Nov 1 17:10:33 CDT 2007


Author: qwell
Date: Thu Nov  1 17:10:33 2007
New Revision: 88164

URL: http://svn.digium.com/view/asterisk?view=rev&rev=88164
Log:
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/

Modified:
    trunk/   (props changed)
    trunk/include/asterisk/jabber.h
    trunk/res/res_jabber.c

Propchange: trunk/
------------------------------------------------------------------------------
    automerge = *

Propchange: trunk/
------------------------------------------------------------------------------
    automerge-email = philippe.sultan at gmail.com

Propchange: trunk/
------------------------------------------------------------------------------
    svnmerge-integrated = /trunk:1-88146

Modified: trunk/include/asterisk/jabber.h
URL: http://svn.digium.com/view/asterisk/trunk/include/asterisk/jabber.h?view=diff&rev=88164&r1=88163&r2=88164
==============================================================================
--- trunk/include/asterisk/jabber.h (original)
+++ trunk/include/asterisk/jabber.h Thu Nov  1 17:10:33 2007
@@ -44,6 +44,19 @@
 
 #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"
@@ -132,12 +145,19 @@
 	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;

Modified: trunk/res/res_jabber.c
URL: http://svn.digium.com/view/asterisk/trunk/res/res_jabber.c?view=diff&rev=88164&r1=88163&r2=88164
==============================================================================
--- trunk/res/res_jabber.c (original)
+++ trunk/res/res_jabber.c Thu Nov  1 17:10:33 2007
@@ -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 @@
 #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 @@
 
 /*! \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 @@
 	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 @@
 
 /*!
  * \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 @@
  * 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 @@
 	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 @@
 	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 @@
 	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 @@
 					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 @@
 			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 @@
 							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 @@
 							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 @@
 				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 @@
 				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 @@
 			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 @@
 			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 @@
 			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 @@
 			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 @@
 
 			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 @@
 
 			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 @@
 			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 @@
 			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 @@
 			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 @@
 			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 @@
 			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 @@
 
 /*!
  * \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 @@
 
 /*!
  * \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 @@
 }
 /*!
  * \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 @@
 				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 @@
 
 /*!
  * \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 @@
 				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 @@
 
 /*!
  * \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 @@
 		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 @@
 
 /*!
  * \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 @@
 		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 @@
 
 /*!
  * \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 @@
 		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 @@
 
 /*!
  * \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 @@
 		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 @@
 {
 	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 @@
 			}
 		}
 
-		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 @@
 		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 @@
 		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 @@
 
 /*!
  * \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 @@
 			/* 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 @@
 				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 @@
 }
 /*!
  * \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 @@
 }
 /*!
  * \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 @@
 	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 @@
 
 /*!
  * \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 @@
 	} 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 @@
 
 /*!
  * \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 @@
 		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 @@
 		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 @@
 /*!
  * \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 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 @@
 	
 	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);




More information about the asterisk-commits mailing list