1 /* Copyright (C) 2000-2015 Lavtech.com corp. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2 of the License, or
6 (at your option) any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 */
17
18 #include "udm_config.h"
19
20 #include <stdio.h>
21 #include <stdarg.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <time.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <fcntl.h>
28 #ifdef HAVE_SYS_SOCKET_H
29 #include <sys/socket.h>
30 #endif
31 #include <errno.h>
32
33 #ifdef HAVE_IO_H
34 #include <io.h> /* for Win */
35 #endif
36
37 #ifdef HAVE_DIRECT_H
38 #include <direct.h> /* for Win */
39 #endif
40
41 #ifdef HAVE_SYS_TIME_H
42 #include <sys/time.h>
43 #endif
44
45 #ifdef HAVE_SYS_TIMES_H
46 #include <sys/times.h>
47 #endif
48
49 #ifdef HAVE_UNISTD_H
50 #include <unistd.h>
51 #endif
52 #include <signal.h>
53
54 #include "udm_signals.h"
55 #include "udm_utils.h"
56 #include "udm_ctype.h"
57
58 long tz_offset=0; /* EXT */
59
60 /* Function to convert date returned by web-server to time_t
61 *
62 * Earlier we used strptime, but it seems to be completely broken
63 * on Solaris 2.6. Thanks to Maciek Uhlig <muhlig@us.edu.pl> for pointing
64 * out this and bugfix proposal (to use Apache's ap_parseHTTPdate).
65 *
66 * 10 July 2000 kir.
67 */
68
69 #define BAD_DATE 0
70
71 /*****
72 * BEGIN: Below is taken from Apache's util_date.c
73 */
74
75 /* ====================================================================
76 * Copyright (c) 1996-1999 The Apache Group. All rights reserved.
77 *
78 * Redistribution and use in source and binary forms, with or without
79 * modification, are permitted provided that the following conditions
80 * are met:
81 *
82 * 1. Redistributions of source code must retain the above copyright
83 * notice, this list of conditions and the following disclaimer.
84 *
85 * 2. Redistributions in binary form must reproduce the above copyright
86 * notice, this list of conditions and the following disclaimer in
87 * the documentation and/or other materials provided with the
88 * distribution.
89 *
90 * 3. All advertising materials mentioning features or use of this
91 * software must display the following acknowledgment:
92 * "This product includes software developed by the Apache Group
93 * for use in the Apache HTTP server project (http://www.apache.org/)."
94 *
95 * 4. The names "Apache Server" and "Apache Group" must not be used to
96 * endorse or promote products derived from this software without
97 * prior written permission. For written permission, please contact
98 * apache@apache.org.
99 *
100 * 5. Products derived from this software may not be called "Apache"
101 * nor may "Apache" appear in their names without prior written
102 * permission of the Apache Group.
103 *
104 * 6. Redistributions of any form whatsoever must retain the following
105 * acknowledgment:
106 * "This product includes software developed by the Apache Group
107 * for use in the Apache HTTP server project (http://www.apache.org/)."
108 *
109 * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
110 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
111 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
112 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR
113 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
114 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
115 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
116 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
117 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
118 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
119 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
120 * OF THE POSSIBILITY OF SUCH DAMAGE.
121 * ====================================================================
122 *
123 * This software consists of voluntary contributions made by many
124 * individuals on behalf of the Apache Group and was originally based
125 * on public domain software written at the National Center for
126 * Supercomputing Applications, University of Illinois, Urbana-Champaign.
127 * For more information on the Apache Group and the Apache HTTP server
128 * project, please see <http://www.apache.org/>.
129 *
130 */
131
132
133 /*
134 * Compare a string to a mask
135 * Mask characters (arbitrary maximum is 256 characters, just in case):
136 * @ - uppercase letter
137 * $ - lowercase letter
138 * & - hex digit
139 * # - digit
140 * ~ - digit or space
141 * * - swallow remaining characters
142 * <x> - exact match for any other character
143 */
ap_checkmask(const char * data,const char * mask)144 static int ap_checkmask(const char *data, const char *mask)
145 {
146 int i;
147 char d;
148
149 for (i = 0; i < 256; i++) {
150 d = data[i];
151 switch (mask[i]) {
152 case '\0':
153 return (d == '\0');
154
155 case '*':
156 return 1;
157
158 case '@':
159 if (!udm_isupper(d))
160 return 0;
161 break;
162 case '$':
163 if (!udm_islower(d))
164 return 0;
165 break;
166 case '#':
167 if (!udm_isdigit(d))
168 return 0;
169 break;
170 case '&':
171 if (!udm_isxdigit(d))
172 return 0;
173 break;
174 case '~':
175 if ((d != ' ') && !udm_isdigit(d))
176 return 0;
177 break;
178 default:
179 if (mask[i] != d)
180 return 0;
181 break;
182 }
183 }
184 return 0; /* We only get here if mask is corrupted (exceeds 256) */
185 }
186
187 /*
188 * tm2sec converts a GMT tm structure into the number of seconds since
189 * 1st January 1970 UT. Note that we ignore tm_wday, tm_yday, and tm_dst.
190 *
191 * The return value is always a valid time_t value -- (time_t)0 is returned
192 * if the input date is outside that capable of being represented by time(),
193 * i.e., before Thu, 01 Jan 1970 00:00:00 for all systems and
194 * beyond 2038 for 32bit systems.
195 *
196 * This routine is intended to be very fast, much faster than mktime().
197 */
ap_tm2sec(const struct tm * t)198 static time_t ap_tm2sec(const struct tm * t)
199 {
200 int year;
201 time_t days;
202 static const int dayoffset[12] =
203 {306, 337, 0, 31, 61, 92, 122, 153, 184, 214, 245, 275};
204
205 year = t->tm_year;
206
207 if (year < 70 || ((sizeof(time_t) <= 4) && (year >= 138)))
208 return BAD_DATE;
209
210 /* shift new year to 1st March in order to make leap year calc easy */
211
212 if (t->tm_mon < 2)
213 year--;
214
215 /* Find number of days since 1st March 1900 (in the Gregorian calendar). */
216
217 days = year * 365 + year / 4 - year / 100 + (year / 100 + 3) / 4;
218 days += dayoffset[t->tm_mon] + t->tm_mday - 1;
219 days -= 25508; /* 1 jan 1970 is 25508 days since 1 mar 1900 */
220
221 days = ((days * 24 + t->tm_hour) * 60 + t->tm_min) * 60 + t->tm_sec;
222
223 if (days < 0)
224 return BAD_DATE; /* must have overflowed */
225 else
226 return days; /* must be a valid time */
227 }
228
229
230 /*
231 Scan date string: YYYY-MM-DD
232 */
233 static void
scan_yyyy_mm_dd(struct tm * ds,const char * date)234 scan_yyyy_mm_dd(struct tm *ds, const char *date)
235 {
236 ds->tm_year= ((date[0] - '0') * 10 + (date[1] - '0') - 19) * 100 +
237 (date[2] - '0') * 10 + date[3] - '0';
238 ds->tm_mon= (date[5] - '0') * 10 + (date[6] - '0') - 1;
239 ds->tm_mday= (date[8] - '0') * 10 + (date[9] - '0');
240 }
241
242
243 /*
244 Scan year: YYYY
245 */
246 static void
scan_yyyy(struct tm * ds,const char * date)247 scan_yyyy(struct tm *ds, const char *date)
248 {
249 ds->tm_year= ((date[0] - '0') * 10 + (date[1] - '0') - 19) * 100 +
250 (date[2] - '0') * 10 + date[3] - '0';
251 }
252
253
254 /*
255 Scan time string: hh:mm:ss
256 */
257 static void
scan_hh_mm_ss(struct tm * ds,const char * timstr)258 scan_hh_mm_ss(struct tm *ds, const char *timstr)
259 {
260 ds->tm_hour= ((timstr[0] - '0') * 10) + (timstr[1] - '0');
261 ds->tm_min= ((timstr[3] - '0') * 10) + (timstr[4] - '0');
262 ds->tm_sec= ((timstr[6] - '0') * 10) + (timstr[7] - '0');
263 }
264
265 static const int months[12] =
266 {
267 ('J' << 16) | ('a' << 8) | 'n', ('F' << 16) | ('e' << 8) | 'b',
268 ('M' << 16) | ('a' << 8) | 'r', ('A' << 16) | ('p' << 8) | 'r',
269 ('M' << 16) | ('a' << 8) | 'y', ('J' << 16) | ('u' << 8) | 'n',
270 ('J' << 16) | ('u' << 8) | 'l', ('A' << 16) | ('u' << 8) | 'g',
271 ('S' << 16) | ('e' << 8) | 'p', ('O' << 16) | ('c' << 8) | 't',
272 ('N' << 16) | ('o' << 8) | 'v', ('D' << 16) | ('e' << 8) | 'c'
273 };
274
275 /*
276 Convert month name to month, 0..11
277 */
278 static void
scan_month_name(struct tm * ds,const char * monstr)279 scan_month_name(struct tm *ds, const char *monstr)
280 {
281 int mon, mint= (monstr[0] << 16) | (monstr[1] << 8) | monstr[2];
282 for (mon= 0; mon < 12; mon++)
283 if (mint == months[mon])
284 break;
285 ds->tm_mon= mon;
286 }
287
288
289 static void
scan_time_zone(time_t * zone,const char * str)290 scan_time_zone(time_t *zone, const char *str)
291 {
292 if (ap_checkmask(str, "+####") ||
293 ap_checkmask(str, "-####"))
294 {
295 int h= ((int) (str[1] - '0')) * 10 + (str[2] - '0');
296 int m= ((int) (str[3] - '0')) * 10 + (str[4] - '0');
297 *zone= (h * 60 + m) * 60 * ((str[0] == '-') ? -1 : 1);
298 }
299 }
300
301
302 /*
303 * Parses an HTTP date in one of three standard forms:
304 *
305 * Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123
306 * Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
307 * Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format
308 *
309 * and returns the time_t number of seconds since 1 Jan 1970 GMT, or
310 * 0 if this would be out of range or if the date is invalid.
311 *
312 * The restricted HTTP syntax is
313 *
314 * HTTP-date = rfc1123-date | rfc850-date | asctime-date
315 *
316 * rfc1123-date = wkday "," SP date1 SP time SP "GMT"
317 * rfc850-date = weekday "," SP date2 SP time SP "GMT"
318 * asctime-date = wkday SP date3 SP time SP 4DIGIT
319 *
320 * date1 = 2DIGIT SP month SP 4DIGIT
321 * ; day month year (e.g., 02 Jun 1982)
322 * date2 = 2DIGIT "-" month "-" 2DIGIT
323 * ; day-month-year (e.g., 02-Jun-82)
324 * date3 = month SP ( 2DIGIT | ( SP 1DIGIT ))
325 * ; month day (e.g., Jun 2)
326 *
327 * time = 2DIGIT ":" 2DIGIT ":" 2DIGIT
328 * ; 00:00:00 - 23:59:59
329 *
330 * wkday = "Mon" | "Tue" | "Wed"
331 * | "Thu" | "Fri" | "Sat" | "Sun"
332 *
333 * weekday = "Monday" | "Tuesday" | "Wednesday"
334 * | "Thursday" | "Friday" | "Saturday" | "Sunday"
335 *
336 * month = "Jan" | "Feb" | "Mar" | "Apr"
337 * | "May" | "Jun" | "Jul" | "Aug"
338 * | "Sep" | "Oct" | "Nov" | "Dec"
339 *
340 * However, for the sake of robustness (and Netscapeness), we ignore the
341 * weekday and anything after the time field (including the timezone).
342 *
343 * This routine is intended to be very fast; 10x faster than using sscanf.
344 *
345 * Originally from Andrew Daviel <andrew@vancouver-webpages.com>, 29 Jul 96
346 * but many changes since then.
347 *
348 */
UdmHttpDate2Time_t(const char * date)349 time_t UdmHttpDate2Time_t(const char *date){
350 struct tm ds;
351 time_t zone= 0;
352
353 if (!date)
354 return BAD_DATE;
355
356 while (*date && udm_isspace(*date)) /* Find first non-whitespace char */
357 ++date;
358
359 if (*date == '\0')
360 return BAD_DATE;
361
362 if (ap_checkmask(date, "####-##-##") ||
363 ap_checkmask(date, "####-##-## ##:##:##"))
364 {
365 /*
366 '2004-01-02'
367 '2004-01-02 10:20:30'
368 Non-standard formats, but they can be can met often in user meta tags.
369 */
370 scan_yyyy_mm_dd(&ds, date);
371 if (date[10])
372 scan_hh_mm_ss(&ds, date + 11);
373 else
374 ds.tm_hour= ds.tm_min= ds.tm_sec= 0;
375 goto check_valid_date;
376 }
377 else if (ap_checkmask(date, "##.##.####"))
378 {
379 /*
380 0123456789
381 02.01.2005 non-standard format,
382 but we can meet it quit often in
383 user meta tags in Germany.
384 */
385 scan_yyyy(&ds, date + 6);
386 ds.tm_mon= (date[3] - '0') * 10 + (date[4] - '0') - 1;
387 ds.tm_mday= (date[0] - '0') * 10 + (date[1] - '0');
388 ds.tm_hour= ds.tm_min= ds.tm_sec= 0;
389 goto check_valid_date;
390 } /* 01234567890123456789 */
391 else if (ap_checkmask(date, "####-##-##T##:##:##Z") ||
392 /* ####-##-##T##:##:##.##Z is used in docx, in docProps/core.xml */
393 ap_checkmask(date, "####-##-##T##:##:##.##Z") ||
394 ap_checkmask(date, "####-##-##T##:##:##+##:##") ||
395 ap_checkmask(date, "####-##-##T##:##:##-##:##"))
396 {
397 /*
398 W3C format, also used by OpenSearch
399 http://www.w3.org/TR/NOTE-datetime
400 http://opensearch.a9.com/spec/1.1/response/
401
402 Complete date plus hours, minutes, seconds
403 and UTC timezone designator
404 2005-01-02T10:20:30Z
405 */
406 scan_yyyy_mm_dd(&ds, date);
407 scan_hh_mm_ss(&ds, date + 11);
408 /* TODO: add time zone offset processing and second fractions */
409 goto check_valid_time;
410 }
411 else if (ap_checkmask(date, "##########") ||
412 ap_checkmask(date, "#########"))
413 {
414 /*
415 Unix timestamp format: 9 or 10 digits.
416 */
417 return atoi(date);
418 }
419
420
421 if ((date = strchr(date, ' ')) == NULL) /* Find space after weekday */
422 return BAD_DATE;
423
424 ++date;
425
426 /*
427 Now date points to first char after space, which should be
428 start of the actual date information for all formats.
429 */
430 if (ap_checkmask(date, "## @$$ #### ##:##:## *"))
431 {
432 /*
433 RFC 1123 format
434 Sun, 06 Nov 1994 08:49:37 GMT
435 Sun, 06 Nov 1994 08:49:37 +0400
436 Sun, 06 Nov 1994 08:49:37 -0400
437 */
438 scan_yyyy(&ds, date + 7);
439 ds.tm_mday= ((date[0] - '0') * 10) + (date[1] - '0');
440 scan_month_name(&ds, date + 3);
441 scan_hh_mm_ss(&ds, date + 12);
442 scan_time_zone(&zone, date + 21);
443 } /*0123456789ABCDEFGHIJK*/
444 else if (ap_checkmask(date, "# @$$ #### ##:##:## *"))
445 {
446 /*
447 The same as above, but with a one-digit day
448 Sun, 6 Nov 1994 08:49:37 GMT
449 */
450 scan_yyyy(&ds, date + 6);
451 ds.tm_mday= date[0] - '0';
452 scan_month_name(&ds, date + 2);
453 scan_hh_mm_ss(&ds, date + 11);
454 scan_time_zone(&zone, date + 20);
455 }
456 else if (ap_checkmask(date, "##-@$$-## ##:##:## *"))
457 {
458 /*
459 RFC 850 format:
460 Sunday, 06-Nov-94 08:49:37 GMT
461 */
462 ds.tm_year= ((date[7] - '0') * 10) + (date[8] - '0');
463 if (ds.tm_year < 70)
464 ds.tm_year+= 100;
465 ds.tm_mday= ((date[0] - '0') * 10) + (date[1] - '0');
466 scan_month_name(&ds, date + 3);
467 scan_hh_mm_ss(&ds, date + 10);
468 scan_time_zone(&zone, date + 19);
469 }
470 else if (ap_checkmask(date, "@$$ ~# ##:##:## ####*"))
471 {
472 /*
473 ANSI C's asctime() format
474 Sun Nov 6 08:49:37 1994
475 */
476 scan_yyyy(&ds, date + 16);
477 ds.tm_mday= (date[4] == ' ') ? 0 : (date[4] - '0') * 10;
478 ds.tm_mday+= (date[5] - '0');
479 scan_month_name(&ds, date);
480 scan_hh_mm_ss(&ds, date + 7);
481 }
482 else
483 return BAD_DATE;
484
485 check_valid_time:
486
487 if ((ds.tm_hour > 23) || (ds.tm_min > 59) || (ds.tm_sec > 61))
488 return BAD_DATE;
489
490 check_valid_date:
491
492 if (ds.tm_mday <= 0 || ds.tm_mday > 31)
493 return BAD_DATE;
494
495 if (ds.tm_mon > 11)
496 return BAD_DATE;
497
498 if ((ds.tm_mday == 31) &&
499 (ds.tm_mon == 3 || ds.tm_mon == 5 || ds.tm_mon == 8 || ds.tm_mon == 10))
500 return BAD_DATE;
501
502 /* February gets special check for leapyear */
503
504 if ((ds.tm_mon == 1) &&
505 ((ds.tm_mday > 29)
506 || ((ds.tm_mday == 29)
507 && ((ds.tm_year & 3)
508 || (((ds.tm_year % 100) == 0)
509 && (((ds.tm_year % 400) != 100)))))))
510 return BAD_DATE;
511
512 #if 0
513 {
514 time_t res= ap_tm2sec(&ds);
515 char buf[128];
516 strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &ds);
517 printf("parseHTTPdate: '%s' is %lu: strftime=%s, month=%d\n",
518 date, (long unsigned int) res, buf, ds.tm_mon);
519 }
520 #endif
521
522 return ap_tm2sec(&ds) - zone;
523 }
524
525 /********
526 * END: Above is taken from Apache's util_date.c
527 */
528
UdmFTPDate2Time_t(char * date)529 time_t UdmFTPDate2Time_t(char *date){
530 struct tm ds;
531
532 if (!(ap_checkmask(date+4, "##############*")))
533 return BAD_DATE;
534
535 /* strptime(date+6, "%y%m%d%H%M%S", &tm_s); */
536
537 ds.tm_year = (((date[4] - '0') * 10) + (date[5] - '0') - 19)*100;
538 ds.tm_year += ((date[6] - '0') * 10) + (date[7] - '0');
539
540 ds.tm_mon = ((date[8] - '0') * 10) + (date[9] - '0') - 1;
541 ds.tm_mday = ((date[10] - '0') * 10) + (date[11] - '0');
542
543 ds.tm_hour = ((date[12] - '0') * 10) + (date[13] - '0');
544 ds.tm_min = ((date[14] - '0') * 10) + (date[15] - '0');
545 ds.tm_sec = ((date[16] - '0') * 10) + (date[17] - '0');
546
547 /* printf("parseFTPdate: %s is %lu\n", date, ap_tm2sec(&ds)); */
548
549 return ap_tm2sec(&ds);
550 }
551
Udm_dp2time_t(const char * time_str)552 time_t Udm_dp2time_t(const char * time_str){
553 time_t t=0;
554 long i;
555 char *s;
556 const char *ts;
557
558 /* flag telling us that time_str is exactly <num> without any char
559 * so we think it's seconds
560 * flag==0 means not defined yet
561 * flag==1 means ordinary format (XXXmYYYs)
562 * flag==2 means seconds only
563 */
564 int flag=0;
565
566 ts = time_str;
567 do{
568 i=strtol(ts, &s, 10);
569 if (s==ts){ /* falied to find a number */
570 /* FIXME: report error */
571 return -1;
572 }
573
574 /* ignore spaces */
575 while (udm_isspace(*s))
576 s++;
577
578 switch(*s){
579 case 's': /* seconds */
580 t+=i; flag=1; break;
581 case 'M': /* minutes */
582 t+=i*60; flag=1; break;
583 case 'h': /* hours */
584 t+=i*60*60; flag=1; break;
585 case 'd': /* days */
586 t+=i*60*60*24; flag=1; break;
587 case 'm': /* months */
588 /* I assume month is 30 days */
589 t+=i*60*60*24*30; flag=1; break;
590 case 'y': /* years */
591 t+=i*60*60*24*365; flag=1; break;
592 case '\0': /* end of string */
593 if (flag==1)
594 return -1;
595 else{
596 t=i;
597 flag=2;
598 return t;
599 }
600 default:
601 /* FIXME: report error here! */
602 return -1;
603 }
604 /* go to next char */
605 ts=++s;
606 /* is it end? */
607 } while (*s);
608
609 return t;
610 }
611
612 /* * * * * * * * * * * * *
613 * DEBUG CRAP...
614 */
615
616 /*
617 #define DEBUG_DP2TIME
618 */
619
620 #ifdef DEBUG_DP2TIME
main(int argc,char ** argv)621 int main(int argc, char **argv){
622
623 char *dp;
624
625 if (argc>1)
626 dp=argv[1];
627 else{
628 printf("Usage: %s time_string\n", argv[0]);
629 return 1;
630 }
631
632 printf("str='%s'\ttime=%li\n", dp, Udm_dp2time_t(dp));
633 return 0;
634 }
635 #endif /* DEBUG_DP2TIME */
636
637
UdmTime_t2HttpStr(time_t t,char * str,size_t str_size)638 void UdmTime_t2HttpStr(time_t t, char *str, size_t str_size)
639 {
640 struct tm tim;
641 /* FIXME: I suspect that gmtime IS NOT REENTRANT */
642 tim= *gmtime(&t);
643
644 #ifdef WIN32
645 if (!strftime(str, str_size, "%a, %d %b %Y %H:%M:%S GMT", &tim))
646 #else
647 if (!strftime(str, str_size, "%a, %d %b %Y %H:%M:%S %Z", &tim))
648 #endif
649 *str= '\0';
650 }
651
652 /* Find out tz_offset for the functions above
653 */
654 UDM_API(udm_rc_t)
UdmInitTZ(void)655 UdmInitTZ(void)
656 {
657
658 /*
659 time_t tt;
660 struct tm *tms;
661
662 tzset();
663 tms=localtime(&tt);*/
664 /* localtime sets the external variable timezone */
665 /* tz_offset = tms->tm_gmtoff;
666 return 0;
667 */
668 #ifdef HAVE_TM_GMTOFF
669 time_t tclock;
670 struct tm *tim;
671
672 tzset();
673 tclock = time(NULL);
674 tim=localtime(&tclock);
675 tz_offset = (long)tim->tm_gmtoff;
676 return 0;
677 #else
678 time_t tt;
679 struct tm t, gmt;
680 int days, hours, minutes;
681
682 tzset();
683 tt = time(NULL);
684 gmt = *gmtime(&tt);
685 t = *localtime(&tt);
686 days = t.tm_yday - gmt.tm_yday;
687 hours = ((days < -1 ? 24 : 1 < days ? -24 : days * 24)
688 + t.tm_hour - gmt.tm_hour);
689 minutes = hours * 60 + t.tm_min - gmt.tm_min;
690 tz_offset = 60L * minutes;
691 return 0;
692 #endif /* HAVE_TM_GMTOFF */
693
694 /* ONE MORE VARIANT - how many do we have?
695 struct timezone tz;
696
697 gettimeofday(NULL, &tz);
698 tz_offset=tz.tz_minuteswest*60;
699 return 0;
700 */
701 }
702
703
704 /*
705 Function performance: 1,500,000 times per second.
706 */
707 UDM_API(udm_timer_t)
UdmStartTimer(void)708 UdmStartTimer(void)
709 {
710 #ifdef WIN32
711 return clock();
712 #else
713 struct timeval tv;
714 struct timezone tz;
715 gettimeofday(&tv, &tz);
716 return((tv.tv_sec % 100000) * 1000 + (tv.tv_usec / 1000));
717
718 /*
719 #undef CLOCKS_PER_SEC
720 #define CLOCKS_PER_SEC (sysconf(_SC_CLK_TCK))
721 struct tms tms_tmp;
722 return (float)times(&tms_tmp)*1000/CLOCKS_PER_SEC;
723 */
724 #endif
725 }
726
727
728 double
UdmStopTimer(udm_timer_t * ticks)729 UdmStopTimer(udm_timer_t *ticks)
730 {
731 udm_timer_t ticks0= *ticks;
732 *ticks= UdmStartTimer();
733 return (double) (*ticks - ticks0) / 1000;
734 }
735