#include #include #include #include #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; }