1 /* 2 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 * PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 /* $Id: dns_time.c,v 1.6 2020/02/24 13:49:38 jsg Exp $ */ 18 19 /*! \file */ 20 21 #include <stdio.h> 22 #include <string.h> /* Required for HP/UX (and others?) */ 23 #include <time.h> 24 25 #include <isc/region.h> 26 #include <isc/serial.h> 27 #include <isc/result.h> 28 29 #include <dns/time.h> 30 31 static const int days[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 32 33 isc_result_t 34 dns_time64_totext(int64_t t, isc_buffer_t *target) { 35 struct tm tm; 36 char buf[sizeof("!!!!!!YYYY!!!!!!!!MM!!!!!!!!DD!!!!!!!!HH!!!!!!!!MM!!!!!!!!SS")]; 37 int secs; 38 unsigned int l; 39 isc_region_t region; 40 41 /* 42 * Warning. Do NOT use arguments with side effects with these macros. 43 */ 44 #define is_leap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0) 45 #define year_secs(y) ((is_leap(y) ? 366 : 365 ) * 86400) 46 #define month_secs(m,y) ((days[m] + ((m == 1 && is_leap(y)) ? 1 : 0 )) * 86400) 47 48 tm.tm_year = 70; 49 while (t < 0) { 50 if (tm.tm_year == 0) 51 return (ISC_R_RANGE); 52 tm.tm_year--; 53 secs = year_secs(tm.tm_year + 1900); 54 t += secs; 55 } 56 while ((secs = year_secs(tm.tm_year + 1900)) <= t) { 57 t -= secs; 58 tm.tm_year++; 59 if (tm.tm_year + 1900 > 9999) 60 return (ISC_R_RANGE); 61 } 62 tm.tm_mon = 0; 63 while ((secs = month_secs(tm.tm_mon, tm.tm_year + 1900)) <= t) { 64 t -= secs; 65 tm.tm_mon++; 66 } 67 tm.tm_mday = 1; 68 while (86400 <= t) { 69 t -= 86400; 70 tm.tm_mday++; 71 } 72 tm.tm_hour = 0; 73 while (3600 <= t) { 74 t -= 3600; 75 tm.tm_hour++; 76 } 77 tm.tm_min = 0; 78 while (60 <= t) { 79 t -= 60; 80 tm.tm_min++; 81 } 82 tm.tm_sec = (int)t; 83 /* yyyy mm dd HH MM SS */ 84 snprintf(buf, sizeof(buf), "%04d%02d%02d%02d%02d%02d", 85 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, 86 tm.tm_hour, tm.tm_min, tm.tm_sec); 87 88 isc_buffer_availableregion(target, ®ion); 89 l = strlen(buf); 90 91 if (l > region.length) 92 return (ISC_R_NOSPACE); 93 94 memmove(region.base, buf, l); 95 isc_buffer_add(target, l); 96 return (ISC_R_SUCCESS); 97 } 98 99 int64_t 100 dns_time64_from32(uint32_t value) { 101 time_t now; 102 int64_t start; 103 int64_t t; 104 105 /* 106 * Adjust the time to the closest epoch. This should be changed 107 * to use a 64-bit counterpart to time() if one ever 108 * is defined, but even the current code is good until the year 109 * 2106. 110 */ 111 time(&now); 112 start = (int64_t) now; 113 if (isc_serial_gt(value, now)) 114 t = start + (value - now); 115 else 116 t = start - (now - value); 117 118 return (t); 119 } 120 121 isc_result_t 122 dns_time32_totext(uint32_t value, isc_buffer_t *target) { 123 return (dns_time64_totext(dns_time64_from32(value), target)); 124 } 125