summaryrefslogtreecommitdiff
path: root/res/res_xmpp.c
diff options
context:
space:
mode:
authorKinsey Moore <kmoore@digium.com>2013-09-07 01:03:07 +0000
committerKinsey Moore <kmoore@digium.com>2013-09-07 01:03:07 +0000
commitad89dffb8a2997ad6bbd38ea73762ca0465e70ac (patch)
tree95a74c22da9ce691742c5184713511e34c982416 /res/res_xmpp.c
parent0bed76989a4dada80a2ed8b764e014d7e8851e7c (diff)
Prevent XMPP timeout on blank responses
Sometimes the Google Voice servers have a bad habit of sending out 1 byte replies to the xmpp resource. When a blank 1 byte reply is received from the socket the buffer attempts to wait (endlessly) for the rest of the reply from google which effectively blocks the socket and google voice calls will no longer come into the server. This patch allows the xmpp module to correctly detect empty packets and send out ping replies to google. It also sets a socket timeout on the default socket which prevents the xmpp socket from closing and preventing future google voice calls from coming into the server. Furthermore instead of sending an empty reply back to google we send a proper xmpp ping reply back. This also adds several more socket messages. (closes issue ASTERISK-22347) Reported by: Andrew Nagy Review: https://reviewboard.asterisk.org/r/2771 Patches: xmpp_fix_1.diff uploaded by Andrew Nagy (License #6524) ........ Merged revisions 398618 from http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged revisions 398619 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@398620 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'res/res_xmpp.c')
-rw-r--r--res/res_xmpp.c75
1 files changed, 66 insertions, 9 deletions
diff --git a/res/res_xmpp.c b/res/res_xmpp.c
index e4ecd44ec..1d8f62824 100644
--- a/res/res_xmpp.c
+++ b/res/res_xmpp.c
@@ -2543,13 +2543,7 @@ static void xmpp_log_hook(void *data, const char *xmpp, size_t size, int incomin
}
if (!incoming) {
- if (strlen(xmpp) == 1) {
- if (option_debug > 2 && xmpp[0] == ' ') {
- ast_verbose("\n<--- XMPP keep alive from '%s' --->\n", client->name);
- }
- } else {
- ast_verbose("\n<--- XMPP sent to '%s' --->\n%s\n<------------->\n", client->name, xmpp);
- }
+ ast_verbose("\n<--- XMPP sent to '%s' --->\n%s\n<------------->\n", client->name, xmpp);
} else {
ast_verbose("\n<--- XMPP received from '%s' --->\n%s\n<------------->\n", client->name, xmpp);
}
@@ -3242,6 +3236,40 @@ static int xmpp_resource_is_available(void *obj, void *arg, int flags)
return (resource->status == IKS_SHOW_AVAILABLE) ? CMP_MATCH | CMP_STOP : 0;
}
+/*! \brief Helper function which sends a ping request to a server */
+static int xmpp_ping_request(struct ast_xmpp_client *client, const char *to, const char *from)
+{
+ iks *iq, *ping;
+ int res;
+
+ ast_debug(2, "JABBER: Sending Keep-Alive Ping for client '%s'\n", client->name);
+
+ if (!(iq = iks_new("iq")) || !(ping = iks_new("ping"))) {
+ iks_delete(iq);
+ return -1;
+ }
+
+ iks_insert_attrib(iq, "type", "get");
+ iks_insert_attrib(iq, "to", to);
+ iks_insert_attrib(iq, "from", from);
+
+ ast_xmpp_client_lock(client);
+ iks_insert_attrib(iq, "id", client->mid);
+ ast_xmpp_increment_mid(client->mid);
+ ast_xmpp_client_unlock(client);
+
+ iks_insert_attrib(ping, "xmlns", "urn:xmpp:ping");
+ iks_insert_node(iq, ping);
+
+ res = ast_xmpp_client_send(client, iq);
+
+ iks_delete(ping);
+ iks_delete(iq);
+
+
+ return res;
+}
+
/*! \brief Internal function called when a presence message is received */
static int xmpp_pak_presence(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, iks *node, ikspak *pak)
{
@@ -3545,6 +3573,7 @@ int ast_xmpp_client_disconnect(struct ast_xmpp_client *client)
/*! \brief Internal function used to reconnect an XMPP client to its server */
static int xmpp_client_reconnect(struct ast_xmpp_client *client)
{
+ struct timeval tv = { .tv_sec = 5, .tv_usec = 0 };
RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
int res = IKS_NET_NOCONN;
@@ -3567,6 +3596,9 @@ static int xmpp_client_reconnect(struct ast_xmpp_client *client)
res = iks_connect_via(client->parser, S_OR(clientcfg->server, client->jid->server), clientcfg->port,
ast_test_flag(&clientcfg->flags, XMPP_COMPONENT) ? clientcfg->user : client->jid->server);
+ /* Set socket timeout options */
+ setsockopt(iks_fd(client->parser), SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,sizeof(struct timeval));
+
if (res == IKS_NET_NOCONN) {
ast_log(LOG_ERROR, "No XMPP connection available when trying to connect client '%s'\n", client->name);
return -1;
@@ -3651,6 +3683,14 @@ static int xmpp_client_receive(struct ast_xmpp_client *client, unsigned int time
/* Log the message here, because iksemel's logHook is
unaccessible */
xmpp_log_hook(client, buf, len, 1);
+
+ if(buf[0] == ' ') {
+ ast_debug(1, "JABBER: Detected Google Keep Alive. "
+ "Sending out Ping request for client '%s'\n", client->name);
+ /* If we just send out the ping here then we will have socket
+ * read errors because the socket will timeout */
+ xmpp_ping_request(client, client->jid->server, client->jid->full);
+ }
/* let iksemel deal with the string length,
and reset our buffer */
@@ -3684,6 +3724,7 @@ static void *xmpp_client_thread(void *data)
do {
if (client->state == XMPP_STATE_DISCONNECTING) {
+ ast_debug(1, "JABBER: Disconnecting client '%s'\n", client->name);
break;
}
@@ -3712,8 +3753,12 @@ static void *xmpp_client_thread(void *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);
- if (cfg && cfg->clients && (clientcfg = xmpp_config_find(cfg->clients, client->name))) {
- res = ast_test_flag(&clientcfg->flags, XMPP_KEEPALIVE) ? xmpp_client_send_raw_message(client, " ") : IKS_OK;
+ if (cfg && cfg->clients) {
+ clientcfg = xmpp_config_find(cfg->clients, client->name);
+ }
+
+ if (clientcfg && ast_test_flag(&clientcfg->flags, XMPP_KEEPALIVE)) {
+ res = xmpp_ping_request(client, client->jid->server, client->jid->full);
} else {
res = IKS_OK;
}
@@ -3725,6 +3770,18 @@ static void *xmpp_client_thread(void *data)
}
} else if (res == IKS_NET_RWERR) {
ast_log(LOG_WARNING, "JABBER: socket read error\n");
+ } else if (res == IKS_NET_NOSOCK) {
+ ast_log(LOG_WARNING, "JABBER: No Socket\n");
+ } else if (res == IKS_NET_NOCONN) {
+ ast_log(LOG_WARNING, "JABBER: No Connection\n");
+ } else if (res == IKS_NET_NODNS) {
+ ast_log(LOG_WARNING, "JABBER: No DNS\n");
+ } else if (res == IKS_NET_NOTSUPP) {
+ ast_log(LOG_WARNING, "JABBER: Not Supported\n");
+ } else if (res == IKS_NET_DROPPED) {
+ ast_log(LOG_WARNING, "JABBER: Dropped?\n");
+ } else {
+ ast_debug(5, "JABBER: Unknown\n");
}
} while (1);