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