[asterisk-commits] kmoore: branch 12 r398619 - in /branches/12: ./ res/res_xmpp.c

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri Sep 6 20:02:07 CDT 2013


Author: kmoore
Date: Fri Sep  6 20:02:04 2013
New Revision: 398619

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

Merged revisions 398618 from http://svn.asterisk.org/svn/asterisk/branches/11

Modified:
    branches/12/   (props changed)
    branches/12/res/res_xmpp.c

Propchange: branches/12/
------------------------------------------------------------------------------
Binary property 'branch-11-merged' - no diff available.

Modified: branches/12/res/res_xmpp.c
URL: http://svnview.digium.com/svn/asterisk/branches/12/res/res_xmpp.c?view=diff&rev=398619&r1=398618&r2=398619
==============================================================================
--- branches/12/res/res_xmpp.c (original)
+++ branches/12/res/res_xmpp.c Fri Sep  6 20:02:04 2013
@@ -2543,13 +2543,7 @@
 	}
 
 	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 @@
 	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 @@
 /*! \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 @@
 	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 @@
 		/* 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 @@
 
 	do {
 		if (client->state == XMPP_STATE_DISCONNECTING) {
+			ast_debug(1, "JABBER: Disconnecting client '%s'\n", client->name);
 			break;
 		}
 
@@ -3712,8 +3753,12 @@
 			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 @@
 			}
 		} 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);




More information about the asterisk-commits mailing list