Annotation of libwww/Library/src/HTInet.c, revision 2.9
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.9 ! frystyk 6: ** @(#) $Id: HTInet.c,v 2.8 1996/08/05 17:22: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: */
197: PUBLIC int HTParseInet (HTNet * net, char * host)
198: {
199: int status = 1;
200: SockA *sin = &net->sock_addr;
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:
206: sin->sdn_nam.n_len = min(DN_MAXNAML, strlen(host)); /* <=6 in phase 4 */
207: strncpy (sin->sdn_nam.n_name, host, sin->sdn_nam.n_len + 1);
208:
209: if (PROT_TRACE)
210: HTTrace("DECnet: Parsed address as object number %d on host %.6s...\n",
211: sin->sdn_objnum, host);
212: #else /* Internet */
213: {
214: char *strptr = host;
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
226: sin->sin_addr = inet_addr(host); /* See netinet/in.h */
227: #else
228: sin->sin_addr.s_addr = inet_addr(host); /* See arpa/inet.h */
229: #endif
2.2 frystyk 230: } else {
231: char * port = strchr(host, ':'); /* Chop port */
232: if (port) *port = '\0';
2.1 frystyk 233: status = HTGetHostByName(net, host);
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: FILE *fp;
290: char name[MAXHOSTNAMELEN+1];
291: *(name+MAXHOSTNAMELEN) = '\0';
292:
2.8 frystyk 293: #if defined(HAVE_SYSINFO) && defined(SI_HOSTNAME)
2.1 frystyk 294: if (!fqdn && sysinfo(SI_HOSTNAME, name, MAXHOSTNAMELEN) > 0) {
295: char * dot = strchr(name, '.');
296: if (PROT_TRACE) HTTrace("HostName.... sysinfo says `%s\'\n", name);
297: StrAllocCopy(hostname, name);
298: fqdn = dot ? 2 : 1;
299: }
300: #endif /* HAVE_SYSINFO */
301:
302: #ifdef HAVE_GETHOSTNAME
303: if (!fqdn && gethostname(name, MAXHOSTNAMELEN) == 0) {
304: char * dot = strchr(name, '.');
305: if (PROT_TRACE) HTTrace("HostName.... gethostname says `%s\'\n", name);
306: StrAllocCopy(hostname, name);
307: fqdn = dot ? 2 : 1;
308: }
309: #endif /* HAVE_GETHOSTNAME */
310:
311: #ifdef RESOLV_CONF
312: /* Now try the resolver config file */
313: if (fqdn==1 && (fp = fopen(RESOLV_CONF, "r")) != NULL) {
314: char buffer[80];
315: *(buffer+79) = '\0';
316: while (fgets(buffer, 79, fp)) {
317: if (!strncasecomp(buffer, "domain", 6) ||
318: !strncasecomp(buffer, "search", 6)) {
319: char *domainstr = buffer+6;
320: char *end;
321: while (*domainstr == ' ' || *domainstr == '\t')
322: domainstr++;
323: end = domainstr;
324: while (*end && !isspace(*end))
325: end++;
326: *end = '\0';
327: if (*domainstr) {
328: StrAllocCat(hostname, ".");
329: StrAllocCat(hostname, domainstr);
2.5 frystyk 330: fqdn = 2;
2.1 frystyk 331: break;
332: }
333: }
334: }
335: fclose(fp);
336: }
337: #endif /* RESOLV_CONF */
338:
339: #ifdef HAVE_GETDOMAINNAME
340: /* If everything else has failed then try getdomainname */
341: if (fqdn==1) {
342: if (getdomainname(name, MAXHOSTNAMELEN)) {
343: if (PROT_TRACE)
344: HTTrace("HostName.... Can't get domain name\n");
345: StrAllocCopy(hostname, "");
346: return NULL;
347: }
348:
349: /* If the host name and the first part of the domain name are different
350: then use the former as it is more exact (I guess) */
351: if (strncmp(name, hostname, (int) strlen(hostname))) {
352: char *domain = strchr(name, '.');
353: if (!domain)
354: domain = name;
355: StrAllocCat(hostname, domain);
356: }
357: }
358: #endif /* HAVE_GETDOMAINNAME */
359:
360: if (hostname) {
361: char *strptr = hostname;
362: while (*strptr) {
363: *strptr = TOLOWER(*strptr);
364: strptr++;
365: }
366: if (*(hostname+strlen(hostname)-1) == '.') /* Remove trailing dot */
367: *(hostname+strlen(hostname)-1) = '\0';
368: if (PROT_TRACE) HTTrace("HostName.... FQDN is `%s\'\n", hostname);
369: }
370: return hostname;
371: }
372:
373: /* HTGetMailAddress
374: **
375: ** Get the mail address of the current user on the current host. The
376: ** domain name used is the one initialized in HTSetHostName or
377: ** HTGetHostName. The login name is determined using (ordered):
378: **
379: ** getlogin
380: ** getpwuid(getuid())
381: **
382: ** The weakness about the last attempt is if the user has multiple
383: ** login names each with the same user ID. If this fails as well then:
384: **
385: ** LOGNAME environment variable
386: ** USER environment variable
387: **
2.3 frystyk 388: ** Returns NULL or string to be freed by caller
2.1 frystyk 389: */
2.3 frystyk 390: PUBLIC char * HTGetMailAddress (void)
2.1 frystyk 391: {
392: #ifdef HT_REENTRANT
393: char name[LOGNAME_MAX+1]; /* For getlogin_r or getUserName */
394: #endif
395: #ifdef WWW_MSWINDOWS/* what was the plan for this under windows? - EGP */
396: char name[256]; /* For getlogin_r or getUserName */
397: unsigned int bufSize = sizeof(name);
398: #endif
399: #ifdef HAVE_PWD_H
400: struct passwd * pw_info = NULL;
401: #endif
402: char * login = NULL;
403:
404: #ifdef WWW_MSWINDOWS
405: if (!login && GetUserName(name, &bufSize) != TRUE)
406: if (PROT_TRACE) HTTrace("MailAddress. GetUsername returns NO\n");
407: #endif /* WWW_MSWINDOWS */
408:
409: #ifdef HAVE_CUSERID
410: if (!login && (login = (char *) cuserid(NULL)) == NULL)
411: if (PROT_TRACE) HTTrace("MailAddress. cuserid returns NULL\n");
412: #endif /* HAVE_CUSERID */
413:
414: #ifdef HAVE_GETLOGIN
415: #ifdef HT_REENTRANT
416: if (!login && (login = (char *) getlogin_r(name, LOGNAME_MAX)) == NULL)
417: #else
418: if (!login && (login = (char *) getlogin()) == NULL)
419: #endif /* HT_REENTRANT */
420: if (PROT_TRACE) HTTrace("MailAddress. getlogin returns NULL\n");
421: #endif /* HAVE_GETLOGIN */
422:
423: #ifdef HAVE_PWD_H
424: if (!login && (pw_info = getpwuid(getuid())) != NULL)
425: login = pw_info->pw_name;
426: #endif /* HAVE_PWD_H */
427:
428: if (!login && (login = getenv("LOGNAME")) == NULL)
429: if (PROT_TRACE) HTTrace("MailAddress. LOGNAME not found\n");
430:
431: if (!login && (login = getenv("USER")) == NULL)
432: if (PROT_TRACE) HTTrace("MailAddress. USER not found\n");
433:
434: if (!login) login = HT_DEFAULT_LOGIN;
435:
436: if (login) {
2.3 frystyk 437: char * domain = NULL;
438: char * mailaddress = NULL;
2.1 frystyk 439: StrAllocCopy(mailaddress, login);
440: StrAllocCat(mailaddress, "@");
2.3 frystyk 441: if ((domain = HTGetHostName()) != NULL) {
2.1 frystyk 442: StrAllocCat(mailaddress, domain);
2.3 frystyk 443: HT_FREE(domain);
2.1 frystyk 444: }
445: return mailaddress;
446: }
447: return NULL;
448: }
449:
2.3 frystyk 450: /*
451: ** Except on the NeXT, we pick up the NewsHost name from
452: **
453: ** 1. Environment variable NNTPSERVER
454: ** 2. File SERVER_FILE
455: ** 3. Compilation time macro DEFAULT_NEWS_HOST
456: **
457: ** On the NeXT, we pick up the NewsHost name from, in order:
458: **
459: ** 1. WorldWideWeb default "NewsHost"
460: ** 2. News default "NewsHost"
461: ** 3. Compilation time macro DEFAULT_NEWS_HOST
462: **
463: ** Returns NULL or string to be freed by caller
464: */
465: PUBLIC char * HTGetNewsServer (void)
466: {
467: char * newshost = NULL;
468: char buffer[80];
469:
470: #ifdef NeXTStep
471: if ((newshost = NXGetDefaultValue("WorldWideWeb","NewsHost")) == 0)
472: if ((newshost = NXGetDefaultValue("News","NewsHost")) == 0)
473: newshost = DEFAULT_NEWS_HOST;
474: #else
475: if ((newshost = (char *) getenv("NNTPSERVER")) == NULL) {
476: FILE *fp = fopen(SERVER_FILE, "r");
477: *(buffer+79) = '\0';
478: if (fp) {
479: if (fgets(buffer, 79, fp)) {
480: char *end;
481: newshost = buffer;
482: while (*newshost == ' ' || *newshost == '\t')
483: newshost++;
484: end = newshost;
485: while (*end && !isspace(*end))
486: end++;
487: *end = '\0';
488: }
489: fclose(fp);
490: }
491: }
492: #endif /* NestStep */
493:
494: /* Last resort */
495: if (!newshost || !*newshost) newshost = DEFAULT_NEWS_HOST;
496:
497: /* Canonicalize host name */
498: {
499: char * result = NULL;
500: StrAllocCopy(result, newshost);
501: {
502: char * strptr = result;
503: while (*strptr) {
504: *strptr = TOLOWER(*strptr);
505: strptr++;
506: }
507: }
508: return result;
509: }
510: }
2.1 frystyk 511:
2.3 frystyk 512: /* Timezone Offset
513: ** ---------------
514: ** Calculates the offset from GMT in seconds
2.1 frystyk 515: */
2.3 frystyk 516: PUBLIC time_t HTGetTimeZoneOffset (void)
2.1 frystyk 517: {
2.3 frystyk 518: time_t HTTimeZone = 0;
519: #ifdef HAVE_TIMEZONE
520: {
521: time_t cur_t = time(NULL);
522: #ifdef HT_REENTRANT
523: struct tm loctime;
524: struct tm *local = (struct tm *) localtime_r(&cur_t, &loctime);
525: #else
526: struct tm *local = localtime(&cur_t);
527: #endif /* HT_REENTRANT */
2.7 frystyk 528: #ifdef HAVE_DAYLIGHT
2.3 frystyk 529: if (daylight && local->tm_isdst>0) { /* daylight time? */
2.7 frystyk 530: #else
531: if (local->tm_isdst>0) { /* daylight time? */
532: #endif /* HAVE_DAYLIGHT */
2.3 frystyk 533: #ifdef HAVE_ALTZONE
534: HTTimeZone = altzone;
535: #else
536: /* Assumes a fixed DST offset of 1 hour, which is probably wrong */
537: HTTimeZone = timezone - 3600;
538: #endif /* HAVE_ALTZONE */
539: } else { /* no */
540: HTTimeZone = timezone;
541: }
542: HTTimeZone = -HTTimeZone;
543: if (CORE_TRACE)
544: HTTrace("TimeZone.... GMT + (%02d) hours (including DST)\n",
545: (int) HTTimeZone/3600);
546: }
547: #else
548: #ifdef HAVE_TM_GMTOFF
549: {
550: time_t cur_t = time(NULL);
551: #ifdef HT_REENTRANT
552: struct tm loctime;
553: localtime_r(&cur_t, &loctime);
554: #else
555: struct tm * local = localtime(&cur_t);
556: #endif /* HT_REENTRANT */
557: HTTimeZone = local->tm_gmtoff;
558: if (CORE_TRACE)
559: HTTrace("TimeZone.... GMT + (%02d) hours (including DST)\n",
560: (int)local->tm_gmtoff / 3600);
561: }
562: #else
563: if (CORE_TRACE) HTTrace("TimeZone.... Not defined\n");
564: #endif /* HAVE_TM_GMTOFF */
565: #endif /* HAVE_TIMEZONE */
566: return HTTimeZone;
2.6 frystyk 567: }
568:
569: /*
570: ** Finds a temporary name in in the directory given. If the directory
2.9 ! frystyk 571: ** is NULL then don't prepend anything.
2.6 frystyk 572: ** If success, the result must be freed by caller, else we return NULL
573: */
574: PUBLIC char * HTGetTmpFileName (const char * dir)
575: {
576: char * result = NULL;
577: char * offset = NULL;
578: if (!(result = (char *) HT_MALLOC(dir ? strlen(dir) : 0 +HT_MAX_TMPNAM+2)))
579: HT_OUTOFMEM("HTGetTmpFileName");
580: if (dir && *dir) {
581: strcpy(result, dir);
582: offset = result+strlen(result)-1;
583: if (*offset != '/') *offset++ = '/';
584: } else
585: offset = result;
586: #ifdef HT_REENTRANT
587: tmpnam_r(offset);
588: #else
589: tmpnam(offset);
590: #endif
2.9 ! frystyk 591:
! 592: /*
! 593: ** If we don't have a dir then remove what the system call may have
! 594: ** prepended the response with
! 595: */
! 596: if (offset == result) {
! 597: #ifdef WWW_MSWINDOWS
! 598: char * orig = strrchr(offset, '\\');
! 599: #else
! 600: char * orig = strrchr(offset, '/');
! 601: #endif /* WWW_MSWINDOWS */
! 602: char * dest = result;
! 603: if (orig++) while ((*dest++ = *orig++));
! 604: }
2.6 frystyk 605: return result;
2.1 frystyk 606: }
Webmaster