summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordefanor <defanor@uberspace.net>2023-05-02 13:05:26 +0300
committerdefanor <defanor@uberspace.net>2023-05-02 13:05:26 +0300
commit938963c1d1c6a9b929d28a90030332d4f397ca61 (patch)
tree596869c5f96b7578826c7e84c439f0b6313339b1
parentf53cb7886439619860ff86451318a5a04fc49322 (diff)
Use timespec and monotonic clock for timers
-rw-r--r--emacs/xml_interface.c16
-rw-r--r--examples/basic.c17
-rw-r--r--src/rexmpp.c30
-rw-r--r--src/rexmpp.h12
-rw-r--r--src/rexmpp_dns.c22
-rw-r--r--src/rexmpp_dns.h6
-rw-r--r--src/rexmpp_jingle.c12
-rw-r--r--src/rexmpp_jingle.h6
-rw-r--r--src/rexmpp_tcp.c52
-rw-r--r--src/rexmpp_tcp.h14
10 files changed, 109 insertions, 78 deletions
diff --git a/emacs/xml_interface.c b/emacs/xml_interface.c
index 7db2c63..2f4ebba 100644
--- a/emacs/xml_interface.c
+++ b/emacs/xml_interface.c
@@ -329,8 +329,10 @@ int main (int argc, char **argv) {
fd_set read_fds, write_fds;
int nfds;
- struct timeval tv;
- struct timeval *mtv;
+ struct timespec tv;
+ struct timespec *mtv;
+ struct timeval tv_ms;
+ struct timeval *mtv_ms;
int n = 0;
do {
@@ -367,7 +369,13 @@ int main (int argc, char **argv) {
FD_ZERO(&read_fds);
FD_ZERO(&write_fds);
nfds = rexmpp_fds(&s, &read_fds, &write_fds);
- mtv = rexmpp_timeout(&s, NULL, (struct timeval*)&tv);
+ mtv = rexmpp_timeout(&s, NULL, &tv);
+ mtv_ms = NULL;
+ if (mtv != NULL) {
+ tv_ms.tv_sec = mtv->tv_sec;
+ tv_ms.tv_usec = mtv->tv_nsec / 1000;
+ mtv_ms = &tv_ms;
+ }
/* Add other file descriptors we are interested in, particularly
stdin for user input. */
@@ -375,7 +383,7 @@ int main (int argc, char **argv) {
/* Run select(2) with all those file descriptors and timeouts,
waiting for either user input or some rexmpp event to occur. */
- n = select(nfds, &read_fds, &write_fds, NULL, mtv);
+ n = select(nfds, &read_fds, &write_fds, NULL, mtv_ms);
if (n == -1) {
printf("select error: %s\n", strerror(errno));
break;
diff --git a/examples/basic.c b/examples/basic.c
index 6e195bd..982106a 100644
--- a/examples/basic.c
+++ b/examples/basic.c
@@ -11,6 +11,7 @@
#include <errno.h>
#include <syslog.h>
#include <gsasl.h>
+#include <time.h>
#include <rexmpp.h>
#include <rexmpp_sasl.h>
@@ -155,8 +156,10 @@ int main (int argc, char **argv) {
fd_set read_fds, write_fds;
int nfds;
- struct timeval tv;
- struct timeval *mtv;
+ struct timespec tv;
+ struct timespec *mtv;
+ struct timeval tv_ms;
+ struct timeval *mtv_ms;
int n = 0;
do {
@@ -217,7 +220,13 @@ int main (int argc, char **argv) {
FD_ZERO(&read_fds);
FD_ZERO(&write_fds);
nfds = rexmpp_fds(&s, &read_fds, &write_fds);
- mtv = rexmpp_timeout(&s, NULL, (struct timeval*)&tv);
+ mtv = rexmpp_timeout(&s, NULL, &tv);
+ mtv_ms = NULL;
+ if (mtv != NULL) {
+ tv_ms.tv_sec = mtv->tv_sec;
+ tv_ms.tv_usec = mtv->tv_nsec / 1000;
+ mtv_ms = &tv_ms;
+ }
/* Add other file descriptors we are interested in, particularly
stdin for user input. */
@@ -225,7 +234,7 @@ int main (int argc, char **argv) {
/* Run select(2) with all those file descriptors and timeouts,
waiting for either user input or some rexmpp event to occur. */
- n = select(nfds, &read_fds, &write_fds, NULL, mtv);
+ n = select(nfds, &read_fds, &write_fds, NULL, mtv_ms);
if (n == -1) {
printf("select error: %s\n", strerror(errno));
break;
diff --git a/src/rexmpp.c b/src/rexmpp.c
index e494a14..c29574e 100644
--- a/src/rexmpp.c
+++ b/src/rexmpp.c
@@ -578,7 +578,7 @@ rexmpp_err_t rexmpp_init (rexmpp_t *s,
s->iq_cache = NULL;
s->reconnect_number = 0;
s->next_reconnect_time.tv_sec = 0;
- s->next_reconnect_time.tv_usec = 0;
+ s->next_reconnect_time.tv_nsec = 0;
s->initial_jid.full[0] = '\0';
s->assigned_jid.full[0] = '\0';
s->stanza_queue_size = 1024;
@@ -867,7 +867,7 @@ void rexmpp_schedule_reconnect (rexmpp_t *s) {
if (seconds > 3600) {
seconds = 3600;
}
- gettimeofday(&(s->next_reconnect_time), NULL);
+ clock_gettime(CLOCK_MONOTONIC, &(s->next_reconnect_time));
s->next_reconnect_time.tv_sec += seconds;
rexmpp_log(s, LOG_DEBUG, "Scheduled reconnect number %d, in %d seconds",
s->reconnect_number,
@@ -2495,8 +2495,8 @@ rexmpp_err_t rexmpp_stop (rexmpp_t *s) {
}
rexmpp_err_t rexmpp_run (rexmpp_t *s, fd_set *read_fds, fd_set *write_fds) {
- struct timeval now;
- if (gettimeofday(&now, NULL) != 0) {
+ struct timespec now;
+ if (clock_gettime(CLOCK_MONOTONIC, &now) != 0) {
rexmpp_log(s, LOG_ERR, "Failed to get time: %s", strerror(errno));
return REXMPP_E_OTHER;
}
@@ -2772,11 +2772,11 @@ int rexmpp_fds (rexmpp_t *s, fd_set *read_fds, fd_set *write_fds) {
return max_fd;
}
-struct timeval *rexmpp_timeout (rexmpp_t *s,
- struct timeval *max_tv,
- struct timeval *tv)
+struct timespec *rexmpp_timeout (rexmpp_t *s,
+ struct timespec *max_tv,
+ struct timespec *tv)
{
- struct timeval *ret = max_tv;
+ struct timespec *ret = max_tv;
if (s->resolver_state != REXMPP_RESOLVER_NONE &&
s->resolver_state != REXMPP_RESOLVER_READY) {
@@ -2787,14 +2787,14 @@ struct timeval *rexmpp_timeout (rexmpp_t *s,
ret = rexmpp_jingle_timeout(s, ret, tv);
- struct timeval now;
- gettimeofday(&now, NULL);
+ struct timespec now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
if (s->reconnect_number > 0 &&
s->next_reconnect_time.tv_sec > now.tv_sec &&
(ret == NULL ||
s->next_reconnect_time.tv_sec - now.tv_sec < ret->tv_sec)) {
tv->tv_sec = s->next_reconnect_time.tv_sec - now.tv_sec;
- tv->tv_usec = 0;
+ tv->tv_nsec = 0;
ret = tv;
}
@@ -2803,20 +2803,20 @@ struct timeval *rexmpp_timeout (rexmpp_t *s,
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;
+ tv->tv_nsec = 0;
ret = tv;
}
}
#ifdef HAVE_CURL
- long curl_timeout;
+ long curl_timeout; /* in milliseconds */
curl_multi_timeout(s->curl_multi, &curl_timeout);
if (curl_timeout >= 0 &&
(curl_timeout / 1000 < ret->tv_sec ||
(curl_timeout / 1000 == ret->tv_sec &&
- (curl_timeout % 1000) * 1000 < ret->tv_usec))) {
+ (curl_timeout % 1000) * 1000000 < ret->tv_nsec))) {
tv->tv_sec = curl_timeout / 1000;
- tv->tv_usec = (curl_timeout % 1000) * 1000;
+ tv->tv_nsec = (curl_timeout % 1000) * 1000000;
ret = tv;
}
#endif
diff --git a/src/rexmpp.h b/src/rexmpp.h
index 71edacb..13b6c08 100644
--- a/src/rexmpp.h
+++ b/src/rexmpp.h
@@ -322,7 +322,7 @@ struct rexmpp
/* Connection and stream management. */
unsigned int reconnect_number;
time_t reconnect_seconds;
- struct timeval next_reconnect_time;
+ struct timespec next_reconnect_time;
xmlNodePtr stanza_queue;
uint32_t stanzas_out_count;
uint32_t stanzas_out_acknowledged;
@@ -481,13 +481,13 @@ void rexmpp_iq_reply (rexmpp_t *s,
@param[in] s ::rexmpp
@param[in] max_tv An existing timeout (can be NULL), to return if
there's no more urgent timeouts.
- @param[in,out] tv An allocated timeval structure, to store the time
- in.
+ @param[in,out] tv An allocated timespec structure, to store the
+ time in.
@returns A pointer to either max_tv or tv.
*/
-struct timeval *rexmpp_timeout (rexmpp_t *s,
- struct timeval *max_tv,
- struct timeval *tv);
+struct timespec *rexmpp_timeout (rexmpp_t *s,
+ struct timespec *max_tv,
+ struct timespec *tv);
/**
@brief Sets file descriptors to watch.
diff --git a/src/rexmpp_dns.c b/src/rexmpp_dns.c
index 5c3f4f6..1894481 100644
--- a/src/rexmpp_dns.c
+++ b/src/rexmpp_dns.c
@@ -181,16 +181,30 @@ int rexmpp_dns_fds (rexmpp_t *s, fd_set *read_fds, fd_set *write_fds) {
#endif
}
-struct timeval * rexmpp_dns_timeout (rexmpp_t *s,
- struct timeval *max_tv,
- struct timeval *tv)
+struct timespec * rexmpp_dns_timeout (rexmpp_t *s,
+ struct timespec *max_tv,
+ struct timespec *tv)
{
#if defined(USE_UNBOUND)
(void)s;
(void)tv;
return max_tv;
#elif defined(USE_CARES)
- return ares_timeout(s->resolver.channel, max_tv, tv);
+ struct timeval tv_ms;
+ struct timeval *max_tv_ms = NULL;
+ if (max_tv != NULL) {
+ max_tv_ms = &tv_ms;
+ tv_ms.tv_sec = tv->tv_sec;
+ tv_ms.tv_usec = tv->tv_nsec / 1000;
+ }
+ struct timeval *ret_ms = ares_timeout(s->resolver.channel, max_tv_ms, &tv_ms);
+ if (ret_ms == max_tv_ms) {
+ return max_tv;
+ } else {
+ tv->tv_sec = tv_ms.tv_sec;
+ tv->tv_nsec = tv_ms.tv_usec * 1000;
+ return tv;
+ }
#else
(void)s;
(void)max_tv;
diff --git a/src/rexmpp_dns.h b/src/rexmpp_dns.h
index 6641238..abfe6b7 100644
--- a/src/rexmpp_dns.h
+++ b/src/rexmpp_dns.h
@@ -103,9 +103,9 @@ int rexmpp_dns_fds (rexmpp_t *s, fd_set *read_fds, fd_set *write_fds);
/**
@brief Reports timeouts.
*/
-struct timeval * rexmpp_dns_timeout (rexmpp_t *s,
- struct timeval *max_tv,
- struct timeval *tv);
+struct timespec * rexmpp_dns_timeout (rexmpp_t *s,
+ struct timespec *max_tv,
+ struct timespec *tv);
typedef void (*dns_query_cb_t) (rexmpp_t *s, void *ptr, rexmpp_dns_result_t *result);
diff --git a/src/rexmpp_jingle.c b/src/rexmpp_jingle.c
index 3a72a95..8499dc8 100644
--- a/src/rexmpp_jingle.c
+++ b/src/rexmpp_jingle.c
@@ -1779,9 +1779,9 @@ int rexmpp_jingle_fds(rexmpp_t *s, fd_set *read_fds, fd_set *write_fds) {
return (nfds + 1);
}
-struct timeval * rexmpp_jingle_timeout (rexmpp_t *s,
- struct timeval *max_tv,
- struct timeval *tv) {
+struct timespec * rexmpp_jingle_timeout (rexmpp_t *s,
+ struct timespec *max_tv,
+ struct timespec *tv) {
#ifdef ENABLE_CALLS
gint poll_timeout;
GPollFD poll_fds[10];
@@ -1811,12 +1811,12 @@ struct timeval * rexmpp_jingle_timeout (rexmpp_t *s,
if (poll_timeout >= 0) {
int sec = poll_timeout / 1000;
- int usec = (poll_timeout % 1000) * 1000;
+ int nsec = (poll_timeout % 1000) * 1000000;
if (max_tv == NULL ||
(max_tv->tv_sec > sec ||
- (max_tv->tv_sec == sec && max_tv->tv_usec > usec))) {
+ (max_tv->tv_sec == sec && max_tv->tv_nsec > nsec))) {
tv->tv_sec = sec;
- tv->tv_usec = usec;
+ tv->tv_nsec = nsec;
max_tv = tv;
}
}
diff --git a/src/rexmpp_jingle.h b/src/rexmpp_jingle.h
index cd23efb..d3e11eb 100644
--- a/src/rexmpp_jingle.h
+++ b/src/rexmpp_jingle.h
@@ -121,9 +121,9 @@ struct rexmpp_jingle_ctx {
int rexmpp_jingle_init (rexmpp_t *s);
rexmpp_err_t rexmpp_jingle_run (rexmpp_t *s, fd_set *read_fds, fd_set *write_fds);
-struct timeval * rexmpp_jingle_timeout (rexmpp_t *s,
- struct timeval *max_tv,
- struct timeval *tv);
+struct timespec * rexmpp_jingle_timeout (rexmpp_t *s,
+ struct timespec *max_tv,
+ struct timespec *tv);
int rexmpp_jingle_fds(rexmpp_t *s, fd_set *read_fds, fd_set *write_fds);
rexmpp_err_t
diff --git a/src/rexmpp_tcp.c b/src/rexmpp_tcp.c
index a248fec..a9c5547 100644
--- a/src/rexmpp_tcp.c
+++ b/src/rexmpp_tcp.c
@@ -50,10 +50,10 @@ void rexmpp_tcp_dns_a_cb (rexmpp_t *s,
conn->addr_cur_v4 = -1;
if (conn->resolution_v6 == REXMPP_CONN_RESOLUTION_WAITING) {
/* Wait for 50 ms for IPv6. */
- gettimeofday(&(conn->next_connection_time), NULL);
- conn->next_connection_time.tv_usec += REXMPP_TCP_IPV6_DELAY_MS * 1000;
- if (conn->next_connection_time.tv_usec >= 1000000) {
- conn->next_connection_time.tv_usec -= 1000000;
+ clock_gettime(CLOCK_MONOTONIC, &(conn->next_connection_time));
+ conn->next_connection_time.tv_nsec += REXMPP_TCP_IPV6_DELAY_MS * 1000000;
+ if (conn->next_connection_time.tv_nsec >= 1000000000) {
+ conn->next_connection_time.tv_nsec -= 1000000000;
conn->next_connection_time.tv_sec++;
}
}
@@ -132,7 +132,7 @@ rexmpp_tcp_conn_init (rexmpp_t *s,
conn->fd = -1;
conn->dns_secure = 0;
conn->next_connection_time.tv_sec = 0;
- conn->next_connection_time.tv_usec = 0;
+ conn->next_connection_time.tv_nsec = 0;
conn->resolution_v4 = REXMPP_CONN_RESOLUTION_INACTIVE;
conn->resolution_v6 = REXMPP_CONN_RESOLUTION_INACTIVE;
@@ -210,7 +210,7 @@ rexmpp_tcp_conn_proceed (rexmpp_t *s,
fd_set *write_fds)
{
(void)read_fds; /* Not checking any read FDs at the moment. */
- struct timeval now;
+ struct timespec now;
int i;
/* Check for successful connections. */
@@ -250,10 +250,10 @@ rexmpp_tcp_conn_proceed (rexmpp_t *s,
if (conn->connection_attempts < REXMPP_TCP_MAX_CONNECTION_ATTEMPTS &&
(rexmpp_tcp_conn_ipv4_available(conn) ||
rexmpp_tcp_conn_ipv6_available(conn))) {
- gettimeofday(&now, NULL);
+ clock_gettime(CLOCK_MONOTONIC, &now);
if (now.tv_sec > conn->next_connection_time.tv_sec ||
(now.tv_sec == conn->next_connection_time.tv_sec &&
- now.tv_usec >= conn->next_connection_time.tv_usec)) {
+ now.tv_nsec >= conn->next_connection_time.tv_nsec)) {
/* Time to attempt a new connection. */
int use_ipv6 = 0;
if (rexmpp_tcp_conn_ipv4_available(conn) &&
@@ -307,10 +307,10 @@ rexmpp_tcp_conn_proceed (rexmpp_t *s,
conn->sockets[conn->connection_attempts] = rexmpp_tcp_socket(s, domain);
if (connect(conn->sockets[conn->connection_attempts], addr, addrlen)) {
if (errno == EINPROGRESS) {
- gettimeofday(&(conn->next_connection_time), NULL);
- conn->next_connection_time.tv_usec += REXMPP_TCP_CONN_DELAY_MS * 1000;
- if (conn->next_connection_time.tv_usec >= 1000000) {
- conn->next_connection_time.tv_usec -= 1000000;
+ clock_gettime(CLOCK_MONOTONIC, &(conn->next_connection_time));
+ conn->next_connection_time.tv_nsec += REXMPP_TCP_CONN_DELAY_MS * 1000000;
+ if (conn->next_connection_time.tv_nsec >= 1000000000) {
+ conn->next_connection_time.tv_nsec -= 1000000000;
conn->next_connection_time.tv_sec++;
}
conn->connection_attempts++;
@@ -339,14 +339,14 @@ rexmpp_tcp_conn_proceed (rexmpp_t *s,
}
}
- gettimeofday(&now, NULL);
+ clock_gettime(CLOCK_MONOTONIC, &now);
if (active_connections ||
conn->resolution_v4 == REXMPP_CONN_RESOLUTION_WAITING ||
conn->resolution_v6 == REXMPP_CONN_RESOLUTION_WAITING ||
(conn->next_connection_time.tv_sec > now.tv_sec ||
(conn->next_connection_time.tv_sec == now.tv_sec &&
- conn->next_connection_time.tv_usec > now.tv_usec))) {
+ conn->next_connection_time.tv_nsec > now.tv_nsec))) {
return REXMPP_CONN_IN_PROGRESS;
} else {
return REXMPP_CONN_FAILURE;
@@ -374,13 +374,13 @@ int rexmpp_tcp_conn_fds (rexmpp_t *s,
return max_fd;
}
-struct timeval *rexmpp_tcp_conn_timeout (rexmpp_t *s,
- rexmpp_tcp_conn_t *conn,
- struct timeval *max_tv,
- struct timeval *tv)
+struct timespec *rexmpp_tcp_conn_timeout (rexmpp_t *s,
+ rexmpp_tcp_conn_t *conn,
+ struct timespec *max_tv,
+ struct timespec *tv)
{
- struct timeval now;
- struct timeval *ret = max_tv;
+ struct timespec now;
+ struct timespec *ret = max_tv;
if (conn->resolution_v4 == REXMPP_CONN_RESOLUTION_WAITING ||
conn->resolution_v6 == REXMPP_CONN_RESOLUTION_WAITING) {
ret = rexmpp_dns_timeout(s, max_tv, tv);
@@ -389,20 +389,20 @@ struct timeval *rexmpp_tcp_conn_timeout (rexmpp_t *s,
conn->resolution_v6 == REXMPP_CONN_RESOLUTION_SUCCESS ||
(conn->resolution_v4 == REXMPP_CONN_RESOLUTION_INACTIVE &&
conn->resolution_v6 == REXMPP_CONN_RESOLUTION_INACTIVE)) {
- gettimeofday(&now, NULL);
+ clock_gettime(CLOCK_MONOTONIC, &now);
if (now.tv_sec < conn->next_connection_time.tv_sec ||
(now.tv_sec == conn->next_connection_time.tv_sec &&
- now.tv_usec <= conn->next_connection_time.tv_usec)) {
+ now.tv_nsec <= conn->next_connection_time.tv_nsec)) {
if (ret == NULL ||
ret->tv_sec > conn->next_connection_time.tv_sec - now.tv_sec ||
(ret->tv_sec == conn->next_connection_time.tv_sec - now.tv_sec &&
- ret->tv_usec > conn->next_connection_time.tv_usec - now.tv_usec)) {
+ ret->tv_nsec > conn->next_connection_time.tv_nsec - now.tv_nsec)) {
ret = tv;
tv->tv_sec = conn->next_connection_time.tv_sec - now.tv_sec;
- if (conn->next_connection_time.tv_usec > now.tv_usec) {
- tv->tv_usec = conn->next_connection_time.tv_usec - now.tv_usec;
+ if (conn->next_connection_time.tv_nsec > now.tv_nsec) {
+ tv->tv_nsec = conn->next_connection_time.tv_nsec - now.tv_nsec;
} else {
- tv->tv_usec = conn->next_connection_time.tv_usec + 1000000 - now.tv_usec;
+ tv->tv_nsec = conn->next_connection_time.tv_nsec + 1000000000 - now.tv_nsec;
tv->tv_sec--;
}
}
diff --git a/src/rexmpp_tcp.h b/src/rexmpp_tcp.h
index 5a296cc..1440fa1 100644
--- a/src/rexmpp_tcp.h
+++ b/src/rexmpp_tcp.h
@@ -98,8 +98,8 @@ struct rexmpp_tcp_connection {
/** @brief The number of connection attempts so far. */
int connection_attempts;
- /** @brief Next scheduled connection time. */
- struct timeval next_connection_time;
+ /** @brief Next scheduled connection time (monotonic). */
+ struct timespec next_connection_time;
/** @brief File descriptor of a connected socket. */
int fd;
/** @brief Whether the A or AAAA records used to establish the final
@@ -175,13 +175,13 @@ int rexmpp_tcp_conn_fds (rexmpp_t *s,
@param[in] s ::rexmpp
@param[in] conn An active connection structure.
@param[in] max_tv An existing maximum timeout.
- @param[out] tv A timeval structure to store a new timeout in.
+ @param[out] tv A timespec structure to store a new timeout in.
@returns A pointer to either max_tv or tv, depending on which one
is smaller.
*/
-struct timeval *rexmpp_tcp_conn_timeout (rexmpp_t *s,
- rexmpp_tcp_conn_t *conn,
- struct timeval *max_tv,
- struct timeval *tv);
+struct timespec *rexmpp_tcp_conn_timeout (rexmpp_t *s,
+ rexmpp_tcp_conn_t *conn,
+ struct timespec *max_tv,
+ struct timespec *tv);
#endif