diff options
author | qwell <qwell@f38db490-d61c-443f-a65b-d21fe96a405b> | 2007-11-01 22:10:33 +0000 |
---|---|---|
committer | qwell <qwell@f38db490-d61c-443f-a65b-d21fe96a405b> | 2007-11-01 22:10:33 +0000 |
commit | 0468ce965ba8aedffe65713a74f1ec082f269d67 (patch) | |
tree | 9ebd302008b72aa900ba72873291520ed651dc4a /res | |
parent | 23373716db61af1d1f68ed80ffdad6c6d0819dcf (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.c | 437 |
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); |