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