dnl Checks for library functions.
AC_TYPE_SIGNAL
-AC_CHECK_FUNCS([asprintf fchmod fork gettimeofday random select setns strdup usleep getifaddrs freeifaddrs],
+AC_CHECK_FUNCS([asprintf fchmod fork gettimeofday random pselect select setns strdup usleep getifaddrs freeifaddrs],
[], [], [#include "$srcdir/src/have.h"]
)
return false;
}
- if(mesh->loop.now.tv_sec >= st.st_mtime + mesh->invitation_timeout) {
+ if(time(NULL) >= st.st_mtime + mesh->invitation_timeout) {
logger(mesh, MESHLINK_ERROR, "Peer tried to use an outdated invitation file %s\n", name);
fclose(f);
unlink(used_path);
c->outgoing->timeout = 0;
if(c->outgoing->ev.cb) {
- timeout_set(&mesh->loop, &c->outgoing->ev, &(struct timeval) {
+ timeout_set(&mesh->loop, &c->outgoing->ev, &(struct timespec) {
0, 0
});
}
return status;
}
#endif
-
-#ifndef HAVE_GETTIMEOFDAY
-int gettimeofday(struct timeval *tv, void *tz) {
-#ifdef HAVE_MINGW
- FILETIME ft;
- GetSystemTimeAsFileTime(&ft);
- uint64_t lt = (uint64_t)ft.dwLowDateTime | ((uint64_t)ft.dwHighDateTime << 32);
- lt -= 116444736000000000ULL;
- tv->tv_sec = lt / 10000000;
- tv->tv_usec = (lt / 10) % 1000000;
-#else
-#warning No high resolution time source!
- tv->tv_sec = time(NULL);
- tv->tv_usec = 0;
-#endif
- return 0;
-}
-#endif
-
-#ifndef HAVE_USLEEP
-int usleep(long long usec) {
- struct timeval tv = {usec / 1000000, (usec / 1000) % 1000};
- select(0, NULL, NULL, NULL, &tv);
- return 0;
-}
-#endif
extern int vasprintf(char **, const char *, va_list ap);
#endif
-#ifndef HAVE_GETTIMEOFDAY
-extern int gettimeofday(struct timeval *, void *);
-#endif
-
-#ifndef HAVE_USLEEP
-extern int usleep(long long usec);
-#endif
-
-#ifndef timeradd
-#define timeradd(a, b, r)\
- do {\
- (r)->tv_sec = (a)->tv_sec + (b)->tv_sec;\
- (r)->tv_usec = (a)->tv_usec + (b)->tv_usec;\
- if((r)->tv_usec >= 1000000)\
- (r)->tv_sec++, (r)->tv_usec -= 1000000;\
- } while (0)
-#endif
-
-#ifndef timersub
-#define timersub(a, b, r)\
- do {\
- (r)->tv_sec = (a)->tv_sec - (b)->tv_sec;\
- (r)->tv_usec = (a)->tv_usec - (b)->tv_usec;\
- if((r)->tv_usec < 0)\
- (r)->tv_sec--, (r)->tv_usec += 1000000;\
- } while (0)
-#endif
-
#ifdef HAVE_MINGW
#define mkdir(a, b) mkdir(a)
#ifndef SHUT_RDWR
#include "utils.h"
#include "xalloc.h"
-static int io_compare(const io_t *a, const io_t *b) {
- return a->fd - b->fd;
+#ifndef EVENT_CLOCK
+#if defined(CLOCK_MONOTONIC_RAW) && defined(__x86_64__)
+#define EVENT_CLOCK CLOCK_MONOTONIC_RAW
+#else
+#define EVENT_CLOCK CLOCK_MONOTONIC
+#endif
+#endif
+
+static void timespec_add(const struct timespec *a, const struct timespec *b, struct timespec *r) {
+ r->tv_sec = a->tv_sec + b->tv_sec;
+ r->tv_nsec = a->tv_nsec + b->tv_nsec;
+
+ if(r->tv_nsec > 1000000000) {
+ r->tv_sec++, r->tv_nsec -= 1000000000;
+ }
}
-static int timeout_compare(const timeout_t *a, const timeout_t *b) {
- struct timeval diff;
- timersub(&a->tv, &b->tv, &diff);
+static void timespec_sub(const struct timespec *a, const struct timespec *b, struct timespec *r) {
+ r->tv_sec = a->tv_sec - b->tv_sec;
+ r->tv_nsec = a->tv_nsec - b->tv_nsec;
- if(diff.tv_sec < 0) {
- return -1;
+ if(r->tv_nsec < 0) {
+ r->tv_sec--, r->tv_nsec += 1000000000;
}
+}
- if(diff.tv_sec > 0) {
- return 1;
+static bool timespec_lt(const struct timespec *a, const struct timespec *b) {
+ if(a->tv_sec == b->tv_sec) {
+ return a->tv_nsec < b->tv_nsec;
+ } else {
+ return a->tv_sec < b->tv_sec;
}
+}
- if(diff.tv_usec < 0) {
- return -1;
- }
+static void timespec_clear(struct timespec *a) {
+ a->tv_sec = 0;
+}
- if(diff.tv_usec > 0) {
- return 1;
- }
+static bool timespec_isset(const struct timespec *a) {
+ return a->tv_sec;
+}
- if(a < b) {
- return -1;
- }
+static int io_compare(const io_t *a, const io_t *b) {
+ return a->fd - b->fd;
+}
- if(a > b) {
+static int timeout_compare(const timeout_t *a, const timeout_t *b) {
+ if(a->tv.tv_sec < b->tv.tv_sec) {
+ return -1;
+ } else if(a->tv.tv_sec > b->tv.tv_sec) {
+ return 1;
+ } else if(a->tv.tv_nsec < b->tv.tv_nsec) {
+ return -1;
+ } else if(a->tv.tv_nsec > b->tv.tv_nsec) {
return 1;
+ } else if(a < b) {
+ return -1;
+ } else if(a > b) {
+ return 1;
+ } else {
+ return 0;
}
-
- return 0;
}
void io_add(event_loop_t *loop, io_t *io, io_cb_t cb, void *data, int fd, int flags) {
io->cb = NULL;
}
-void timeout_add(event_loop_t *loop, timeout_t *timeout, timeout_cb_t cb, void *data, struct timeval *tv) {
+void timeout_add(event_loop_t *loop, timeout_t *timeout, timeout_cb_t cb, void *data, struct timespec *tv) {
timeout->cb = cb;
timeout->data = data;
timeout->node.data = timeout;
timeout_set(loop, timeout, tv);
}
-void timeout_set(event_loop_t *loop, timeout_t *timeout, struct timeval *tv) {
+void timeout_set(event_loop_t *loop, timeout_t *timeout, struct timespec *tv) {
assert(timeout->cb);
- if(timerisset(&timeout->tv)) {
+ if(timespec_isset(&timeout->tv)) {
splay_unlink_node(&loop->timeouts, &timeout->node);
}
if(!loop->now.tv_sec) {
- gettimeofday(&loop->now, NULL);
+ clock_gettime(EVENT_CLOCK, &loop->now);
}
- timeradd(&loop->now, tv, &timeout->tv);
+ timespec_add(&loop->now, tv, &timeout->tv);
if(!splay_insert_node(&loop->timeouts, &timeout->node)) {
abort();
static void timeout_disable(event_loop_t *loop, timeout_t *timeout) {
splay_unlink_node(&loop->timeouts, &timeout->node);
- timeout->tv = (struct timeval) {
- 0, 0
- };
+ timespec_clear(&timeout->tv);
}
void timeout_del(event_loop_t *loop, timeout_t *timeout) {
return;
}
- if(timerisset(&timeout->tv)) {
+ if(timespec_isset(&timeout->tv)) {
timeout_disable(loop, timeout);
}
fd_set writable;
while(loop->running) {
- gettimeofday(&loop->now, NULL);
- struct timeval diff, it, *tv = NULL;
+ clock_gettime(EVENT_CLOCK, &loop->now);
+ struct timespec it, ts = {3600, 0};
while(loop->timeouts.head) {
timeout_t *timeout = loop->timeouts.head->data;
- timersub(&timeout->tv, &loop->now, &diff);
- if(diff.tv_sec < 0) {
+ if(timespec_lt(&timeout->tv, &loop->now)) {
timeout_disable(loop, timeout);
timeout->cb(loop, timeout->data);
} else {
- tv = &diff;
+ timespec_sub(&timeout->tv, &loop->now, &ts);
break;
}
}
if(loop->idle_cb) {
it = loop->idle_cb(loop, loop->idle_data);
- if(it.tv_sec >= 0 && (!tv || timercmp(&it, tv, <))) {
- tv = ⁢
+ if(it.tv_sec >= 0 && timespec_lt(&it, &ts)) {
+ ts = it;
}
}
// release mesh mutex during select
pthread_mutex_unlock(mutex);
- int n = select(fds, &readable, &writable, NULL, tv);
+#ifdef HAVE_PSELECT
+ int n = pselect(fds, &readable, &writable, NULL, &ts, NULL);
+#else
+ struct timeval tv = {ts.tv_sec, ts.tv_nsec / 1000};
+ int n = select(fds, &readable, &writable, NULL, (struct timeval *)&tv);
+#endif
pthread_mutex_lock(mutex);
- gettimeofday(&loop->now, NULL);
+ clock_gettime(EVENT_CLOCK, &loop->now);
if(n < 0) {
if(sockwouldblock(errno)) {
loop->signals.compare = (splay_compare_t)signal_compare;
loop->pipefd[0] = -1;
loop->pipefd[1] = -1;
- gettimeofday(&loop->now, NULL);
+ clock_gettime(EVENT_CLOCK, &loop->now);
}
void event_loop_exit(event_loop_t *loop) {
typedef void (*io_cb_t)(event_loop_t *loop, void *data, int flags);
typedef void (*timeout_cb_t)(event_loop_t *loop, void *data);
typedef void (*signal_cb_t)(event_loop_t *loop, void *data);
-typedef struct timeval(*idle_cb_t)(event_loop_t *loop, void *data);
+typedef struct timespec(*idle_cb_t)(event_loop_t *loop, void *data);
typedef struct io_t {
struct splay_node_t node;
typedef struct timeout_t {
struct splay_node_t node;
- struct timeval tv;
+ struct timespec tv;
timeout_cb_t cb;
void *data;
} timeout_t;
volatile bool running;
bool deletion;
- struct timeval now;
+ struct timespec now;
splay_tree_t timeouts;
idle_cb_t idle_cb;
extern void io_del(event_loop_t *loop, io_t *io);
extern void io_set(event_loop_t *loop, io_t *io, int flags);
-extern void timeout_add(event_loop_t *loop, timeout_t *timeout, timeout_cb_t cb, void *data, struct timeval *tv);
+extern void timeout_add(event_loop_t *loop, timeout_t *timeout, timeout_cb_t cb, void *data, struct timespec *tv);
extern void timeout_del(event_loop_t *loop, timeout_t *timeout);
-extern void timeout_set(event_loop_t *loop, timeout_t *timeout, struct timeval *tv);
+extern void timeout_set(event_loop_t *loop, timeout_t *timeout, struct timespec *tv);
extern void signal_add(event_loop_t *loop, signal_t *sig, signal_cb_t cb, void *data, uint8_t signum);
extern void signal_trigger(event_loop_t *loop, signal_t *sig);
if(n->status.reachable) {
logger(mesh, MESHLINK_DEBUG, "Node %s became reachable", n->name);
bool first_time_reachable = !n->last_reachable;
- n->last_reachable = mesh->loop.now.tv_sec;
+ n->last_reachable = time(NULL);
if(first_time_reachable) {
if(!node_write_config(mesh, n)) {
}
} else {
logger(mesh, MESHLINK_DEBUG, "Node %s became unreachable", n->name);
- n->last_unreachable = mesh->loop.now.tv_sec;
+ n->last_unreachable = time(NULL);
}
}
mesh->last_unreachable = mesh->loop.now.tv_sec;
if(mesh->threadstarted) {
- timeout_set(&mesh->loop, &mesh->periodictimer, &(struct timeval) {
+ timeout_set(&mesh->loop, &mesh->periodictimer, &(struct timespec) {
0, prng(mesh, TIMER_FUDGE)
});
}
return true;
}
-static struct timeval idle(event_loop_t *loop, void *data) {
+static bool timespec_lt(const struct timespec *a, const struct timespec *b) {
+ if(a->tv_sec == b->tv_sec) {
+ return a->tv_nsec < b->tv_nsec;
+ } else {
+ return a->tv_sec < b->tv_sec;
+ }
+}
+
+static struct timespec idle(event_loop_t *loop, void *data) {
(void)loop;
meshlink_handle_t *mesh = data;
- struct timeval t, tmin = {3600, 0};
+ struct timespec t, tmin = {3600, 0};
for splay_each(node_t, n, mesh->nodes) {
if(!n->utcp) {
t = utcp_timeout(n->utcp);
- if(timercmp(&t, &tmin, <)) {
+ if(timespec_lt(&t, &tmin)) {
tmin = t;
}
}
n->status.udp_confirmed = false;
if(n->status.reachable) {
- n->last_unreachable = mesh->loop.now.tv_sec;
+ n->last_unreachable = time(NULL);
}
/* Graph updates will suppress status updates for blacklisted nodes, so we need to
n->status.blacklisted = false;
if(n->status.reachable) {
- n->last_reachable = mesh->loop.now.tv_sec;
+ n->last_reachable = time(NULL);
update_node_status(mesh, n);
}
int contradicting_del_edge;
int sleeptime;
time_t connection_burst_time;
- time_t last_config_check;
time_t last_hard_try;
time_t last_unreachable;
timeout_t pingtimer;
}
/// Fudge value of ~0.1 seconds, in microseconds.
-static const unsigned int TIMER_FUDGE = 0x20000;
+static const unsigned int TIMER_FUDGE = 0x8000000;
#endif
}
}
- timeout_set(&mesh->loop, data, &(struct timeval) {
+ timeout_set(&mesh->loop, data, &(struct timespec) {
1, prng(mesh, TIMER_FUDGE)
});
}
if(mesh->contradicting_del_edge > 100 && mesh->contradicting_add_edge > 100) {
logger(mesh, MESHLINK_WARNING, "Possible node with same Name as us! Sleeping %d seconds.", mesh->sleeptime);
- usleep(mesh->sleeptime * 1000000LL);
+ struct timespec ts = {mesh->sleeptime, 0};
+ clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL);
mesh->sleeptime *= 2;
if(mesh->sleeptime < 0) {
}
}
- timeout_set(&mesh->loop, data, &(struct timeval) {
+ timeout_set(&mesh->loop, data, &(struct timespec) {
timeout, prng(mesh, TIMER_FUDGE)
});
}
for list_each(outgoing_t, outgoing, mesh->outgoings) {
outgoing->timeout = 0;
- if(outgoing->ev.cb)
- timeout_set(&mesh->loop, &outgoing->ev, &(struct timeval) {
- 0, 0
- });
+ if(outgoing->ev.cb) {
+ timeout_set(&mesh->loop, &outgoing->ev, &(struct timespec) {
+ 0, 0
+ });
+ }
}
/* For active connections, check if their addresses are still valid.
}
/* Kick the ping timeout handler */
- timeout_set(&mesh->loop, &mesh->pingtimer, &(struct timeval) {
+ timeout_set(&mesh->loop, &mesh->pingtimer, &(struct timespec) {
0, 0
});
}
this is where it all happens...
*/
void main_loop(meshlink_handle_t *mesh) {
- timeout_add(&mesh->loop, &mesh->pingtimer, timeout_handler, &mesh->pingtimer, &(struct timeval) {
+ timeout_add(&mesh->loop, &mesh->pingtimer, timeout_handler, &mesh->pingtimer, &(struct timespec) {
1, prng(mesh, TIMER_FUDGE)
});
- timeout_add(&mesh->loop, &mesh->periodictimer, periodic_handler, &mesh->periodictimer, &(struct timeval) {
+ timeout_add(&mesh->loop, &mesh->periodictimer, periodic_handler, &mesh->periodictimer, &(struct timespec) {
0, 0
});
n->status.broadcast = false;
end:
- timeout_set(&mesh->loop, &n->mtutimeout, &(struct timeval) {
+ timeout_set(&mesh->loop, &n->mtutimeout, &(struct timespec) {
timeout, prng(mesh, TIMER_FUDGE)
});
}
void send_mtu_probe(meshlink_handle_t *mesh, node_t *n) {
- timeout_add(&mesh->loop, &n->mtutimeout, send_mtu_probe_handler, n, &(struct timeval) {
+ timeout_add(&mesh->loop, &n->mtutimeout, send_mtu_probe_handler, n, &(struct timespec) {
1, 0
});
send_mtu_probe_handler(&mesh->loop, n);
/* Done. */
- mesh->last_config_check = mesh->loop.now.tv_sec;
mesh->last_unreachable = mesh->loop.now.tv_sec;
return true;
outgoing->timeout = mesh->maxtimeout;
}
- timeout_add(&mesh->loop, &outgoing->ev, retry_outgoing_handler, outgoing, &(struct timeval) {
+ timeout_add(&mesh->loop, &outgoing->ev, retry_outgoing_handler, outgoing, &(struct timespec) {
outgoing->timeout, prng(mesh, TIMER_FUDGE)
});
}
if(left) {
- timeout_set(&mesh->loop, &mesh->past_request_timeout, &(struct timeval) {
+ timeout_set(&mesh->loop, &mesh->past_request_timeout, &(struct timespec) {
10, prng(mesh, TIMER_FUDGE)
});
}
new->firstseen = mesh->loop.now.tv_sec;
if(!mesh->past_request_tree->head) {
- timeout_set(&mesh->loop, &mesh->past_request_timeout, &(struct timeval) {
+ timeout_set(&mesh->loop, &mesh->past_request_timeout, &(struct timespec) {
10, prng(mesh, TIMER_FUDGE)
});
}
assert(!mesh->past_request_tree);
mesh->past_request_tree = splay_alloc_tree((splay_compare_t) past_request_compare, (splay_action_t) free_past_request);
- timeout_add(&mesh->loop, &mesh->past_request_timeout, age_past_requests, NULL, &(struct timeval) {
+ timeout_add(&mesh->loop, &mesh->past_request_timeout, age_past_requests, NULL, &(struct timespec) {
0, 0
});
}
for list_each(outgoing_t, outgoing, mesh->outgoings) {
if(outgoing->node == from && outgoing->ev.cb) {
outgoing->timeout = 0;
- timeout_set(&mesh->loop, &outgoing->ev, &(struct timeval) {
+ timeout_set(&mesh->loop, &outgoing->ev, &(struct timespec) {
0, 0
});
}
-Subproject commit 96b97ab1291e339a36952532db8ce72e7efc45a1
+Subproject commit 0c3abf9e3538c482639ed32b0e85104495db5b4f