Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.13.12 ]​[ nginx-1.12.2 ]​

0001 
0002 /*
0003  * Copyright (C) Igor Sysoev
0004  * Copyright (C) Nginx, Inc.
0005  */
0006 
0007 
0008 #include <ngx_config.h>
0009 #include <ngx_core.h>
0010 
0011 
0012 /*
0013  * The time may be updated by signal handler or by several threads.
0014  * The time update operations are rare and require to hold the ngx_time_lock.
0015  * The time read operations are frequent, so they are lock-free and get time
0016  * values and strings from the current slot.  Thus thread may get the corrupted
0017  * values only if it is preempted while copying and then it is not scheduled
0018  * to run more than NGX_TIME_SLOTS seconds.
0019  */
0020 
0021 #define NGX_TIME_SLOTS   64
0022 
0023 static ngx_uint_t        slot;
0024 static ngx_atomic_t      ngx_time_lock;
0025 
0026 volatile ngx_msec_t      ngx_current_msec;
0027 volatile ngx_time_t     *ngx_cached_time;
0028 volatile ngx_str_t       ngx_cached_err_log_time;
0029 volatile ngx_str_t       ngx_cached_http_time;
0030 volatile ngx_str_t       ngx_cached_http_log_time;
0031 volatile ngx_str_t       ngx_cached_http_log_iso8601;
0032 volatile ngx_str_t       ngx_cached_syslog_time;
0033 
0034 #if !(NGX_WIN32)
0035 
0036 /*
0037  * localtime() and localtime_r() are not Async-Signal-Safe functions, therefore,
0038  * they must not be called by a signal handler, so we use the cached
0039  * GMT offset value. Fortunately the value is changed only two times a year.
0040  */
0041 
0042 static ngx_int_t         cached_gmtoff;
0043 #endif
0044 
0045 static ngx_time_t        cached_time[NGX_TIME_SLOTS];
0046 static u_char            cached_err_log_time[NGX_TIME_SLOTS]
0047                                     [sizeof("1970/09/28 12:00:00")];
0048 static u_char            cached_http_time[NGX_TIME_SLOTS]
0049                                     [sizeof("Mon, 28 Sep 1970 06:00:00 GMT")];
0050 static u_char            cached_http_log_time[NGX_TIME_SLOTS]
0051                                     [sizeof("28/Sep/1970:12:00:00 +0600")];
0052 static u_char            cached_http_log_iso8601[NGX_TIME_SLOTS]
0053                                     [sizeof("1970-09-28T12:00:00+06:00")];
0054 static u_char            cached_syslog_time[NGX_TIME_SLOTS]
0055                                     [sizeof("Sep 28 12:00:00")];
0056 
0057 
0058 static char  *week[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
0059 static char  *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
0060                            "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
0061 
0062 void
0063 ngx_time_init(void)
0064 {
0065     ngx_cached_err_log_time.len = sizeof("1970/09/28 12:00:00") - 1;
0066     ngx_cached_http_time.len = sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1;
0067     ngx_cached_http_log_time.len = sizeof("28/Sep/1970:12:00:00 +0600") - 1;
0068     ngx_cached_http_log_iso8601.len = sizeof("1970-09-28T12:00:00+06:00") - 1;
0069     ngx_cached_syslog_time.len = sizeof("Sep 28 12:00:00") - 1;
0070 
0071     ngx_cached_time = &cached_time[0];
0072 
0073     ngx_time_update();
0074 }
0075 
0076 
0077 void
0078 ngx_time_update(void)
0079 {
0080     u_char          *p0, *p1, *p2, *p3, *p4;
0081     ngx_tm_t         tm, gmt;
0082     time_t           sec;
0083     ngx_uint_t       msec;
0084     ngx_time_t      *tp;
0085     struct timeval   tv;
0086 
0087     if (!ngx_trylock(&ngx_time_lock)) {
0088         return;
0089     }
0090 
0091     ngx_gettimeofday(&tv);
0092 
0093     sec = tv.tv_sec;
0094     msec = tv.tv_usec / 1000;
0095 
0096     ngx_current_msec = (ngx_msec_t) sec * 1000 + msec;
0097 
0098     tp = &cached_time[slot];
0099 
0100     if (tp->sec == sec) {
0101         tp->msec = msec;
0102         ngx_unlock(&ngx_time_lock);
0103         return;
0104     }
0105 
0106     if (slot == NGX_TIME_SLOTS - 1) {
0107         slot = 0;
0108     } else {
0109         slot++;
0110     }
0111 
0112     tp = &cached_time[slot];
0113 
0114     tp->sec = sec;
0115     tp->msec = msec;
0116 
0117     ngx_gmtime(sec, &gmt);
0118 
0119 
0120     p0 = &cached_http_time[slot][0];
0121 
0122     (void) ngx_sprintf(p0, "%s, %02d %s %4d %02d:%02d:%02d GMT",
0123                        week[gmt.ngx_tm_wday], gmt.ngx_tm_mday,
0124                        months[gmt.ngx_tm_mon - 1], gmt.ngx_tm_year,
0125                        gmt.ngx_tm_hour, gmt.ngx_tm_min, gmt.ngx_tm_sec);
0126 
0127 #if (NGX_HAVE_GETTIMEZONE)
0128 
0129     tp->gmtoff = ngx_gettimezone();
0130     ngx_gmtime(sec + tp->gmtoff * 60, &tm);
0131 
0132 #elif (NGX_HAVE_GMTOFF)
0133 
0134     ngx_localtime(sec, &tm);
0135     cached_gmtoff = (ngx_int_t) (tm.ngx_tm_gmtoff / 60);
0136     tp->gmtoff = cached_gmtoff;
0137 
0138 #else
0139 
0140     ngx_localtime(sec, &tm);
0141     cached_gmtoff = ngx_timezone(tm.ngx_tm_isdst);
0142     tp->gmtoff = cached_gmtoff;
0143 
0144 #endif
0145 
0146 
0147     p1 = &cached_err_log_time[slot][0];
0148 
0149     (void) ngx_sprintf(p1, "%4d/%02d/%02d %02d:%02d:%02d",
0150                        tm.ngx_tm_year, tm.ngx_tm_mon,
0151                        tm.ngx_tm_mday, tm.ngx_tm_hour,
0152                        tm.ngx_tm_min, tm.ngx_tm_sec);
0153 
0154 
0155     p2 = &cached_http_log_time[slot][0];
0156 
0157     (void) ngx_sprintf(p2, "%02d/%s/%d:%02d:%02d:%02d %c%02i%02i",
0158                        tm.ngx_tm_mday, months[tm.ngx_tm_mon - 1],
0159                        tm.ngx_tm_year, tm.ngx_tm_hour,
0160                        tm.ngx_tm_min, tm.ngx_tm_sec,
0161                        tp->gmtoff < 0 ? '-' : '+',
0162                        ngx_abs(tp->gmtoff / 60), ngx_abs(tp->gmtoff % 60));
0163 
0164     p3 = &cached_http_log_iso8601[slot][0];
0165 
0166     (void) ngx_sprintf(p3, "%4d-%02d-%02dT%02d:%02d:%02d%c%02i:%02i",
0167                        tm.ngx_tm_year, tm.ngx_tm_mon,
0168                        tm.ngx_tm_mday, tm.ngx_tm_hour,
0169                        tm.ngx_tm_min, tm.ngx_tm_sec,
0170                        tp->gmtoff < 0 ? '-' : '+',
0171                        ngx_abs(tp->gmtoff / 60), ngx_abs(tp->gmtoff % 60));
0172 
0173     p4 = &cached_syslog_time[slot][0];
0174 
0175     (void) ngx_sprintf(p4, "%s %2d %02d:%02d:%02d",
0176                        months[tm.ngx_tm_mon - 1], tm.ngx_tm_mday,
0177                        tm.ngx_tm_hour, tm.ngx_tm_min, tm.ngx_tm_sec);
0178 
0179     ngx_memory_barrier();
0180 
0181     ngx_cached_time = tp;
0182     ngx_cached_http_time.data = p0;
0183     ngx_cached_err_log_time.data = p1;
0184     ngx_cached_http_log_time.data = p2;
0185     ngx_cached_http_log_iso8601.data = p3;
0186     ngx_cached_syslog_time.data = p4;
0187 
0188     ngx_unlock(&ngx_time_lock);
0189 }
0190 
0191 
0192 #if !(NGX_WIN32)
0193 
0194 void
0195 ngx_time_sigsafe_update(void)
0196 {
0197     u_char          *p, *p2;
0198     ngx_tm_t         tm;
0199     time_t           sec;
0200     ngx_time_t      *tp;
0201     struct timeval   tv;
0202 
0203     if (!ngx_trylock(&ngx_time_lock)) {
0204         return;
0205     }
0206 
0207     ngx_gettimeofday(&tv);
0208 
0209     sec = tv.tv_sec;
0210 
0211     tp = &cached_time[slot];
0212 
0213     if (tp->sec == sec) {
0214         ngx_unlock(&ngx_time_lock);
0215         return;
0216     }
0217 
0218     if (slot == NGX_TIME_SLOTS - 1) {
0219         slot = 0;
0220     } else {
0221         slot++;
0222     }
0223 
0224     tp = &cached_time[slot];
0225 
0226     tp->sec = 0;
0227 
0228     ngx_gmtime(sec + cached_gmtoff * 60, &tm);
0229 
0230     p = &cached_err_log_time[slot][0];
0231 
0232     (void) ngx_sprintf(p, "%4d/%02d/%02d %02d:%02d:%02d",
0233                        tm.ngx_tm_year, tm.ngx_tm_mon,
0234                        tm.ngx_tm_mday, tm.ngx_tm_hour,
0235                        tm.ngx_tm_min, tm.ngx_tm_sec);
0236 
0237     p2 = &cached_syslog_time[slot][0];
0238 
0239     (void) ngx_sprintf(p2, "%s %2d %02d:%02d:%02d",
0240                        months[tm.ngx_tm_mon - 1], tm.ngx_tm_mday,
0241                        tm.ngx_tm_hour, tm.ngx_tm_min, tm.ngx_tm_sec);
0242 
0243     ngx_memory_barrier();
0244 
0245     ngx_cached_err_log_time.data = p;
0246     ngx_cached_syslog_time.data = p2;
0247 
0248     ngx_unlock(&ngx_time_lock);
0249 }
0250 
0251 #endif
0252 
0253 
0254 u_char *
0255 ngx_http_time(u_char *buf, time_t t)
0256 {
0257     ngx_tm_t  tm;
0258 
0259     ngx_gmtime(t, &tm);
0260 
0261     return ngx_sprintf(buf, "%s, %02d %s %4d %02d:%02d:%02d GMT",
0262                        week[tm.ngx_tm_wday],
0263                        tm.ngx_tm_mday,
0264                        months[tm.ngx_tm_mon - 1],
0265                        tm.ngx_tm_year,
0266                        tm.ngx_tm_hour,
0267                        tm.ngx_tm_min,
0268                        tm.ngx_tm_sec);
0269 }
0270 
0271 
0272 u_char *
0273 ngx_http_cookie_time(u_char *buf, time_t t)
0274 {
0275     ngx_tm_t  tm;
0276 
0277     ngx_gmtime(t, &tm);
0278 
0279     /*
0280      * Netscape 3.x does not understand 4-digit years at all and
0281      * 2-digit years more than "37"
0282      */
0283 
0284     return ngx_sprintf(buf,
0285                        (tm.ngx_tm_year > 2037) ?
0286                                          "%s, %02d-%s-%d %02d:%02d:%02d GMT":
0287                                          "%s, %02d-%s-%02d %02d:%02d:%02d GMT",
0288                        week[tm.ngx_tm_wday],
0289                        tm.ngx_tm_mday,
0290                        months[tm.ngx_tm_mon - 1],
0291                        (tm.ngx_tm_year > 2037) ? tm.ngx_tm_year:
0292                                                  tm.ngx_tm_year % 100,
0293                        tm.ngx_tm_hour,
0294                        tm.ngx_tm_min,
0295                        tm.ngx_tm_sec);
0296 }
0297 
0298 
0299 void
0300 ngx_gmtime(time_t t, ngx_tm_t *tp)
0301 {
0302     ngx_int_t   yday;
0303     ngx_uint_t  n, sec, min, hour, mday, mon, year, wday, days, leap;
0304 
0305     /* the calculation is valid for positive time_t only */
0306 
0307     n = (ngx_uint_t) t;
0308 
0309     days = n / 86400;
0310 
0311     /* January 1, 1970 was Thursday */
0312 
0313     wday = (4 + days) % 7;
0314 
0315     n %= 86400;
0316     hour = n / 3600;
0317     n %= 3600;
0318     min = n / 60;
0319     sec = n % 60;
0320 
0321     /*
0322      * the algorithm based on Gauss' formula,
0323      * see src/http/ngx_http_parse_time.c
0324      */
0325 
0326     /* days since March 1, 1 BC */
0327     days = days - (31 + 28) + 719527;
0328 
0329     /*
0330      * The "days" should be adjusted to 1 only, however, some March 1st's go
0331      * to previous year, so we adjust them to 2.  This causes also shift of the
0332      * last February days to next year, but we catch the case when "yday"
0333      * becomes negative.
0334      */
0335 
0336     year = (days + 2) * 400 / (365 * 400 + 100 - 4 + 1);
0337 
0338     yday = days - (365 * year + year / 4 - year / 100 + year / 400);
0339 
0340     if (yday < 0) {
0341         leap = (year % 4 == 0) && (year % 100 || (year % 400 == 0));
0342         yday = 365 + leap + yday;
0343         year--;
0344     }
0345 
0346     /*
0347      * The empirical formula that maps "yday" to month.
0348      * There are at least 10 variants, some of them are:
0349      *     mon = (yday + 31) * 15 / 459
0350      *     mon = (yday + 31) * 17 / 520
0351      *     mon = (yday + 31) * 20 / 612
0352      */
0353 
0354     mon = (yday + 31) * 10 / 306;
0355 
0356     /* the Gauss' formula that evaluates days before the month */
0357 
0358     mday = yday - (367 * mon / 12 - 30) + 1;
0359 
0360     if (yday >= 306) {
0361 
0362         year++;
0363         mon -= 10;
0364 
0365         /*
0366          * there is no "yday" in Win32 SYSTEMTIME
0367          *
0368          * yday -= 306;
0369          */
0370 
0371     } else {
0372 
0373         mon += 2;
0374 
0375         /*
0376          * there is no "yday" in Win32 SYSTEMTIME
0377          *
0378          * yday += 31 + 28 + leap;
0379          */
0380     }
0381 
0382     tp->ngx_tm_sec = (ngx_tm_sec_t) sec;
0383     tp->ngx_tm_min = (ngx_tm_min_t) min;
0384     tp->ngx_tm_hour = (ngx_tm_hour_t) hour;
0385     tp->ngx_tm_mday = (ngx_tm_mday_t) mday;
0386     tp->ngx_tm_mon = (ngx_tm_mon_t) mon;
0387     tp->ngx_tm_year = (ngx_tm_year_t) year;
0388     tp->ngx_tm_wday = (ngx_tm_wday_t) wday;
0389 }
0390 
0391 
0392 time_t
0393 ngx_next_time(time_t when)
0394 {
0395     time_t     now, next;
0396     struct tm  tm;
0397 
0398     now = ngx_time();
0399 
0400     ngx_libc_localtime(now, &tm);
0401 
0402     tm.tm_hour = (int) (when / 3600);
0403     when %= 3600;
0404     tm.tm_min = (int) (when / 60);
0405     tm.tm_sec = (int) (when % 60);
0406 
0407     next = mktime(&tm);
0408 
0409     if (next == -1) {
0410         return -1;
0411     }
0412 
0413     if (next - now > 0) {
0414         return next;
0415     }
0416 
0417     tm.tm_mday++;
0418 
0419     /* mktime() should normalize a date (Jan 32, etc) */
0420 
0421     next = mktime(&tm);
0422 
0423     if (next != -1) {
0424         return next;
0425     }
0426 
0427     return -1;
0428 }