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