source: ogServer-Git/sources/schedule.c @ 16e45fa

Last change on this file since 16e45fa was a63ec0b, checked in by OpenGnSys Support Team <soporte-og@…>, 4 years ago

#942 Fix immediate procedures

New versions of ogAdmServer handle pending commands in a different way.
Instant procedures uses the old way, now unsupported, so we need to
adapt instant procedures.

This commit adapts instant procedures to work with the new pending
commands implementation.

  • Property mode set to 100644
File size: 9.9 KB
Line 
1#include "schedule.h"
2#include "list.h"
3#include <sys/types.h>
4#include <stdbool.h>
5#include <stdint.h>
6#include <stdlib.h>
7#include <syslog.h>
8#include <time.h>
9#include <ev.h>
10
11struct og_schedule *current_schedule = NULL;
12static LIST_HEAD(schedule_list);
13
14static void og_schedule_add(struct og_schedule *new)
15{
16        struct og_schedule *schedule, *next;
17
18        list_for_each_entry_safe(schedule, next, &schedule_list, list) {
19                if (new->seconds < schedule->seconds) {
20                        list_add_tail(&new->list, &schedule->list);
21                        return;
22                }
23        }
24        list_add_tail(&new->list, &schedule_list);
25}
26
27/* Returns the days in a month from the weekday. */
28static void get_days_from_weekday(struct tm *tm, int wday, int *days, int *j)
29{
30        int i, mday = 0;
31
32        tm->tm_mday = 1;
33
34        //Shift week to start on Sunday instead of Monday
35        if (wday == 6)
36                wday = 0;
37        else
38                wday++;
39
40        /* A bit bruteforce, but simple. */
41        for (i = 0; i <= 30; i++) {
42                mktime(tm);
43                /* Not this weekday, skip. */
44                if (tm->tm_wday != wday) {
45                        tm->tm_mday++;
46                        continue;
47                }
48                /* Not interested in next month. */
49                if (tm->tm_mday < mday)
50                        break;
51
52                /* Found a matching. */
53                mday = tm->tm_mday;
54                days[(*j)++] = tm->tm_mday;
55                tm->tm_mday++;
56        }
57}
58
59/* Returns the days in the given week. */
60static void get_days_from_week(struct tm *tm, int week, int *days, int *k)
61{
62        int i, j, week_counter = 0;
63        bool week_over = false;
64
65        tm->tm_mday = 1;
66
67        /* Remaining days of this month. */
68        for (i = 0; i <= 30; i++) {
69                mktime(tm);
70
71                /* Last day of this week? */
72                if (tm->tm_wday == 6)
73                        week_over = true;
74
75                /* Not the week we are searching for. */
76                if (week != week_counter) {
77                        tm->tm_mday++;
78                        if (week_over) {
79                                week_counter++;
80                                week_over = false;
81                        }
82                        continue;
83                }
84
85                /* Found matching. */
86                for (j = tm->tm_wday; j <= 6; j++) {
87                        days[(*k)++] = tm->tm_mday++;
88                        mktime(tm);
89                }
90                break;
91        }
92}
93
94static int monthdays[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
95
96static int last_month_day(struct tm *tm)
97{
98        /* Leap year? Adjust it. */
99        if (tm->tm_mon == 1) {
100                tm->tm_mday = 29;
101                mktime(tm);
102                if (tm->tm_mday == 29)
103                        return 29;
104
105                tm->tm_mon = 1;
106        }
107
108        return monthdays[tm->tm_mon];
109}
110
111/* Returns the days in the given week. */
112static void get_last_week(struct tm *tm, int *days, int *j)
113{
114        int i, last_day;
115
116        last_day = last_month_day(tm);
117        tm->tm_mday = last_day;
118
119        for (i = last_day; i >= last_day - 6; i--) {
120                mktime(tm);
121
122                days[(*j)++] = tm->tm_mday;
123
124
125                /* Last day of this week? */
126                if (tm->tm_wday == 1)
127                        break;
128
129                tm->tm_mday--;
130        }
131}
132
133static void og_parse_years(uint16_t years_mask, int years[])
134{
135        int i, j = 0;
136
137        for (i = 0; i < 16; i++) {
138                if ((1 << i) & years_mask)
139                        years[j++] = 2010 + i - 1900;
140        }
141}
142
143static void og_parse_months(uint16_t months_mask, int months[])
144{
145        int i, j = 0;
146
147        for (i = 0; i < 12; i++) {
148                if ((1 << i) & months_mask)
149                        months[j++] = i + 1;
150        }
151}
152
153static void og_parse_days(uint32_t days_mask, int *days)
154{
155        int i, j = 0;
156
157        for (i = 0; i < 31; i++) {
158                if ((1 << i) & days_mask)
159                        days[j++] = i + 1;
160        }
161}
162
163static void og_parse_hours(uint16_t hours_mask, uint8_t am_pm, int hours[])
164{
165        int pm = 12 * am_pm;
166        int i, j = 0;
167
168        for (i = 0; i < 12; i++) {
169                if ((1 << i) & hours_mask)
170                        hours[j++] = i + pm + 1;
171        }
172}
173
174static void og_schedule_remove_duplicates()
175{
176        struct og_schedule *schedule, *next, *prev = NULL;
177
178        list_for_each_entry_safe(schedule, next, &schedule_list, list) {
179                if (!prev) {
180                        prev = schedule;
181                        continue;
182                }
183                if (prev->seconds == schedule->seconds &&
184                    prev->task_id == schedule->task_id) {
185                        list_del(&prev->list);
186                        free(prev);
187                }
188                prev = schedule;
189        }
190}
191
192static bool og_schedule_stale(time_t seconds)
193{
194        time_t now;
195
196        now = time(NULL);
197        if (seconds < now)
198                return true;
199
200        return false;
201}
202
203static void og_schedule_create_weekdays(int month, int year,
204                                        int *hours, int minutes, int week_days,
205                                        uint32_t task_id, uint32_t schedule_id,
206                                        enum og_schedule_type type,
207                                        bool on_start)
208{
209        struct og_schedule *schedule;
210        int month_days[5];
211        int n_month_days;
212        time_t seconds;
213        uint32_t wday;
214        struct tm tm;
215        int k, l;
216
217        for (wday = 0; wday < 7; wday++) {
218                if (!((1 << wday) & week_days))
219                        continue;
220
221                memset(&tm, 0, sizeof(tm));
222                tm.tm_mon = month;
223                tm.tm_year = year;
224
225                n_month_days = 0;
226                memset(month_days, 0, sizeof(month_days));
227                get_days_from_weekday(&tm, wday, month_days, &n_month_days);
228
229                for (k = 0; month_days[k] != 0 && k < n_month_days; k++) {
230                        for (l = 0; hours[l] != 0 && l < 31; l++) {
231                                memset(&tm, 0, sizeof(tm));
232                                tm.tm_year = year;
233                                tm.tm_mon = month;
234                                tm.tm_mday = month_days[k];
235                                tm.tm_hour = hours[l] - 1;
236                                tm.tm_min = minutes;
237                                seconds = mktime(&tm);
238
239                                if (on_start && og_schedule_stale(seconds))
240                                        continue;
241
242                                schedule = (struct og_schedule *)
243                                        calloc(1, sizeof(struct og_schedule));
244                                if (!schedule)
245                                        return;
246
247                                schedule->seconds = seconds;
248                                schedule->task_id = task_id;
249                                schedule->schedule_id = schedule_id;
250                                schedule->type = type;
251                                og_schedule_add(schedule);
252                        }
253                }
254        }
255}
256
257static void og_schedule_create_weeks(int month, int year,
258                                     int *hours, int minutes, int weeks,
259                                     uint32_t task_id, uint32_t schedule_id,
260                                     enum og_schedule_type type, bool on_start)
261{
262        struct og_schedule *schedule;
263        int month_days[7];
264        int n_month_days;
265        time_t seconds;
266        struct tm tm;
267        int week;
268        int k, l;
269
270        for (week = 0; week < 5; week++) {
271                if (!((1 << week) & weeks))
272                        continue;
273
274                memset(&tm, 0, sizeof(tm));
275                tm.tm_mon = month;
276                tm.tm_year = year;
277
278                n_month_days = 0;
279                memset(month_days, 0, sizeof(month_days));
280                if (week == 5)
281                        get_last_week(&tm, month_days, &n_month_days);
282                else
283                        get_days_from_week(&tm,  week, month_days, &n_month_days);
284
285                for (k = 0; month_days[k] != 0 && k < n_month_days; k++) {
286                        for (l = 0; hours[l] != 0 && l < 31; l++) {
287                                memset(&tm, 0, sizeof(tm));
288                                tm.tm_year = year;
289                                tm.tm_mon = month;
290                                tm.tm_mday = month_days[k];
291                                tm.tm_hour = hours[l] - 1;
292                                tm.tm_min = minutes;
293                                seconds = mktime(&tm);
294
295                                if (on_start && og_schedule_stale(seconds))
296                                        continue;
297
298                                schedule = (struct og_schedule *)
299                                        calloc(1, sizeof(struct og_schedule));
300                                if (!schedule)
301                                        return;
302
303                                schedule->seconds = seconds;
304                                schedule->task_id = task_id;
305                                schedule->schedule_id = schedule_id;
306                                schedule->type = type;
307                                og_schedule_add(schedule);
308                        }
309                }
310        }
311}
312
313static void og_schedule_create_days(int month, int year,
314                                    int *hours, int minutes, int *days,
315                                    uint32_t task_id, uint32_t schedule_id,
316                                    enum og_schedule_type type, bool on_start)
317{
318        struct og_schedule *schedule;
319        time_t seconds;
320        struct tm tm;
321        int k, l;
322
323        for (k = 0; days[k] != 0 && k < 31; k++) {
324                for (l = 0; hours[l] != 0 && l < 31; l++) {
325
326                        memset(&tm, 0, sizeof(tm));
327                        tm.tm_year = year;
328                        tm.tm_mon = month;
329                        tm.tm_mday = days[k];
330                        tm.tm_hour = hours[l] - 1;
331                        tm.tm_min = minutes;
332                        seconds = mktime(&tm);
333
334                        if (on_start && og_schedule_stale(seconds))
335                                continue;
336
337                        schedule = (struct og_schedule *)
338                                calloc(1, sizeof(struct og_schedule));
339                        if (!schedule)
340                                return;
341
342                        schedule->seconds = seconds;
343                        schedule->task_id = task_id;
344                        schedule->schedule_id = schedule_id;
345                        schedule->type = type;
346                        og_schedule_add(schedule);
347                }
348        }
349}
350
351void og_schedule_create(unsigned int schedule_id, unsigned int task_id,
352                        enum og_schedule_type type,
353                        struct og_schedule_time *time)
354{
355        int year, month, minutes;
356        int months[12] = {};
357        int years[12] = {};
358        int hours[12] = {};
359        int days[31] = {};
360        int i, j;
361
362        og_parse_years(time->years, years);
363        og_parse_months(time->months, months);
364        og_parse_days(time->days, days);
365        og_parse_hours(time->hours, time->am_pm, hours);
366        minutes = time->minutes;
367
368        for (i = 0; years[i] != 0 && i < 12; i++) {
369                for (j = 0; months[j] != 0 && j < 12; j++) {
370                        month = months[j] - 1;
371                        year = years[i];
372
373                        if (time->week_days)
374                                og_schedule_create_weekdays(month, year,
375                                                            hours, minutes,
376                                                            time->week_days,
377                                                            task_id,
378                                                            schedule_id,
379                                                            type,
380                                                            time->on_start);
381
382                        if (time->weeks)
383                                og_schedule_create_weeks(month, year,
384                                                         hours, minutes,
385                                                         time->weeks,
386                                                         task_id,
387                                                         schedule_id,
388                                                         type, time->on_start);
389
390                        if (time->days)
391                                og_schedule_create_days(month, year,
392                                                        hours, minutes,
393                                                        days,
394                                                        task_id,
395                                                        schedule_id,
396                                                        type, time->on_start);
397                }
398        }
399
400        og_schedule_remove_duplicates();
401}
402
403void og_schedule_delete(struct ev_loop *loop, uint32_t schedule_id)
404{
405        struct og_schedule *schedule, *next;
406
407        list_for_each_entry_safe(schedule, next, &schedule_list, list) {
408                if (schedule->schedule_id != schedule_id)
409                        continue;
410
411                list_del(&schedule->list);
412                if (current_schedule == schedule) {
413                        ev_timer_stop(loop, &schedule->timer);
414                        current_schedule = NULL;
415                        og_schedule_refresh(loop);
416                }
417                free(schedule);
418        }
419}
420
421void og_schedule_update(struct ev_loop *loop, unsigned int schedule_id,
422                        unsigned int task_id, struct og_schedule_time *time)
423{
424        og_schedule_delete(loop, schedule_id);
425        og_schedule_create(schedule_id, task_id, OG_SCHEDULE_TASK, time);
426}
427
428static void og_agent_timer_cb(struct ev_loop *loop, ev_timer *timer, int events)
429{
430        struct og_schedule *current;
431
432        current = container_of(timer, struct og_schedule, timer);
433        og_schedule_run(current->task_id, current->schedule_id, current->type);
434
435        ev_timer_stop(loop, timer);
436        list_del(&current->list);
437        free(current);
438
439        og_schedule_next(loop);
440}
441
442void og_schedule_next(struct ev_loop *loop)
443{
444        struct og_schedule *schedule;
445        time_t now, seconds;
446
447        if (list_empty(&schedule_list)) {
448                current_schedule = NULL;
449                return;
450        }
451
452        schedule = list_first_entry(&schedule_list, struct og_schedule, list);
453        now = time(NULL);
454        if (schedule->seconds <= now)
455                seconds = 0;
456        else
457                seconds = schedule->seconds - now;
458
459        ev_timer_init(&schedule->timer, og_agent_timer_cb, seconds, 0.);
460        ev_timer_start(loop, &schedule->timer);
461        current_schedule = schedule;
462}
463
464void og_schedule_refresh(struct ev_loop *loop)
465{
466        if (current_schedule)
467                ev_timer_stop(loop, &current_schedule->timer);
468
469        og_schedule_next(loop);
470}
Note: See TracBrowser for help on using the repository browser.