diff --git a/res/res_xmpp.c b/res/res_xmpp.c index e4ecd44ecae61f76bbd51c0c0e496a7d3b954311..1d8f62824ea5895488a589c73fe9e894fc2df7db 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);