Annotation of libwww/Library/src/HTInet.c, revision 2.17
2.1 frystyk 1: /* HTInet.c
2: ** GENERIC INTERNET UTILITIES
3: **
4: ** (c) COPYRIGHT MIT 1995.
5: ** Please first read the full copyright statement in the file COPYRIGH.
2.17 ! frystyk 6: ** @(#) $Id: HTInet.c,v 2.16 1997/04/05 00:25:32 frystyk Exp $
2.1 frystyk 7: **
8: ** This code is in common between client and server sides.
9: **
10: ** 16 Mar 96 HFN Spawned off from HTTCP.c
11: */
12:
13: /* Library include files */
14: #include "sysdep.h"
15: #include "WWWUtil.h"
16: #include "HTParse.h"
17: #include "HTAlert.h"
18: #include "HTError.h"
19: #include "HTNetMan.h"
20: #include "HTDNS.h"
21: #include "HTInet.h" /* Implemented here */
22:
2.3 frystyk 23: #ifndef DEFAULT_NEWS_HOST
24: #define DEFAULT_NEWS_HOST "news"
25: #endif
2.1 frystyk 26:
2.3 frystyk 27: #ifndef SERVER_FILE
28: #define SERVER_FILE "/usr/local/lib/rn/server"
29: #endif
2.1 frystyk 30:
31: /* ------------------------------------------------------------------------- */
32:
33: /*
34: ** Returns the string equivalent to the errno passed in the argument.
35: ** We can't use errno directly as we have both errno and socerrno. The
36: ** result is a static buffer.
37: */
38: PUBLIC const char * HTErrnoString (int errornumber)
39: {
40: #ifdef HAVE_STRERROR
41: return strerror(errornumber);
42: #else
43: #ifdef HAVE_SYS_ERRLIST
44: #ifdef HAVE_SYS_NERR
45: return (errno < sys_nerr ? sys_errlist[errno] : "Unknown error");
46: #else
47: return sys_errlist[errno];
48: #endif /* HAVE_SYS_NERR */
49: #else
50: #ifdef VMS
51: static char buf[60];
52: sprintf(buf, "Unix errno=%ld dec, VMS error=%lx hex", errornumber,
53: vaxc$errno);
54: return buf;
55: #else
56: #ifdef _WINSOCKAPI_
57: static char buf[60];
58: sprintf(buf, "Unix errno=%ld dec, WinSock error=%ld", errornumber,
59: WSAGetLastError());
60: return buf;
61: #else
62: return "(Error number not translated)";
63: #endif /* _WINSOCKAPI_ */
64: #endif /* VMS */
65: #endif /* HAVE_SYS_ERRLIST */
66: #endif /* HAVE_STRERROR */
67: }
68:
69:
70: /* Debug error message
71: */
72: PUBLIC int HTInetStatus (int errnum, char * where)
73: {
74: #ifdef VMS
75: if (PROT_TRACE) HTTrace("System Error Unix = %ld dec\n", errno);
76: if (PROT_TRACE) HTTrace("System Error VMS = %lx hex\n", vaxc$errno);
77: return (-vaxc$errno);
78: #else
79: #ifdef _WINSOCKAPI_
80: if (PROT_TRACE) HTTrace("System Error Unix = %ld dec\n", errno);
81: if (PROT_TRACE) HTTrace("System Error WinSock error=%lx hex\n",
82: WSAGetLastError());
83: return (-errnum);
84: #else
85: if (PROT_TRACE)
86: HTTrace("System Error %d after call to %s() failed\n............ %s\n",
87: errno, where, HTErrnoString(errnum));
88: return (-errnum);
89: #endif /* _WINSOCKAPI_ */
90: #endif /* VMS */
91: }
92:
93:
94: /* Parse a cardinal value parse_cardinal()
95: ** ----------------------
96: **
97: ** On entry,
98: ** *pp points to first character to be interpreted, terminated by
99: ** non 0:9 character.
100: ** *pstatus points to status already valid
101: ** maxvalue gives the largest allowable value.
102: **
103: ** On exit,
104: ** *pp points to first unread character
105: ** *pstatus points to status updated iff bad
106: */
107:
108: PUBLIC unsigned int HTCardinal (int * pstatus,
109: char ** pp,
110: unsigned int max_value)
111: {
112: unsigned int n=0;
113: if ( (**pp<'0') || (**pp>'9')) { /* Null string is error */
114: *pstatus = -3; /* No number where one expeceted */
115: return 0;
116: }
117: while ((**pp>='0') && (**pp<='9')) n = n*10 + *((*pp)++) - '0';
118:
119: if (n>max_value) {
120: *pstatus = -4; /* Cardinal outside range */
121: return 0;
122: }
123:
124: return n;
125: }
126:
127: /* ------------------------------------------------------------------------- */
128: /* SIGNAL HANDLING */
129: /* ------------------------------------------------------------------------- */
130:
131: #ifdef WWWLIB_SIG
132: /* HTSetSignal
133: ** This function sets up signal handlers. This might not be necessary to
134: ** call if the application has its own handlers.
135: */
136: #include <signal.h>
137: PUBLIC void HTSetSignal (void)
138: {
139: /* On some systems (SYSV) it is necessary to catch the SIGPIPE signal
140: ** when attemting to connect to a remote host where you normally should
141: ** get `connection refused' back
142: */
143: if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
144: if (PROT_TRACE) HTTrace("HTSignal.... Can't catch SIGPIPE\n");
145: } else {
146: if (PROT_TRACE) HTTrace("HTSignal.... Ignoring SIGPIPE\n");
147: }
148: }
149: #else
150: #ifdef WWW_WIN_DLL
151: PUBLIC void HTSetSignal (void) {}
152: #endif /* WWW_WIN_DLL */
153: #endif /* WWWLIB_SIG */
154:
155: /* ------------------------------------------------------------------------- */
156: /* HOST NAME FUNCTIONS */
157: /* ------------------------------------------------------------------------- */
158:
159: /* Produce a string for an Internet address
160: ** ----------------------------------------
161: **
162: ** On exit,
163: ** returns a pointer to a static string which must be copied if
164: ** it is to be kept.
165: */
166: PUBLIC const char * HTInetString (SockA * sin)
167: {
168: #ifndef DECNET /* Function only used below for a trace message */
169: #if 0
170: /* This dumps core on some Sun systems :-(. The problem is now, that
171: the current implememtation only works for IP-addresses and not in
172: other address spaces. */
173: return inet_ntoa(sin->sin_addr);
174: #endif
175: static char string[16];
176: sprintf(string, "%d.%d.%d.%d",
177: (int)*((unsigned char *)(&sin->sin_addr)+0),
178: (int)*((unsigned char *)(&sin->sin_addr)+1),
179: (int)*((unsigned char *)(&sin->sin_addr)+2),
180: (int)*((unsigned char *)(&sin->sin_addr)+3));
181: return string;
182: #else
183: return "";
184: #endif /* Decnet */
185: }
186:
187: /* Parse a network node address and port
188: ** -------------------------------------
189: ** It is assumed that any portnumber and numeric host address
190: ** is given in decimal notation. Separation character is '.'
2.2 frystyk 191: ** Any port number gets chopped off
2.1 frystyk 192: ** Returns:
193: ** >0 Number of homes
194: ** 0 Wait for persistent socket
195: ** -1 Error
196: */
2.11 frystyk 197: PUBLIC int HTParseInet (HTHost * host, char * hostname, HTRequest * request)
2.1 frystyk 198: {
199: int status = 1;
2.11 frystyk 200: SockA *sin = &host->sock_addr;
2.1 frystyk 201:
202: #ifdef DECNET
203: /* read Decnet node name. @@ Should know about DECnet addresses, but it's
204: probably worth waiting until the Phase transition from IV to V. */
205:
2.11 frystyk 206: sin->sdn_nam.n_len = min(DN_MAXNAML, strlen(hostname)); /* <=6 in phase 4 */
207: strncpy (sin->sdn_nam.n_name, hostname, sin->sdn_nam.n_len + 1);
2.1 frystyk 208:
209: if (PROT_TRACE)
210: HTTrace("DECnet: Parsed address as object number %d on host %.6s...\n",
2.11 frystyk 211: sin->sdn_objnum, hostname);
2.1 frystyk 212: #else /* Internet */
213: {
2.11 frystyk 214: char *strptr = hostname;
2.1 frystyk 215: while (*strptr) {
216: if (*strptr == ':') {
217: *strptr = '\0'; /* Don't want port number in numeric host */
218: break;
219: }
220: if (!isdigit(*strptr) && *strptr != '.')
221: break;
222: strptr++;
223: }
224: if (!*strptr) {
225: #ifdef GUSI
2.11 frystyk 226: sin->sin_addr = inet_addr(hostname); /* See netinet/in.h */
2.1 frystyk 227: #else
2.11 frystyk 228: sin->sin_addr.s_addr = inet_addr(hostname); /* See arpa/inet.h */
2.1 frystyk 229: #endif
2.2 frystyk 230: } else {
2.11 frystyk 231: char * port = strchr(hostname, ':'); /* Chop port */
2.2 frystyk 232: if (port) *port = '\0';
2.11 frystyk 233: status = HTGetHostByName(host, hostname, request);
2.2 frystyk 234: }
2.1 frystyk 235: if (PROT_TRACE) {
236: if (status > 0)
237: HTTrace("ParseInet... as port %d on %s with %d homes\n",
238: (int) ntohs(sin->sin_port), HTInetString(sin), status);
239: }
240: }
241: #endif /* Internet vs. Decnet */
242: return status;
243: }
244:
245:
2.3 frystyk 246: #if 0
2.1 frystyk 247: /* HTGetDomainName
248: ** Returns the current domain name without the local host name.
249: ** The response is pointing to a static area that might be changed
250: ** using HTSetHostName().
251: **
252: ** Returns NULL on error, "" if domain name is not found
253: */
2.3 frystyk 254: PRIVATE char * HTGetDomainName (void)
2.1 frystyk 255: {
2.3 frystyk 256: char * host = HTGetHostName();
257: char * domain;
2.1 frystyk 258: if (host && *host) {
259: if ((domain = strchr(host, '.')) != NULL)
260: return ++domain;
261: else
262: return "";
263: } else
264: return NULL;
265: }
2.3 frystyk 266: #endif
2.1 frystyk 267:
268: /* HTGetHostName
269: ** Returns the name of this host. It uses the following algoritm:
270: **
271: ** 1) gethostname()
272: ** 2) if the hostname doesn't contain any '.' try to read
273: ** /etc/resolv.conf. If there is no domain line in this file then
274: ** 3) Try getdomainname and do as the man pages say for resolv.conf (sun)
275: ** If there is no domain line in this file, then it is derived
276: ** from the domain name set by the domainname(1) command, usually
277: ** by removing the first component. For example, if the domain-
278: ** name is set to ``foo.podunk.edu'' then the default domain name
279: ** used will be ``pudunk.edu''.
280: **
281: ** This is the same procedure as used by res_init() and sendmail.
282: **
283: ** Return: hostname on success else NULL
284: */
2.3 frystyk 285: PUBLIC char * HTGetHostName (void)
2.1 frystyk 286: {
2.3 frystyk 287: char * hostname = NULL;
2.1 frystyk 288: int fqdn = 0; /* 0=no, 1=host, 2=fqdn */
289: char name[MAXHOSTNAMELEN+1];
290: *(name+MAXHOSTNAMELEN) = '\0';
291:
2.8 frystyk 292: #if defined(HAVE_SYSINFO) && defined(SI_HOSTNAME)
2.1 frystyk 293: if (!fqdn && sysinfo(SI_HOSTNAME, name, MAXHOSTNAMELEN) > 0) {
294: char * dot = strchr(name, '.');
295: if (PROT_TRACE) HTTrace("HostName.... sysinfo says `%s\'\n", name);
296: StrAllocCopy(hostname, name);
297: fqdn = dot ? 2 : 1;
298: }
299: #endif /* HAVE_SYSINFO */
300:
301: #ifdef HAVE_GETHOSTNAME
302: if (!fqdn && gethostname(name, MAXHOSTNAMELEN) == 0) {
303: char * dot = strchr(name, '.');
304: if (PROT_TRACE) HTTrace("HostName.... gethostname says `%s\'\n", name);
305: StrAllocCopy(hostname, name);
306: fqdn = dot ? 2 : 1;
307: }
308: #endif /* HAVE_GETHOSTNAME */
309:
310: #ifdef RESOLV_CONF
311: /* Now try the resolver config file */
2.14 frystyk 312: {
313: FILE *fp;
314: if (fqdn==1 && (fp = fopen(RESOLV_CONF, "r")) != NULL) {
315: char buffer[80];
316: *(buffer+79) = '\0';
317: while (fgets(buffer, 79, fp)) {
318: if (!strncasecomp(buffer, "domain", 6) ||
319: !strncasecomp(buffer, "search", 6)) {
320: char *domainstr = buffer+6;
321: char *end;
322: while (*domainstr == ' ' || *domainstr == '\t')
323: domainstr++;
324: end = domainstr;
325: while (*end && !isspace(*end))
326: end++;
327: *end = '\0';
328: if (*domainstr) {
329: StrAllocCat(hostname, ".");
330: StrAllocCat(hostname, domainstr);
331: fqdn = 2;
332: break;
333: }
2.1 frystyk 334: }
335: }
2.14 frystyk 336: fclose(fp);
2.1 frystyk 337: }
338: }
339: #endif /* RESOLV_CONF */
340:
341: #ifdef HAVE_GETDOMAINNAME
342: /* If everything else has failed then try getdomainname */
343: if (fqdn==1) {
344: if (getdomainname(name, MAXHOSTNAMELEN)) {
345: if (PROT_TRACE)
346: HTTrace("HostName.... Can't get domain name\n");
347: StrAllocCopy(hostname, "");
348: return NULL;
349: }
350:
351: /* If the host name and the first part of the domain name are different
352: then use the former as it is more exact (I guess) */
353: if (strncmp(name, hostname, (int) strlen(hostname))) {
354: char *domain = strchr(name, '.');
355: if (!domain)
356: domain = name;
357: StrAllocCat(hostname, domain);
358: }
359: }
360: #endif /* HAVE_GETDOMAINNAME */
361:
362: if (hostname) {
363: char *strptr = hostname;
364: while (*strptr) {
365: *strptr = TOLOWER(*strptr);
366: strptr++;
367: }
368: if (*(hostname+strlen(hostname)-1) == '.') /* Remove trailing dot */
369: *(hostname+strlen(hostname)-1) = '\0';
370: if (PROT_TRACE) HTTrace("HostName.... FQDN is `%s\'\n", hostname);
371: }
372: return hostname;
373: }
374:
375: /* HTGetMailAddress
376: **
377: ** Get the mail address of the current user on the current host. The
378: ** domain name used is the one initialized in HTSetHostName or
379: ** HTGetHostName. The login name is determined using (ordered):
380: **
381: ** getlogin
382: ** getpwuid(getuid())
383: **
384: ** The weakness about the last attempt is if the user has multiple
385: ** login names each with the same user ID. If this fails as well then:
386: **
387: ** LOGNAME environment variable
388: ** USER environment variable
389: **
2.3 frystyk 390: ** Returns NULL or string to be freed by caller
2.1 frystyk 391: */
2.3 frystyk 392: PUBLIC char * HTGetMailAddress (void)
2.1 frystyk 393: {
394: #ifdef HT_REENTRANT
395: char name[LOGNAME_MAX+1]; /* For getlogin_r or getUserName */
396: #endif
397: #ifdef WWW_MSWINDOWS/* what was the plan for this under windows? - EGP */
398: char name[256]; /* For getlogin_r or getUserName */
399: unsigned int bufSize = sizeof(name);
400: #endif
401: #ifdef HAVE_PWD_H
402: struct passwd * pw_info = NULL;
403: #endif
404: char * login = NULL;
405:
406: #ifdef WWW_MSWINDOWS
407: if (!login && GetUserName(name, &bufSize) != TRUE)
408: if (PROT_TRACE) HTTrace("MailAddress. GetUsername returns NO\n");
409: #endif /* WWW_MSWINDOWS */
410:
411: #ifdef HAVE_CUSERID
412: if (!login && (login = (char *) cuserid(NULL)) == NULL)
413: if (PROT_TRACE) HTTrace("MailAddress. cuserid returns NULL\n");
414: #endif /* HAVE_CUSERID */
415:
416: #ifdef HAVE_GETLOGIN
417: #ifdef HT_REENTRANT
418: if (!login && (login = (char *) getlogin_r(name, LOGNAME_MAX)) == NULL)
419: #else
420: if (!login && (login = (char *) getlogin()) == NULL)
421: #endif /* HT_REENTRANT */
422: if (PROT_TRACE) HTTrace("MailAddress. getlogin returns NULL\n");
423: #endif /* HAVE_GETLOGIN */
424:
425: #ifdef HAVE_PWD_H
426: if (!login && (pw_info = getpwuid(getuid())) != NULL)
427: login = pw_info->pw_name;
428: #endif /* HAVE_PWD_H */
429:
430: if (!login && (login = getenv("LOGNAME")) == NULL)
431: if (PROT_TRACE) HTTrace("MailAddress. LOGNAME not found\n");
432:
433: if (!login && (login = getenv("USER")) == NULL)
434: if (PROT_TRACE) HTTrace("MailAddress. USER not found\n");
435:
436: if (!login) login = HT_DEFAULT_LOGIN;
437:
438: if (login) {
2.3 frystyk 439: char * domain = NULL;
440: char * mailaddress = NULL;
2.1 frystyk 441: StrAllocCopy(mailaddress, login);
442: StrAllocCat(mailaddress, "@");
2.3 frystyk 443: if ((domain = HTGetHostName()) != NULL) {
2.1 frystyk 444: StrAllocCat(mailaddress, domain);
2.3 frystyk 445: HT_FREE(domain);
2.1 frystyk 446: }
447: return mailaddress;
448: }
449: return NULL;
450: }
451:
2.3 frystyk 452: /*
453: ** Except on the NeXT, we pick up the NewsHost name from
454: **
455: ** 1. Environment variable NNTPSERVER
456: ** 2. File SERVER_FILE
457: ** 3. Compilation time macro DEFAULT_NEWS_HOST
458: **
459: ** On the NeXT, we pick up the NewsHost name from, in order:
460: **
461: ** 1. WorldWideWeb default "NewsHost"
462: ** 2. News default "NewsHost"
463: ** 3. Compilation time macro DEFAULT_NEWS_HOST
464: **
465: ** Returns NULL or string to be freed by caller
466: */
467: PUBLIC char * HTGetNewsServer (void)
468: {
469: char * newshost = NULL;
470: char buffer[80];
471:
472: #ifdef NeXTStep
473: if ((newshost = NXGetDefaultValue("WorldWideWeb","NewsHost")) == 0)
474: if ((newshost = NXGetDefaultValue("News","NewsHost")) == 0)
475: newshost = DEFAULT_NEWS_HOST;
476: #else
477: if ((newshost = (char *) getenv("NNTPSERVER")) == NULL) {
478: FILE *fp = fopen(SERVER_FILE, "r");
479: *(buffer+79) = '\0';
480: if (fp) {
481: if (fgets(buffer, 79, fp)) {
482: char *end;
483: newshost = buffer;
484: while (*newshost == ' ' || *newshost == '\t')
485: newshost++;
486: end = newshost;
487: while (*end && !isspace(*end))
488: end++;
489: *end = '\0';
490: }
491: fclose(fp);
492: }
493: }
494: #endif /* NestStep */
495:
496: /* Last resort */
497: if (!newshost || !*newshost) newshost = DEFAULT_NEWS_HOST;
498:
499: /* Canonicalize host name */
500: {
501: char * result = NULL;
502: StrAllocCopy(result, newshost);
503: {
504: char * strptr = result;
505: while (*strptr) {
506: *strptr = TOLOWER(*strptr);
507: strptr++;
508: }
509: }
510: return result;
511: }
512: }
2.1 frystyk 513:
2.3 frystyk 514: /* Timezone Offset
515: ** ---------------
516: ** Calculates the offset from GMT in seconds
2.1 frystyk 517: */
2.3 frystyk 518: PUBLIC time_t HTGetTimeZoneOffset (void)
2.1 frystyk 519: {
2.10 frystyk 520: static time_t HTTimeZone = -1; /* Invalid timezone offset */
521: if (HTTimeZone != -1) return HTTimeZone; /* Already done */
2.3 frystyk 522: #ifdef HAVE_TIMEZONE
523: {
524: time_t cur_t = time(NULL);
525: #ifdef HT_REENTRANT
526: struct tm loctime;
527: struct tm *local = (struct tm *) localtime_r(&cur_t, &loctime);
528: #else
529: struct tm *local = localtime(&cur_t);
530: #endif /* HT_REENTRANT */
2.7 frystyk 531: #ifdef HAVE_DAYLIGHT
2.3 frystyk 532: if (daylight && local->tm_isdst>0) { /* daylight time? */
2.7 frystyk 533: #else
534: if (local->tm_isdst>0) { /* daylight time? */
535: #endif /* HAVE_DAYLIGHT */
2.3 frystyk 536: #ifdef HAVE_ALTZONE
537: HTTimeZone = altzone;
538: #else
539: /* Assumes a fixed DST offset of 1 hour, which is probably wrong */
540: HTTimeZone = timezone - 3600;
541: #endif /* HAVE_ALTZONE */
542: } else { /* no */
543: HTTimeZone = timezone;
544: }
545: HTTimeZone = -HTTimeZone;
546: if (CORE_TRACE)
547: HTTrace("TimeZone.... GMT + (%02d) hours (including DST)\n",
548: (int) HTTimeZone/3600);
549: }
550: #else
551: #ifdef HAVE_TM_GMTOFF
552: {
553: time_t cur_t = time(NULL);
554: #ifdef HT_REENTRANT
555: struct tm loctime;
556: localtime_r(&cur_t, &loctime);
557: #else
558: struct tm * local = localtime(&cur_t);
559: #endif /* HT_REENTRANT */
560: HTTimeZone = local->tm_gmtoff;
561: if (CORE_TRACE)
562: HTTrace("TimeZone.... GMT + (%02d) hours (including DST)\n",
563: (int)local->tm_gmtoff / 3600);
564: }
565: #else
566: if (CORE_TRACE) HTTrace("TimeZone.... Not defined\n");
567: #endif /* HAVE_TM_GMTOFF */
568: #endif /* HAVE_TIMEZONE */
569: return HTTimeZone;
2.6 frystyk 570: }
571:
572: /*
573: ** Finds a temporary name in in the directory given. If the directory
2.9 frystyk 574: ** is NULL then don't prepend anything.
2.6 frystyk 575: ** If success, the result must be freed by caller, else we return NULL
576: */
2.16 frystyk 577: PUBLIC char * HTGetTmpFileName (const char * abs_dir)
2.6 frystyk 578: {
2.16 frystyk 579: #ifdef HAVE_TEMPNAM
580: return tempnam(abs_dir, NULL);
581: #else
582: /*
583: ** This is only approx. as we don't know if this file exists or not.
584: ** Hopefully, tempnam() exists on enough platforms so that this is not
585: ** a problem.
586: */
2.6 frystyk 587: char * result = NULL;
588: char * offset = NULL;
2.16 frystyk 589: if (!(result = (char *) HT_MALLOC((abs_dir ? strlen(abs_dir) : 0) +
590: HT_MAX_TMPNAM + 2)))
2.6 frystyk 591: HT_OUTOFMEM("HTGetTmpFileName");
2.16 frystyk 592:
593: #ifdef WWW_MSWINDOWS
594: if (abs_dir) {
595: #else
596: if (abs_dir && *abs_dir=='/') {
597: #endif /* WWW_MSWINDOWS */
598: strcpy(result, abs_dir);
599: offset = result+strlen(result);
600: if (*(offset-1) != '/') *offset++ = '/';
601:
2.6 frystyk 602: #ifdef HT_REENTRANT
2.16 frystyk 603: tmpnam_r(offset);
2.6 frystyk 604: #else
2.16 frystyk 605: tmpnam(offset);
2.6 frystyk 606: #endif
2.9 frystyk 607:
2.16 frystyk 608: {
2.9 frystyk 609: #ifdef WWW_MSWINDOWS
2.16 frystyk 610: char * orig = strrchr(offset, '\\');
2.9 frystyk 611: #else
2.16 frystyk 612: char * orig = strrchr(offset, '/');
2.9 frystyk 613: #endif /* WWW_MSWINDOWS */
2.16 frystyk 614: char * dest = offset;
615: if (orig++) while ((*dest++ = *orig++));
616: }
617: } else {
618: offset = result;
619: #ifdef HT_REENTRANT
620: tmpnam_r(offset);
621: #else
622: tmpnam(offset);
623: #endif
624: offset = result;
2.9 frystyk 625: }
2.6 frystyk 626: return result;
2.16 frystyk 627: #endif /* HAVE_TEMPNAM */
2.11 frystyk 628: }
629:
630: /*
631: ** Copied from X utilities
632: */
2.12 frystyk 633: PUBLIC ms_t HTGetTimeInMillis (void)
2.11 frystyk 634: {
2.13 eric 635: #ifdef WWW_MSWINDOWS
636: return GetTickCount();
637: #else /* WWW_MSWINDOWS */
2.17 ! frystyk 638: #ifdef HAVE_GETTIMEOFDAY
2.11 frystyk 639: struct timeval tp;
640: gettimeofday(&tp, NULL);
641: return(tp.tv_sec * 1000) + (tp.tv_usec / 1000);
2.17 ! frystyk 642: #else
! 643: return((ms_t) 0);
! 644: #endif
2.13 eric 645: #endif /* !WWW_MSWINDOWS */
2.1 frystyk 646: }
Webmaster