From 956b5c640177dfb20484b925108ffa8c0573330f Mon Sep 17 00:00:00 2001 From: Benedikt Heine Date: Sun, 17 Sep 2017 01:26:53 +0200 Subject: [PATCH] Use gint64 as microseconds for internal timeunit time(NULL) is vulnerable against timeshifts by NTP, timezones,... g_get_monotonic_time() is not, but counts its in microseconds with the gint64 datatype. To prevent any conversion bugs, all internal timeformats are now using a gint64 and only get converted during import or export (DBus notification arrives, configuration reading, age threshold display). --- config.def.h | 6 ++--- src/dbus.c | 10 +-------- src/dunst.c | 55 ++++++++++++++++++---------------------------- src/notification.c | 35 ++++++++++++++--------------- src/notification.h | 11 +++++----- src/rules.h | 2 +- src/settings.c | 12 +++++----- src/settings.h | 6 ++--- src/x11/x.c | 2 +- 9 files changed, 58 insertions(+), 81 deletions(-) diff --git a/config.def.h b/config.def.h index 6061851..18411b4 100644 --- a/config.def.h +++ b/config.def.h @@ -10,7 +10,7 @@ char *lowbgcolor = "#aaaaff"; char *lowfgcolor = "#000000"; char *format = "%s %b"; /* default format */ -int timeouts[] = { 10, 10, 0 }; /* low, normal, critical */ +gint64 timeouts[] = { 10*G_USEC_PER_SEC, 10*G_USEC_PER_SEC, 0 }; /* low, normal, critical */ char *icons[] = { "dialog-information", "dialog-information", "dialog-warning" }; /* low, normal, critical */ unsigned int transparency = 0; /* transparency */ @@ -20,8 +20,8 @@ char *class = "Dunst"; /* the class of dunst notification windows */ int shrink = false; /* shrinking */ int sort = true; /* sort messages by urgency */ int indicate_hidden = true; /* show count of hidden messages */ -int idle_threshold = 0; /* don't timeout notifications when idle for x seconds */ -int show_age_threshold = -1; /* show age of notification, when notification is older than x seconds */ +gint64 idle_threshold = 0; /* don't timeout notifications when idle for x seconds */ +gint64 show_age_threshold = -1; /* show age of notification, when notification is older than x seconds */ enum alignment align = left; /* text alignment [left/center/right] */ int sticky_history = true; int history_length = 20; /* max amount of notifications kept in history */ diff --git a/src/dbus.c b/src/dbus.c index 064c233..4893193 100644 --- a/src/dbus.c +++ b/src/dbus.c @@ -236,21 +236,13 @@ static void on_notify(GDBusConnection *connection, fflush(stdout); - if (timeout > 0) { - /* do some rounding */ - timeout = (timeout + 500) / 1000; - if (timeout < 1) { - timeout = 1; - } - } - notification *n = notification_create(); n->appname = appname; n->summary = summary; n->body = body; n->icon = icon; n->raw_icon = raw_icon; - n->timeout = timeout; + n->timeout = timeout < 0 ? -1 : timeout * 1000; n->markup = settings.markup; n->progress = (progress < 0 || progress > 100) ? 0 : progress + 1; n->urgency = urgency; diff --git a/src/dunst.c b/src/dunst.c index d571625..7e55f0d 100644 --- a/src/dunst.c +++ b/src/dunst.c @@ -12,7 +12,6 @@ #include #include #include -#include #include "dbus.h" #include "menu.h" @@ -70,7 +69,7 @@ void check_timeouts(void) /* don't timeout when user is idle */ if (x_is_idle() && !n->transient) { - n->start = time(NULL); + n->start = g_get_monotonic_time(); continue; } @@ -80,7 +79,7 @@ void check_timeouts(void) } /* remove old message */ - if (difftime(time(NULL), n->start) > n->timeout) { + if (g_get_monotonic_time() - n->start > n->timeout) { notification_close(n, 1); } } @@ -122,7 +121,7 @@ void update_lists() if (!n) return; - n->start = time(NULL); + n->start = g_get_monotonic_time(); if (!n->redisplayed && n->script) { notification_run_script(n); } @@ -173,49 +172,37 @@ void wake_up(void) run(NULL); } -static int get_sleep_time(void) +static gint64 get_sleep_time(void) { + gint64 sleep = G_MAXINT64; - if (settings.show_age_threshold == 0) { - /* we need to update every second */ - return 1; - } - - int min_ttl = INT_MAX; - int max_age = 0; + gint64 max_age = 0; for (GList *iter = g_queue_peek_head_link(displayed); iter; iter = iter->next) { notification *n = iter->data; max_age = MAX(max_age, notification_get_age(n)); - int ttl = notification_get_ttl(n); - if (ttl >= 0) { - min_ttl = MIN(min_ttl, ttl); - } + gint64 ttl = notification_get_ttl(n); + if (ttl >= 0) + sleep = MIN(sleep, ttl); } - int min_timeout; - int show_age_timeout = settings.show_age_threshold - max_age; - - if (show_age_timeout < 1) { - return 1; + /* if age_threshold is hit, seconds have to get updated every second */ + if (settings.show_age_threshold >= 0) { + if (settings.show_age_threshold > max_age) + sleep = MIN(sleep, settings.show_age_threshold - max_age); + else + sleep = MIN(sleep, 1000*1000); } - min_timeout = MIN(show_age_timeout, min_ttl); - - /* show_age_timeout might be negative */ - if (min_timeout < 1) { - return 1; - } else { - return min_timeout; - } + return sleep; } gboolean run(void *data) { update_lists(); static int timeout_cnt = 0; - static int next_timeout = 0; + static gint64 next_timeout = 0; if (data) { timeout_cnt--; @@ -234,13 +221,13 @@ gboolean run(void *data) } if (xctx.visible) { - int now = time(NULL); - int sleep = get_sleep_time(); + gint64 now = g_get_monotonic_time(); + gint64 sleep = get_sleep_time(); + gint64 timeout_at = now + sleep; if (sleep > 0) { - int timeout_at = now + sleep; if (timeout_cnt == 0 || timeout_at < next_timeout) { - g_timeout_add_seconds(sleep, run, mainloop); + g_timeout_add(sleep/1000, run, mainloop); next_timeout = timeout_at; timeout_cnt++; } diff --git a/src/notification.c b/src/notification.c index 6d9a8c0..7e77f9a 100644 --- a/src/notification.c +++ b/src/notification.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include @@ -39,7 +38,7 @@ void notification_print(notification *n) printf("\ticon: '%s'\n", n->icon); printf("\traw_icon set: %s\n", (n->raw_icon ? "true" : "false")); printf("\tcategory: %s\n", n->category); - printf("\ttimeout: %d\n", n->timeout); + printf("\ttimeout: %ld\n", n->timeout/1000); printf("\turgency: %d\n", n->urgency); printf("\ttransient: %d\n", n->transient); printf("\tformatted: '%s'\n", n->msg); @@ -478,7 +477,7 @@ int notification_init(notification *n, int id) } else { orig->progress = n->progress; } - orig->start = time(NULL); + orig->start = g_get_monotonic_time(); notification_free(n); wake_up(); return orig->id; @@ -502,10 +501,10 @@ int notification_init(notification *n, int id) } n->timeout = - n->timeout == -1 ? settings.timeouts[n->urgency] : n->timeout; + n->timeout < 0 ? settings.timeouts[n->urgency] : n->timeout; n->start = 0; - n->timestamp = time(NULL); + n->timestamp = g_get_monotonic_time(); n->redisplayed = false; @@ -671,26 +670,26 @@ void notification_update_text_to_render(notification *n) } /* print age */ - int hours, minutes, seconds; - time_t t_delta = time(NULL) - n->timestamp; + gint64 hours, minutes, seconds; + gint64 t_delta = g_get_monotonic_time() - n->timestamp; if (settings.show_age_threshold >= 0 && t_delta >= settings.show_age_threshold) { - hours = t_delta / 3600; - minutes = t_delta / 60 % 60; - seconds = t_delta % 60; + hours = t_delta / G_USEC_PER_SEC / 3600; + minutes = t_delta / G_USEC_PER_SEC / 60 % 60; + seconds = t_delta / G_USEC_PER_SEC % 60; char *new_buf; if (hours > 0) { new_buf = - g_strdup_printf("%s (%dh %dm %ds old)", buf, hours, + g_strdup_printf("%s (%ldh %ldm %lds old)", buf, hours, minutes, seconds); } else if (minutes > 0) { new_buf = - g_strdup_printf("%s (%dm %ds old)", buf, minutes, + g_strdup_printf("%s (%ldm %lds old)", buf, minutes, seconds); } else { - new_buf = g_strdup_printf("%s (%ds old)", buf, seconds); + new_buf = g_strdup_printf("%s (%lds old)", buf, seconds); } g_free(buf); @@ -700,16 +699,16 @@ void notification_update_text_to_render(notification *n) n->text_to_render = buf; } -int notification_get_ttl(notification *n) { - if (n->timeout == 0) { +gint64 notification_get_ttl(notification *n) { + if (n->timeout < 0) { return -1; } else { - return n->timeout - (time(NULL) - n->start); + return n->timeout - (g_get_monotonic_time() - n->start); } } -int notification_get_age(notification *n) { - return time(NULL) - n->timestamp; +gint64 notification_get_age(notification *n) { + return g_get_monotonic_time() - n->timestamp; } /* diff --git a/src/notification.h b/src/notification.h index a76b19d..befb9ce 100644 --- a/src/notification.h +++ b/src/notification.h @@ -4,7 +4,6 @@ #include #include -#include #include "settings.h" @@ -42,9 +41,9 @@ typedef struct _notification { char *text_to_render; const char *format; char *dbus_client; - time_t start; - time_t timestamp; - int timeout; + gint64 start; + gint64 timestamp; + gint64 timeout; int urgency; enum markup_mode markup; bool redisplayed; /* has been displayed before? */ @@ -75,8 +74,8 @@ int notification_close(notification *n, int reason); void notification_print(notification *n); void notification_replace_single_field(char **haystack, char **needle, const char *replacement, enum markup_mode markup_mode); void notification_update_text_to_render(notification *n); -int notification_get_ttl(notification *n); -int notification_get_age(notification *n); +gint64 notification_get_ttl(notification *n); +gint64 notification_get_age(notification *n); void notification_do_action(notification *n); #endif diff --git a/src/rules.h b/src/rules.h index b692b98..a813d98 100644 --- a/src/rules.h +++ b/src/rules.h @@ -19,7 +19,7 @@ typedef struct _rule_t { int msg_urgency; /* actions */ - int timeout; + gint64 timeout; int urgency; enum markup_mode markup; int history_ignore; diff --git a/src/settings.c b/src/settings.c index cee42e0..e81221b 100644 --- a/src/settings.c +++ b/src/settings.c @@ -197,7 +197,7 @@ void load_settings(char *cmdline_config_path) "Ignore newline characters in notifications" ); - settings.idle_threshold = option_get_int( + settings.idle_threshold = G_USEC_PER_SEC * option_get_int( "global", "idle_threshold", "-idle_threshold", idle_threshold, "Don't timeout notifications if user is longer idle than threshold" @@ -279,7 +279,7 @@ void load_settings(char *cmdline_config_path) } } - settings.show_age_threshold = option_get_int( + settings.show_age_threshold = G_USEC_PER_SEC * option_get_int( "global", "show_age_threshold", "-show_age_threshold", show_age_threshold, "When should the age of the notification be displayed?" @@ -490,7 +490,7 @@ void load_settings(char *cmdline_config_path) "Frame color for notifications with low urgency" ); - settings.timeouts[LOW] = option_get_int( + settings.timeouts[LOW] = G_USEC_PER_SEC * option_get_int( "urgency_low", "timeout", "-lto", timeouts[LOW], "Timeout for notifications with low urgency" @@ -520,7 +520,7 @@ void load_settings(char *cmdline_config_path) "Frame color for notifications with normal urgency" ); - settings.timeouts[NORM] = option_get_int( + settings.timeouts[NORM] = G_USEC_PER_SEC * option_get_int( "urgency_normal", "timeout", "-nto", timeouts[NORM], "Timeout for notifications with normal urgency" @@ -550,7 +550,7 @@ void load_settings(char *cmdline_config_path) "Frame color for notifications with critical urgency" ); - settings.timeouts[CRIT] = option_get_int( + settings.timeouts[CRIT] = G_USEC_PER_SEC * option_get_int( "urgency_critical", "timeout", "-cto", timeouts[CRIT], "Timeout for notifications with critical urgency" @@ -637,7 +637,7 @@ void load_settings(char *cmdline_config_path) r->body = ini_get_string(cur_section, "body", r->body); r->icon = ini_get_string(cur_section, "icon", r->icon); r->category = ini_get_string(cur_section, "category", r->category); - r->timeout = ini_get_int(cur_section, "timeout", r->timeout); + r->timeout = G_USEC_PER_SEC * ini_get_int(cur_section, "timeout", r->timeout); { char *c = ini_get_string( diff --git a/src/settings.h b/src/settings.h index 337b2d7..0577f42 100644 --- a/src/settings.h +++ b/src/settings.h @@ -30,7 +30,7 @@ typedef struct _settings { char *lowfgcolor; char *lowframecolor; char *format; - int timeouts[3]; + gint64 timeouts[3]; char *icons[3]; unsigned int transparency; char *geom; @@ -39,8 +39,8 @@ typedef struct _settings { int shrink; int sort; int indicate_hidden; - int idle_threshold; - int show_age_threshold; + gint64 idle_threshold; + gint64 show_age_threshold; enum alignment align; int sticky_history; int history_length; diff --git a/src/x11/x.c b/src/x11/x.c index b8a98b8..45dae1c 100644 --- a/src/x11/x.c +++ b/src/x11/x.c @@ -900,7 +900,7 @@ bool x_is_idle(void) if (settings.idle_threshold == 0) { return false; } - return xctx.screensaver_info->idle / 1000 > settings.idle_threshold; + return xctx.screensaver_info->idle > settings.idle_threshold / 1000; } /* TODO move to x_mainloop_* */