summaryrefslogtreecommitdiff
path: root/ecp/server/timer.c
diff options
context:
space:
mode:
Diffstat (limited to 'ecp/server/timer.c')
-rw-r--r--ecp/server/timer.c98
1 files changed, 98 insertions, 0 deletions
diff --git a/ecp/server/timer.c b/ecp/server/timer.c
new file mode 100644
index 0000000..ab30633
--- /dev/null
+++ b/ecp/server/timer.c
@@ -0,0 +1,98 @@
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+
+#include <ecp/core.h>
+
+#include "dir.h"
+
+#include "server.h"
+#include "timer.h"
+
+static struct timespec timer_ts_mono;
+static timer_t timer_ann_block_id;
+static timer_t timer_online_switch_id;
+
+int timer_set_next(time_t tv_now) {
+ struct itimerspec its = { 0 };
+ time_t tv_midnight;
+ int rv = 0;
+
+ /* next midnight */
+ tv_midnight = (tv_now / ONLINE_SWITCH_PERIOD) * ONLINE_SWITCH_PERIOD + ONLINE_SWITCH_PERIOD;
+
+ if (tv_now < (tv_midnight - ANN_BLOCK_TIME)) {
+ dir_announce_allow();
+
+ its.it_value.tv_sec = tv_midnight - ANN_BLOCK_TIME;
+ rv = timer_settime(timer_ann_block_id, TIMER_ABSTIME, &its, NULL);
+ if (rv) return ECP_ERR;
+ } else {
+ dir_announce_block();
+ }
+
+ its.it_value.tv_sec = tv_midnight;
+ rv = timer_settime(timer_online_switch_id, TIMER_ABSTIME, &its, NULL);
+ if (rv) return ECP_ERR;
+
+ return ECP_OK;
+}
+
+void timer_ann_block(union sigval timer_data) {
+ dir_announce_block();
+}
+
+void timer_online_switch(union sigval timer_data) {
+ ECPSocket *sock = timer_data.sival_ptr;
+ struct timespec ts_prev;
+ int rv;
+
+ ts_prev = timer_ts_mono;
+ clock_gettime(CLOCK_MONOTONIC, &timer_ts_mono);
+
+ /* exit if someone is messing with realtime clock */
+ if ((timer_ts_mono.tv_sec - ts_prev.tv_sec) < (ONLINE_SWITCH_PERIOD / 2)) goto online_switch_fin;
+
+ dir_online_switch(sock, 1);
+
+online_switch_fin:
+ rv = timer_set_next(time(NULL));
+ if (rv) LOG(LOG_ERR, "timer_online_switch: set next timer err:%d\n", rv);
+}
+
+int timer_init(ECPSocket *sock) {
+ struct sigevent timer_ann_block_evt = { 0 };
+ struct sigevent timer_online_switch_evt = { 0 };
+ time_t tv_now;
+ int rv = 0;
+
+ timer_ann_block_evt.sigev_notify = SIGEV_THREAD;
+ timer_ann_block_evt.sigev_notify_function = timer_ann_block;
+ timer_ann_block_evt.sigev_value.sival_ptr = NULL;
+ rv = timer_create(CLOCK_REALTIME, &timer_ann_block_evt, &timer_ann_block_id);
+ if (rv) return ECP_ERR;
+
+ timer_online_switch_evt.sigev_notify = SIGEV_THREAD;
+ timer_online_switch_evt.sigev_notify_function = timer_online_switch;
+ timer_online_switch_evt.sigev_value.sival_ptr = sock;
+ rv = timer_create(CLOCK_REALTIME, &timer_online_switch_evt, &timer_online_switch_id);
+ if (rv) {
+ timer_delete(timer_ann_block_id);
+ return ECP_ERR;
+ }
+
+ /* ensure that first dir_online_switch is executed */
+ clock_gettime(CLOCK_MONOTONIC, &timer_ts_mono);
+ timer_ts_mono.tv_sec -= ONLINE_SWITCH_PERIOD / 2;
+
+ tv_now = time(NULL);
+ dit_init_serial(tv_now / ONLINE_SWITCH_PERIOD);
+ rv = timer_set_next(tv_now);
+ if (rv) {
+ timer_delete(timer_ann_block_id);
+ timer_delete(timer_online_switch_id);
+ return rv;
+ }
+
+ return ECP_OK;
+}