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 *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 */

View File

@ -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;

View File

@ -12,7 +12,6 @@
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#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++;
}

View File

@ -11,7 +11,6 @@
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
#include <libgen.h>
@ -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;
}
/*

View File

@ -4,7 +4,6 @@
#include <glib.h>
#include <stdbool.h>
#include <time.h>
#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

View File

@ -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;

View File

@ -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(

View File

@ -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;

View File

@ -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_* */