diff --git a/src/base.h b/src/base.h index 108f6630..2162ebef 100644 --- a/src/base.h +++ b/src/base.h @@ -53,11 +53,11 @@ struct connection { const struct server_socket *srv_socket; /* reference to the server-socket */ /* timestamps */ - time_t read_idle_ts; - time_t close_timeout_ts; - time_t write_request_ts; + unix_time64_t read_idle_ts; + unix_time64_t close_timeout_ts; + unix_time64_t write_request_ts; + unix_time64_t connection_start; - time_t connection_start; uint32_t request_count; /* number of requests handled in this connection */ int keep_alive_idle; /* remember max_keep_alive_idle from config */ }; @@ -172,7 +172,7 @@ struct server { log_error_st *errh; - time_t loadts; + unix_time64_t loadts; double loadavg[3]; /* members used at start-up or rarely used */ @@ -184,8 +184,8 @@ struct server { server_socket_array srv_sockets_inherited; buffer_plugin plugins; - time_t startup_ts; - time_t graceful_expire_ts; + unix_time64_t startup_ts; + unix_time64_t graceful_expire_ts; uid_t uid; gid_t gid; diff --git a/src/connections.c b/src/connections.c index b0b126b6..1176d7f9 100644 --- a/src/connections.c +++ b/src/connections.c @@ -1423,7 +1423,7 @@ connection_state_machine (connection * const con) } -static void connection_check_timeout (connection * const con, const time_t cur_ts) { +static void connection_check_timeout (connection * const con, const unix_time64_t cur_ts) { const int waitevents = fdevent_fdnode_interest(con->fdn); int changed = 0; int t_diff; @@ -1580,7 +1580,7 @@ static void connection_check_timeout (connection * const con, const time_t cur_t } } -void connection_periodic_maint (server * const srv, const time_t cur_ts) { +void connection_periodic_maint (server * const srv, const unix_time64_t cur_ts) { /* check all connections for timeouts */ connections * const conns = &srv->conns; for (size_t ndx = 0; ndx < conns->used; ++ndx) { diff --git a/src/connections.h b/src/connections.h index d7bfdaa5..c0190928 100644 --- a/src/connections.h +++ b/src/connections.h @@ -12,7 +12,7 @@ void connections_free(server *srv); __attribute_cold__ void connection_graceful_shutdown_maint (server *srv); -void connection_periodic_maint (server *srv, time_t cur_ts); +void connection_periodic_maint (server *srv, unix_time64_t cur_ts); int connection_send_1xx (request_st *r, connection *con); diff --git a/src/fdevent.c b/src/fdevent.c index cf587852..894a4e10 100644 --- a/src/fdevent.c +++ b/src/fdevent.c @@ -828,7 +828,7 @@ typedef struct fdevent_cmd_pipe { pid_t pid; int fds[2]; const char *cmd; - time_t start; + unix_time64_t start; } fdevent_cmd_pipe; typedef struct fdevent_cmd_pipes { @@ -868,7 +868,7 @@ static pid_t fdevent_open_logger_pipe_spawn(const char *logger, int rfd) { } -static void fdevent_restart_logger_pipe(fdevent_cmd_pipe *fcp, time_t ts) { +static void fdevent_restart_logger_pipe(fdevent_cmd_pipe *fcp, unix_time64_t ts) { if (fcp->pid > 0) return; /* assert */ if (fcp->start + 5 < ts) { /* limit restart to once every 5 sec */ /* restart child process using existing pipe fds */ @@ -878,7 +878,7 @@ static void fdevent_restart_logger_pipe(fdevent_cmd_pipe *fcp, time_t ts) { } -void fdevent_restart_logger_pipes(time_t ts) { +void fdevent_restart_logger_pipes(unix_time64_t ts) { for (uint32_t i = 0; i < cmd_pipes.used; ++i) { fdevent_cmd_pipe * const fcp = cmd_pipes.ptr+i; if (fcp->pid > 0) continue; @@ -887,7 +887,7 @@ void fdevent_restart_logger_pipes(time_t ts) { } -int fdevent_waitpid_logger_pipe_pid(pid_t pid, time_t ts) { +int fdevent_waitpid_logger_pipe_pid(pid_t pid, unix_time64_t ts) { for (uint32_t i = 0; i < cmd_pipes.used; ++i) { fdevent_cmd_pipe * const fcp = cmd_pipes.ptr+i; if (pid != fcp->pid) continue; @@ -911,7 +911,7 @@ int fdevent_reaped_logger_pipe(pid_t pid) { for (uint32_t i = 0; i < cmd_pipes.used; ++i) { fdevent_cmd_pipe *fcp = cmd_pipes.ptr+i; if (fcp->pid == pid) { - time_t ts = log_monotonic_secs; + unix_time64_t ts = log_monotonic_secs; if (fcp->start + 5 < ts) { /* limit restart to once every 5 sec */ fcp->start = ts; fcp->pid = fdevent_open_logger_pipe_spawn(fcp->cmd,fcp->fds[0]); diff --git a/src/fdevent.h b/src/fdevent.h index 6d56f6c3..016d7480 100644 --- a/src/fdevent.h +++ b/src/fdevent.h @@ -104,8 +104,8 @@ int fdevent_waitpid_intr(pid_t pid, int *status); int fdevent_open_logger(const char *logger); int fdevent_cycle_logger(const char *logger, int *curfd); int fdevent_reaped_logger_pipe(pid_t pid); -int fdevent_waitpid_logger_pipe_pid(pid_t pid, time_t ts); -void fdevent_restart_logger_pipes(time_t ts); +int fdevent_waitpid_logger_pipe_pid(pid_t pid, unix_time64_t ts); +void fdevent_restart_logger_pipes(unix_time64_t ts); void fdevent_close_logger_pipes(void); void fdevent_breakagelog_logger_pipe(int fd); void fdevent_clr_logger_pipe_pids(void); diff --git a/src/first.h b/src/first.h index d02938eb..0380b22f 100644 --- a/src/first.h +++ b/src/first.h @@ -53,6 +53,49 @@ #endif +/* TODO: would be more accurate to create build-system test for sizeof(time_t)*/ +#ifndef HAS_TIME_BITS64 + #if defined(_LP64) || defined(__LP64__) || defined(_WIN64) + #define HAS_TIME_BITS64 1 + #elif defined(__TIMESIZE) + #if __TIMESIZE == 64 + #define HAS_TIME_BITS64 1 + #else + #define HAS_TIME_BITS64 0 + #endif + #elif defined(_WIN32) + #ifndef _USE_32BIT_TIME_T + #define HAS_TIME_BITS64 1 + #else + #define HAS_TIME_BITS64 0 + #endif + #elif defined(_ILP32) \ + && !defined(__NetBSD__) && !defined(__OpenBSD__) \ + && (!defined(__FreeBSD__) || !defined(__i386__)) \ + && !(defined(__APPLE__) && defined(__MACH__)) + #define HAS_TIME_BITS64 0 + #else + #define HAS_TIME_BITS64 1 + #endif +#endif + +/* non-standard types created for lighttpd for Y2038 problem + * reference: https://en.wikipedia.org/wiki/Year_2038_problem */ +#if HAS_TIME_BITS64 +typedef time_t unix_time64_t; +typedef struct timespec unix_timespec64_t; +#define TIME64_CAST(t) (t) +#else /* !HAS_TIME_BITS64 */ +typedef int64_t unix_time64_t; +struct unix_timespec64 { + unix_time64_t tv_sec; /* seconds */ + long tv_nsec; /* nanoseconds */ +}; +typedef struct unix_timespec64 unix_timespec64_t; +#define TIME64_CAST(t) ((unix_time64_t)(uint32_t)(t)) +#endif /* !HAS_TIME_BITS64 */ + + #define UNUSED(x) ( (void)(x) ) diff --git a/src/gw_backend.c b/src/gw_backend.c index abbcfd72..ca22c79d 100644 --- a/src/gw_backend.c +++ b/src/gw_backend.c @@ -246,7 +246,7 @@ static void gw_proc_connect_success(gw_host *host, gw_proc *proc, int debug, req __attribute_cold__ static void gw_proc_connect_error(request_st * const r, gw_host *host, gw_proc *proc, pid_t pid, int errnum, int debug) { - const time_t cur_ts = log_monotonic_secs; + const unix_time64_t cur_ts = log_monotonic_secs; log_error_st * const errh = r->conf.errh; log_perror(errh, __FILE__, __LINE__, /*(caller should set errno = errnum)*/ "establishing connection failed: socket: %s", proc->connection_name->ptr); @@ -2581,7 +2581,7 @@ static void gw_handle_trigger_host(gw_host * const host, log_error_st * const er /* check each child proc to detect if proc exited */ gw_proc *proc; - time_t idle_timestamp; + unix_time64_t idle_timestamp; int overload = 1; for (proc = host->first; proc; proc = proc->next) { @@ -2729,7 +2729,7 @@ handler_t gw_handle_waitpid_cb(server *srv, void *p_d, pid_t pid, int status) { * or global scope (for convenience)) * (unable to use p->defaults.debug since gw_plugin_config * might be part of a larger plugin_config) */ - const time_t cur_ts = log_monotonic_secs; + const unix_time64_t cur_ts = log_monotonic_secs; gw_exts *exts = conf->exts; for (uint32_t j = 0; j < exts->used; ++j) { gw_extension *ex = exts->exts+j; diff --git a/src/gw_backend.h b/src/gw_backend.h index de2159fd..fdf2f5f4 100644 --- a/src/gw_backend.h +++ b/src/gw_backend.h @@ -26,7 +26,7 @@ typedef struct gw_proc { PROC_STATE_KILLED /* killed (signal sent to proc) */ } state; uint32_t load; /* number of requests waiting on this process */ - time_t last_used; /* see idle_timeout */ + unix_time64_t last_used; /* see idle_timeout */ int *stats_load; int *stats_connected; pid_t pid; /* PID of the spawned process (0 if not spawned locally) */ @@ -35,7 +35,7 @@ typedef struct gw_proc { socklen_t saddrlen; struct sockaddr *saddr; - time_t disabled_until; /* proc disabled until given time */ + unix_time64_t disabled_until; /* proc disabled until given time */ struct gw_proc *prev; /* see first */ /* either tcp:: or unix: for debugging purposes */ @@ -301,7 +301,7 @@ typedef struct gw_handler_ctx { unsigned short gw_mode; /* mode: GW_AUTHORIZER or GW_RESPONDER */ gw_connection_state_t state; - time_t state_timestamp; + /*unix_time64_t state_timestamp;*//*(unused)*/ chunkqueue *rb; /* read queue */ off_t wb_reqlen; diff --git a/src/h2.c b/src/h2.c index 35e21bc9..e976d89a 100644 --- a/src/h2.c +++ b/src/h2.c @@ -2005,7 +2005,7 @@ h2_send_headers (request_st * const r, connection * const con) if (!light_btst(r->resp_htags, HTTP_HEADER_DATE)) { /* HTTP/1.1 and later requires a Date: header */ /* "date: " 6-chars + 30-chars for "%a, %d %b %Y %T GMT" + '\0' */ - static time_t tlast = 0; + static unix_time64_t tlast = 0; static char tstr[36] = "date: "; memset(&lsx, 0, sizeof(lsxpack_header_t)); @@ -2017,7 +2017,7 @@ h2_send_headers (request_st * const r, connection * const con) lsx.hpack_index = LSHPACK_HDR_DATE; /* cache the generated timestamp */ - const time_t cur_ts = log_epoch_secs; + const unix_time64_t cur_ts = log_epoch_secs; if (__builtin_expect ( (tlast != cur_ts), 0)) http_date_time_to_str(tstr+6, sizeof(tstr)-6, (tlast = cur_ts)); diff --git a/src/h2.h b/src/h2.h index d32fc466..7c3d6266 100644 --- a/src/h2.h +++ b/src/h2.h @@ -75,7 +75,7 @@ struct h2con { uint32_t h2_cid; uint32_t h2_sid; int32_t sent_goaway; - time_t sent_settings; + unix_time64_t sent_settings; uint32_t s_header_table_size; /* SETTINGS_HEADER_TABLE_SIZE */ uint32_t s_enable_push; /* SETTINGS_ENABLE_PUSH */ uint32_t s_max_concurrent_streams; /* SETTINGS_MAX_CONCURRENT_STREAMS */ @@ -84,7 +84,7 @@ struct h2con { uint32_t s_max_header_list_size; /* SETTINGS_MAX_HEADER_LIST_SIZE */ struct lshpack_dec decoder; struct lshpack_enc encoder; - time_t half_closed_ts; + unix_time64_t half_closed_ts; }; void h2_send_goaway (connection *con, request_h2error_t e); diff --git a/src/http-header-glue.c b/src/http-header-glue.c index a2e88ec0..2d537c40 100644 --- a/src/http-header-glue.c +++ b/src/http-header-glue.c @@ -134,7 +134,7 @@ int http_response_redirect_to_directory(request_st * const r, int status) { #define MTIME_CACHE_MAX 16 struct mtime_cache_type { - time_t mtime; /* key */ + unix_time64_t mtime; /* key */ buffer str; /* buffer for string representation */ }; static struct mtime_cache_type mtime_cache[MTIME_CACHE_MAX]; @@ -143,14 +143,17 @@ static char mtime_cache_str[MTIME_CACHE_MAX][HTTP_DATE_SZ]; void strftime_cache_reset(void) { for (int i = 0; i < MTIME_CACHE_MAX; ++i) { - mtime_cache[i].mtime = (time_t)-1; + mtime_cache[i].mtime = -1; mtime_cache[i].str.ptr = mtime_cache_str[i]; mtime_cache[i].str.used = sizeof(mtime_cache_str[0]); mtime_cache[i].str.size = sizeof(mtime_cache_str[0]); } } -static const buffer * strftime_cache_get(const time_t last_mod) { +static const buffer * strftime_cache_get(const unix_time64_t last_mod) { + /*(note: not bothering to convert *here* if last_mod < 0 (for cache key); + * last_mod < 0 handled in http_date_time_to_str() call to gmtime64_r())*/ + static int mtime_cache_idx; for (int j = 0; j < MTIME_CACHE_MAX; ++j) { @@ -168,7 +171,7 @@ static const buffer * strftime_cache_get(const time_t last_mod) { } -const buffer * http_response_set_last_modified(request_st * const r, const time_t lmtime) { +const buffer * http_response_set_last_modified(request_st * const r, const unix_time64_t lmtime) { buffer * const vb = http_header_response_set_ptr(r, HTTP_HEADER_LAST_MODIFIED, CONST_STR_LEN("Last-Modified")); @@ -177,7 +180,7 @@ const buffer * http_response_set_last_modified(request_st * const r, const time_ } -int http_response_handle_cachable(request_st * const r, const buffer * const lmod, const time_t lmtime) { +int http_response_handle_cachable(request_st * const r, const buffer * const lmod, const unix_time64_t lmtime) { if (!(r->rqst_htags & (light_bshift(HTTP_HEADER_IF_NONE_MATCH) |light_bshift(HTTP_HEADER_IF_MODIFIED_SINCE)))) { diff --git a/src/http_date.c b/src/http_date.c index 05b81a92..2ade922d 100644 --- a/src/http_date.c +++ b/src/http_date.c @@ -47,14 +47,14 @@ http_date_parse_RFC_850 (const char *s, struct tm * const tm) * than 50 years in the future as representing the most recent year in * the past that had the same last two digits. */ - static time_t tm_year_last_check; + static unix_time64_t tm_year_last_check; static int tm_year_cur; static int tm_year_base; /* (log_epoch_secs is a global variable, maintained elsewhere) */ /* (optimization: check for year change no more than once per min) */ if (log_epoch_secs >= tm_year_last_check + 60) { struct tm tm_cur; - if (NULL != gmtime_r(&log_epoch_secs, &tm_cur)) { + if (NULL != gmtime64_r(&log_epoch_secs, &tm_cur)) { tm_year_last_check = log_epoch_secs; if (tm_cur.tm_year != tm_year_cur) { tm_year_cur = tm_cur.tm_year; @@ -265,12 +265,12 @@ http_date_str_to_tm (const char * const s, const uint32_t len, uint32_t -http_date_time_to_str (char * const s, const size_t sz, const time_t t) +http_date_time_to_str (char * const s, const size_t sz, const unix_time64_t t) { /*('max' is expected to be >= 30 (IMF-fixdate is 29 chars + '\0'))*/ struct tm tm; const char fmt[] = "%a, %d %b %Y %T GMT"; /*IMF-fixdate fmt*/ - return (__builtin_expect( (NULL != gmtime_r(&t, &tm)), 1)) + return (__builtin_expect( (NULL != gmtime64_r(&t, &tm)), 1)) ? (uint32_t)strftime(s, sz, fmt, &tm) : 0; } @@ -278,13 +278,17 @@ http_date_time_to_str (char * const s, const size_t sz, const time_t t) int http_date_if_modified_since (const char * const ifmod, const uint32_t ifmodlen, - const time_t lmtime) + const unix_time64_t lmtime) { struct tm ifmodtm; if (NULL == http_date_str_to_tm(ifmod, ifmodlen, &ifmodtm)) return 1; /* date parse error */ const time_t ifmtime = timegm(&ifmodtm); + #if HAS_TIME_BITS64 return (lmtime > ifmtime); + #else + return (TIME64_CAST(lmtime) > TIME64_CAST(ifmtime) || ifmtime==(time_t)-1); + #endif /* returns 0 if not modified since, * returns 1 if modified since or date parse error */ } diff --git a/src/http_date.h b/src/http_date.h index a426c11a..b10bdbb8 100644 --- a/src/http_date.h +++ b/src/http_date.h @@ -18,9 +18,9 @@ extern "C" { #define HTTP_DATE_SZ 30 /* (IMF-fixdate is 29 chars + '\0') */ -uint32_t http_date_time_to_str (char *s, size_t sz, time_t t); +uint32_t http_date_time_to_str (char *s, size_t sz, unix_time64_t t); -int http_date_if_modified_since (const char *ifmod, uint32_t ifmodlen, time_t lmtime); +int http_date_if_modified_since (const char *ifmod, uint32_t ifmodlen, unix_time64_t lmtime); /*(convenience macro to append IMF-fixdate to (buffer *))*/ #define http_date_time_append(b, t) \ diff --git a/src/log.c b/src/log.c index 0fa96d34..75176f08 100644 --- a/src/log.c +++ b/src/log.c @@ -21,29 +21,58 @@ # include #endif -time_t log_epoch_secs = 0; -time_t log_monotonic_secs = 0; +unix_time64_t log_epoch_secs = 0; +unix_time64_t log_monotonic_secs = 0; -int log_clock_gettime_realtime (struct timespec *ts) { - #ifdef HAVE_CLOCK_GETTIME - return clock_gettime(CLOCK_REALTIME, ts); - #else - /* Mac OSX does not provide clock_gettime() - * e.g. defined(__APPLE__) && defined(__MACH__) */ - struct timeval tv; - gettimeofday(&tv, NULL); - ts->tv_sec = tv.tv_sec; - ts->tv_nsec = tv.tv_usec * 1000; - return 0; - #endif +int log_clock_gettime_realtime (unix_timespec64_t *ts) { + #ifdef HAVE_CLOCK_GETTIME + #if HAS_TIME_BITS64 + return clock_gettime(CLOCK_REALTIME, ts); + #else + struct timespec ts32; + int rc = clock_gettime(CLOCK_REALTIME, &ts32); + if (0 == rc) { + /*(treat negative 32-bit tv.tv_sec as unsigned)*/ + ts->tv_sec = TIME64_CAST(ts32.tv_sec); + ts->tv_nsec = ts32.tv_nsec; + } + return rc; + #endif + #else + /* Mac OSX before 10.12 Sierra does not provide clock_gettime() + * e.g. defined(__APPLE__) && defined(__MACH__) + * && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101200 */ + struct timeval tv; + gettimeofday(&tv, NULL); + #if HAS_TIME_BITS64 + ts->tv_sec = tv.tv_sec; + #else /*(treat negative 32-bit tv.tv_sec as unsigned)*/ + ts->tv_sec = TIME64_CAST(tv.tv_sec); + #endif + ts->tv_nsec = tv.tv_usec * 1000; + return 0; + #endif } -int log_clock_gettime_monotonic (struct timespec *ts) { - #ifdef HAVE_CLOCK_GETTIME - return clock_gettime(CLOCK_MONOTONIC, ts); - #else - return log_clock_gettime_realtime(ts); /*(fallback)*/ - #endif +int log_clock_gettime_monotonic (unix_timespec64_t *ts) { + #ifdef HAVE_CLOCK_GETTIME + #if HAS_TIME_BITS64 + return clock_gettime(CLOCK_MONOTONIC, ts); + #else + struct timespec ts32; + int rc = clock_gettime(CLOCK_MONOTONIC, &ts32); + if (0 == rc) { + /*(treat negative 32-bit tv.tv_sec as unsigned)*/ + /*(negative 32-bit should not happen on monotonic clock + * unless system running continously for > 68 years)*/ + ts->tv_sec = TIME64_CAST(ts32.tv_sec); + ts->tv_nsec = ts32.tv_nsec; + } + return rc; + #endif + #else + return log_clock_gettime_realtime(ts); /*(fallback)*/ + #endif } /* retry write on EINTR or when not all data was written */ @@ -64,7 +93,7 @@ ssize_t write_all(int fd, const void * const buf, size_t count) { } static int log_buffer_prepare(const log_error_st *errh, const char *filename, unsigned int line, buffer *b) { - static time_t tlast; + static unix_time64_t tlast; static uint32_t tlen; static char tstr[24]; /* 20 "%F %T" incl '\0' +3 ": (" */ switch(errh->errorlog_mode) { @@ -78,7 +107,7 @@ static int log_buffer_prepare(const log_error_st *errh, const char *filename, un tlast = log_epoch_secs; tlen = (uint32_t) strftime(tstr, sizeof(tstr), "%F %T", - localtime_r(&tlast, &tm)); + localtime64_r(&tlast, &tm)); tstr[ tlen] = ':'; tstr[++tlen] = ' '; tstr[++tlen] = '('; diff --git a/src/log.h b/src/log.h index d5011f35..4a4d9bbf 100644 --- a/src/log.h +++ b/src/log.h @@ -5,12 +5,11 @@ #include "base_decls.h" #include "buffer.h" -extern time_t log_epoch_secs; -extern time_t log_monotonic_secs; +extern unix_time64_t log_epoch_secs; +extern unix_time64_t log_monotonic_secs; -struct timespec; /* declaration */ -int log_clock_gettime_realtime (struct timespec *ts); -int log_clock_gettime_monotonic (struct timespec *ts); +int log_clock_gettime_realtime (unix_timespec64_t *ts); +int log_clock_gettime_monotonic (unix_timespec64_t *ts); ssize_t write_all(int fd, const void* buf, size_t count); diff --git a/src/mod_accesslog.c b/src/mod_accesslog.c index 4bf96dba..85b6f9db 100644 --- a/src/mod_accesslog.c +++ b/src/mod_accesslog.c @@ -137,7 +137,7 @@ typedef struct { } format_field; typedef struct { - time_t last_generated_accesslog_ts; + unix_time64_t last_generated_accesslog_ts; buffer ts_accesslog_str; #if defined(__STDC_VERSION__) && __STDC_VERSION__-0 >= 199901L /* C99 */ format_field ptr[]; /* C99 VLA */ @@ -793,7 +793,7 @@ SIGHUP_FUNC(log_access_cycle) { static int log_access_record (const request_st * const r, buffer * const b, format_fields * const parsed_format) { const connection * const con = r->con; const buffer *vb; - struct timespec ts = { 0, 0 }; + unix_timespec64_t ts = { 0, 0 }; int flush = 0; for (const format_field *f = parsed_format->ptr; f->type != FIELD_UNSET; ++f) { @@ -807,17 +807,17 @@ static int log_access_record (const request_st * const r, buffer * const b, form if (f->opt & ~(FORMAT_FLAG_TIME_BEGIN|FORMAT_FLAG_TIME_END)) { if (f->opt & FORMAT_FLAG_TIME_SEC) { - time_t t = (!(f->opt & FORMAT_FLAG_TIME_BEGIN)) ? log_epoch_secs : r->start_hp.tv_sec; + unix_time64_t t = (!(f->opt & FORMAT_FLAG_TIME_BEGIN)) ? log_epoch_secs : r->start_hp.tv_sec; buffer_append_int(b, (intmax_t)t); } else if (f->opt & (FORMAT_FLAG_TIME_MSEC|FORMAT_FLAG_TIME_USEC|FORMAT_FLAG_TIME_NSEC)) { - off_t t; /*(expected to be 64-bit since large file support enabled)*/ + unix_time64_t t; long ns; if (!(f->opt & FORMAT_FLAG_TIME_BEGIN)) { if (0 == ts.tv_sec) log_clock_gettime_realtime(&ts); - t = (off_t)ts.tv_sec; + t = ts.tv_sec; ns = ts.tv_nsec; } else { - t = (off_t)r->start_hp.tv_sec; + t = r->start_hp.tv_sec; ns = r->start_hp.tv_nsec; } if (f->opt & FORMAT_FLAG_TIME_MSEC) { @@ -858,11 +858,11 @@ static int log_access_record (const request_st * const r, buffer * const b, form } else { buffer * const ts_accesslog_str = &parsed_format->ts_accesslog_str; /* cache the generated timestamp (only if ! FORMAT_FLAG_TIME_BEGIN) */ - time_t t; + unix_time64_t t; struct tm tm; if (!(f->opt & FORMAT_FLAG_TIME_BEGIN)) { - const time_t cur_ts = log_epoch_secs; + const unix_time64_t cur_ts = log_epoch_secs; if (parsed_format->last_generated_accesslog_ts == cur_ts) { buffer_append_string_buffer(b, ts_accesslog_str); break; @@ -880,11 +880,11 @@ static int log_access_record (const request_st * const r, buffer * const b, form #if defined(HAVE_STRUCT_TM_GMTOFF) buffer_append_strftime(ts_accesslog_str, fmt ? fmt : "[%d/%b/%Y:%T %z]", - localtime_r(&t, &tm)); + localtime64_r(&t, &tm)); #else /* HAVE_STRUCT_TM_GMTOFF */ buffer_append_strftime(ts_accesslog_str, fmt ? fmt : "[%d/%b/%Y:%T +0000]", - gmtime_r(&t, &tm)); + gmtime64_r(&t, &tm)); #endif /* HAVE_STRUCT_TM_GMTOFF */ buffer_append_string_buffer(b, ts_accesslog_str); } @@ -894,7 +894,7 @@ static int log_access_record (const request_st * const r, buffer * const b, form if (f->opt & FORMAT_FLAG_TIME_SEC) { buffer_append_int(b, log_epoch_secs - r->start_hp.tv_sec); } else { - const struct timespec * const bs = &r->start_hp; + const unix_timespec64_t * const bs = &r->start_hp; off_t tdiff; /*(expected to be 64-bit since large file support enabled)*/ if (0 == ts.tv_sec) log_clock_gettime_realtime(&ts); tdiff = (off_t)(ts.tv_sec - bs->tv_sec)*1000000000 + (ts.tv_nsec - bs->tv_nsec); diff --git a/src/mod_auth.c b/src/mod_auth.c index 627ddcb2..c0beb355 100644 --- a/src/mod_auth.c +++ b/src/mod_auth.c @@ -45,7 +45,7 @@ typedef struct { typedef struct { const struct http_auth_require_t *require; - time_t ctime; + unix_time64_t ctime; int dalgo; uint32_t dlen; uint32_t ulen; @@ -144,7 +144,7 @@ http_auth_cache_insert (splay_tree ** const sptree, const int ndx, void * const /* walk though cache, collect expired ids, and remove them in a second loop */ static void -mod_auth_tag_old_entries (splay_tree * const t, int * const keys, int * const ndx, const time_t max_age, const time_t cur_ts) +mod_auth_tag_old_entries (splay_tree * const t, int * const keys, int * const ndx, const time_t max_age, const unix_time64_t cur_ts) { if (*ndx == 8192) return; /*(must match num array entries in keys[])*/ if (t->left) @@ -160,7 +160,7 @@ mod_auth_tag_old_entries (splay_tree * const t, int * const keys, int * const nd __attribute_noinline__ static void -mod_auth_periodic_cleanup(splay_tree **sptree_ptr, const time_t max_age, const time_t cur_ts) +mod_auth_periodic_cleanup(splay_tree **sptree_ptr, const time_t max_age, const unix_time64_t cur_ts) { splay_tree *sptree = *sptree_ptr; int max_ndx, i; @@ -184,7 +184,7 @@ mod_auth_periodic_cleanup(splay_tree **sptree_ptr, const time_t max_age, const t TRIGGER_FUNC(mod_auth_periodic) { const plugin_data * const p = p_d; - const time_t cur_ts = log_monotonic_secs; + const unix_time64_t cur_ts = log_monotonic_secs; if (cur_ts & 0x7) return HANDLER_GO_ON; /*(continue once each 8 sec)*/ UNUSED(srv); @@ -867,7 +867,7 @@ enum http_auth_digest_params_e { typedef struct http_auth_digest_params_t { const char *ptr[http_auth_digest_params_sz]; uint16_t len[http_auth_digest_params_sz]; - time_t send_nextnonce_ts; + unix_time64_t send_nextnonce_ts; unsigned char rdigest[MD_DIGEST_LENGTH_MAX]; /*(last member)*/ } http_auth_digest_params_t; @@ -964,7 +964,7 @@ mod_auth_digest_mutate (http_auth_info_t * const ai, const http_auth_digest_para static void -mod_auth_append_nonce (buffer *b, time_t cur_ts, const struct http_auth_require_t *require, int dalgo, int *rndptr) +mod_auth_append_nonce (buffer *b, unix_time64_t cur_ts, const struct http_auth_require_t *require, int dalgo, int *rndptr) { buffer_append_uint_hex(b, (uintmax_t)cur_ts); buffer_append_string_len(b, CONST_STR_LEN(":")); @@ -1028,7 +1028,7 @@ mod_auth_append_nonce (buffer *b, time_t cur_ts, const struct http_auth_require_ static void -mod_auth_digest_www_authenticate (buffer *b, time_t cur_ts, const struct http_auth_require_t *require, int nonce_stale) +mod_auth_digest_www_authenticate (buffer *b, unix_time64_t cur_ts, const struct http_auth_require_t *require, int nonce_stale) { int algos = nonce_stale ? nonce_stale : require->algorithm; int n = 0; @@ -1093,7 +1093,7 @@ mod_auth_send_401_unauthorized_digest(request_st * const r, const struct http_au static void -mod_auth_digest_authentication_info (buffer *b, time_t cur_ts, const struct http_auth_require_t *require, int dalgo) +mod_auth_digest_authentication_info (buffer *b, unix_time64_t cur_ts, const struct http_auth_require_t *require, int dalgo) { buffer_clear(b); buffer_append_string_len(b, CONST_STR_LEN("nextnonce=\"")); @@ -1336,13 +1336,13 @@ mod_auth_digest_validate_nonce (request_st * const r, const struct http_auth_req * data value (included for unique nonces) will be exposed in the nonce * along with the timestamp, and the additional secret will be used to * validate that the server generated the nonce using that secret. */ - time_t ts = 0; + unix_time64_t ts = 0; const unsigned char * const nonce = (unsigned char *)dp->ptr[e_nonce]; int i; - for (i = 0; i < 8 && light_isxdigit(nonce[i]); ++i) - ts =(time_t)((uint32_t)ts << 4) | hex2int(nonce[i]); + for (i = 0; i < 16 && light_isxdigit(nonce[i]); ++i) + ts = (unix_time64_t)((uint64_t)ts << 4) | hex2int(nonce[i]); - const time_t cur_ts = log_epoch_secs; + const unix_time64_t cur_ts = log_epoch_secs; if (nonce[i] != ':' || ts > cur_ts || cur_ts - ts > 600) { /*(10 mins)*/ /* nonce is stale; have client regenerate digest */ return mod_auth_send_401_unauthorized_digest(r, require, ai->dalgo); diff --git a/src/mod_cml_lua.c b/src/mod_cml_lua.c index 91f19c01..95971334 100644 --- a/src/mod_cml_lua.c +++ b/src/mod_cml_lua.c @@ -192,7 +192,7 @@ int cache_parse_lua(request_st * const r, plugin_data * const p, const buffer * /* up to now it is a cache-hit, check if all files exist */ int curelem; - time_t mtime = 0; + unix_time64_t mtime = 0; if (!lua_to_c_is_table(L, "output_include")) { log_error(r->conf.errh, __FILE__, __LINE__, @@ -261,7 +261,8 @@ int cache_parse_lua(request_st * const r, plugin_data * const p, const buffer * } } else { chunkqueue_append_file_fd(&r->write_queue, b, fd, 0, st.st_size); - if (st.st_mtime > mtime) mtime = st.st_mtime; + if (mtime < TIME64_CAST(st.st_mtime)) + mtime = TIME64_CAST(st.st_mtime); } } else { /* not a string */ diff --git a/src/mod_dirlisting.c b/src/mod_dirlisting.c index 3bf0da55..e5134992 100644 --- a/src/mod_dirlisting.c +++ b/src/mod_dirlisting.c @@ -102,8 +102,8 @@ typedef struct { typedef struct { uint32_t namelen; - time_t mtime; - off_t size; + unix_time64_t mtime; + off_t size; } dirls_entry_t; typedef struct { @@ -1125,7 +1125,7 @@ static void http_list_directory(request_st * const r, handler_ctx * const hctx) buffer_append_string_len(out, CONST_STR_LEN("/\">")); buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_MINIMAL_XML); buffer_append_string_len(out, CONST_STR_LEN("/")); - buffer_append_strftime(out, "%Y-%b-%d %T", localtime_r(&tmp->mtime, &tm)); + buffer_append_strftime(out, "%Y-%b-%d %T", localtime64_r(&tmp->mtime, &tm)); buffer_append_string_len(out, CONST_STR_LEN("-  Directory\n")); if (buffer_string_space(out) < 256) { @@ -1166,7 +1166,7 @@ static void http_list_directory(request_st * const r, handler_ctx * const hctx) buffer_append_string_len(out, CONST_STR_LEN("\">")); buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_MINIMAL_XML); buffer_append_string_len(out, CONST_STR_LEN("")); - buffer_append_strftime(out, "%Y-%b-%d %T", localtime_r(&tmp->mtime, &tm)); + buffer_append_strftime(out, "%Y-%b-%d %T", localtime64_r(&tmp->mtime, &tm)); size_t buflen = http_list_directory_sizefmt(sizebuf, sizeof(sizebuf), tmp->size); struct const_iovec iov[] = { @@ -1357,7 +1357,7 @@ static handler_t mod_dirlisting_cache_check (request_st * const r, plugin_data * stat_cache_entry * const sce = stat_cache_get_entry_open(tb, 1); if (NULL == sce || sce->fd == -1) return HANDLER_GO_ON; - if (sce->st.st_mtime + p->conf.cache->max_age < log_epoch_secs) + if (TIME64_CAST(sce->st.st_mtime) + p->conf.cache->max_age < log_epoch_secs) return HANDLER_GO_ON; /* Note: dirlist < 350 or so entries will generally trigger file diff --git a/src/mod_expire.c b/src/mod_expire.c index b216bc18..6927ce70 100644 --- a/src/mod_expire.c +++ b/src/mod_expire.c @@ -247,8 +247,8 @@ SETDEFAULTS_FUNC(mod_expire_set_defaults) { static handler_t mod_expire_set_header (request_st * const r, const time_t * const off) { - const time_t cur_ts = log_epoch_secs; - time_t expires = off[1]; + const unix_time64_t cur_ts = log_epoch_secs; + unix_time64_t expires = off[1]; if (0 == off[0]) { /* access */ expires += cur_ts; } @@ -256,7 +256,7 @@ mod_expire_set_header (request_st * const r, const time_t * const off) const stat_cache_st * const st = stat_cache_path_stat(&r->physical.path); /* can't set modification-based expire if mtime is not available */ if (NULL == st) return HANDLER_GO_ON; - expires += st->st_mtime; + expires += TIME64_CAST(st->st_mtime); } /* expires should be at least cur_ts */ diff --git a/src/mod_gnutls.c b/src/mod_gnutls.c index e9a892a2..a5e4fb45 100644 --- a/src/mod_gnutls.c +++ b/src/mod_gnutls.c @@ -68,8 +68,8 @@ typedef struct { gnutls_datum_t *ssl_pemfile_x509; gnutls_privkey_t ssl_pemfile_pkey; const buffer *ssl_stapling_file; - time_t ssl_stapling_loadts; - time_t ssl_stapling_nextts; + unix_time64_t ssl_stapling_loadts; + unix_time64_t ssl_stapling_nextts; } plugin_cert; typedef struct { @@ -273,15 +273,15 @@ mod_gnutls_datum_wipe (gnutls_datum_t * const d) * to store keys that are not yet active * (mirror from mod_openssl, even though not all bits are used here) */ typedef struct tlsext_ticket_key_st { - time_t active_ts; /* tickets not issued w/ key until activation timestamp */ - time_t expire_ts; /* key not valid after expiration timestamp */ + unix_time64_t active_ts; /* tickets not issued w/ key until activation ts*/ + unix_time64_t expire_ts; /* key not valid after expiration timestamp */ unsigned char tick_key_name[TLSEXT_KEYNAME_LENGTH]; unsigned char tick_hmac_key[TLSEXT_TICK_KEY_LENGTH]; unsigned char tick_aes_key[TLSEXT_TICK_KEY_LENGTH]; } tlsext_ticket_key_t; static tlsext_ticket_key_t session_ticket_keys[1]; /* temp store until active */ -static time_t stek_rotate_ts; +static unix_time64_t stek_rotate_ts; static gnutls_datum_t session_ticket_key; @@ -348,8 +348,8 @@ mod_gnutls_session_ticket_key_file (const char *fn) if (0 != fdevent_load_file_bytes((char *)buf,(off_t)sizeof(buf),0,fn,NULL)) return rc; if (buf[0] == 0) { /*(format version 0)*/ - session_ticket_keys[0].active_ts = buf[1]; - session_ticket_keys[0].expire_ts = buf[2]; + session_ticket_keys[0].active_ts = TIME64_CAST(buf[1]); + session_ticket_keys[0].expire_ts = TIME64_CAST(buf[2]); #ifndef __COVERITY__ memcpy(&session_ticket_keys[0].tick_key_name, buf+3, 80); #else @@ -369,16 +369,17 @@ mod_gnutls_session_ticket_key_file (const char *fn) static void -mod_gnutls_session_ticket_key_check (server *srv, const plugin_data *p, const time_t cur_ts) +mod_gnutls_session_ticket_key_check (server *srv, const plugin_data *p, const unix_time64_t cur_ts) { - static time_t detect_retrograde_ts; + static unix_time64_t detect_retrograde_ts; if (detect_retrograde_ts > cur_ts && detect_retrograde_ts - cur_ts > 28800) stek_rotate_ts = 0; detect_retrograde_ts = cur_ts; if (p->ssl_stek_file) { struct stat st; - if (0 == stat(p->ssl_stek_file, &st) && st.st_mtime > stek_rotate_ts + if (0 == stat(p->ssl_stek_file, &st) + && TIME64_CAST(st.st_mtime) > stek_rotate_ts && mod_gnutls_session_ticket_key_file(p->ssl_stek_file)) { stek_rotate_ts = cur_ts; } @@ -923,7 +924,7 @@ mod_gnutls_expire_stapling_file (server *srv, plugin_cert *pc) static int -mod_gnutls_reload_stapling_file (server *srv, plugin_cert *pc, const time_t cur_ts) +mod_gnutls_reload_stapling_file (server *srv, plugin_cert *pc, const unix_time64_t cur_ts) { #if GNUTLS_VERSION_NUMBER < 0x030603 /* load file into gnutls_ocsp_resp_t before loading into @@ -970,7 +971,7 @@ mod_gnutls_reload_stapling_file (server *srv, plugin_cert *pc, const time_t cur_ pc->ssl_stapling_loadts = cur_ts; pc->ssl_stapling_nextts = nextupd; - if (pc->ssl_stapling_nextts == (time_t)-1) { + if (pc->ssl_stapling_nextts == -1) { /* "Next Update" might not be provided by OCSP responder * Use 3600 sec (1 hour) in that case. */ /* retry in 1 hour if unable to determine Next Update */ @@ -985,13 +986,13 @@ mod_gnutls_reload_stapling_file (server *srv, plugin_cert *pc, const time_t cur_ static int -mod_gnutls_refresh_stapling_file (server *srv, plugin_cert *pc, const time_t cur_ts) +mod_gnutls_refresh_stapling_file (server *srv, plugin_cert *pc, const unix_time64_t cur_ts) { if (pc->ssl_stapling_nextts > cur_ts + 256) return 0; /* skip check for refresh unless close to expire */ struct stat st; if (0 != stat(pc->ssl_stapling_file->ptr, &st) - || st.st_mtime <= pc->ssl_stapling_loadts) { + || TIME64_CAST(st.st_mtime) <= pc->ssl_stapling_loadts) { if (pc->ssl_stapling_nextts < cur_ts) mod_gnutls_expire_stapling_file(srv, pc); return 0; @@ -1001,7 +1002,7 @@ mod_gnutls_refresh_stapling_file (server *srv, plugin_cert *pc, const time_t cur static void -mod_gnutls_refresh_stapling_files (server *srv, const plugin_data *p, const time_t cur_ts) +mod_gnutls_refresh_stapling_files (server *srv, const plugin_data *p, const unix_time64_t cur_ts) { /* future: might construct array of (plugin_cert *) at startup * to avoid the need to search for them here */ @@ -2979,7 +2980,7 @@ REQUEST_FUNC(mod_gnutls_handle_request_reset) TRIGGER_FUNC(mod_gnutls_handle_trigger) { const plugin_data * const p = p_d; - const time_t cur_ts = log_epoch_secs; + const unix_time64_t cur_ts = log_epoch_secs; if (cur_ts & 0x3f) return HANDLER_GO_ON; /*(continue once each 64 sec)*/ mod_gnutls_session_ticket_key_check(srv, p, cur_ts); diff --git a/src/mod_mbedtls.c b/src/mod_mbedtls.c index 8c258706..56c86858 100644 --- a/src/mod_mbedtls.c +++ b/src/mod_mbedtls.c @@ -262,15 +262,15 @@ static void elogf(log_error_st * const errh, * to store keys that are not yet active * (mirror from mod_openssl, even though not all bits are used here) */ typedef struct tlsext_ticket_key_st { - time_t active_ts; /* tickets not issued w/ key until activation timestamp */ - time_t expire_ts; /* key not valid after expiration timestamp */ + unix_time64_t active_ts; /* tickets not issued w/ key until activation ts*/ + unix_time64_t expire_ts; /* key not valid after expiration timestamp */ unsigned char tick_key_name[TLSEXT_KEYNAME_LENGTH]; unsigned char tick_hmac_key[TLSEXT_TICK_KEY_LENGTH]; unsigned char tick_aes_key[TLSEXT_TICK_KEY_LENGTH]; } tlsext_ticket_key_t; static tlsext_ticket_key_t session_ticket_keys[1]; /* temp store until active */ -static time_t stek_rotate_ts; +static unix_time64_t stek_rotate_ts; static int @@ -311,8 +311,8 @@ mod_mbedtls_session_ticket_key_file (const char *fn) if (0 != fdevent_load_file_bytes((char *)buf,(off_t)sizeof(buf),0,fn,NULL)) return rc; if (buf[0] == 0) { /*(format version 0)*/ - session_ticket_keys[0].active_ts = buf[1]; - session_ticket_keys[0].expire_ts = buf[2]; + session_ticket_keys[0].active_ts = TIME64_CAST(buf[1]); + session_ticket_keys[0].expire_ts = TIME64_CAST(buf[2]); #ifndef __COVERITY__ memcpy(&session_ticket_keys[0].tick_key_name, buf+3, 80); #else @@ -332,12 +332,13 @@ mod_mbedtls_session_ticket_key_file (const char *fn) static void -mod_mbedtls_session_ticket_key_check (plugin_data *p, const time_t cur_ts) +mod_mbedtls_session_ticket_key_check (plugin_data *p, const unix_time64_t cur_ts) { if (NULL == p->ssl_stek_file) return; struct stat st; - if (0 == stat(p->ssl_stek_file, &st) && st.st_mtime > stek_rotate_ts + if (0 == stat(p->ssl_stek_file, &st) + && TIME64_CAST(st.st_mtime) > stek_rotate_ts && mod_mbedtls_session_ticket_key_file(p->ssl_stek_file)) { stek_rotate_ts = cur_ts; } @@ -361,7 +362,7 @@ mod_mbedtls_session_ticket_key_check (plugin_data *p, const time_t cur_ts) mbedtls_cipher_get_key_bitlen(&key->ctx), MBEDTLS_ENCRYPT); if (0 != rc) { /* expire key immediately if error occurs */ - key->generation_time = cur_ts > ctx->ticket_lifetime + key->generation_time = cur_ts > (unix_time64_t)ctx->ticket_lifetime ? cur_ts - ctx->ticket_lifetime - 1 : 0; ctx->active = 1 - ctx->active; @@ -2616,7 +2617,7 @@ REQUEST_FUNC(mod_mbedtls_handle_request_reset) TRIGGER_FUNC(mod_mbedtls_handle_trigger) { plugin_data * const p = p_d; - const time_t cur_ts = log_epoch_secs; + const unix_time64_t cur_ts = log_epoch_secs; if (cur_ts & 0x3f) return HANDLER_GO_ON; /*(continue once each 64 sec)*/ UNUSED(srv); UNUSED(p); diff --git a/src/mod_nss.c b/src/mod_nss.c index db2b42ee..650bc329 100644 --- a/src/mod_nss.c +++ b/src/mod_nss.c @@ -124,8 +124,8 @@ typedef struct { SECKEYPrivateKey *ssl_pemfile_pkey; SSLExtraServerCertData ssl_credex; const buffer *ssl_stapling_file; - time_t ssl_stapling_loadts; - time_t ssl_stapling_nextts; + unix_time64_t ssl_stapling_loadts; + unix_time64_t ssl_stapling_nextts; SECItemArray OCSPResponses; SECItem OCSPResponse; } plugin_cert; @@ -1035,7 +1035,7 @@ mod_nss_expire_stapling_file (server *srv, plugin_cert *pc) static int -mod_nss_reload_stapling_file (server *srv, plugin_cert *pc, const time_t cur_ts) +mod_nss_reload_stapling_file (server *srv, plugin_cert *pc, const unix_time64_t cur_ts) { SECItem f; int rc = mod_nss_load_file(pc->ssl_stapling_file->ptr, &f, srv->errh); @@ -1068,11 +1068,11 @@ mod_nss_reload_stapling_file (server *srv, plugin_cert *pc, const time_t cur_ts) * XXX: *not* implementing our own ASN.1 DER decoder for OCSP response * ssl.stapling-file will be reloaded hourly */ - time_t nextupd = (time_t)-1; + unix_time64_t nextupd = -1; pc->ssl_stapling_loadts = cur_ts; pc->ssl_stapling_nextts = nextupd; - if (pc->ssl_stapling_nextts == (time_t)-1) { + if (pc->ssl_stapling_nextts == -1) { /* "Next Update" might not be provided by OCSP responder * Use 3600 sec (1 hour) in that case. */ /* retry in 1 hour if unable to determine Next Update */ @@ -1087,13 +1087,13 @@ mod_nss_reload_stapling_file (server *srv, plugin_cert *pc, const time_t cur_ts) static int -mod_nss_refresh_stapling_file (server *srv, plugin_cert *pc, const time_t cur_ts) +mod_nss_refresh_stapling_file (server *srv, plugin_cert *pc, const unix_time64_t cur_ts) { if (pc->ssl_stapling_nextts > cur_ts + 256) return 0; /* skip check for refresh unless close to expire */ struct stat st; if (0 != stat(pc->ssl_stapling_file->ptr, &st) - || st.st_mtime <= pc->ssl_stapling_loadts) { + || TIME64_CAST(st.st_mtime) <= pc->ssl_stapling_loadts) { if (pc->ssl_stapling_nextts < cur_ts) mod_nss_expire_stapling_file(srv, pc); return 0; @@ -1103,7 +1103,7 @@ mod_nss_refresh_stapling_file (server *srv, plugin_cert *pc, const time_t cur_ts static void -mod_nss_refresh_stapling_files (server *srv, const plugin_data *p, const time_t cur_ts) +mod_nss_refresh_stapling_files (server *srv, const plugin_data *p, const unix_time64_t cur_ts) { /* future: might construct array of (plugin_cert *) at startup * to avoid the need to search for them here */ @@ -2734,7 +2734,7 @@ REQUEST_FUNC(mod_nss_handle_request_reset) TRIGGER_FUNC(mod_nss_handle_trigger) { const plugin_data * const p = p_d; - const time_t cur_ts = log_epoch_secs; + const unix_time64_t cur_ts = log_epoch_secs; if (cur_ts & 0x3f) return HANDLER_GO_ON; /*(continue once each 64 sec)*/ mod_nss_refresh_stapling_files(srv, p, cur_ts); diff --git a/src/mod_openssl.c b/src/mod_openssl.c index dd34d4cf..a31b57f0 100644 --- a/src/mod_openssl.c +++ b/src/mod_openssl.c @@ -102,8 +102,8 @@ typedef struct { const buffer *ssl_pemfile; const buffer *ssl_privkey; const buffer *ssl_stapling_file; - time_t ssl_stapling_loadts; - time_t ssl_stapling_nextts; + unix_time64_t ssl_stapling_loadts; + unix_time64_t ssl_stapling_nextts; char must_staple; char self_issued; } plugin_cert; @@ -215,19 +215,19 @@ handler_ctx_free (handler_ctx *hctx) /* openssl has a huge number of interfaces, but not the most useful; * construct our own session ticket encryption key structure */ typedef struct tlsext_ticket_key_st { - time_t active_ts; /* tickets not issued w/ key until activation timestamp */ - time_t expire_ts; /* key not valid after expiration timestamp */ + unix_time64_t active_ts; /* tickets not issued w/ key until activation ts*/ + unix_time64_t expire_ts; /* key not valid after expiration timestamp */ unsigned char tick_key_name[TLSEXT_KEYNAME_LENGTH]; unsigned char tick_hmac_key[TLSEXT_TICK_KEY_LENGTH]; unsigned char tick_aes_key[TLSEXT_TICK_KEY_LENGTH]; } tlsext_ticket_key_t; static tlsext_ticket_key_t session_ticket_keys[4]; -static time_t stek_rotate_ts; +static unix_time64_t stek_rotate_ts; static int -mod_openssl_session_ticket_key_generate (time_t active_ts, time_t expire_ts) +mod_openssl_session_ticket_key_generate (unix_time64_t active_ts, unix_time64_t expire_ts) { /* openssl RAND_*bytes() functions are called multiple times since the * funcs might have a 32-byte limit on number of bytes returned each call @@ -275,7 +275,7 @@ mod_openssl_session_ticket_key_rotate (void) static tlsext_ticket_key_t * tlsext_ticket_key_get (void) { - const time_t cur_ts = log_epoch_secs; + const unix_time64_t cur_ts = log_epoch_secs; const int e = sizeof(session_ticket_keys)/sizeof(*session_ticket_keys) - 1; for (int i = 0; i < e; ++i) { if (session_ticket_keys[i].active_ts > cur_ts) continue; @@ -290,7 +290,7 @@ static tlsext_ticket_key_t * tlsext_ticket_key_find (unsigned char key_name[16], int *refresh) { *refresh = 0; - const time_t cur_ts = log_epoch_secs; + const unix_time64_t cur_ts = log_epoch_secs; const int e = sizeof(session_ticket_keys)/sizeof(*session_ticket_keys) - 1; for (int i = 0; i < e; ++i) { if (session_ticket_keys[i].expire_ts < cur_ts) continue; @@ -304,7 +304,7 @@ tlsext_ticket_key_find (unsigned char key_name[16], int *refresh) static void -tlsext_ticket_wipe_expired (const time_t cur_ts) +tlsext_ticket_wipe_expired (const unix_time64_t cur_ts) { const int e = sizeof(session_ticket_keys)/sizeof(*session_ticket_keys) - 1; for (int i = 0; i < e; ++i) { @@ -422,8 +422,8 @@ mod_openssl_session_ticket_key_file (const char *fn) if (0 != fdevent_load_file_bytes((char *)buf,(off_t)sizeof(buf),0,fn,NULL)) return rc; if (buf[0] == 0) { /*(format version 0)*/ - session_ticket_keys[3].active_ts = buf[1]; - session_ticket_keys[3].expire_ts = buf[2]; + session_ticket_keys[3].active_ts = TIME64_CAST(buf[1]); + session_ticket_keys[3].expire_ts = TIME64_CAST(buf[2]); #ifndef __COVERITY__ /* intentional; hide from Coverity Scan */ /* intentionally copy 80 bytes into consecutive arrays * tick_key_name[], tick_hmac_key[], tick_aes_key[] */ @@ -438,9 +438,9 @@ mod_openssl_session_ticket_key_file (const char *fn) static void -mod_openssl_session_ticket_key_check (const plugin_data *p, const time_t cur_ts) +mod_openssl_session_ticket_key_check (const plugin_data *p, const unix_time64_t cur_ts) { - static time_t detect_retrograde_ts; + static unix_time64_t detect_retrograde_ts; if (detect_retrograde_ts > cur_ts && detect_retrograde_ts - cur_ts > 28800) stek_rotate_ts = 0; detect_retrograde_ts = cur_ts; @@ -448,7 +448,8 @@ mod_openssl_session_ticket_key_check (const plugin_data *p, const time_t cur_ts) int rotate = 0; if (p->ssl_stek_file) { struct stat st; - if (0 == stat(p->ssl_stek_file, &st) && st.st_mtime > stek_rotate_ts) + if (0 == stat(p->ssl_stek_file, &st) + && TIME64_CAST(st.st_mtime) > stek_rotate_ts) rotate = mod_openssl_session_ticket_key_file(p->ssl_stek_file); tlsext_ticket_wipe_expired(cur_ts); } @@ -1405,7 +1406,7 @@ mod_openssl_load_stapling_file (const char *file, log_error_st *errh, buffer *b) #if !defined(BORINGSSL_API_VERSION) -static time_t +static unix_time64_t mod_openssl_asn1_time_to_posix (ASN1_TIME *asn1time) { #ifdef LIBRESSL_VERSION_NUMBER @@ -1416,7 +1417,7 @@ mod_openssl_asn1_time_to_posix (ASN1_TIME *asn1time) /*(Note: incorrectly assumes GMT if 'Z' or offset not provided)*/ /*(Note: incorrectly ignores if local timezone might be in DST)*/ - if (NULL == asn1time || NULL == asn1time->data) return (time_t)-1; + if (NULL == asn1time || NULL == asn1time->data) return -1; const char *s = (const char *)asn1time->data; size_t len = strlen(s); struct tm x; @@ -1425,20 +1426,20 @@ mod_openssl_asn1_time_to_posix (ASN1_TIME *asn1time) x.tm_wday = 0; switch (asn1time->type) { case V_ASN1_UTCTIME: /* 2-digit year */ - if (len < 8) return (time_t)-1; + if (len < 8) return -1; len -= 8; x.tm_year = (s[0]-'0')*10 + (s[1]-'0'); x.tm_year += (x.tm_year < 50 ? 2000 : 1900); s += 2; break; case V_ASN1_GENERALIZEDTIME: /* 4-digit year */ - if (len < 10) return (time_t)-1; + if (len < 10) return -1; len -= 10; x.tm_year = (s[0]-'0')*1000+(s[1]-'0')*100+(s[2]-'0')*10+(s[3]-'0'); s += 4; break; default: - return (time_t)-1; + return -1; } x.tm_mon = (s[0]-'0')*10 + (s[1]-'0'); x.tm_mday = (s[2]-'0')*10 + (s[3]-'0'); @@ -1468,16 +1469,16 @@ mod_openssl_asn1_time_to_posix (ASN1_TIME *asn1time) if (*s == '-') offset = -offset; } else if (s[0] != '\0' && (s[0] != 'Z' || s[1] != '\0')) - return (time_t)-1; + return -1; if (x.tm_year == 9999 && x.tm_mon == 12 && x.tm_mday == 31 && x.tm_hour == 23 && x.tm_min == 59 && x.tm_sec == 59 && s[0] == 'Z') - return (time_t)-1; // 99991231235959Z RFC 5280 + return -1; // 99991231235959Z RFC 5280 x.tm_year-= 1900; x.tm_mon -= 1; time_t t = timegm(&x); - return (t != (time_t)-1) ? t + offset : t; + return (t != -1) ? TIME64_CAST(t) + offset : t; #else @@ -1485,34 +1486,34 @@ mod_openssl_asn1_time_to_posix (ASN1_TIME *asn1time) int day, sec; return ASN1_TIME_diff(&day, &sec, NULL, asn1time) ? log_epoch_secs + day*86400 + sec - : (time_t)-1; + : -1; #endif } #endif -static time_t +static unix_time64_t mod_openssl_ocsp_next_update (plugin_cert *pc) { #if defined(BORINGSSL_API_VERSION) UNUSED(pc); - return (time_t)-1; /*(not implemented)*/ + return -1; /*(not implemented)*/ #else buffer *der = pc->ssl_stapling; const unsigned char *p = (unsigned char *)der->ptr; /*(p gets modified)*/ OCSP_RESPONSE *ocsp = d2i_OCSP_RESPONSE(NULL, &p, buffer_clen(der)); - if (NULL == ocsp) return (time_t)-1; + if (NULL == ocsp) return -1; OCSP_BASICRESP *bs = OCSP_response_get1_basic(ocsp); if (NULL == bs) { OCSP_RESPONSE_free(ocsp); - return (time_t)-1; + return -1; } /* XXX: should save and evaluate cert status returned by these calls */ ASN1_TIME *nextupd = NULL; OCSP_single_get0_status(OCSP_resp_get0(bs, 0), NULL, NULL, NULL, &nextupd); - time_t t = nextupd ? mod_openssl_asn1_time_to_posix(nextupd) : (time_t)-1; + unix_time64_t t = nextupd ? mod_openssl_asn1_time_to_posix(nextupd) : -1; /* Note: trust external process which creates ssl.stapling-file to verify * (as well as to validate certificate status) @@ -1545,7 +1546,7 @@ mod_openssl_expire_stapling_file (server *srv, plugin_cert *pc) static int -mod_openssl_reload_stapling_file (server *srv, plugin_cert *pc, const time_t cur_ts) +mod_openssl_reload_stapling_file (server *srv, plugin_cert *pc, const unix_time64_t cur_ts) { buffer *b = mod_openssl_load_stapling_file(pc->ssl_stapling_file->ptr, srv->errh, pc->ssl_stapling); @@ -1554,7 +1555,7 @@ mod_openssl_reload_stapling_file (server *srv, plugin_cert *pc, const time_t cur pc->ssl_stapling = b; /*(unchanged unless orig was NULL)*/ pc->ssl_stapling_loadts = cur_ts; pc->ssl_stapling_nextts = mod_openssl_ocsp_next_update(pc); - if (pc->ssl_stapling_nextts == (time_t)-1) { + if (pc->ssl_stapling_nextts == -1) { /* "Next Update" might not be provided by OCSP responder * Use 3600 sec (1 hour) in that case. */ /* retry in 1 hour if unable to determine Next Update */ @@ -1571,13 +1572,13 @@ mod_openssl_reload_stapling_file (server *srv, plugin_cert *pc, const time_t cur static int -mod_openssl_refresh_stapling_file (server *srv, plugin_cert *pc, const time_t cur_ts) +mod_openssl_refresh_stapling_file (server *srv, plugin_cert *pc, const unix_time64_t cur_ts) { if (pc->ssl_stapling && pc->ssl_stapling_nextts > cur_ts + 256) return 1; /* skip check for refresh unless close to expire */ struct stat st; if (0 != stat(pc->ssl_stapling_file->ptr, &st) - || st.st_mtime <= pc->ssl_stapling_loadts) { + || TIME64_CAST(st.st_mtime) <= pc->ssl_stapling_loadts) { if (pc->ssl_stapling && pc->ssl_stapling_nextts < cur_ts) mod_openssl_expire_stapling_file(srv, pc); return 1; @@ -1587,7 +1588,7 @@ mod_openssl_refresh_stapling_file (server *srv, plugin_cert *pc, const time_t cu static void -mod_openssl_refresh_stapling_files (server *srv, const plugin_data *p, const time_t cur_ts) +mod_openssl_refresh_stapling_files (server *srv, const plugin_data *p, const unix_time64_t cur_ts) { /* future: might construct array of (plugin_cert *) at startup * to avoid the need to search for them here */ @@ -3633,7 +3634,7 @@ REQUEST_FUNC(mod_openssl_handle_request_reset) TRIGGER_FUNC(mod_openssl_handle_trigger) { const plugin_data * const p = p_d; - const time_t cur_ts = log_epoch_secs; + const unix_time64_t cur_ts = log_epoch_secs; if (cur_ts & 0x3f) return HANDLER_GO_ON; /*(continue once each 64 sec)*/ UNUSED(srv); UNUSED(p); diff --git a/src/mod_secdownload.c b/src/mod_secdownload.c index 58da9a3f..f656f846 100644 --- a/src/mod_secdownload.c +++ b/src/mod_secdownload.c @@ -23,7 +23,7 @@ * uri-prefix := '/' any* # whatever was configured: must start with a '/') * mac := [a-zA-Z0-9_-]{mac_len} # mac length depends on selected algorithm * protected-path := '/' - * timestamp := [a-f0-9]{8} # timestamp when the checksum was calculated + * timestamp := [a-f0-9]{1,16} # timestamp when the checksum was calculated * # to prevent access after timeout (active requests * # will finish successfully even after the timeout) * rel-path := '/' any* # the protected path; changing the path breaks the @@ -41,7 +41,7 @@ use Digest::MD5 qw(md5_hex); my $secret = "verysecret"; my $rel_path = "/index.html" - my $xtime = sprintf("%08x", time); + my $xtime = sprintf("%x", time); my $url = '/'. md5_hex($secret . $rel_path . $xtime) . '/' . $xtime . $rel_path; * * # hmac-sha1 @@ -52,7 +52,7 @@ use MIME::Base64 qw(encode_base64url); my $secret = "verysecret"; my $rel_path = "/index.html" - my $protected_path = '/' . sprintf("%08x", time) . $rel_path; + my $protected_path = '/' . sprintf("%x", time) . $rel_path; my $url = '/'. encode_base64url(hmac_sha1($protected_path, $secret)) . $protected_path; * * # hmac-sha256 @@ -62,7 +62,7 @@ use MIME::Base64 qw(encode_base64url); my $secret = "verysecret"; my $rel_path = "/index.html" - my $protected_path = '/' . sprintf("%08x", time) . $rel_path; + my $protected_path = '/' . sprintf("%x", time) . $rel_path; my $url = '/'. encode_base64url(hmac_sha256($protected_path, $secret)) . $protected_path; * */ @@ -144,18 +144,19 @@ static int secdl_verify_mac(plugin_config *config, const char* protected_path, c /* legacy message: * protected_path := '/' - * timestamp-hex := [0-9a-f]{8} + * timestamp-hex := [0-9a-f]{1,16} * rel-path := '/' any* * (the protected path was already verified) * message = */ ts_str = protected_path + 1; - rel_uri = ts_str + 8; + rel_uri = ts_str; + do { ++rel_uri; } while (*rel_uri != '/'); struct const_iovec iov[] = { { BUF_PTR_LEN(config->secret) } ,{ rel_uri, strlen(rel_uri) } - ,{ ts_str, 8 } + ,{ ts_str, (size_t)(rel_uri - ts_str) } }; MD5_iov(HA1, iov, sizeof(iov)/sizeof(*iov)); @@ -352,27 +353,6 @@ SETDEFAULTS_FUNC(mod_secdownload_set_defaults) { return HANDLER_GO_ON; } -/** - * checks if the supplied string is a hex string - * - * @param str a possible hex string - * @return if the supplied string is a valid hex string 1 is returned otherwise 0 - */ - -static int is_hex_len(const char *str, size_t len) { - size_t i; - - if (NULL == str) return 0; - - for (i = 0; i < len && *str; i++, str++) { - /* illegal characters */ - if (!light_isxdigit(*str)) - return 0; - } - - return i == len; -} - /** * checks if the supplied string is a base64 (modified URL) string * @@ -397,7 +377,6 @@ static int is_base64_len(const char *str, size_t len) { URIHANDLER_FUNC(mod_secdownload_uri_handler) { plugin_data *p = p_d; const char *rel_uri, *ts_str, *mac_str, *protected_path; - time_t ts = 0; size_t i, mac_len; if (NULL != r->handler_module) return HANDLER_GO_ON; @@ -443,26 +422,22 @@ URIHANDLER_FUNC(mod_secdownload_uri_handler) { if (*protected_path != '/') return HANDLER_GO_ON; ts_str = protected_path + 1; - if (!is_hex_len(ts_str, 8)) return HANDLER_GO_ON; - if (*(ts_str + 8) != '/') return HANDLER_GO_ON; - - for (i = 0; i < 8; i++) { - ts = (time_t)((uint32_t)ts << 4) | hex2int(ts_str[i]); + uint64_t ts = 0; + for (i = 0; i < 16 && light_isxdigit(ts_str[i]); ++i) { + ts = (ts << 4) | hex2int(ts_str[i]); } - - const time_t cur_ts = log_epoch_secs; + rel_uri = ts_str + i; + if (i == 0 || *rel_uri != '/') return HANDLER_GO_ON; /* timed-out */ - if ( (cur_ts > ts && (unsigned int) (cur_ts - ts) > p->conf.timeout) || - (cur_ts < ts && (unsigned int) (ts - cur_ts) > p->conf.timeout) ) { + const uint64_t cur_ts = (uint64_t)log_epoch_secs; + if ((cur_ts > ts ? cur_ts - ts : ts - cur_ts) > p->conf.timeout) { /* "Gone" as the url will never be valid again instead of "408 - Timeout" where the request may be repeated */ r->http_status = 410; return HANDLER_FINISHED; } - rel_uri = ts_str + 8; - buffer * const tb = r->tmp_buf; if (p->conf.path_segments) { diff --git a/src/mod_ssi.c b/src/mod_ssi.c index 7b34583b..955dcc98 100644 --- a/src/mod_ssi.c +++ b/src/mod_ssi.c @@ -58,7 +58,7 @@ static void handler_ctx_free(handler_ctx *hctx) { } /* The newest modified time of included files for include statement */ -static volatile time_t include_file_last_mtime = 0; +static volatile unix_time64_t include_file_last_mtime = 0; INIT_FUNC(mod_ssi_init) { plugin_data *p; @@ -207,13 +207,14 @@ static int build_ssi_cgi_vars(request_st * const r, handler_ctx * const p) { return 0; } -static void mod_ssi_timefmt (buffer * const b, buffer *timefmtb, time_t t, int localtm) { +static void mod_ssi_timefmt (buffer * const b, buffer *timefmtb, unix_time64_t t, int localtm) { struct tm tm; const char * const timefmt = buffer_is_blank(timefmtb) ? "%a, %d %b %Y %T %Z" : timefmtb->ptr; - buffer_append_strftime(b, timefmt, - localtm ? localtime_r(&t, &tm) : gmtime_r(&t, &tm)); + buffer_append_strftime(b, timefmt, localtm + ? localtime64_r(&t, &tm) + : gmtime64_r(&t, &tm)); if (buffer_is_blank(b)) buffer_copy_string_len(b, CONST_STR_LEN("(none)")); } @@ -604,8 +605,6 @@ static int process_ssi_stmt(request_st * const r, handler_ctx * const p, const c int fd = stat_cache_open_rdonly_fstat(p->stat_fn, &stb, r->conf.follow_symlink); if (fd >= 0) { - time_t t = stb.st_mtime; - switch (ssicmd) { case SSI_FSIZE: buffer_clear(tb); @@ -626,13 +625,13 @@ static int process_ssi_stmt(request_st * const r, handler_ctx * const p, const c break; case SSI_FLASTMOD: buffer_clear(tb); - mod_ssi_timefmt(tb, p->timefmt, t, 1); + mod_ssi_timefmt(tb, p->timefmt, stb.st_mtime, 1); chunkqueue_append_mem(cq, BUF_PTR_LEN(tb)); break; case SSI_INCLUDE: /* Keep the newest mtime of included files */ - if (stb.st_mtime > include_file_last_mtime) - include_file_last_mtime = stb.st_mtime; + if (include_file_last_mtime < TIME64_CAST(stb.st_mtime)) + include_file_last_mtime = TIME64_CAST(stb.st_mtime); if (file_path || 0 == p->conf.ssi_recursion_max) { /* don't process if #include file="..." is used */ @@ -1235,7 +1234,7 @@ static int mod_ssi_handle_request(request_st * const r, handler_ctx * const p) { /* Generate "ETag" & "Last-Modified" headers */ /* use most recently modified include file for ETag and Last-Modified */ - if (st.st_mtime < include_file_last_mtime) + if (TIME64_CAST(st.st_mtime) < include_file_last_mtime) st.st_mtime = include_file_last_mtime; http_etag_create(&r->physical.etag, &st, r->conf.etag_flags); diff --git a/src/mod_status.c b/src/mod_status.c index b035c11a..4f846263 100644 --- a/src/mod_status.c +++ b/src/mod_status.c @@ -232,7 +232,7 @@ static void mod_status_get_multiplier(buffer *b, double avg, int size) { buffer_append_string_len(b, unit, 2); } -static void mod_status_html_rtable_r (buffer * const b, const request_st * const r, const connection * const con, const time_t cur_ts) { +static void mod_status_html_rtable_r (buffer * const b, const request_st * const r, const connection * const con, const unix_time64_t cur_ts) { buffer_append_str3(b, CONST_STR_LEN(""), BUF_PTR_LEN(&con->dst_addr_buf), CONST_STR_LEN("")); @@ -292,7 +292,7 @@ static void mod_status_html_rtable_r (buffer * const b, const request_st * const buffer_append_string_len(b, CONST_STR_LEN("\n")); } -static void mod_status_html_rtable (request_st * const rq, const server * const srv, const time_t cur_ts) { +static void mod_status_html_rtable (request_st * const rq, const server * const srv, const unix_time64_t cur_ts) { /* connection table and URLs might be large, so double-buffer to aggregate * before sending to chunkqueue, which might be temporary file * (avoid write() per connection) */ @@ -328,8 +328,8 @@ static handler_t mod_status_handle_server_status_html(server *srv, request_st * buffer_string_prepare_append(b, 8192-1);/*(status page base HTML is ~5.2k)*/ double avg; uint32_t j; - time_t ts; - const time_t cur_ts = log_epoch_secs; + unix_time64_t ts; + const unix_time64_t cur_ts = log_epoch_secs; int days, hours, mins, seconds; @@ -498,7 +498,7 @@ static handler_t mod_status_handle_server_status_html(server *srv, request_st * ts = srv->startup_ts; struct tm tm; - buffer_append_strftime(b, "%F %T", localtime_r(&ts, &tm)); + buffer_append_strftime(b, "%F %T", localtime64_r(&ts, &tm)); buffer_append_string_len(b, CONST_STR_LEN("\n" "absolute (since start)\n" "Requests")); diff --git a/src/mod_trigger_b4_dl.c b/src/mod_trigger_b4_dl.c index 5d118812..dd8fe974 100644 --- a/src/mod_trigger_b4_dl.c +++ b/src/mod_trigger_b4_dl.c @@ -404,7 +404,7 @@ URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) { log_error(r->conf.errh, __FILE__, __LINE__, "(debug) remote-ip: %s", remote_ip->ptr); } - const time_t cur_ts = log_epoch_secs; + const unix_time64_t cur_ts = log_epoch_secs; /* check if URL is a trigger -> insert IP into DB */ if (mod_trigger_b4_dl_match(p->conf.trigger_regex, &r->uri.path)) { @@ -449,7 +449,7 @@ URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) { # if defined(HAVE_GDBM_H) if (p->conf.db) { datum key, val; - time_t last_hit; + unix_time64_t last_hit = 0; *(const char **)&key.dptr = remote_ip->ptr; key.dsize = buffer_clen(remote_ip); @@ -461,7 +461,13 @@ URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) { return mod_trigger_b4_dl_deny(r, p); } - memcpy(&last_hit, val.dptr, sizeof(time_t)); + if (val.dsize == sizeof(last_hit)) + memcpy(&last_hit, val.dptr, val.dsize); + else if (val.dsize == 4) { + int32_t t; + memcpy(&t, val.dptr, val.dsize); + last_hit = t; + } free(val.dptr); @@ -519,7 +525,7 @@ URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) { } #if defined(HAVE_GDBM_H) -static void mod_trigger_b4_dl_trigger_gdbm(GDBM_FILE db, const time_t cur_ts, const int trigger_timeout) { +static void mod_trigger_b4_dl_trigger_gdbm(GDBM_FILE db, const unix_time64_t cur_ts, const int trigger_timeout) { datum key, val, okey; okey.dptr = NULL; @@ -528,7 +534,7 @@ static void mod_trigger_b4_dl_trigger_gdbm(GDBM_FILE db, const time_t cur_ts, co * we don't care as the next round will remove them. We don't have to perfect here. */ for (key = gdbm_firstkey(db); key.dptr; key = gdbm_nextkey(db, okey)) { - time_t last_hit; + unix_time64_t last_hit = 0; if (okey.dptr) { free(okey.dptr); okey.dptr = NULL; @@ -536,7 +542,13 @@ static void mod_trigger_b4_dl_trigger_gdbm(GDBM_FILE db, const time_t cur_ts, co val = gdbm_fetch(db, key); - memcpy(&last_hit, val.dptr, sizeof(time_t)); + if (val.dsize == sizeof(last_hit)) + memcpy(&last_hit, val.dptr, val.dsize); + else if (val.dsize == 4) { + int32_t t; + memcpy(&t, val.dptr, val.dsize); + last_hit = t; + } free(val.dptr); @@ -554,7 +566,7 @@ static void mod_trigger_b4_dl_trigger_gdbm(GDBM_FILE db, const time_t cur_ts, co TRIGGER_FUNC(mod_trigger_b4_dl_handle_trigger) { /* check DB each minute */ - const time_t cur_ts = log_epoch_secs; + const unix_time64_t cur_ts = log_epoch_secs; if (cur_ts % 60 != 0) return HANDLER_GO_ON; UNUSED(srv); diff --git a/src/mod_userdir.c b/src/mod_userdir.c index ff2f465f..aac0c75d 100644 --- a/src/mod_userdir.c +++ b/src/mod_userdir.c @@ -31,7 +31,7 @@ typedef struct { PLUGIN_DATA; plugin_config defaults; plugin_config conf; - time_t cache_ts[2]; + unix_time64_t cache_ts[2]; buffer cache_user[2]; buffer cache_path[2]; } plugin_data; @@ -184,7 +184,7 @@ static handler_t mod_userdir_docroot_construct(request_st * const r, plugin_data if (!p->conf.basepath) { #ifdef HAVE_PWD_H /* getpwnam() lookup is expensive; first check 2-element cache */ - const time_t cur_ts = log_monotonic_secs; + const unix_time64_t cur_ts = log_monotonic_secs; int cached = -1; const int cache_sz =(int)(sizeof(p->cache_user)/sizeof(*p->cache_user)); for (int i = 0; i < cache_sz; ++i) { @@ -208,7 +208,7 @@ static handler_t mod_userdir_docroot_construct(request_st * const r, plugin_data } /* update cache, replacing oldest entry */ cached = 0; - time_t cache_ts = p->cache_ts[0]; + unix_time64_t cache_ts = p->cache_ts[0]; for (int i = 1; i < cache_sz; ++i) { if (cache_ts > p->cache_ts[i]) { cache_ts = p->cache_ts[i]; diff --git a/src/mod_vhostdb.c b/src/mod_vhostdb.c index 786e6582..6b9a4221 100644 --- a/src/mod_vhostdb.c +++ b/src/mod_vhostdb.c @@ -44,7 +44,7 @@ typedef struct { char *document_root; uint32_t slen; uint32_t dlen; - time_t ctime; + unix_time64_t ctime; } vhostdb_cache_entry; static vhostdb_cache_entry * @@ -323,7 +323,7 @@ REQUEST_FUNC(mod_vhostdb_handle_docroot) { /* walk though cache, collect expired ids, and remove them in a second loop */ static void -mod_vhostdb_tag_old_entries (splay_tree * const t, int * const keys, int * const ndx, const time_t max_age, const time_t cur_ts) +mod_vhostdb_tag_old_entries (splay_tree * const t, int * const keys, int * const ndx, const time_t max_age, const unix_time64_t cur_ts) { if (*ndx == 8192) return; /*(must match num array entries in keys[])*/ if (t->left) @@ -339,7 +339,7 @@ mod_vhostdb_tag_old_entries (splay_tree * const t, int * const keys, int * const __attribute_noinline__ static void -mod_vhostdb_periodic_cleanup(splay_tree **sptree_ptr, const time_t max_age, const time_t cur_ts) +mod_vhostdb_periodic_cleanup(splay_tree **sptree_ptr, const time_t max_age, const unix_time64_t cur_ts) { splay_tree *sptree = *sptree_ptr; int max_ndx, i; @@ -363,7 +363,7 @@ mod_vhostdb_periodic_cleanup(splay_tree **sptree_ptr, const time_t max_age, cons TRIGGER_FUNC(mod_vhostdb_periodic) { const plugin_data * const p = p_d; - const time_t cur_ts = log_monotonic_secs; + const unix_time64_t cur_ts = log_monotonic_secs; if (cur_ts & 0x7) return HANDLER_GO_ON; /*(continue once each 8 sec)*/ UNUSED(srv); diff --git a/src/mod_webdav.c b/src/mod_webdav.c index 9394577b..3b17a5ba 100644 --- a/src/mod_webdav.c +++ b/src/mod_webdav.c @@ -3135,7 +3135,7 @@ webdav_propfind_live_props (const webdav_propfind_bufs * const restrict pb, * i.e. wherever the status is 201 Created) */ struct tm tm; - if (__builtin_expect( (NULL != gmtime_r(&pb->st.st_ctime, &tm)), 1)) { + if (__builtin_expect( (NULL != gmtime64_r(&pb->st.st_ctime, &tm)), 1)) { buffer_append_string_len(b, CONST_STR_LEN( "")); buffer_append_strftime(b, "%FT%TZ", &tm)); diff --git a/src/mod_wolfssl.c b/src/mod_wolfssl.c index 96d5b150..d410b0bb 100644 --- a/src/mod_wolfssl.c +++ b/src/mod_wolfssl.c @@ -119,8 +119,8 @@ typedef struct { const buffer *ssl_pemfile; const buffer *ssl_privkey; const buffer *ssl_stapling_file; - time_t ssl_stapling_loadts; - time_t ssl_stapling_nextts; + unix_time64_t ssl_stapling_loadts; + unix_time64_t ssl_stapling_nextts; char must_staple; } plugin_cert; @@ -231,19 +231,19 @@ handler_ctx_free (handler_ctx *hctx) /* openssl has a huge number of interfaces, but not the most useful; * construct our own session ticket encryption key structure */ typedef struct tlsext_ticket_key_st { - time_t active_ts; /* tickets not issued w/ key until activation timestamp */ - time_t expire_ts; /* key not valid after expiration timestamp */ + unix_time64_t active_ts; /* tickets not issued w/ key until activation ts*/ + unix_time64_t expire_ts; /* key not valid after expiration timestamp */ unsigned char tick_key_name[TLSEXT_KEYNAME_LENGTH]; unsigned char tick_hmac_key[TLSEXT_TICK_KEY_LENGTH]; unsigned char tick_aes_key[TLSEXT_TICK_KEY_LENGTH]; } tlsext_ticket_key_t; static tlsext_ticket_key_t session_ticket_keys[4]; -static time_t stek_rotate_ts; +static unix_time64_t stek_rotate_ts; static int -mod_openssl_session_ticket_key_generate (time_t active_ts, time_t expire_ts) +mod_openssl_session_ticket_key_generate (unix_time64_t active_ts, unix_time64_t expire_ts) { /* openssl RAND_*bytes() functions are called multiple times since the * funcs might have a 32-byte limit on number of bytes returned each call @@ -288,7 +288,7 @@ mod_openssl_session_ticket_key_rotate (void) static tlsext_ticket_key_t * tlsext_ticket_key_get (void) { - const time_t cur_ts = log_epoch_secs; + const unix_time64_t cur_ts = log_epoch_secs; const int e = sizeof(session_ticket_keys)/sizeof(*session_ticket_keys) - 1; for (int i = 0; i < e; ++i) { if (session_ticket_keys[i].active_ts > cur_ts) continue; @@ -303,7 +303,7 @@ static tlsext_ticket_key_t * tlsext_ticket_key_find (unsigned char key_name[16], int *refresh) { *refresh = 0; - const time_t cur_ts = log_epoch_secs; + const unix_time64_t cur_ts = log_epoch_secs; const int e = sizeof(session_ticket_keys)/sizeof(*session_ticket_keys) - 1; for (int i = 0; i < e; ++i) { if (session_ticket_keys[i].expire_ts < cur_ts) continue; @@ -317,7 +317,7 @@ tlsext_ticket_key_find (unsigned char key_name[16], int *refresh) static void -tlsext_ticket_wipe_expired (const time_t cur_ts) +tlsext_ticket_wipe_expired (const unix_time64_t cur_ts) { const int e = sizeof(session_ticket_keys)/sizeof(*session_ticket_keys) - 1; for (int i = 0; i < e; ++i) { @@ -407,8 +407,8 @@ mod_openssl_session_ticket_key_file (const char *fn) if (0 != fdevent_load_file_bytes((char *)buf,(off_t)sizeof(buf),0,fn,NULL)) return rc; if (buf[0] == 0) { /*(format version 0)*/ - session_ticket_keys[3].active_ts = buf[1]; - session_ticket_keys[3].expire_ts = buf[2]; + session_ticket_keys[3].active_ts = TIME64_CAST(buf[1]); + session_ticket_keys[3].expire_ts = TIME64_CAST(buf[2]); #ifndef __COVERITY__ /* intentional; hide from Coverity Scan */ /* intentionally copy 80 bytes into consecutive arrays * tick_key_name[], tick_hmac_key[], tick_aes_key[] */ @@ -423,9 +423,9 @@ mod_openssl_session_ticket_key_file (const char *fn) static void -mod_openssl_session_ticket_key_check (const plugin_data *p, const time_t cur_ts) +mod_openssl_session_ticket_key_check (const plugin_data *p, const unix_time64_t cur_ts) { - static time_t detect_retrograde_ts; + static unix_time64_t detect_retrograde_ts; if (detect_retrograde_ts > cur_ts && detect_retrograde_ts - cur_ts > 28800) stek_rotate_ts = 0; detect_retrograde_ts = cur_ts; @@ -433,7 +433,8 @@ mod_openssl_session_ticket_key_check (const plugin_data *p, const time_t cur_ts) int rotate = 0; if (p->ssl_stek_file) { struct stat st; - if (0 == stat(p->ssl_stek_file, &st) && st.st_mtime > stek_rotate_ts) + if (0 == stat(p->ssl_stek_file, &st) + && TIME64_CAST(st.st_mtime) > stek_rotate_ts) rotate = mod_openssl_session_ticket_key_file(p->ssl_stek_file); tlsext_ticket_wipe_expired(cur_ts); } @@ -1374,7 +1375,7 @@ mod_openssl_load_stapling_file (const char *file, log_error_st *errh, buffer *b) } -static time_t +static unix_time64_t mod_openssl_asn1_time_to_posix (ASN1_TIME *asn1time) { #if LIBWOLFSSL_VERSION_HEX >= 0x04002000 @@ -1384,31 +1385,31 @@ mod_openssl_asn1_time_to_posix (ASN1_TIME *asn1time) int day, sec; return wolfSSL_ASN1_TIME_diff(&day, &sec, NULL, asn1time) ? log_epoch_secs + day*86400 + sec - : (time_t)-1; + : -1; #else UNUSED(asn1time); - return (time_t)-1; + return -1; #endif } -static time_t +static unix_time64_t mod_openssl_ocsp_next_update (plugin_cert *pc) { #if defined(WOLFSSL_VERSION) /* XXX: future TODO */ UNUSED(pc); (void)mod_openssl_asn1_time_to_posix(NULL); - return (time_t)-1; /*(not implemented)*/ + return -1; /*(not implemented)*/ #else buffer *der = pc->ssl_stapling; const unsigned char *p = (unsigned char *)der->ptr; /*(p gets modified)*/ OCSP_RESPONSE *ocsp = d2i_OCSP_RESPONSE(NULL, &p, buffer_clen(der)); - if (NULL == ocsp) return (time_t)-1; + if (NULL == ocsp) return -1; OCSP_BASICRESP *bs = OCSP_response_get1_basic(ocsp); if (NULL == bs) { OCSP_RESPONSE_free(ocsp); - return (time_t)-1; + return -1; } /* XXX: should save and evaluate cert status returned by these calls */ @@ -1431,14 +1432,14 @@ mod_openssl_ocsp_next_update (plugin_cert *pc) if (id == NULL) { OCSP_BASICRESP_free(bs); OCSP_RESPONSE_free(ocsp); - return (time_t)-1; + return -1; } OCSP_resp_find_status(bs, id, NULL, NULL, NULL, NULL, &nextupd); OCSP_CERTID_free(id); #else OCSP_single_get0_status(OCSP_resp_get0(bs, 0), NULL, NULL, NULL, &nextupd); #endif - time_t t = nextupd ? mod_openssl_asn1_time_to_posix(nextupd) : (time_t)-1; + unix_time64_t t = nextupd ? mod_openssl_asn1_time_to_posix(nextupd) : -1; /* Note: trust external process which creates ssl.stapling-file to verify * (as well as to validate certificate status) @@ -1471,7 +1472,7 @@ mod_openssl_expire_stapling_file (server *srv, plugin_cert *pc) static int -mod_openssl_reload_stapling_file (server *srv, plugin_cert *pc, const time_t cur_ts) +mod_openssl_reload_stapling_file (server *srv, plugin_cert *pc, const unix_time64_t cur_ts) { buffer *b = mod_openssl_load_stapling_file(pc->ssl_stapling_file->ptr, srv->errh, pc->ssl_stapling); @@ -1480,7 +1481,7 @@ mod_openssl_reload_stapling_file (server *srv, plugin_cert *pc, const time_t cur pc->ssl_stapling = b; /*(unchanged unless orig was NULL)*/ pc->ssl_stapling_loadts = cur_ts; pc->ssl_stapling_nextts = mod_openssl_ocsp_next_update(pc); - if (pc->ssl_stapling_nextts == (time_t)-1) { + if (pc->ssl_stapling_nextts == -1) { /* "Next Update" might not be provided by OCSP responder * Use 3600 sec (1 hour) in that case. */ /* retry in 1 hour if unable to determine Next Update */ @@ -1497,13 +1498,13 @@ mod_openssl_reload_stapling_file (server *srv, plugin_cert *pc, const time_t cur static int -mod_openssl_refresh_stapling_file (server *srv, plugin_cert *pc, const time_t cur_ts) +mod_openssl_refresh_stapling_file (server *srv, plugin_cert *pc, const unix_time64_t cur_ts) { if (pc->ssl_stapling && pc->ssl_stapling_nextts > cur_ts + 256) return 1; /* skip check for refresh unless close to expire */ struct stat st; if (0 != stat(pc->ssl_stapling_file->ptr, &st) - || st.st_mtime <= pc->ssl_stapling_loadts) { + || TIME64_CAST(st.st_mtime) <= pc->ssl_stapling_loadts) { if (pc->ssl_stapling && pc->ssl_stapling_nextts < cur_ts) mod_openssl_expire_stapling_file(srv, pc); return 1; @@ -1513,7 +1514,7 @@ mod_openssl_refresh_stapling_file (server *srv, plugin_cert *pc, const time_t cu static void -mod_openssl_refresh_stapling_files (server *srv, const plugin_data *p, const time_t cur_ts) +mod_openssl_refresh_stapling_files (server *srv, const plugin_data *p, const unix_time64_t cur_ts) { /* future: might construct array of (plugin_cert *) at startup * to avoid the need to search for them here */ @@ -3398,7 +3399,7 @@ REQUEST_FUNC(mod_openssl_handle_request_reset) TRIGGER_FUNC(mod_openssl_handle_trigger) { const plugin_data * const p = p_d; - const time_t cur_ts = log_epoch_secs; + const unix_time64_t cur_ts = log_epoch_secs; if (cur_ts & 0x3f) return HANDLER_GO_ON; /*(continue once each 64 sec)*/ UNUSED(srv); UNUSED(p); diff --git a/src/mod_wstunnel.c b/src/mod_wstunnel.c index 2b6a29b6..ac26812b 100644 --- a/src/mod_wstunnel.c +++ b/src/mod_wstunnel.c @@ -172,7 +172,7 @@ typedef struct { mod_wstunnel_frame_t frame; int hybivers; - time_t ping_ts; + unix_time64_t ping_ts; int subproto; log_error_st *errh; /*(for mod_wstunnel module-specific DEBUG_*() macros)*/ @@ -588,7 +588,7 @@ static handler_t mod_wstunnel_check_extension(request_st * const r, void *p_d) { TRIGGER_FUNC(mod_wstunnel_handle_trigger) { const plugin_data * const p = p_d; - const time_t cur_ts = log_monotonic_secs + 1; + const unix_time64_t cur_ts = log_monotonic_secs + 1; gw_handle_trigger(srv, p_d); @@ -615,7 +615,7 @@ TRIGGER_FUNC(mod_wstunnel_handle_trigger) { if (0 != hctx->hybivers && hctx->conf.ping_interval > 0 - && (time_t)hctx->conf.ping_interval + hctx->ping_ts < cur_ts) { + && (int32_t)hctx->conf.ping_interval + hctx->ping_ts < cur_ts) { hctx->ping_ts = cur_ts; mod_wstunnel_frame_send(hctx, MOD_WEBSOCKET_FRAME_TYPE_PING, CONST_STR_LEN("ping")); joblist_append(con); diff --git a/src/request.h b/src/request.h index 0f6793a0..a25dfc8b 100644 --- a/src/request.h +++ b/src/request.h @@ -184,7 +184,7 @@ struct request_st { off_t bytes_written_ckpt; /* used by mod_accesslog */ off_t bytes_read_ckpt; /* used by mod_accesslog */ - struct timespec start_hp; + unix_timespec64_t start_hp; int error_handler_saved_status; /* error-handler */ http_method_t error_handler_saved_method; /* error-handler */ diff --git a/src/response.c b/src/response.c index 0b29aef7..e9cf89dd 100644 --- a/src/response.c +++ b/src/response.c @@ -141,11 +141,11 @@ http_response_write_header (request_st * const r) if (!light_btst(r->resp_htags, HTTP_HEADER_DATE)) { /* HTTP/1.1 and later requires a Date: header */ /* "\r\nDate: " 8-chars + 30-chars "%a, %d %b %Y %T GMT" + '\0' */ - static time_t tlast = 0; + static unix_time64_t tlast = 0; static char tstr[40] = "\r\nDate: "; /* cache the generated timestamp */ - const time_t cur_ts = log_epoch_secs; + const unix_time64_t cur_ts = log_epoch_secs; if (__builtin_expect ( (tlast != cur_ts), 0)) http_date_time_to_str(tstr+8, sizeof(tstr)-8, (tlast = cur_ts)); diff --git a/src/response.h b/src/response.h index 4b9943eb..d4151a5f 100644 --- a/src/response.h +++ b/src/response.h @@ -45,8 +45,8 @@ handler_t http_response_reqbody_read_error(request_st *r, int http_status); int http_response_buffer_append_authority(request_st *r, buffer *o); int http_response_redirect_to_directory(request_st *r, int status); -const buffer * http_response_set_last_modified(request_st *r, time_t lmtime); -int http_response_handle_cachable(request_st *r, const buffer *lmod, time_t lmtime); +const buffer * http_response_set_last_modified(request_st *r, unix_time64_t lmtime); +int http_response_handle_cachable(request_st *r, const buffer *lmod, unix_time64_t lmtime); void http_response_body_clear(request_st *r, int preserve_length); void http_response_reset(request_st *r); void http_response_send_file (request_st *r, buffer *path, struct stat_cache_entry *sce); diff --git a/src/server.c b/src/server.c index f77186d3..ed9efb31 100644 --- a/src/server.c +++ b/src/server.c @@ -94,7 +94,7 @@ static volatile sig_atomic_t srv_shutdown = 0; static volatile sig_atomic_t handle_sig_child = 0; static volatile sig_atomic_t handle_sig_alarm = 1; static volatile sig_atomic_t handle_sig_hup = 0; -static time_t idle_limit = 0; +static int idle_limit = 0; #if defined(HAVE_SIGACTION) && defined(SA_SIGINFO) static volatile siginfo_t last_sigterm_info; @@ -222,20 +222,20 @@ static int daemonize(void) { } #endif -static time_t +static unix_time64_t server_monotonic_secs (void) { - struct timespec ts; + unix_timespec64_t ts; return (0 == log_clock_gettime_monotonic(&ts)) ? ts.tv_sec : log_monotonic_secs; } -static time_t +static unix_time64_t server_epoch_secs (server * const srv) { - const time_t cur_ts = log_epoch_secs; - const time_t new_ts = time(NULL); + const unix_time64_t cur_ts = log_epoch_secs; + const unix_time64_t new_ts = TIME64_CAST(time(NULL)); /* attempt to detect large clock jump */ if (new_ts < cur_ts || new_ts - cur_ts > 300) { /*(5 mins)*/ log_error(srv->errh, __FILE__, __LINE__, @@ -271,7 +271,7 @@ static server *server_init(void) { li_rand_reseed(); - srv->startup_ts = log_epoch_secs = time(NULL); + srv->startup_ts = log_epoch_secs = TIME64_CAST(time(NULL)); log_monotonic_secs = server_monotonic_secs(); srv->errh = log_error_st_init(); @@ -1109,7 +1109,7 @@ static int server_main_setup (server * const srv, int argc, char **argv) { "Invalid idle timeout value: %s", optarg); return -1; } - idle_limit = (time_t)timeout; + idle_limit = (int)timeout; break; } case 'p': print_config = 1; break; @@ -1829,7 +1829,7 @@ static void server_handle_sighup (server * const srv) { } __attribute_noinline__ -static void server_handle_sigalrm (server * const srv, time_t mono_ts, time_t last_active_ts) { +static void server_handle_sigalrm (server * const srv, unix_time64_t mono_ts, unix_time64_t last_active_ts) { plugins_call_handle_trigger(srv); @@ -1908,7 +1908,7 @@ static void server_run_con_queue (connections * const restrict joblist) { __attribute_hot__ __attribute_noinline__ static void server_main_loop (server * const srv) { - time_t last_active_ts = server_monotonic_secs(); + unix_time64_t last_active_ts = server_monotonic_secs(); log_epoch_secs = server_epoch_secs(srv); while (!srv_shutdown) { @@ -1923,7 +1923,7 @@ static void server_main_loop (server * const srv) { if (handle_sig_alarm) { handle_sig_alarm = 0; #endif - time_t mono_ts = server_monotonic_secs(); + unix_time64_t mono_ts = server_monotonic_secs(); if (mono_ts != log_monotonic_secs) { server_handle_sigalrm(srv, mono_ts, last_active_ts); } diff --git a/src/stat_cache.c b/src/stat_cache.c index 707e0d2d..ccb47262 100644 --- a/src/stat_cache.c +++ b/src/stat_cache.c @@ -215,7 +215,7 @@ typedef struct fam_dir_entry { buffer name; int refcnt; FAMRequest req; - time_t stat_ts; + unix_time64_t stat_ts; dev_t st_dev; ino_t st_ino; struct fam_dir_entry *fam_parent; @@ -679,7 +679,7 @@ static fam_dir_entry * fam_dir_monitor(stat_cache_fam *scf, char *fn, uint32_t d /* directory already registered */ } - const time_t cur_ts = log_monotonic_secs; + const unix_time64_t cur_ts = log_monotonic_secs; struct stat lst; int ck_dir = fn_is_dir; if (!fn_is_dir && (NULL==fam_dir || cur_ts - fam_dir->stat_ts >= 16)) { @@ -1268,7 +1268,7 @@ stat_cache_entry * stat_cache_get_entry(const buffer * const name) { * check if the directory for this file has changed */ - const time_t cur_ts = log_monotonic_secs; + const unix_time64_t cur_ts = log_monotonic_secs; const int file_ndx = splaytree_djbhash(name->ptr, len); splay_tree *sptree = sc.files = splaytree_splay(sc.files, file_ndx); @@ -1469,7 +1469,7 @@ int stat_cache_open_rdonly_fstat (const buffer *name, struct stat *st, int symli * and remove them in a second loop */ -static void stat_cache_tag_old_entries(splay_tree * const t, int * const keys, int * const ndx, const time_t max_age, const time_t cur_ts) { +static void stat_cache_tag_old_entries(splay_tree * const t, int * const keys, int * const ndx, const time_t max_age, const unix_time64_t cur_ts) { if (*ndx == 8192) return; /*(must match num array entries in keys[])*/ if (t->left) stat_cache_tag_old_entries(t->left, keys, ndx, max_age, cur_ts); @@ -1482,7 +1482,7 @@ static void stat_cache_tag_old_entries(splay_tree * const t, int * const keys, i keys[(*ndx)++] = t->key; } -static void stat_cache_periodic_cleanup(const time_t max_age, const time_t cur_ts) { +static void stat_cache_periodic_cleanup(const time_t max_age, const unix_time64_t cur_ts) { splay_tree *sptree = sc.files; int max_ndx, i; int keys[8192]; /* 32k size on stack */ diff --git a/src/stat_cache.h b/src/stat_cache.h index 42bd1ab2..0a3612e6 100644 --- a/src/stat_cache.h +++ b/src/stat_cache.h @@ -13,7 +13,7 @@ typedef struct stat stat_cache_st; typedef struct stat_cache_entry { buffer name; - time_t stat_ts; + unix_time64_t stat_ts; int fd; int refcnt; #if defined(HAVE_FAM_H) || defined(HAVE_SYS_INOTIFY_H) || defined(HAVE_SYS_EVENT_H) diff --git a/src/sys-time.h b/src/sys-time.h index 903d384a..7b5d95f3 100644 --- a/src/sys-time.h +++ b/src/sys-time.h @@ -55,4 +55,109 @@ timegm (const struct tm * const tm) #endif #endif + +/* non-standard functions created for lighttpd for Y2038 problem + * reference: https://en.wikipedia.org/wiki/Year_2038_problem + * + * lighttpd does not expect to deal with dates earlier than 1970, + * and can therefore treat dates earlier than 1970 as having overflowed + * 32-bit signed time_t, signifying dates after Tue, 19 Jan 2038 03:14:07 GMT + * + * 1954, 1982, 2010, 2038 begin on Thu and are two years offset from leap year. + * Attempt to adjust a timestamp > INT32_MAX back to a similar year, starting on + * same weekday, and being same distance from next leap year; use gmtime_r() + * or localtime_r(); and then adjust tm.tm_year back to the year of the original + * timestamp. (Note that the calculations here are valid for the specific range + * of input timestamps mapped to 1970 and 2099. The year 2000 was a leap year, + * so crossing 2000 *does not* require special-casing here, but the year 2100 + * *is not* a leap year in the Gregorian calendar, so this code is not valid + * after 28 Feb 2100. Since the max validity of these kludges could only be + * until 7 Feb 2106, this code has chosen not to special-case 2100-2106 and + * produces incorrect results after 28 Feb 2100.) + */ +#if HAS_TIME_BITS64 + +#define gmtime64_r(timep,result) gmtime_r((timep),(result)) +#define localtime64_r(timep,result) localtime_r((timep),(result)) + +#else /* !HAS_TIME_BITS64 */ + +#define gmtime64_r(timep,result) gmtime_y2038_kludge32(*(timep),(result)) +#define localtime64_r(timep,result) localtime_y2038_kludge32(*(timep),(result)) + +static inline struct tm * +gmtime_y2038_kludge32 (unix_time64_t t, struct tm *result); +static inline struct tm * +gmtime_y2038_kludge32 (unix_time64_t t, struct tm *result) +{ + if ((uint64_t)t <= INT32_MAX) { + time_t tt = (time_t)t; + return gmtime_r(&tt, result); + } + else { + /*(treat negative time as having overflowed 32-bit time_t)*/ + if (t < 0) + t = TIME64_CAST(t); + time_t tt = (time_t)(t - 2650838400LL); + if (gmtime_r(&tt, result)) { + result->tm_year += 84; + return result; + } + else if (t < 3914709247LL) { + /*(ok through Tue, 19 Jan 2094 03:14:07 GMT)*/ + tt = (time_t)(t - 1767225600LL); + if (gmtime_r(&tt, result)) { + result->tm_year += 56; + return result; + } + } + + /*(choose to forever return gmtime_r() equivalent of + * Thu, 01 Jan 1970 00:00:00 GMT) + *(returning NULL not expected by lighttpd and might crash)*/ + tt = 0; + gmtime_r(&tt, result); + return result; + } +} + +static inline struct tm * +localtime_y2038_kludge32 (unix_time64_t t, struct tm *result); +static inline struct tm * +localtime_y2038_kludge32 (unix_time64_t t, struct tm *result) +{ + if ((uint64_t)t <= INT32_MAX) { + time_t tt = (time_t)t; + return localtime_r(&tt, result); + } + else { + /*(treat negative time as having overflowed 32-bit time_t)*/ + if (t < 0) + t = TIME64_CAST(t); + time_t tt = (time_t)(t - 2650838400LL); + if (localtime_r(&tt, result)) { + result->tm_year += 84; + return result; + } + else if (t < 3914709247LL) { + /*(ok through Tue, 19 Jan 2094 03:14:07 GMT)*/ + tt = (time_t)(t - 1767225600LL); + if (localtime_r(&tt, result)) { + result->tm_year += 56; + return result; + } + } + + /*(choose to forever return localtime_r() equivalent of + * Thu, 01 Jan 1970 00:00:00 GMT) + *(returning NULL not expected by lighttpd and might crash)*/ + tt = 0; + localtime_r(&tt, result); + return result; + } +} + +#endif /* !HAS_TIME_BITS64 */ + + #endif