OpenDNSSEC-signer  1.4.7
duration.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2009 NLNet Labs. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
19  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
21  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
22  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
23  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  */
26 
32 #include "shared/allocator.h"
33 #include "shared/duration.h"
34 #include "shared/log.h"
35 
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <time.h>
40 
41 static const char* duration_str = "duration";
42 
43 
50 {
51  duration_type* duration;
52  allocator_type* allocator = allocator_create(malloc, free);
53  if (!allocator) {
54  ods_log_error("[%s] cannot create: no allocator available",
55  duration_str);
56  return NULL;
57  }
58 
59  duration = (duration_type*) allocator_alloc(allocator,
60  sizeof(duration_type));
61  if (!duration) {
62  ods_log_error("[%s] cannot create: allocator failed", duration_str);
63  allocator_cleanup(allocator);
64  return NULL;
65  }
66  duration->allocator = allocator;
67  duration->years = 0;
68  duration->months = 0;
69  duration->weeks = 0;
70  duration->days = 0;
71  duration->hours = 0;
72  duration->minutes = 0;
73  duration->seconds = 0;
74  return duration;
75 }
76 
77 
82 int
84 {
85  if (!d1 && !d2) {
86  return 0;
87  }
88  if (!d1 || !d2) {
89  return d1?-1:1;
90  }
91 
92  if (d1->years != d2->years) {
93  return d1->years - d2->years;
94  }
95  if (d1->months != d2->months) {
96  return d1->months - d2->months;
97  }
98  if (d1->weeks != d2->weeks) {
99  return d1->weeks - d2->weeks;
100  }
101  if (d1->days != d2->days) {
102  return d1->days - d2->days;
103  }
104  if (d1->hours != d2->hours) {
105  return d1->hours - d2->hours;
106  }
107  if (d1->minutes != d2->minutes) {
108  return d1->minutes - d2->minutes;
109  }
110  if (d1->seconds != d2->seconds) {
111  return d1->seconds - d2->seconds;
112  }
113 
114  return 0;
115 }
116 
117 
124 {
125  duration_type* duration = duration_create();
126  char* P, *X, *T, *W;
127  int not_weeks = 0;
128 
129  if (!duration) {
130  ods_log_error("[%s] cannot create from string %s: create failed",
131  duration_str, str);
132  return NULL;
133  }
134  if (!str) {
135  return duration;
136  }
137 
138  P = strchr(str, 'P');
139  if (!P) {
140  ods_log_error("[%s] cannot create from string %s: P not found",
141  duration_str, str);
142  duration_cleanup(duration);
143  return NULL;
144  }
145 
146  T = strchr(str, 'T');
147  X = strchr(str, 'Y');
148  if (X) {
149  duration->years = atoi(str+1);
150  str = X;
151  not_weeks = 1;
152  }
153  X = strchr(str, 'M');
154  if (X && (!T || (size_t) (X-P) < (size_t) (T-P))) {
155  duration->months = atoi(str+1);
156  str = X;
157  not_weeks = 1;
158  }
159  X = strchr(str, 'D');
160  if (X) {
161  duration->days = atoi(str+1);
162  str = X;
163  not_weeks = 1;
164  }
165  if (T) {
166  str = T;
167  not_weeks = 1;
168  }
169  X = strchr(str, 'H');
170  if (X && T) {
171  duration->hours = atoi(str+1);
172  str = X;
173  not_weeks = 1;
174  }
175  X = strrchr(str, 'M');
176  if (X && T && (size_t) (X-P) > (size_t) (T-P)) {
177  duration->minutes = atoi(str+1);
178  str = X;
179  not_weeks = 1;
180  }
181  X = strchr(str, 'S');
182  if (X && T) {
183  duration->seconds = atoi(str+1);
184  str = X;
185  not_weeks = 1;
186  }
187 
188  W = strchr(str, 'W');
189  if (W) {
190  if (not_weeks) {
191  ods_log_error("[%s] cannot create from string: parse error",
192  duration_str, P);
193  duration_cleanup(duration);
194  return NULL;
195  } else {
196  duration->weeks = atoi(str+1);
197  str = W;
198  }
199  }
200  return duration;
201 }
202 
203 
208 static size_t
209 digits_in_number(time_t duration)
210 {
211  uint32_t period = (uint32_t) duration;
212  size_t count = 0;
213  if (!period) {
214  return 1;
215  }
216  while (period > 0) {
217  count++;
218  period /= 10;
219  }
220  return count;
221 }
222 
223 
228 char*
230 {
231  char* str = NULL, *num = NULL;
232  size_t count = 2;
233  int T = 0, D = 0;
234 
235  if (!duration) {
236  return NULL;
237  }
238 
239  if (duration->years > 0) {
240  count = count + 1 + digits_in_number(duration->years);
241  D = 1;
242  }
243  if (duration->months > 0) {
244  count = count + 1 + digits_in_number(duration->months);
245  D = 1;
246  }
247  if (duration->weeks > 0) {
248  count = count + 1 + digits_in_number(duration->weeks);
249  D = 1;
250  }
251  if (duration->days > 0) {
252  count = count + 1 + digits_in_number(duration->days);
253  D = 1;
254  }
255  if (duration->hours > 0) {
256  count = count + 1 + digits_in_number(duration->hours);
257  T = 1;
258  }
259  if (duration->minutes > 0) {
260  count = count + 1 + digits_in_number(duration->minutes);
261  T = 1;
262  }
263  if (duration->seconds > 0 ||
264  (!D && !duration->hours && !duration->minutes)) {
265  count = count + 1 + digits_in_number(duration->seconds);
266  T = 1;
267  }
268  if (T) {
269  count++;
270  }
271 
272  str = (char*) calloc(count, sizeof(char));
273  str[0] = 'P';
274  str[1] = '\0';
275 
276  if (duration->years > 0) {
277  count = digits_in_number(duration->years);
278  num = (char*) calloc(count+2, sizeof(char));
279  if (num) {
280  snprintf(num, count+2, "%uY", (uint32_t) duration->years);
281  str = strncat(str, num, count+2);
282  free((void*) num);
283  } else {
284  goto duration2string_num_calloc_failed;
285  }
286  }
287  if (duration->months > 0) {
288  count = digits_in_number(duration->months);
289  num = (char*) calloc(count+2, sizeof(char));
290  if (num) {
291  snprintf(num, count+2, "%uM", (uint32_t) duration->months);
292  str = strncat(str, num, count+2);
293  free((void*) num);
294  } else {
295  goto duration2string_num_calloc_failed;
296  }
297  }
298  if (duration->weeks > 0) {
299  count = digits_in_number(duration->weeks);
300  num = (char*) calloc(count+2, sizeof(char));
301  if (num) {
302  snprintf(num, count+2, "%uW", (uint32_t) duration->weeks);
303  str = strncat(str, num, count+2);
304  free((void*) num);
305  } else {
306  goto duration2string_num_calloc_failed;
307  }
308  }
309  if (duration->days > 0) {
310  count = digits_in_number(duration->days);
311  num = (char*) calloc(count+2, sizeof(char));
312  if (num) {
313  snprintf(num, count+2, "%uD", (uint32_t) duration->days);
314  str = strncat(str, num, count+2);
315  free((void*) num);
316  } else {
317  goto duration2string_num_calloc_failed;
318  }
319  }
320  if (T) {
321  str = strncat(str, "T", 1);
322  }
323  if (duration->hours > 0) {
324  count = digits_in_number(duration->hours);
325  num = (char*) calloc(count+2, sizeof(char));
326  if (num) {
327  snprintf(num, count+2, "%uH", (uint32_t) duration->hours);
328  str = strncat(str, num, count+2);
329  free((void*) num);
330  } else {
331  goto duration2string_num_calloc_failed;
332  }
333  }
334  if (duration->minutes > 0) {
335  count = digits_in_number(duration->minutes);
336  num = (char*) calloc(count+2, sizeof(char));
337  if (num) {
338  snprintf(num, count+2, "%uM", (uint32_t) duration->minutes);
339  str = strncat(str, num, count+2);
340  free((void*) num);
341  } else {
342  goto duration2string_num_calloc_failed;
343  }
344  }
345  if (duration->seconds > 0 ||
346  (!D && !duration->hours && !duration->minutes)) {
347  count = digits_in_number(duration->seconds);
348  num = (char*) calloc(count+2, sizeof(char));
349  if (num) {
350  snprintf(num, count+2, "%uS", (uint32_t) duration->seconds);
351  str = strncat(str, num, count+2);
352  free((void*) num);
353  } else {
354  goto duration2string_num_calloc_failed;
355  }
356  }
357  return str;
358 
359 duration2string_num_calloc_failed:
360  ods_log_error("[%s] cannot create string: malloc error", duration_str);
361  free((void*) str);
362  return NULL;
363 }
364 
365 
370 time_t
372 {
373  time_t period = 0;
374  char* dstr = NULL;
375 
376  if (duration) {
377  period += (duration->seconds);
378  period += (duration->minutes)*60;
379  period += (duration->hours)*3600;
380  period += (duration->days)*86400;
381  period += (duration->weeks)*86400*7;
382  period += (duration->months)*86400*31;
383  period += (duration->years)*86400*365;
384 
385  if (duration->months || duration->years) {
386  /* [TODO] calculate correct number of days in this month/year */
387  dstr = duration2string(duration);
388  ods_log_warning("[%s] converting duration %s to approximate value",
389  duration_str, dstr?dstr:"(null)");
390  free((void*) dstr);
391  }
392  }
393  return period;
394 }
395 
400 time_t
401 time_minimum(time_t a, time_t b)
402 {
403  return (a < b ? a : b);
404 }
405 
410 time_t
411 time_maximum(time_t a, time_t b)
412 {
413  return (a > b ? a : b);
414 }
415 
416 
421 time_t
422 ods_rand(time_t mod)
423 {
424 #ifdef HAVE_ARC4RANDOM_UNIFORM
425  return (time_t) (arc4random_uniform((uint32_t) mod+1));
426 #elif HAVE_ARC4RANDOM
427  return (time_t) (arc4random() % (unsigned) mod+1);
428 #else
429  return (time_t) (random() % (unsigned) mod+1);
430 #endif
431 }
432 
433 
434 /* Number of days per month (except for February in leap years). */
435 static const int mdays[] = {
436  31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
437 };
438 
439 
440 static int
441 is_leap_year(int year)
442 {
443  return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
444 }
445 
446 
447 static int
448 leap_days(int y1, int y2)
449 {
450  --y1;
451  --y2;
452  return (y2/4 - y1/4) - (y2/100 - y1/100) + (y2/400 - y1/400);
453 }
454 
455 
456 #ifdef ENFORCER_TIMESHIFT
457 /*
458  * Code taken from NSD 3.2.5, which is
459  * code adapted from Python 2.4.1 sources (Lib/calendar.py).
460  */
461 static time_t
462 mktime_from_utc(const struct tm *tm)
463 {
464  int year = 1900 + tm->tm_year;
465  time_t days = 365 * ((time_t) (year - 1970)) +
466  ((time_t) leap_days(1970, year));
467  time_t hours;
468  time_t minutes;
469  time_t seconds;
470  int i;
471 
472  for (i = 0; i < tm->tm_mon; ++i) {
473  days += mdays[i];
474  }
475  if (tm->tm_mon > 1 && is_leap_year(year)) {
476  ++days;
477  }
478  days += tm->tm_mday - 1;
479 
480  hours = days * 24 + tm->tm_hour;
481  minutes = hours * 60 + tm->tm_min;
482  seconds = minutes * 60 + tm->tm_sec;
483 
484  return seconds;
485 }
486 
487 
492 static time_t
493 timeshift2time(const char *time)
494 {
495  /* convert a string in format YYMMDDHHMMSS to time_t */
496  struct tm tm;
497  time_t timeshift = 0;
498 
499  /* Try to scan the time... */
500  if (strptime(time, "%Y%m%d%H%M%S", &tm)) {
501  timeshift = mktime_from_utc(&tm);
502  }
503  return timeshift;
504 }
505 #endif
506 
507 
512 time_t
513 time_now(void)
514 {
515 #ifdef ENFORCER_TIMESHIFT
516  const char* env = getenv("ENFORCER_TIMESHIFT");
517  if (env) {
518  return timeshift2time(env);
519  } else
520 #endif /* ENFORCER_TIMESHIFT */
521 
522  return time(NULL);
523 }
524 
525 
530 uint32_t
531 time_datestamp(time_t tt, const char* format, char** str)
532 {
533  time_t t;
534  struct tm *tmp;
535  uint32_t ut = 0;
536  char outstr[32];
537 
538  if (tt) {
539  t = tt;
540  } else {
541  t = time_now();
542  }
543 
544  tmp = localtime(&t);
545  if (tmp == NULL) {
546  ods_log_error("[%s] time_datestamp: localtime() failed", duration_str);
547  return 0;
548  }
549 
550  if (strftime(outstr, sizeof(outstr), format, tmp) == 0) {
551  ods_log_error("[%s] time_datestamp: strftime() failed", duration_str);
552  return 0;
553  }
554 
555  ut = (uint32_t) strtoul(outstr, NULL, 10);
556  if (str) {
557  *str = strdup(outstr);
558  }
559  return ut;
560 }
561 
562 static void
563 time_itoa_reverse(char* s)
564 {
565  int i, j;
566  char c;
567 
568  for (i = 0, j = strlen(s)-1; i<j; i++, j--) {
569  c = s[i];
570  s[i] = s[j];
571  s[j] = c;
572  }
573  return;
574 }
575 
576 
581 void
582 time_itoa(time_t n, char* s)
583 {
584  int i = 0;
585 
586  do { /* generate digits in reverse order */
587  s[i++] = n % 10 + '0'; /* get next digit */
588  } while ((n /= 10) > 0); /* delete it */
589  s[i] = '\0';
590  time_itoa_reverse(s);
591  return;
592 }
593 
594 
599 void
601 {
602  allocator_type* allocator;
603 
604  if (!duration) {
605  return;
606  }
607  allocator = duration->allocator;
608  allocator_deallocate(allocator, (void*) duration);
609  allocator_cleanup(allocator);
610  return;
611 }
time_t hours
Definition: duration.h:53
uint32_t time_datestamp(time_t tt, const char *format, char **str)
Definition: duration.c:531
void * allocator_alloc(allocator_type *allocator, size_t size)
Definition: allocator.c:66
duration_type * duration_create(void)
Definition: duration.c:49
time_t minutes
Definition: duration.h:54
time_t seconds
Definition: duration.h:55
void ods_log_error(const char *format,...)
Definition: log.c:334
time_t years
Definition: duration.h:49
time_t weeks
Definition: duration.h:51
time_t months
Definition: duration.h:50
void duration_cleanup(duration_type *duration)
Definition: duration.c:600
time_t time_maximum(time_t a, time_t b)
Definition: duration.c:411
allocator_type * allocator_create(void *(*allocator)(size_t size), void(*deallocator)(void *))
Definition: allocator.c:47
char * duration2string(duration_type *duration)
Definition: duration.c:229
time_t duration2time(duration_type *duration)
Definition: duration.c:371
int duration_compare(duration_type *d1, duration_type *d2)
Definition: duration.c:83
void allocator_cleanup(allocator_type *allocator)
Definition: allocator.c:151
void time_itoa(time_t n, char *s)
Definition: duration.c:582
void allocator_deallocate(allocator_type *allocator, void *data)
Definition: allocator.c:135
allocator_type * allocator
Definition: duration.h:48
duration_type * duration_create_from_string(const char *str)
Definition: duration.c:123
time_t ods_rand(time_t mod)
Definition: duration.c:422
time_t time_minimum(time_t a, time_t b)
Definition: duration.c:401
void ods_log_warning(const char *format,...)
Definition: log.c:318
time_t days
Definition: duration.h:52
time_t time_now(void)
Definition: duration.c:513