mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-29 18:19:30 +00:00
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: https://origsvn.digium.com/svn/asterisk/trunk@88164 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -45,6 +45,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"
|
||||
#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;
|
||||
|
435
res/res_jabber.c
435
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);
|
||||
|
Reference in New Issue
Block a user