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).
This commit is contained in:
Benedikt Heine 2017-09-17 01:26:53 +02:00
parent 7a02d8e48a
commit 956b5c6401
9 changed files with 58 additions and 81 deletions

View File

@ -10,7 +10,7 @@ char *lowbgcolor = "#aaaaff";
char *lowfgcolor = "#000000"; char *lowfgcolor = "#000000";
char *format = "%s %b"; /* default format */ 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 */ char *icons[] = { "dialog-information", "dialog-information", "dialog-warning" }; /* low, normal, critical */
unsigned int transparency = 0; /* transparency */ unsigned int transparency = 0; /* transparency */
@ -20,8 +20,8 @@ char *class = "Dunst"; /* the class of dunst notification windows */
int shrink = false; /* shrinking */ int shrink = false; /* shrinking */
int sort = true; /* sort messages by urgency */ int sort = true; /* sort messages by urgency */
int indicate_hidden = true; /* show count of hidden messages */ int indicate_hidden = true; /* show count of hidden messages */
int idle_threshold = 0; /* don't timeout notifications when idle for x seconds */ gint64 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 show_age_threshold = -1; /* show age of notification, when notification is older than x seconds */
enum alignment align = left; /* text alignment [left/center/right] */ enum alignment align = left; /* text alignment [left/center/right] */
int sticky_history = true; int sticky_history = true;
int history_length = 20; /* max amount of notifications kept in history */ int history_length = 20; /* max amount of notifications kept in history */

View File

@ -236,21 +236,13 @@ static void on_notify(GDBusConnection *connection,
fflush(stdout); fflush(stdout);
if (timeout > 0) {
/* do some rounding */
timeout = (timeout + 500) / 1000;
if (timeout < 1) {
timeout = 1;
}
}
notification *n = notification_create(); notification *n = notification_create();
n->appname = appname; n->appname = appname;
n->summary = summary; n->summary = summary;
n->body = body; n->body = body;
n->icon = icon; n->icon = icon;
n->raw_icon = raw_icon; n->raw_icon = raw_icon;
n->timeout = timeout; n->timeout = timeout < 0 ? -1 : timeout * 1000;
n->markup = settings.markup; n->markup = settings.markup;
n->progress = (progress < 0 || progress > 100) ? 0 : progress + 1; n->progress = (progress < 0 || progress > 100) ? 0 : progress + 1;
n->urgency = urgency; n->urgency = urgency;

View File

@ -12,7 +12,6 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <time.h>
#include "dbus.h" #include "dbus.h"
#include "menu.h" #include "menu.h"
@ -70,7 +69,7 @@ void check_timeouts(void)
/* don't timeout when user is idle */ /* don't timeout when user is idle */
if (x_is_idle() && !n->transient) { if (x_is_idle() && !n->transient) {
n->start = time(NULL); n->start = g_get_monotonic_time();
continue; continue;
} }
@ -80,7 +79,7 @@ void check_timeouts(void)
} }
/* remove old message */ /* remove old message */
if (difftime(time(NULL), n->start) > n->timeout) { if (g_get_monotonic_time() - n->start > n->timeout) {
notification_close(n, 1); notification_close(n, 1);
} }
} }
@ -122,7 +121,7 @@ void update_lists()
if (!n) if (!n)
return; return;
n->start = time(NULL); n->start = g_get_monotonic_time();
if (!n->redisplayed && n->script) { if (!n->redisplayed && n->script) {
notification_run_script(n); notification_run_script(n);
} }
@ -173,49 +172,37 @@ void wake_up(void)
run(NULL); run(NULL);
} }
static int get_sleep_time(void) static gint64 get_sleep_time(void)
{ {
gint64 sleep = G_MAXINT64;
if (settings.show_age_threshold == 0) { gint64 max_age = 0;
/* we need to update every second */
return 1;
}
int min_ttl = INT_MAX;
int max_age = 0;
for (GList *iter = g_queue_peek_head_link(displayed); iter; for (GList *iter = g_queue_peek_head_link(displayed); iter;
iter = iter->next) { iter = iter->next) {
notification *n = iter->data; notification *n = iter->data;
max_age = MAX(max_age, notification_get_age(n)); max_age = MAX(max_age, notification_get_age(n));
int ttl = notification_get_ttl(n); gint64 ttl = notification_get_ttl(n);
if (ttl >= 0) { if (ttl >= 0)
min_ttl = MIN(min_ttl, ttl); sleep = MIN(sleep, ttl);
}
} }
int min_timeout; /* if age_threshold is hit, seconds have to get updated every second */
int show_age_timeout = settings.show_age_threshold - max_age; if (settings.show_age_threshold >= 0) {
if (settings.show_age_threshold > max_age)
if (show_age_timeout < 1) { sleep = MIN(sleep, settings.show_age_threshold - max_age);
return 1; else
sleep = MIN(sleep, 1000*1000);
} }
min_timeout = MIN(show_age_timeout, min_ttl); return sleep;
/* show_age_timeout might be negative */
if (min_timeout < 1) {
return 1;
} else {
return min_timeout;
}
} }
gboolean run(void *data) gboolean run(void *data)
{ {
update_lists(); update_lists();
static int timeout_cnt = 0; static int timeout_cnt = 0;
static int next_timeout = 0; static gint64 next_timeout = 0;
if (data) { if (data) {
timeout_cnt--; timeout_cnt--;
@ -234,13 +221,13 @@ gboolean run(void *data)
} }
if (xctx.visible) { if (xctx.visible) {
int now = time(NULL); gint64 now = g_get_monotonic_time();
int sleep = get_sleep_time(); gint64 sleep = get_sleep_time();
gint64 timeout_at = now + sleep;
if (sleep > 0) { if (sleep > 0) {
int timeout_at = now + sleep;
if (timeout_cnt == 0 || timeout_at < next_timeout) { 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; next_timeout = timeout_at;
timeout_cnt++; timeout_cnt++;
} }

View File

@ -11,7 +11,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <time.h>
#include <unistd.h> #include <unistd.h>
#include <libgen.h> #include <libgen.h>
@ -39,7 +38,7 @@ void notification_print(notification *n)
printf("\ticon: '%s'\n", n->icon); printf("\ticon: '%s'\n", n->icon);
printf("\traw_icon set: %s\n", (n->raw_icon ? "true" : "false")); printf("\traw_icon set: %s\n", (n->raw_icon ? "true" : "false"));
printf("\tcategory: %s\n", n->category); 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("\turgency: %d\n", n->urgency);
printf("\ttransient: %d\n", n->transient); printf("\ttransient: %d\n", n->transient);
printf("\tformatted: '%s'\n", n->msg); printf("\tformatted: '%s'\n", n->msg);
@ -478,7 +477,7 @@ int notification_init(notification *n, int id)
} else { } else {
orig->progress = n->progress; orig->progress = n->progress;
} }
orig->start = time(NULL); orig->start = g_get_monotonic_time();
notification_free(n); notification_free(n);
wake_up(); wake_up();
return orig->id; return orig->id;
@ -502,10 +501,10 @@ int notification_init(notification *n, int id)
} }
n->timeout = n->timeout =
n->timeout == -1 ? settings.timeouts[n->urgency] : n->timeout; n->timeout < 0 ? settings.timeouts[n->urgency] : n->timeout;
n->start = 0; n->start = 0;
n->timestamp = time(NULL); n->timestamp = g_get_monotonic_time();
n->redisplayed = false; n->redisplayed = false;
@ -671,26 +670,26 @@ void notification_update_text_to_render(notification *n)
} }
/* print age */ /* print age */
int hours, minutes, seconds; gint64 hours, minutes, seconds;
time_t t_delta = time(NULL) - n->timestamp; gint64 t_delta = g_get_monotonic_time() - n->timestamp;
if (settings.show_age_threshold >= 0 if (settings.show_age_threshold >= 0
&& t_delta >= settings.show_age_threshold) { && t_delta >= settings.show_age_threshold) {
hours = t_delta / 3600; hours = t_delta / G_USEC_PER_SEC / 3600;
minutes = t_delta / 60 % 60; minutes = t_delta / G_USEC_PER_SEC / 60 % 60;
seconds = t_delta % 60; seconds = t_delta / G_USEC_PER_SEC % 60;
char *new_buf; char *new_buf;
if (hours > 0) { if (hours > 0) {
new_buf = new_buf =
g_strdup_printf("%s (%dh %dm %ds old)", buf, hours, g_strdup_printf("%s (%ldh %ldm %lds old)", buf, hours,
minutes, seconds); minutes, seconds);
} else if (minutes > 0) { } else if (minutes > 0) {
new_buf = new_buf =
g_strdup_printf("%s (%dm %ds old)", buf, minutes, g_strdup_printf("%s (%ldm %lds old)", buf, minutes,
seconds); seconds);
} else { } else {
new_buf = g_strdup_printf("%s (%ds old)", buf, seconds); new_buf = g_strdup_printf("%s (%lds old)", buf, seconds);
} }
g_free(buf); g_free(buf);
@ -700,16 +699,16 @@ void notification_update_text_to_render(notification *n)
n->text_to_render = buf; n->text_to_render = buf;
} }
int notification_get_ttl(notification *n) { gint64 notification_get_ttl(notification *n) {
if (n->timeout == 0) { if (n->timeout < 0) {
return -1; return -1;
} else { } else {
return n->timeout - (time(NULL) - n->start); return n->timeout - (g_get_monotonic_time() - n->start);
} }
} }
int notification_get_age(notification *n) { gint64 notification_get_age(notification *n) {
return time(NULL) - n->timestamp; return g_get_monotonic_time() - n->timestamp;
} }
/* /*

View File

@ -4,7 +4,6 @@
#include <glib.h> #include <glib.h>
#include <stdbool.h> #include <stdbool.h>
#include <time.h>
#include "settings.h" #include "settings.h"
@ -42,9 +41,9 @@ typedef struct _notification {
char *text_to_render; char *text_to_render;
const char *format; const char *format;
char *dbus_client; char *dbus_client;
time_t start; gint64 start;
time_t timestamp; gint64 timestamp;
int timeout; gint64 timeout;
int urgency; int urgency;
enum markup_mode markup; enum markup_mode markup;
bool redisplayed; /* has been displayed before? */ bool redisplayed; /* has been displayed before? */
@ -75,8 +74,8 @@ int notification_close(notification *n, int reason);
void notification_print(notification *n); void notification_print(notification *n);
void notification_replace_single_field(char **haystack, char **needle, const char *replacement, enum markup_mode markup_mode); 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); void notification_update_text_to_render(notification *n);
int notification_get_ttl(notification *n); gint64 notification_get_ttl(notification *n);
int notification_get_age(notification *n); gint64 notification_get_age(notification *n);
void notification_do_action(notification *n); void notification_do_action(notification *n);
#endif #endif

View File

@ -19,7 +19,7 @@ typedef struct _rule_t {
int msg_urgency; int msg_urgency;
/* actions */ /* actions */
int timeout; gint64 timeout;
int urgency; int urgency;
enum markup_mode markup; enum markup_mode markup;
int history_ignore; int history_ignore;

View File

@ -197,7 +197,7 @@ void load_settings(char *cmdline_config_path)
"Ignore newline characters in notifications" "Ignore newline characters in notifications"
); );
settings.idle_threshold = option_get_int( settings.idle_threshold = G_USEC_PER_SEC * option_get_int(
"global", "global",
"idle_threshold", "-idle_threshold", idle_threshold, "idle_threshold", "-idle_threshold", idle_threshold,
"Don't timeout notifications if user is longer idle than 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", "global",
"show_age_threshold", "-show_age_threshold", show_age_threshold, "show_age_threshold", "-show_age_threshold", show_age_threshold,
"When should the age of the notification be displayed?" "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" "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", "urgency_low",
"timeout", "-lto", timeouts[LOW], "timeout", "-lto", timeouts[LOW],
"Timeout for notifications with low urgency" "Timeout for notifications with low urgency"
@ -520,7 +520,7 @@ void load_settings(char *cmdline_config_path)
"Frame color for notifications with normal urgency" "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", "urgency_normal",
"timeout", "-nto", timeouts[NORM], "timeout", "-nto", timeouts[NORM],
"Timeout for notifications with normal urgency" "Timeout for notifications with normal urgency"
@ -550,7 +550,7 @@ void load_settings(char *cmdline_config_path)
"Frame color for notifications with critical urgency" "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", "urgency_critical",
"timeout", "-cto", timeouts[CRIT], "timeout", "-cto", timeouts[CRIT],
"Timeout for notifications with critical urgency" "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->body = ini_get_string(cur_section, "body", r->body);
r->icon = ini_get_string(cur_section, "icon", r->icon); r->icon = ini_get_string(cur_section, "icon", r->icon);
r->category = ini_get_string(cur_section, "category", r->category); 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( char *c = ini_get_string(

View File

@ -30,7 +30,7 @@ typedef struct _settings {
char *lowfgcolor; char *lowfgcolor;
char *lowframecolor; char *lowframecolor;
char *format; char *format;
int timeouts[3]; gint64 timeouts[3];
char *icons[3]; char *icons[3];
unsigned int transparency; unsigned int transparency;
char *geom; char *geom;
@ -39,8 +39,8 @@ typedef struct _settings {
int shrink; int shrink;
int sort; int sort;
int indicate_hidden; int indicate_hidden;
int idle_threshold; gint64 idle_threshold;
int show_age_threshold; gint64 show_age_threshold;
enum alignment align; enum alignment align;
int sticky_history; int sticky_history;
int history_length; int history_length;

View File

@ -900,7 +900,7 @@ bool x_is_idle(void)
if (settings.idle_threshold == 0) { if (settings.idle_threshold == 0) {
return false; 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_* */ /* TODO move to x_mainloop_* */