summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordefanor <defanor@uberspace.net>2020-06-04 19:46:29 +0300
committerdefanor <defanor@uberspace.net>2020-06-04 19:46:29 +0300
commit53fecaf5a2101b75f0a8dcbca2ac4a8578bd3adf (patch)
treef3800a59d3e7cbe1f03362572055819bcb01b14a
parent9c6b0b4deafdba16f105349243399a6799d646a1 (diff)
Implement XEP-0199: XMPP Ping
-rw-r--r--README1
-rw-r--r--src/rexmpp.c44
-rw-r--r--src/rexmpp.h5
3 files changed, 50 insertions, 0 deletions
diff --git a/README b/README
index 4efc99c..3a43f2a 100644
--- a/README
+++ b/README
@@ -38,6 +38,7 @@ A rough roadmap:
[+] "Happy Eyeballs" (RFC 8305).
[+] XEP-0368: SRV records for XMPP over TLS.
[+] SOCKS5 (RFC 1928) support. Implemented, though can be improved.
+[+] XEP-0199: XMPP Ping.
- Library refinement:
diff --git a/src/rexmpp.c b/src/rexmpp.c
index 282118f..4b7a62c 100644
--- a/src/rexmpp.c
+++ b/src/rexmpp.c
@@ -198,6 +198,8 @@ xmlNodePtr rexmpp_xml_default_disco_info () {
xmlNodePtr disco_feature =
rexmpp_xml_feature("http://jabber.org/protocol/disco#info");
identity->next = disco_feature;
+ xmlNodePtr ping_feature = rexmpp_xml_feature("urn:xmpp:ping");
+ disco_feature->next = ping_feature;
return identity;
}
@@ -266,6 +268,9 @@ rexmpp_err_t rexmpp_init (rexmpp_t *s, const char *jid)
s->sasl_property_cb = NULL;
s->xml_in_cb = NULL;
s->xml_out_cb = NULL;
+ s->ping_delay = 600;
+ s->ping_requested = 0;
+ s->last_network_activity = 0;
if (jid == NULL) {
rexmpp_log(s, LOG_CRIT, "No initial JID is provided.");
@@ -389,6 +394,7 @@ void rexmpp_cleanup (rexmpp_t *s) {
s->server_srv_tls_cur = NULL;
}
s->sm_state = REXMPP_SM_INACTIVE;
+ s->ping_requested = 0;
}
/* Frees the things that persist through reconnects. */
@@ -606,6 +612,7 @@ rexmpp_err_t rexmpp_send_continue (rexmpp_t *s)
0);
}
if (ret > 0) {
+ s->last_network_activity = time(NULL);
s->send_buffer_sent += ret;
if (s->send_buffer_sent == s->send_buffer_len) {
free(s->send_buffer);
@@ -824,6 +831,7 @@ void rexmpp_recv (rexmpp_t *s) {
chunk_raw_len = recv(s->server_socket, chunk_raw, 4096, 0);
}
if (chunk_raw_len > 0) {
+ s->last_network_activity = time(NULL);
if (s->sasl_state == REXMPP_SASL_ACTIVE) {
sasl_err = gsasl_decode(s->sasl_session, chunk_raw, chunk_raw_len,
&chunk, &chunk_len);
@@ -1216,6 +1224,14 @@ void rexmpp_carbons_enabled (rexmpp_t *s,
}
}
+void rexmpp_pong (rexmpp_t *s,
+ xmlNodePtr req,
+ xmlNodePtr response,
+ int success)
+{
+ s->ping_requested = 0;
+}
+
void rexmpp_iq_discovery_info (rexmpp_t *s,
xmlNodePtr req,
xmlNodePtr response,
@@ -1464,6 +1480,8 @@ void rexmpp_process_element (rexmpp_t *s) {
if (node != NULL) {
free(node);
}
+ } else if (rexmpp_xml_match(query, "urn:xmpp:ping", "ping")) {
+ rexmpp_iq_reply(s, elem, "result", NULL);
} else {
/* An unknown request. */
rexmpp_iq_reply(s, elem, "error",
@@ -1917,6 +1935,22 @@ rexmpp_err_t rexmpp_run (rexmpp_t *s, fd_set *read_fds, fd_set *write_fds) {
rexmpp_send_continue(s);
}
+ /* Pinging the server. */
+ if (s->tcp_state == REXMPP_TCP_CONNECTED &&
+ s->last_network_activity + s->ping_delay <= time(NULL)) {
+ if (s->ping_requested == 0) {
+ s->ping_requested = 1;
+ xmlNodePtr ping_cmd = xmlNewNode(NULL, "ping");
+ xmlNewNs(ping_cmd, "urn:xmpp:ping", NULL);
+ rexmpp_iq_new(s, "get", jid_bare_to_host(s->initial_jid),
+ ping_cmd, rexmpp_pong);
+ } else {
+ rexmpp_log(s, LOG_WARNING, "Ping timeout, reconnecting.");
+ rexmpp_cleanup(s);
+ rexmpp_schedule_reconnect(s);
+ }
+ }
+
/* Receiving data. Leads to all kinds of things. */
if (s->tcp_state == REXMPP_TCP_CONNECTED &&
FD_ISSET(s->server_socket, read_fds) &&
@@ -2048,5 +2082,15 @@ struct timeval *rexmpp_timeout (rexmpp_t *s,
ret = tv;
}
+ if (s->tcp_state == REXMPP_TCP_CONNECTED &&
+ s->last_network_activity + s->ping_delay > now.tv_sec) {
+ time_t next_ping = s->last_network_activity + s->ping_delay - now.tv_sec;
+ if (ret == NULL || next_ping < ret->tv_sec) {
+ tv->tv_sec = next_ping;
+ tv->tv_usec = 0;
+ ret = tv;
+ }
+ }
+
return ret;
}
diff --git a/src/rexmpp.h b/src/rexmpp.h
index 2660877..9f748cf 100644
--- a/src/rexmpp.h
+++ b/src/rexmpp.h
@@ -272,6 +272,11 @@ struct rexmpp
uint32_t stanzas_in_count;
char *stream_id;
+ /* Server ping configuration and state. */
+ int ping_delay;
+ int ping_requested;
+ time_t last_network_activity;
+
/* DNS-related structures. */
ares_channel resolver_channel;
struct ares_srv_reply *server_srv;