1/* 2 * Copyright (C) 2004, 2005, 2007, 2009-2012 Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (C) 1998-2003 Internet Software Consortium. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 * PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18/* $Id$ */ 19 20/*! \file */ 21 22#include <config.h> 23 24#include <stdio.h> 25#include <isc/string.h> /* Required for HP/UX (and others?) */ 26#include <time.h> 27#include <ctype.h> 28 29#include <isc/print.h> 30#include <isc/region.h> 31#include <isc/serial.h> 32#include <isc/stdtime.h> 33#include <isc/util.h> 34 35#include <dns/result.h> 36#include <dns/time.h> 37 38static int days[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 39 40isc_result_t 41dns_time64_totext(isc_int64_t t, isc_buffer_t *target) { 42 struct tm tm; 43 char buf[sizeof("YYYYMMDDHHMMSS")]; 44 int secs; 45 unsigned int l; 46 isc_region_t region; 47 48/* 49 * Warning. Do NOT use arguments with side effects with these macros. 50 */ 51#define is_leap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0) 52#define year_secs(y) ((is_leap(y) ? 366 : 365 ) * 86400) 53#define month_secs(m,y) ((days[m] + ((m == 1 && is_leap(y)) ? 1 : 0 )) * 86400) 54 55 tm.tm_year = 70; 56 while (t < 0) { 57 if (tm.tm_year == 0) 58 return (ISC_R_RANGE); 59 tm.tm_year--; 60 secs = year_secs(tm.tm_year + 1900); 61 t += secs; 62 } 63 while ((secs = year_secs(tm.tm_year + 1900)) <= t) { 64 t -= secs; 65 tm.tm_year++; 66 if (tm.tm_year + 1900 > 9999) 67 return (ISC_R_RANGE); 68 } 69 tm.tm_mon = 0; 70 while ((secs = month_secs(tm.tm_mon, tm.tm_year + 1900)) <= t) { 71 t -= secs; 72 tm.tm_mon++; 73 } 74 tm.tm_mday = 1; 75 while (86400 <= t) { 76 t -= 86400; 77 tm.tm_mday++; 78 } 79 tm.tm_hour = 0; 80 while (3600 <= t) { 81 t -= 3600; 82 tm.tm_hour++; 83 } 84 tm.tm_min = 0; 85 while (60 <= t) { 86 t -= 60; 87 tm.tm_min++; 88 } 89 tm.tm_sec = (int)t; 90 /* yyyy mm dd HH MM SS */ 91 snprintf(buf, sizeof(buf), "%04d%02d%02d%02d%02d%02d", 92 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, 93 tm.tm_hour, tm.tm_min, tm.tm_sec); 94 95 isc_buffer_availableregion(target, ®ion); 96 l = strlen(buf); 97 98 if (l > region.length) 99 return (ISC_R_NOSPACE); 100 101 memcpy(region.base, buf, l); 102 isc_buffer_add(target, l); 103 return (ISC_R_SUCCESS); 104} 105 106isc_int64_t 107dns_time64_from32(isc_uint32_t value) { 108 isc_stdtime_t now; 109 isc_int64_t start; 110 isc_int64_t t; 111 112 /* 113 * Adjust the time to the closest epoch. This should be changed 114 * to use a 64-bit counterpart to isc_stdtime_get() if one ever 115 * is defined, but even the current code is good until the year 116 * 2106. 117 */ 118 isc_stdtime_get(&now); 119 start = (isc_int64_t) now; 120 if (isc_serial_gt(value, now)) 121 t = start + (value - now); 122 else 123 t = start - (now - value); 124 125 return (t); 126} 127 128isc_result_t 129dns_time32_totext(isc_uint32_t value, isc_buffer_t *target) { 130 return (dns_time64_totext(dns_time64_from32(value), target)); 131} 132 133isc_result_t 134dns_time64_fromtext(const char *source, isc_int64_t *target) { 135 int year, month, day, hour, minute, second; 136 isc_int64_t value; 137 int secs; 138 int i; 139 140#define RANGE(min, max, value) \ 141 do { \ 142 if (value < (min) || value > (max)) \ 143 return (ISC_R_RANGE); \ 144 } while (0) 145 146 if (strlen(source) != 14U) 147 return (DNS_R_SYNTAX); 148 /* 149 * Confirm the source only consists digits. sscanf() allows some 150 * minor exceptions. 151 */ 152 for (i = 0; i < 14; i++) { 153 if (!isdigit((unsigned char)source[i])) 154 return (DNS_R_SYNTAX); 155 } 156 if (sscanf(source, "%4d%2d%2d%2d%2d%2d", 157 &year, &month, &day, &hour, &minute, &second) != 6) 158 return (DNS_R_SYNTAX); 159 160 RANGE(0, 9999, year); 161 RANGE(1, 12, month); 162 RANGE(1, days[month - 1] + 163 ((month == 2 && is_leap(year)) ? 1 : 0), day); 164 RANGE(0, 23, hour); 165 RANGE(0, 59, minute); 166 RANGE(0, 60, second); /* 60 == leap second. */ 167 168 /* 169 * Calculate seconds from epoch. 170 * Note: this uses a idealized calendar. 171 */ 172 value = second + (60 * minute) + (3600 * hour) + ((day - 1) * 86400); 173 for (i = 0; i < (month - 1); i++) 174 value += days[i] * 86400; 175 if (is_leap(year) && month > 2) 176 value += 86400; 177 if (year < 1970) { 178 for (i = 1969; i >= year; i--) { 179 secs = (is_leap(i) ? 366 : 365) * 86400; 180 value -= secs; 181 } 182 } else { 183 for (i = 1970; i < year; i++) { 184 secs = (is_leap(i) ? 366 : 365) * 86400; 185 value += secs; 186 } 187 } 188 189 *target = value; 190 return (ISC_R_SUCCESS); 191} 192 193isc_result_t 194dns_time32_fromtext(const char *source, isc_uint32_t *target) { 195 isc_int64_t value64; 196 isc_result_t result; 197 result = dns_time64_fromtext(source, &value64); 198 if (result != ISC_R_SUCCESS) 199 return (result); 200 *target = (isc_uint32_t)value64; 201 202 return (ISC_R_SUCCESS); 203} 204