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