1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
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;
}
|