2
* $Id: ping.c,v 1.10 2009/04/03 11:21:35 cdidier Exp $
4
* Copyright (C) 2007,2008,2009 Colin DIDIER
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License version 2 as
8
* published by the Free Software Foundation.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License along
16
* with this program; if not, write to the Free Software Foundation, Inc.,
17
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
33
#include "xmpp-servers.h"
34
#include "xmpp-commands.h"
35
#include "tool_datalist.h"
39
#define XMLNS_PING "urn:xmpp:ping"
46
static int timeout_tag;
47
static GSList *supported_servers;
48
static DATALIST *pings;
51
request_ping(XMPP_SERVER_REC *server, const char *dest)
58
recoded = xmpp_recode_in(dest);
59
lmsg = lm_message_new_with_sub_type(recoded,
60
LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_GET);
62
node = lm_message_node_add_child(lmsg->node, "ping", NULL);
63
lm_message_node_set_attribute(node, XMLNS, XMLNS_PING);
64
if (strcmp(dest, server->domain) == 0) {
65
g_free(server->ping_id);
67
g_strdup(lm_message_node_get_attribute(lmsg->node, "id"));
68
g_get_current_time(&server->lag_sent);
69
server->lag_last_check = time(NULL);
71
pd = g_new0(struct ping_data, 1);
73
g_strdup(lm_message_node_get_attribute(lmsg->node, "id"));
74
g_get_current_time(&pd->time);
75
datalist_add(pings, server, dest, pd);
77
signal_emit("xmpp send iq", 2, server, lmsg);
78
lm_message_unref(lmsg);
82
send_ping(XMPP_SERVER_REC *server, const char *dest, const char *id)
87
recoded = xmpp_recode_in(dest);
88
lmsg = lm_message_new_with_sub_type(recoded,
89
LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_RESULT);
92
lm_message_node_set_attribute(lmsg->node, "id", id);
93
signal_emit("xmpp send iq", 2, server, lmsg);
94
lm_message_unref(lmsg);
98
sig_recv_iq(XMPP_SERVER_REC *server, LmMessage *lmsg, const int type,
99
const char *id, const char *from, const char *to)
104
struct ping_data *pd;
106
if (type == LM_MESSAGE_SUB_TYPE_RESULT) {
107
/* pong response from server of our ping */
108
if (server->ping_id != NULL && strcmp(from, server->domain) == 0
109
&& strcmp(id, server->ping_id) == 0) {
110
g_get_current_time(&now);
112
(int)get_timeval_diff(&now, &server->lag_sent);
113
memset(&server->lag_sent, 0, sizeof(server->lag_sent));
114
g_free_and_null(server->ping_id);
115
signal_emit("server lag", 1, server);
116
} else if (lmsg->node->children == NULL
117
&& (rec = datalist_find(pings, server, from)) != NULL) {
119
if (strcmp(id, pd->id) == 0) {
120
g_get_current_time(&now);
121
signal_emit("xmpp ping", 3, server, from,
122
get_timeval_diff(&now, &pd->time));
125
} else if (type == LM_MESSAGE_SUB_TYPE_GET) {
126
node = lm_find_node(lmsg->node, "query", XMLNS, XMLNS_PING);
128
send_ping(server, from,
129
lm_message_node_get_attribute(lmsg->node, "id"));
134
sig_server_features(XMPP_SERVER_REC *server)
136
if (disco_have_feature(server->server_features, XMLNS_PING))
137
supported_servers = g_slist_prepend(supported_servers, server);
141
sig_disconnected(XMPP_SERVER_REC *server)
143
if (!IS_XMPP_SERVER(server))
145
supported_servers = g_slist_remove(supported_servers, server);
146
datalist_cleanup(pings, server);
150
check_ping_func(void)
153
XMPP_SERVER_REC *server;
155
int lag_check_time, max_lag;
157
lag_check_time = settings_get_time("lag_check_time")/1000;
158
max_lag = settings_get_time("lag_max_before_disconnect")/1000;
159
if (lag_check_time <= 0)
162
for (tmp = supported_servers; tmp != NULL; tmp = tmp->next) {
163
server = XMPP_SERVER(tmp->data);
164
if (server->lag_sent.tv_sec != 0) {
165
/* waiting for lag reply */
167
(now - server->lag_sent.tv_sec) > max_lag) {
168
/* too much lag - disconnect */
169
signal_emit("server lag disconnect", 1,
171
server->connection_lost = TRUE;
172
server_disconnect(SERVER(server));
174
} else if ((server->lag_last_check + lag_check_time) < now &&
176
/* no commands in buffer - get the lag */
177
request_ping(server, server->domain);
183
/* SYNTAX: PING [[<jid>[/<resource>]]|[<name]] */
185
cmd_ping(const char *data, XMPP_SERVER_REC *server, WI_ITEM_REC *item)
187
char *cmd_dest, *dest;
190
CMD_XMPP_SERVER(server);
191
if (!cmd_get_params(data, &free_arg, 1, &cmd_dest))
193
dest = xmpp_get_dest(cmd_dest, server, item);
194
request_ping(server, dest);
196
cmd_params_free(free_arg);
200
freedata_func(DATALIST_REC *rec)
202
g_free(((struct ping_data *)rec->data)->id);
209
supported_servers = NULL;
210
pings = datalist_new(freedata_func);
211
disco_add_feature(XMLNS_PING);
212
signal_add("xmpp recv iq", sig_recv_iq);
213
signal_add("xmpp server features", sig_server_features);
214
signal_add("server disconnected", sig_disconnected);
215
command_bind_xmpp("ping", NULL, (SIGNAL_FUNC)cmd_ping);
216
timeout_tag = g_timeout_add(1000, (GSourceFunc)check_ping_func, NULL);
222
g_source_remove(timeout_tag);
223
signal_remove("xmpp recv iq", sig_recv_iq);
224
signal_remove("xmpp server features", sig_server_features);
225
signal_remove("server disconnected", sig_disconnected);
226
command_unbind("ping", (SIGNAL_FUNC)cmd_ping);
227
g_slist_free(supported_servers);
228
datalist_destroy(pings);