summaryrefslogtreecommitdiff
path: root/res
diff options
context:
space:
mode:
Diffstat (limited to 'res')
-rw-r--r--res/res_pjsip_sdp_rtp.c4
-rw-r--r--res/res_xmpp.c157
2 files changed, 100 insertions, 61 deletions
diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c
index a82475774..b66c1aeb8 100644
--- a/res/res_pjsip_sdp_rtp.c
+++ b/res/res_pjsip_sdp_rtp.c
@@ -163,6 +163,10 @@ static int rtp_check_timeout(const void *data)
ast_log(LOG_NOTICE, "Disconnecting channel '%s' for lack of RTP activity in %d seconds\n",
ast_channel_name(chan), elapsed);
+ ast_channel_lock(chan);
+ ast_channel_hangupcause_set(chan, AST_CAUSE_REQUESTED_CHAN_UNAVAIL);
+ ast_channel_unlock(chan);
+
ast_softhangup(chan, AST_SOFTHANGUP_DEV);
ast_channel_unref(chan);
diff --git a/res/res_xmpp.c b/res/res_xmpp.c
index ab4ee9e4f..cc9d56f32 100644
--- a/res/res_xmpp.c
+++ b/res/res_xmpp.c
@@ -1629,6 +1629,35 @@ static int xmpp_resource_immediate(void *obj, void *arg, int flags)
return CMP_MATCH | CMP_STOP;
}
+#define BUDDY_OFFLINE 6
+#define BUDDY_NOT_IN_ROSTER 7
+
+static int get_buddy_status(struct ast_xmpp_client_config *clientcfg, char *screenname, char *resource)
+{
+ int status = BUDDY_OFFLINE;
+ struct ast_xmpp_resource *res;
+ struct ast_xmpp_buddy *buddy = ao2_find(clientcfg->client->buddies, screenname, OBJ_KEY);
+
+ if (!buddy) {
+ return BUDDY_NOT_IN_ROSTER;
+ }
+
+ res = ao2_callback(
+ buddy->resources,
+ 0,
+ ast_strlen_zero(resource) ? xmpp_resource_immediate : xmpp_resource_cmp,
+ resource);
+
+ if (res) {
+ status = res->status;
+ }
+
+ ao2_cleanup(res);
+ ao2_cleanup(buddy);
+
+ return status;
+}
+
/*
* \internal
* \brief Dial plan function status(). puts the status of watched user
@@ -1642,10 +1671,7 @@ static int xmpp_status_exec(struct ast_channel *chan, const char *data)
{
RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
- struct ast_xmpp_buddy *buddy;
- struct ast_xmpp_resource *resource;
char *s = NULL, status[2];
- int stat = 7;
static int deprecation_warning = 0;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(sender);
@@ -1684,25 +1710,7 @@ static int xmpp_status_exec(struct ast_channel *chan, const char *data)
return -1;
}
- if (!(buddy = ao2_find(clientcfg->client->buddies, jid.screenname, OBJ_KEY))) {
- ast_log(LOG_WARNING, "Could not find buddy in list: '%s'\n", jid.screenname);
- return -1;
- }
-
- if (ast_strlen_zero(jid.resource) || !(resource = ao2_callback(buddy->resources, 0, xmpp_resource_cmp, jid.resource))) {
- resource = ao2_callback(buddy->resources, OBJ_NODATA, xmpp_resource_immediate, NULL);
- }
-
- ao2_ref(buddy, -1);
-
- if (resource) {
- stat = resource->status;
- ao2_ref(resource, -1);
- } else {
- ast_log(LOG_NOTICE, "Resource '%s' of buddy '%s' was not found\n", jid.resource, jid.screenname);
- }
-
- snprintf(status, sizeof(status), "%d", stat);
+ snprintf(status, sizeof(status), "%d", get_buddy_status(clientcfg, jid.screenname, jid.resource));
pbx_builtin_setvar_helper(chan, args.variable, status);
return 0;
@@ -1721,9 +1729,6 @@ static int acf_jabberstatus_read(struct ast_channel *chan, const char *name, cha
{
RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
- struct ast_xmpp_buddy *buddy;
- struct ast_xmpp_resource *resource;
- int stat = 7;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(sender);
AST_APP_ARG(jid);
@@ -1755,25 +1760,7 @@ static int acf_jabberstatus_read(struct ast_channel *chan, const char *name, cha
return -1;
}
- if (!(buddy = ao2_find(clientcfg->client->buddies, jid.screenname, OBJ_KEY))) {
- ast_log(LOG_WARNING, "Could not find buddy in list: '%s'\n", jid.screenname);
- return -1;
- }
-
- if (ast_strlen_zero(jid.resource) || !(resource = ao2_callback(buddy->resources, 0, xmpp_resource_cmp, jid.resource))) {
- resource = ao2_callback(buddy->resources, OBJ_NODATA, xmpp_resource_immediate, NULL);
- }
-
- ao2_ref(buddy, -1);
-
- if (resource) {
- stat = resource->status;
- ao2_ref(resource, -1);
- } else {
- ast_log(LOG_NOTICE, "Resource %s of buddy %s was not found.\n", jid.resource, jid.screenname);
- }
-
- snprintf(buf, buflen, "%d", stat);
+ snprintf(buf, buflen, "%d", get_buddy_status(clientcfg, jid.screenname, jid.resource));
return 0;
}
@@ -2561,10 +2548,16 @@ static void xmpp_log_hook(void *data, const char *xmpp, size_t size, int incomin
static int xmpp_client_send_raw_message(struct ast_xmpp_client *client, const char *message)
{
int ret;
-#ifdef HAVE_OPENSSL
- int len = strlen(message);
+ if (client->state == XMPP_STATE_DISCONNECTED) {
+ /* iks_send_raw will crash without a connection */
+ return IKS_NET_NOCONN;
+ }
+
+#ifdef HAVE_OPENSSL
if (xmpp_is_secure(client)) {
+ int len = strlen(message);
+
ret = SSL_write(client->ssl_session, message, len);
if (ret) {
/* Log the message here, because iksemel's logHook is
@@ -2628,12 +2621,31 @@ static int xmpp_client_request_tls(struct ast_xmpp_client *client, struct ast_xm
#endif
}
+#ifdef HAVE_OPENSSL
+static char *openssl_error_string(void)
+{
+ char *buf = NULL, *ret;
+ size_t len;
+ BIO *bio = BIO_new(BIO_s_mem());
+
+ ERR_print_errors(bio);
+ len = BIO_get_mem_data(bio, &buf);
+ ret = ast_calloc(1, len + 1);
+ if (ret) {
+ memcpy(ret, buf, len);
+ }
+ BIO_free(bio);
+ return ret;
+}
+#endif
+
/*! \brief Internal function called when we receive a response to our TLS initiation request */
static int xmpp_client_requested_tls(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
{
#ifdef HAVE_OPENSSL
int sock;
long ssl_opts;
+ char *err;
#endif
if (!strcmp(iks_name(node), "success")) {
@@ -2669,7 +2681,7 @@ static int xmpp_client_requested_tls(struct ast_xmpp_client *client, struct ast_
goto failure;
}
- if (!SSL_connect(client->ssl_session)) {
+ if (SSL_connect(client->ssl_session) <= 0) {
goto failure;
}
@@ -2689,7 +2701,10 @@ static int xmpp_client_requested_tls(struct ast_xmpp_client *client, struct ast_
return 0;
failure:
- ast_log(LOG_ERROR, "TLS connection for client '%s' cannot be established. OpenSSL initialization failed.\n", client->name);
+ err = openssl_error_string();
+ ast_log(LOG_ERROR, "TLS connection for client '%s' cannot be established. "
+ "OpenSSL initialization failed: %s\n", client->name, err);
+ ast_free(err);
return -1;
#endif
}
@@ -3564,6 +3579,7 @@ int ast_xmpp_client_disconnect(struct ast_xmpp_client *client)
{
if ((client->thread != AST_PTHREADT_NULL) && !pthread_equal(pthread_self(), client->thread)) {
xmpp_client_change_state(client, XMPP_STATE_DISCONNECTING);
+ pthread_cancel(client->thread);
pthread_join(client->thread, NULL);
client->thread = AST_PTHREADT_NULL;
}
@@ -3743,22 +3759,37 @@ static int xmpp_client_receive(struct ast_xmpp_client *client, unsigned int time
return IKS_OK;
}
+static void sleep_with_backoff(unsigned int *sleep_time)
+{
+ /* We're OK with our thread dying here */
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+
+ sleep(*sleep_time);
+ *sleep_time = MIN(60, *sleep_time * 2);
+
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+}
+
/*! \brief XMPP client connection thread */
static void *xmpp_client_thread(void *data)
{
struct ast_xmpp_client *client = data;
int res = IKS_NET_RWERR;
+ unsigned int sleep_time = 1;
+
+ /* We only allow cancellation while sleeping */
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
do {
if (client->state == XMPP_STATE_DISCONNECTING) {
- ast_debug(1, "JABBER: Disconnecting client '%s'\n", client->name);
+ ast_debug(1, "[%s] Disconnecting\n", client->name);
break;
}
if (res == IKS_NET_RWERR || client->timeout == 0) {
- ast_debug(3, "Connecting client '%s'\n", client->name);
+ ast_debug(3, "[%s] Connecting\n", client->name);
if ((res = xmpp_client_reconnect(client)) != IKS_OK) {
- sleep(4);
+ sleep_with_backoff(&sleep_time);
res = IKS_NET_RWERR;
}
continue;
@@ -3773,9 +3804,9 @@ static void *xmpp_client_thread(void *data)
}
if (res == IKS_HOOK) {
- ast_debug(2, "JABBER: Got hook event.\n");
+ ast_debug(2, "[%s] Got hook event\n", client->name);
} else if (res == IKS_NET_TLSFAIL) {
- ast_log(LOG_ERROR, "JABBER: Failure in TLS.\n");
+ ast_log(LOG_ERROR, "[%s] TLS failure\n", client->name);
} else if (!client->timeout && client->state == XMPP_STATE_CONNECTED) {
RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
@@ -3793,22 +3824,26 @@ static void *xmpp_client_thread(void *data)
if (res == IKS_OK) {
client->timeout = 50;
} else {
- ast_log(LOG_WARNING, "JABBER: Network Timeout\n");
+ ast_log(LOG_WARNING, "[%s] Network timeout\n", client->name);
}
} else if (res == IKS_NET_RWERR) {
- ast_log(LOG_WARNING, "JABBER: socket read error\n");
+ ast_log(LOG_WARNING, "[%s] Socket read error\n", client->name);
+ ast_xmpp_client_disconnect(client);
+ sleep_with_backoff(&sleep_time);
} else if (res == IKS_NET_NOSOCK) {
- ast_log(LOG_WARNING, "JABBER: No Socket\n");
+ ast_log(LOG_WARNING, "[%s] No socket\n", client->name);
} else if (res == IKS_NET_NOCONN) {
- ast_log(LOG_WARNING, "JABBER: No Connection\n");
+ ast_log(LOG_WARNING, "[%s] No connection\n", client->name);
} else if (res == IKS_NET_NODNS) {
- ast_log(LOG_WARNING, "JABBER: No DNS\n");
+ ast_log(LOG_WARNING, "[%s] No DNS\n", client->name);
} else if (res == IKS_NET_NOTSUPP) {
- ast_log(LOG_WARNING, "JABBER: Not Supported\n");
+ ast_log(LOG_WARNING, "[%s] Not supported\n", client->name);
} else if (res == IKS_NET_DROPPED) {
- ast_log(LOG_WARNING, "JABBER: Dropped?\n");
+ ast_log(LOG_WARNING, "[%s] Dropped?\n", client->name);
} else if (res == IKS_NET_UNKNOWN) {
- ast_debug(5, "JABBER: Unknown\n");
+ ast_debug(5, "[%s] Unknown\n", client->name);
+ } else if (res == IKS_OK) {
+ sleep_time = 1;
}
} while (1);