1 /*
2 * $LynxId: HTTCP.c,v 1.126 2013/07/21 00:22:52 tom Exp $
3 *
4 * Generic Communication Code HTTCP.c
5 * ==========================
6 *
7 * This code is in common between client and server sides.
8 *
9 * 16 Jan 92 TBL Fix strtol() undefined on CMU Mach.
10 * 25 Jun 92 JFG Added DECNET option through TCP socket emulation.
11 * 13 Sep 93 MD Added correct return of vmserrorno for HTInetStatus.
12 * Added decoding of vms error message for MULTINET.
13 * 7-DEC-1993 Bjorn S. Nilsson, ALEPH, CERN, VMS UCX ioctl() changes
14 * (done of Mosaic)
15 * 19 Feb 94 Danny Mayer Added Bjorn Fixes to Lynx version
16 * 7 Mar 94 Danny Mayer Added Fix UCX version for full domain name
17 * 20 May 94 Andy Harper Added support for CMU TCP/IP transport
18 * 17 Nov 94 Andy Harper Added support for SOCKETSHR transport
19 * 16 Jul 95 S. Bjorndahl added kluge to deal with LIBCMU bug
20 */
21
22 #include <HTUtils.h>
23 #include <HTParse.h>
24 #include <HTAlert.h>
25 #include <HTTCP.h>
26 #include <LYGlobalDefs.h> /* added for no_suspend */
27 #include <LYUtils.h>
28
29 #ifdef NSL_FORK
30 #include <signal.h>
31 #include <www_wait.h>
32 #endif /* NSL_FORK */
33
34 #ifdef HAVE_RESOLV_H
35 #include <resolv.h>
36 #endif
37
38 #ifdef __DJGPP__
39 #include <netdb.h>
40 #endif /* __DJGPP__ */
41
42 #define LYNX_ADDRINFO struct addrinfo
43 #define LYNX_HOSTENT struct hostent
44
45 #define OK_HOST(p) ((p) != 0 && ((p)->h_length) != 0)
46
47 #ifdef SVR4_BSDSELECT
48 int BSDselect(int nfds,
49 fd_set * readfds,
50 fd_set * writefds,
51 fd_set * exceptfds,
52 struct timeval *select_timeout);
53
54 #ifdef select
55 #undef select
56 #endif /* select */
57 #define select BSDselect
58 #ifdef SOCKS
59 #ifdef Rselect
60 #undef Rselect
61 #endif /* Rselect */
62 #define Rselect BSDselect
63 #endif /* SOCKS */
64 #endif /* SVR4_BSDSELECT */
65
66 #include <LYLeaks.h>
67
68 /*
69 * Module-Wide variables
70 */
71 static char *hostname = NULL; /* The name of this host */
72
73 /*
74 * PUBLIC VARIABLES
75 */
76 #ifdef SOCKS
77 unsigned long socks_bind_remoteAddr; /* for long Rbind */
78 #endif /* SOCKS */
79
80 /* Encode INET status (as in sys/errno.h) inet_status()
81 * ------------------
82 *
83 * On entry,
84 * where gives a description of what caused the error
85 * global errno gives the error number in the Unix way.
86 *
87 * On return,
88 * returns a negative status in the Unix way.
89 */
90
91 #ifdef DECL_SYS_ERRLIST
92 extern char *sys_errlist[]; /* see man perror on cernvax */
93 extern int sys_nerr;
94 #endif /* DECL_SYS_ERRLIST */
95
96 #ifdef __DJGPP__
ResolveYield(void)97 static int ResolveYield(void)
98 {
99 return HTCheckForInterrupt()? 0 : 1;
100 }
101 #endif
102
103 #if defined(VMS) && defined(UCX)
104 /*
105 * A routine to mimic the ioctl function for UCX.
106 * Bjorn S. Nilsson, 25-Nov-1993. Based on an example in the UCX manual.
107 */
108 #include <HTioctl.h>
109
HTioctl(int d,int request,int * argp)110 int HTioctl(int d,
111 int request,
112 int *argp)
113 {
114 int sdc, status;
115 unsigned short fun, iosb[4];
116 char *p5, *p6;
117 struct comm {
118 int command;
119 char *addr;
120 } ioctl_comm;
121 struct it2 {
122 unsigned short len;
123 unsigned short opt;
124 struct comm *addr;
125 } ioctl_desc;
126
127 if ((sdc = vaxc$get_sdc(d)) == 0) {
128 set_errno(EBADF);
129 return -1;
130 }
131 ioctl_desc.opt = UCX$C_IOCTL;
132 ioctl_desc.len = sizeof(struct comm);
133
134 ioctl_desc.addr = &ioctl_comm;
135 if (request & IOC_OUT) {
136 fun = IO$_SENSEMODE;
137 p5 = 0;
138 p6 = (char *) &ioctl_desc;
139 } else {
140 fun = IO$_SETMODE;
141 p5 = (char *) &ioctl_desc;
142 p6 = 0;
143 }
144 ioctl_comm.command = request;
145 ioctl_comm.addr = (char *) argp;
146 status = sys$qiow(0, sdc, fun, iosb, 0, 0, 0, 0, 0, 0, p5, p6);
147 if (!(status & 01)) {
148 set_errno(status);
149 return -1;
150 }
151 if (!(iosb[0] & 01)) {
152 set_errno(iosb[0]);
153 return -1;
154 }
155 return 0;
156 }
157 #endif /* VMS && UCX */
158
159 #define MY_FORMAT "TCP: Error %d in `SOCKET_ERRNO' after call to %s() failed.\n\t%s\n"
160 /* third arg is transport/platform specific */
161
162 /* Report Internet Error
163 * ---------------------
164 */
HTInetStatus(const char * where)165 int HTInetStatus(const char *where)
166 {
167 int status;
168 int saved_errno = errno;
169
170 #ifdef VMS
171 #ifdef MULTINET
172 SOCKET_ERRNO = vmserrno;
173 #endif /* MULTINET */
174 #endif /* VMS */
175
176 #ifdef VM
177 CTRACE((tfp, MY_FORMAT, SOCKET_ERRNO, where,
178 "(Error number not translated)")); /* What Is the VM equiv? */
179 #define ER_NO_TRANS_DONE
180 #endif /* VM */
181
182 #ifdef VMS
183 #ifdef MULTINET
184 CTRACE((tfp, MY_FORMAT, SOCKET_ERRNO, where,
185 vms_errno_string()));
186 #else
187 CTRACE((tfp, MY_FORMAT, SOCKET_ERRNO, where,
188 ((SOCKET_ERRNO > 0 && SOCKET_ERRNO <= 65) ?
189 strerror(SOCKET_ERRNO) : "(Error number not translated)")));
190 #endif /* MULTINET */
191 #define ER_NO_TRANS_DONE
192 #endif /* VMS */
193
194 #ifdef HAVE_STRERROR
195 CTRACE((tfp, MY_FORMAT, SOCKET_ERRNO, where,
196 strerror(SOCKET_ERRNO)));
197 #define ER_NO_TRANS_DONE
198 #endif /* HAVE_STRERROR */
199
200 #ifndef ER_NO_TRANS_DONE
201 CTRACE((tfp, MY_FORMAT, SOCKET_ERRNO, where,
202 (SOCKET_ERRNO < sys_nerr ?
203 sys_errlist[SOCKET_ERRNO] : "Unknown error")));
204 #endif /* !ER_NO_TRANS_DONE */
205
206 #ifdef VMS
207 #ifndef MULTINET
208 CTRACE((tfp,
209 " Unix error number (SOCKET_ERRNO) = %ld dec\n",
210 SOCKET_ERRNO));
211 CTRACE((tfp,
212 " VMS error (vaxc$errno) = %lx hex\n",
213 vaxc$errno));
214 #endif /* MULTINET */
215 #endif /* VMS */
216
217 set_errno(saved_errno);
218
219 #ifdef VMS
220 /*
221 * uerrno and errno happen to be zero if vmserrno <> 0
222 */
223 #ifdef MULTINET
224 status = -vmserrno;
225 #else
226 status = -vaxc$errno;
227 #endif /* MULTINET */
228 #else
229 status = -SOCKET_ERRNO;
230 #endif /* VMS */
231 return status;
232 }
233
234 /* Parse a cardinal value parse_cardinal()
235 * ----------------------
236 *
237 * On entry,
238 * *pp points to first character to be interpreted, terminated by
239 * non 0:9 character.
240 * *pstatus points to status already valid
241 * maxvalue gives the largest allowable value.
242 *
243 * On exit,
244 * *pp points to first unread character
245 * *pstatus points to status updated iff bad
246 */
HTCardinal(int * pstatus,char ** pp,unsigned int max_value)247 unsigned int HTCardinal(int *pstatus,
248 char **pp,
249 unsigned int max_value)
250 {
251 unsigned int n;
252
253 if ((**pp < '0') || (**pp > '9')) { /* Null string is error */
254 *pstatus = -3; /* No number where one expected */
255 return 0;
256 }
257
258 n = 0;
259 while ((**pp >= '0') && (**pp <= '9'))
260 n = n * 10 + (unsigned) (*((*pp)++) - '0');
261
262 if (n > max_value) {
263 *pstatus = -4; /* Cardinal outside range */
264 return 0;
265 }
266
267 return n;
268 }
269
270 #ifndef DECNET /* Function only used below for a trace message */
271 /* Produce a string for an Internet address
272 * ----------------------------------------
273 *
274 * On exit,
275 * returns a pointer to a static string which must be copied if
276 * it is to be kept.
277 */
HTInetString(SockA * soc_in)278 const char *HTInetString(SockA * soc_in)
279 {
280 #ifdef INET6
281 static char hostbuf[MAXHOSTNAMELEN];
282
283 getnameinfo((struct sockaddr *) soc_in,
284 SOCKADDR_LEN(soc_in),
285 hostbuf, (socklen_t) sizeof(hostbuf),
286 NULL, 0,
287 NI_NUMERICHOST);
288 return hostbuf;
289 #else
290 static char string[20];
291
292 sprintf(string, "%d.%d.%d.%d",
293 (int) *((unsigned char *) (&soc_in->sin_addr) + 0),
294 (int) *((unsigned char *) (&soc_in->sin_addr) + 1),
295 (int) *((unsigned char *) (&soc_in->sin_addr) + 2),
296 (int) *((unsigned char *) (&soc_in->sin_addr) + 3));
297 return string;
298 #endif /* INET6 */
299 }
300 #endif /* !DECNET */
301
302 /* Check whether string is a valid Internet hostname - kw
303 * -------------------------------------------------
304 *
305 * Checks whether
306 * - contains only valid chars for domain names (actually, the
307 * restrictions are somewhat relaxed),
308 * - no leading dots or empty segments,
309 * - no segment starts with '-' or '+' [this protects telnet command],
310 * - max. length of dot-separated segment <= 63 (RFC 1034,1035),
311 * - total length <= 254 (if it ends with dot) or 253 (otherwise)
312 * [an interpretation of RFC 1034,1035, although RFC 1123
313 * suggests 255 as limit - kw].
314 *
315 * Note: user (before '@') and port (after ':') components from
316 * host part of URL should be already stripped (if appropriate)
317 * from the input string.
318 *
319 * On exit,
320 * returns 1 if valid, otherwise 0.
321 */
valid_hostname(char * name)322 BOOL valid_hostname(char *name)
323 {
324 int i = 1, iseg = 0;
325 char *cp = name;
326
327 if (!(name && *name))
328 return NO;
329 for (; (*cp && i <= 253); cp++, i++) {
330 if (*cp == '.') {
331 if (iseg == 0) {
332 return NO;
333 } else {
334 iseg = 0;
335 continue;
336 }
337 } else if (iseg == 0 && (*cp == '-' || *cp == '+')) {
338 return NO;
339 } else if (++iseg > 63) {
340 return NO;
341 }
342 if (!isalnum(UCH(*cp)) &&
343 *cp != '-' && *cp != '_' &&
344 *cp != '$' && *cp != '+') {
345 return NO;
346 }
347 }
348 return (BOOL) (*cp == '\0' || (*cp == '.' && iseg != 0 && cp[1] == '\0'));
349 }
350
351 /* for transfer of status from child to parent: */
352 typedef struct _statuses {
353 size_t rehostentlen;
354 int h_length;
355 int child_errno; /* sometimes useful to pass this on */
356 int child_h_errno;
357 BOOL h_errno_valid;
358 } STATUSES;
359
360 /*
361 * Function to allow us to be killed with a normal signal (not
362 * SIGKILL), but don't go through normal libc exit() processing, which
363 * would screw up parent's stdio. -BL
364 */
365 #ifdef NSL_FORK
quench(int sig GCC_UNUSED)366 static void quench(int sig GCC_UNUSED)
367 {
368 _exit(2);
369 }
370 #endif
371
372 int lynx_nsl_status = HT_OK;
373
374 #define DEBUG_HOSTENT /* disable in case of problems */
375 #define DEBUG_HOSTENT_CHILD /* for NSL_FORK, may screw up trace file */
376
377 /*
378 * dump_hostent - dumps the contents of a LYNX_HOSTENT to the
379 * trace log or stderr, including all pointer values, strings, and
380 * addresses, in a format inspired by gdb's print format. - kw
381 */
dump_hostent(const char * msgprefix,void * data)382 static void dump_hostent(const char *msgprefix,
383 void *data)
384 {
385 if (TRACE) {
386 int i;
387 char **pcnt;
388 const LYNX_HOSTENT *phost = data;
389
390 CTRACE((tfp, "%s: %p ", msgprefix, (const void *) phost));
391 if (phost) {
392 CTRACE((tfp, "{ h_name = %p", phost->h_name));
393 if (phost->h_name) {
394 CTRACE((tfp, " \"%s\",", phost->h_name));
395 } else {
396 CTRACE((tfp, ","));
397 }
398 CTRACE((tfp, "\n\t h_aliases = %p", (void *) phost->h_aliases));
399 if (phost->h_aliases) {
400 CTRACE((tfp, " {"));
401 for (pcnt = phost->h_aliases; *pcnt; pcnt++) {
402 CTRACE((tfp, "%s %p \"%s\"",
403 (pcnt == phost->h_aliases ? " " : ", "),
404 *pcnt, *pcnt));
405 }
406 CTRACE((tfp, "%s0x0 },\n\t",
407 (*phost->h_aliases ? ", " : " ")));
408 } else {
409 CTRACE((tfp, ",\n\t"));
410 }
411 CTRACE((tfp, " h_addrtype = %d,", phost->h_addrtype));
412 CTRACE((tfp, " h_length = %d,\n\t", phost->h_length));
413 CTRACE((tfp, " h_addr_list = %p", (void *) phost->h_addr_list));
414 if (phost->h_addr_list) {
415 CTRACE((tfp, " {"));
416 for (pcnt = phost->h_addr_list; *pcnt; pcnt++) {
417 CTRACE((tfp, "%s %p",
418 (pcnt == phost->h_addr_list ? "" : ","),
419 *pcnt));
420 for (i = 0; i < phost->h_length; i++) {
421 CTRACE((tfp, "%s%d%s", (i == 0 ? " \"" : "."),
422 (int) *((unsigned char *) (*pcnt) + i),
423 (i + 1 == phost->h_length ? "\"" : "")));
424 }
425 }
426 if (*phost->h_addr_list) {
427 CTRACE((tfp, ", 0x0 } }"));
428 } else {
429 CTRACE((tfp, " 0x0 } }"));
430 }
431 } else {
432 CTRACE((tfp, "}"));
433 }
434 }
435 CTRACE((tfp, "\n"));
436 fflush(tfp);
437 }
438 }
439
440 #ifdef NSL_FORK
441
442 /*
443 * Even though it is a small amount, we cannot count on reading the whole
444 * struct via a pipe in one read -TD
445 */
read_bytes(int fd,char * buffer,size_t length)446 static unsigned read_bytes(int fd, char *buffer, size_t length)
447 {
448 unsigned result = 0;
449
450 while (length != 0) {
451 unsigned got = (unsigned) read(fd, buffer, length);
452
453 if ((int) got > 0) {
454 result += got;
455 buffer += got;
456 length -= got;
457 } else {
458 break;
459 }
460 }
461 return result;
462 }
463
read_hostent(int fd,char * buffer,size_t length)464 static unsigned read_hostent(int fd, char *buffer, size_t length)
465 {
466 unsigned have = read_bytes(fd, buffer, length);
467
468 if (have) {
469 LYNX_HOSTENT *data = (LYNX_HOSTENT *) (void *) buffer;
470 char *next_char = (char *) data + sizeof(*data);
471 char **next_ptr = (char **) (void *) next_char;
472 long offset = 0;
473 int n;
474 int num_addrs = 0;
475 int num_aliases = 0;
476
477 if (data->h_addr_list) {
478 data->h_addr_list = next_ptr;
479 while (next_ptr[num_addrs] != 0) {
480 ++num_addrs;
481 }
482 next_ptr += (num_addrs + 1);
483 next_char += (size_t) (num_addrs + 1) * sizeof(data->h_addr_list[0]);
484 }
485
486 if (data->h_aliases) {
487 data->h_aliases = next_ptr;
488 while (next_ptr[num_aliases] != 0) {
489 ++num_aliases;
490 }
491 next_char += (size_t) (num_aliases + 1) * sizeof(data->h_aliases[0]);
492 }
493
494 if (data->h_name) {
495 offset = next_char - data->h_name;
496 data->h_name = next_char;
497 } else if (data->h_addr_list) {
498 offset = next_char - (char *) data->h_addr_list[0];
499 } else if (data->h_aliases) {
500 offset = next_char - (char *) data->h_aliases[0];
501 }
502
503 if (data->h_addr_list) {
504 for (n = 0; n < num_addrs; ++n) {
505 data->h_addr_list[n] += offset;
506 }
507 }
508
509 if (data->h_aliases) {
510 for (n = 0; n < num_aliases; ++n) {
511 data->h_aliases[n] += offset;
512 }
513 }
514 }
515
516 return have;
517 }
518 #endif /* NSL_FORK */
519
520 /*
521 * fill_rehostent - copies as much as possible relevant content from
522 * the LYNX_HOSTENT pointed to by phost to the char buffer given
523 * by rehostent, subject to maximum output length rehostentsize,
524 * following pointers and building self-contained output which can be
525 * cast to a LYNX_HOSTENT. - kw
526 * See also description of LYGetHostByName.
527 */
528 #if defined(NSL_FORK) || defined(_WINDOWS_NSL)
529
530 #define REHOSTENT_SIZE 128 /* not bigger than pipe buffer! */
531
532 typedef struct {
533 LYNX_HOSTENT h;
534 char rest[REHOSTENT_SIZE];
535 } AlignedHOSTENT;
536
fill_rehostent(void ** rehostent,const LYNX_HOSTENT * phost)537 static size_t fill_rehostent(void **rehostent,
538 const LYNX_HOSTENT *phost)
539 {
540 LYNX_HOSTENT *data = 0;
541 int num_addrs = 0;
542 int num_aliases = 0;
543 char *result = 0;
544 char *p_next_char;
545 char **p_next_charptr;
546 size_t name_len = 0;
547 size_t need = sizeof(LYNX_HOSTENT);
548 int n;
549
550 if (!phost)
551 return 0;
552
553 if (phost->h_name) {
554 name_len = strlen(phost->h_name);
555 need += name_len + 1;
556 }
557 if (phost->h_addr_list) {
558 while (phost->h_addr_list[num_addrs]) {
559 num_addrs++;
560 }
561 need += ((size_t) num_addrs + 1) * ((size_t) phost->h_length
562 + sizeof(phost->h_addr_list[0]));
563 }
564 if (phost->h_aliases) {
565 while (phost->h_aliases[num_aliases]) {
566 need += strlen(phost->h_aliases[num_aliases]) + 1;
567 num_aliases++;
568 }
569 need += ((size_t) num_aliases + 1) * sizeof(phost->h_aliases[0]);
570 }
571
572 if ((result = calloc(need, sizeof(char))) == 0)
573 outofmem(__FILE__, "fill_rehostent");
574
575 *rehostent = result;
576
577 data = (LYNX_HOSTENT *) (void *) result;
578
579 data->h_addrtype = phost->h_addrtype;
580 data->h_length = phost->h_length;
581
582 p_next_char = result + sizeof(LYNX_HOSTENT);
583
584 p_next_charptr = (char **) (void *) p_next_char;
585 if (phost->h_addr_list)
586 p_next_char += (size_t) (num_addrs + 1) * sizeof(phost->h_addr_list[0]);
587 if (phost->h_aliases)
588 p_next_char += (size_t) (num_aliases + 1) * sizeof(phost->h_aliases[0]);
589
590 if (phost->h_name) {
591 data->h_name = p_next_char;
592 strcpy(p_next_char, phost->h_name);
593 p_next_char += name_len + 1;
594 }
595
596 if (phost->h_addr_list) {
597 data->h_addr_list = p_next_charptr;
598 for (n = 0; n < num_addrs; ++n) {
599 MemCpy(p_next_char, phost->h_addr_list[n], phost->h_length);
600 *p_next_charptr++ = p_next_char;
601 p_next_char += phost->h_length;
602 }
603 ++p_next_charptr;
604 }
605
606 if (phost->h_aliases) {
607 data->h_aliases = p_next_charptr;
608 for (n = 0; n < num_aliases; ++n) {
609 strcpy(p_next_char, phost->h_aliases[n]);
610 *p_next_charptr++ = p_next_char;
611 p_next_char += strlen(phost->h_aliases[n]) + 1;;
612 }
613 }
614 return need;
615 }
616 #endif /* NSL_FORK */
617
618 /*
619 * This chunk of code is used in both win32 and cygwin.
620 */
621 #if defined(_WINDOWS_NSL)
622 static LYNX_HOSTENT *gbl_phost; /* Pointer to host - See netdb.h */
623
624 #if !(defined(__CYGWIN__) && defined(NSL_FORK))
625 static int donelookup;
626
_fork_func(void * arg)627 static unsigned long __stdcall _fork_func(void *arg)
628 {
629 const char *host = (const char *) arg;
630 static AlignedHOSTENT aligned_full_rehostent;
631 char *rehostent = (char *) &aligned_full_rehostent;
632 size_t rehostentlen = 0;
633
634 #ifdef SH_EX
635 unsigned long addr;
636
637 addr = (unsigned long) inet_addr(host);
638 if (addr != INADDR_NONE)
639 gbl_phost = gethostbyaddr((char *) &addr, sizeof(addr), AF_INET);
640 else
641 gbl_phost = gethostbyname(host);
642 #else
643 gbl_phost = gethostbyname(host);
644 #endif
645
646 if (gbl_phost) {
647 rehostentlen = fill_rehostent((void **) &rehostent, gbl_phost);
648 if (rehostentlen == 0) {
649 gbl_phost = (LYNX_HOSTENT *) NULL;
650 } else {
651 gbl_phost = (LYNX_HOSTENT *) rehostent;
652 }
653 }
654
655 donelookup = TRUE;
656 return (unsigned long) (gbl_phost);
657 }
658 #endif /* __CYGWIN__ */
659 #endif /* _WINDOWS_NSL */
660
661 #ifdef NSL_FORK
662
663 #ifndef HAVE_H_ERRNO
664 #undef h_errno
665 #define h_errno my_errno
666 static int my_errno;
667
668 #else /* we do HAVE_H_ERRNO: */
669 #ifndef h_errno /* there may be a macro as well as the extern data */
670 extern int h_errno;
671 #endif
672 #endif
673
setup_nsl_fork(void (* really)(char *,char *,STATUSES *,void **),unsigned (* readit)(int,char *,size_t),void (* dumpit)(const char *,void *),char * host,char * port,void ** rehostent)674 static BOOL setup_nsl_fork(void (*really) (char *, char *, STATUSES *, void **),
675 unsigned (*readit) (int, char *, size_t),
676 void (*dumpit) (const char *, void *),
677 char *host,
678 char *port,
679 void **rehostent)
680 {
681 STATUSES statuses;
682
683 /*
684 * fork-based gethostbyname() with checks for interrupts.
685 * - Tom Zerucha (tz@execpc.com) & FM
686 */
687 int got_rehostent = 0;
688
689 #if HAVE_SIGACTION
690 sigset_t old_sigset;
691 sigset_t new_sigset;
692 #endif
693 /*
694 * Pipe, child pid, status buffers, start time, select() control
695 * variables.
696 */
697 int fpid, waitret;
698 int pfd[2], selret;
699 unsigned readret;
700
701 #ifdef HAVE_TYPE_UNIONWAIT
702 union wait waitstat;
703
704 #else
705 int waitstat = 0;
706 #endif
707 time_t start_time = time((time_t *) 0);
708 fd_set readfds;
709 struct timeval one_second;
710 long dns_patience = 30; /* how many seconds will we wait for DNS? */
711 int child_exited = 0;
712
713 memset(&statuses, 0, sizeof(STATUSES));
714 statuses.h_errno_valid = NO;
715
716 /*
717 * Reap any children that have terminated since last time through.
718 * This might include children that we killed, then waited with WNOHANG
719 * before they were actually ready to be reaped. (Should be max of 1
720 * in this state, but the loop is safe if waitpid() is implemented
721 * correctly: returns 0 when children exist but none have exited; -1
722 * with errno == ECHILD when no children.) -BL
723 */
724 do {
725 waitret = waitpid(-1, 0, WNOHANG);
726 } while (waitret > 0 || (waitret == -1 && errno == EINTR));
727 waitret = 0;
728
729 IGNORE_RC(pipe(pfd));
730
731 #if HAVE_SIGACTION
732 /*
733 * Attempt to prevent a rare situation where the child could execute
734 * the Lynx signal handlers because it gets killed before it even has a
735 * chance to reset its handlers, resulting in bogus 'Exiting via
736 * interrupt' message and screen corruption or worse.
737 * Should that continue to be reported, for systems without
738 * sigprocmask(), we need to find a different solutions for those. -
739 * kw 19990430
740 */
741 sigemptyset(&new_sigset);
742 sigaddset(&new_sigset, SIGTERM);
743 sigaddset(&new_sigset, SIGINT);
744 #ifndef NOSIGHUP
745 sigaddset(&new_sigset, SIGHUP);
746 #endif /* NOSIGHUP */
747 #ifdef SIGTSTP
748 sigaddset(&new_sigset, SIGTSTP);
749 #endif /* SIGTSTP */
750 #ifdef SIGWINCH
751 sigaddset(&new_sigset, SIGWINCH);
752 #endif /* SIGWINCH */
753 sigprocmask(SIG_BLOCK, &new_sigset, &old_sigset);
754 #endif /* HAVE_SIGACTION */
755
756 if ((fpid = fork()) == 0) {
757 /*
758 * Child - for the long call.
759 *
760 * Make sure parent can kill us at will. -BL
761 */
762 (void) signal(SIGTERM, quench);
763
764 /*
765 * Also make sure the child does not run one of the signal handlers
766 * that may have been installed by Lynx if one of those signals
767 * occurs. For example we don't want the child to remove temp
768 * files on ^C, let the parent deal with that. - kw
769 */
770 (void) signal(SIGINT, quench);
771 #ifndef NOSIGHUP
772 (void) signal(SIGHUP, quench);
773 #endif /* NOSIGHUP */
774 #ifdef SIGTSTP
775 if (no_suspend)
776 (void) signal(SIGTSTP, SIG_IGN);
777 else
778 (void) signal(SIGTSTP, SIG_DFL);
779 #endif /* SIGTSTP */
780 #ifdef SIGWINCH
781 (void) signal(SIGWINCH, SIG_IGN);
782 #endif /* SIGWINCH */
783 #ifndef __linux__
784 #ifndef DOSPATH
785 signal(SIGBUS, SIG_DFL);
786 #endif /* DOSPATH */
787 #endif /* !__linux__ */
788 signal(SIGSEGV, SIG_DFL);
789 signal(SIGILL, SIG_DFL);
790
791 #if HAVE_SIGACTION
792 /* Restore signal mask to whatever it was before the fork. -kw */
793 sigprocmask(SIG_SETMASK, &old_sigset, NULL);
794 #endif /* HAVE_SIGACTION */
795
796 /*
797 * Child won't use read side. -BL
798 */
799 close(pfd[0]);
800 #ifdef HAVE_H_ERRNO
801 /* to detect cases when it doesn't get set although it should */
802 h_errno = -2;
803 #endif
804 set_errno(0);
805 really(host, port, &statuses, rehostent);
806 /*
807 * Send variables indicating status of lookup to parent. That
808 * includes rehostentlen, which the parent will use as the size for
809 * the second read (if > 0).
810 */
811 if (!statuses.child_errno)
812 statuses.child_errno = errno;
813 IGNORE_RC(write(pfd[1], &statuses, sizeof(statuses)));
814
815 if (statuses.rehostentlen) {
816 /*
817 * Return our resulting rehostent through pipe...
818 */
819 IGNORE_RC(write(pfd[1], *rehostent, statuses.rehostentlen));
820 close(pfd[1]);
821 _exit(0);
822 } else {
823 /*
824 * ... or return error as exit code.
825 */
826 _exit(1);
827 }
828 }
829 #if HAVE_SIGACTION
830 /*
831 * (parent) Restore signal mask to whatever it was before the fork. -
832 * kw
833 */
834 sigprocmask(SIG_SETMASK, &old_sigset, NULL);
835 #endif /* HAVE_SIGACTION */
836
837 /*
838 * (parent) Wait until lookup finishes, or interrupt, or cycled too
839 * many times (just in case) -BL
840 */
841
842 close(pfd[1]); /* parent won't use write side -BL */
843
844 if (fpid < 0) { /* fork failed */
845 close(pfd[0]);
846 goto failed;
847 }
848
849 while (child_exited || (long) (time((time_t *) 0) - start_time) < dns_patience) {
850
851 FD_ZERO(&readfds);
852 /*
853 * This allows us to abort immediately, not after 1-second timeout,
854 * when user hits abort key. Can't do this when using SLANG (or at
855 * least I don't know how), so SLANG users must live with up-to-1s
856 * timeout. -BL
857 *
858 * Whoops -- we need to make sure stdin is actually selectable!
859 * /dev/null isn't, on some systems, which makes some useful Lynx
860 * invocations fail. -BL
861 */
862 {
863 int kbd_fd = LYConsoleInputFD(TRUE);
864
865 if (kbd_fd != INVSOC) {
866 FD_SET(kbd_fd, &readfds);
867 }
868 }
869
870 one_second.tv_sec = 1;
871 one_second.tv_usec = 0;
872 FD_SET(pfd[0], &readfds);
873
874 /*
875 * Return when data received, interrupted, or failed. If nothing
876 * is waiting, we sleep for 1 second in select(), to be nice to the
877 * system. -BL
878 */
879 #ifdef SOCKS
880 if (socks_flag)
881 selret = Rselect(pfd[0] + 1, &readfds, NULL, NULL, &one_second);
882 else
883 #endif /* SOCKS */
884 selret = select(pfd[0] + 1, &readfds, NULL, NULL, &one_second);
885
886 if ((selret > 0) && FD_ISSET(pfd[0], &readfds)) {
887 /*
888 * First get status, including length of address. -BL, kw
889 */
890 readret = read_bytes(pfd[0], (char *) &statuses, sizeof(statuses));
891 if (readret == sizeof(statuses)) {
892 h_errno = statuses.child_h_errno;
893 set_errno(statuses.child_errno);
894 #ifdef HAVE_H_ERRNO
895 if (statuses.h_errno_valid) {
896 lynx_nsl_status = HT_H_ERRNO_VALID;
897 /*
898 * If something went wrong in the child process other
899 * than normal lookup errors, and it appears that we
900 * have enough info to know what went wrong, generate
901 * diagnostic output. ENOMEM observed on linux in
902 * processes constrained with ulimit. It would be too
903 * unkind to abort the session, access to local files
904 * or through a proxy may still work. - kw
905 */
906 if (
907 #ifdef NETDB_INTERNAL /* linux glibc: defined in netdb.h */
908 (errno && h_errno == NETDB_INTERNAL) ||
909 #endif
910 (errno == ENOMEM &&
911 statuses.rehostentlen == 0 &&
912 /* should probably be NETDB_INTERNAL if child
913 memory exhausted, but we may find that
914 h_errno remains unchanged. - kw */
915 h_errno == -2)) {
916 #ifndef MULTINET
917 HTInetStatus("CHILD gethostbyname");
918 #endif
919 HTAlert(LYStrerror(statuses.child_errno));
920 if (errno == ENOMEM) {
921 /*
922 * Not much point in continuing, right? Fake a
923 * 'z', should shorten pointless guessing
924 * cycle. - kw
925 */
926 LYFakeZap(YES);
927 }
928 }
929 }
930 #endif /* HAVE_H_ERRNO */
931 if (statuses.rehostentlen != 0) {
932 /*
933 * Then get the full reorganized hostent. -BL, kw
934 */
935 if ((*rehostent = malloc(statuses.rehostentlen)) == 0)
936 outofmem(__FILE__, "setup_nsl_fork");
937 readret = (*readit) (pfd[0], *rehostent, statuses.rehostentlen);
938 #ifdef DEBUG_HOSTENT
939 dumpit("Read from pipe", *rehostent);
940 #endif
941 if (readret == statuses.rehostentlen) {
942 got_rehostent = 1;
943 lynx_nsl_status = HT_OK;
944 } else if (!statuses.h_errno_valid) {
945 lynx_nsl_status = HT_INTERNAL;
946 }
947 }
948 } else {
949 lynx_nsl_status = HT_ERROR;
950 }
951 /*
952 * Make sure child is cleaned up. -BL
953 */
954 if (!child_exited)
955 waitret = waitpid(fpid, &waitstat, WNOHANG);
956 if (!WIFEXITED(waitstat) && !WIFSIGNALED(waitstat)) {
957 kill(fpid, SIGTERM);
958 waitret = waitpid(fpid, &waitstat, WNOHANG);
959 }
960 break;
961 }
962
963 /*
964 * Clean up if child exited before & no data received. -BL
965 */
966 if (child_exited) {
967 waitret = waitpid(fpid, &waitstat, WNOHANG);
968 break;
969 }
970 /*
971 * If child exited, loop once more looking for data. -BL
972 */
973 if ((waitret = waitpid(fpid, &waitstat, WNOHANG)) > 0) {
974 /*
975 * Data will be arriving right now, so make sure we don't
976 * short-circuit out for too many loops, and skip the interrupt
977 * check. -BL
978 */
979 child_exited = 1;
980 continue;
981 }
982
983 /*
984 * Abort if interrupt key pressed.
985 */
986 if (HTCheckForInterrupt()) {
987 CTRACE((tfp, "LYGetHostByName: INTERRUPTED gethostbyname.\n"));
988 kill(fpid, SIGTERM);
989 waitpid(fpid, NULL, WNOHANG);
990 close(pfd[0]);
991 lynx_nsl_status = HT_INTERRUPTED;
992 return FALSE;
993 }
994 }
995 close(pfd[0]);
996 if (waitret <= 0) {
997 kill(fpid, SIGTERM);
998 waitret = waitpid(fpid, &waitstat, WNOHANG);
999 }
1000 if (waitret > 0) {
1001 if (WIFEXITED(waitstat)) {
1002 CTRACE((tfp,
1003 "LYGetHostByName: NSL_FORK child %d exited, status 0x%x.\n",
1004 (int) waitret, WEXITSTATUS(waitstat)));
1005 } else if (WIFSIGNALED(waitstat)) {
1006 CTRACE((tfp,
1007 "LYGetHostByName: NSL_FORK child %d got signal, status 0x%x!\n",
1008 (int) waitret, WTERMSIG(waitstat)));
1009 #ifdef WCOREDUMP
1010 if (WCOREDUMP(waitstat)) {
1011 CTRACE((tfp,
1012 "LYGetHostByName: NSL_FORK child %d dumped core!\n",
1013 (int) waitret));
1014 }
1015 #endif /* WCOREDUMP */
1016 } else if (WIFSTOPPED(waitstat)) {
1017 CTRACE((tfp,
1018 "LYGetHostByName: NSL_FORK child %d is stopped, status 0x%x!\n",
1019 (int) waitret, WSTOPSIG(waitstat)));
1020 }
1021 }
1022 if (!got_rehostent) {
1023 goto failed;
1024 }
1025 return TRUE;
1026 failed:
1027 return FALSE;
1028 }
1029
1030 /*
1031 * This is called via the child-side of the fork.
1032 */
really_gethostbyname(char * host,char * port GCC_UNUSED,STATUSES * statuses,void ** rehostent)1033 static void really_gethostbyname(char *host,
1034 char *port GCC_UNUSED,
1035 STATUSES * statuses,
1036 void **rehostent)
1037 {
1038 LYNX_HOSTENT *phost; /* Pointer to host - See netdb.h */
1039 LYNX_HOSTENT *result = 0;
1040
1041 (void) port;
1042
1043 phost = gethostbyname(host);
1044 statuses->rehostentlen = 0;
1045 statuses->child_errno = errno;
1046 statuses->child_h_errno = h_errno;
1047 #ifdef HAVE_H_ERRNO
1048 statuses->h_errno_valid = YES;
1049 #endif
1050 #ifdef MVS
1051 CTRACE((tfp, "really_gethostbyname() returned %d\n", phost));
1052 #endif /* MVS */
1053
1054 #ifdef DEBUG_HOSTENT_CHILD
1055 dump_hostent("CHILD gethostbyname", phost);
1056 #endif
1057 if (OK_HOST(phost)) {
1058 statuses->rehostentlen = fill_rehostent(rehostent, phost);
1059 result = (LYNX_HOSTENT *) (*rehostent);
1060 #ifdef DEBUG_HOSTENT_CHILD
1061 dump_hostent("CHILD fill_rehostent", result);
1062 #endif
1063 }
1064 if (statuses->rehostentlen <= sizeof(LYNX_HOSTENT) || !OK_HOST(result)) {
1065 statuses->rehostentlen = 0;
1066 statuses->h_length = 0;
1067 } else {
1068 statuses->h_length = result->h_length;
1069 #ifdef HAVE_H_ERRNO
1070 if (h_errno == -2) /* success, but h_errno unchanged? */
1071 statuses->h_errno_valid = NO;
1072 #endif
1073 }
1074 }
1075 #endif /* NSL_FORK */
1076
1077 /* Resolve an internet hostname, like gethostbyname
1078 * ------------------------------------------------
1079 *
1080 * On entry,
1081 * host points to the given host name, not numeric address,
1082 * without colon or port number.
1083 *
1084 * On exit,
1085 * returns a pointer to a LYNX_HOSTENT in static storage,
1086 * or NULL in case of error or user interruption.
1087 *
1088 * The interface is intended to be exactly the same as for (Unix)
1089 * gethostbyname(), except for the following:
1090 *
1091 * If NSL_FORK is not used, the result of gethostbyname is returned
1092 * directly. Otherwise:
1093 * All lists, addresses, and strings referred to by pointers in the
1094 * returned struct are located, together with the returned struct
1095 * itself, in a buffer of size REHOSTENT_SIZE. If not everything fits,
1096 * some info is omitted, but the function is careful to still return
1097 * a valid structure, without truncating strings; it tries to return,
1098 * in order of decreasing priority, the first address (h_addr_list[0]), the
1099 * official name (h_name), the additional addresses, then alias names.
1100 *
1101 * If NULL is returned, the reason is made available in the global
1102 * variable lynx_nsl_status, with one of the following values:
1103 * HT_INTERRUPTED Interrupted by user
1104 * HT_NOT_ACCEPTABLE Hostname detected as invalid
1105 * (also sets h_errno)
1106 * HT_H_ERRNO_VALID An error occurred, and h_errno holds
1107 * an appropriate value
1108 * HT_ERROR Resolver error, reason not known
1109 * HT_INTERNAL Internal error
1110 */
LYGetHostByName(char * host)1111 LYNX_HOSTENT *LYGetHostByName(char *host)
1112 {
1113
1114 #ifdef NSL_FORK
1115 /* for transfer of result between from child to parent: */
1116 LYNX_HOSTENT *rehostent = 0;
1117 #endif /* NSL_FORK */
1118
1119 LYNX_HOSTENT *result_phost = NULL;
1120
1121 #ifdef __DJGPP__
1122 _resolve_hook = ResolveYield;
1123 #endif
1124
1125 if (!host) {
1126 CTRACE((tfp, "LYGetHostByName: Can't parse `NULL'.\n"));
1127 lynx_nsl_status = HT_INTERNAL;
1128 return NULL;
1129 }
1130 CTRACE((tfp, "LYGetHostByName: parsing `%s'.\n", host));
1131
1132 /* Could disable this if all our callers already check - kw */
1133 if (HTCheckForInterrupt()) {
1134 CTRACE((tfp, "LYGetHostByName: INTERRUPTED for '%s'.\n", host));
1135 lynx_nsl_status = HT_INTERRUPTED;
1136 return NULL;
1137 }
1138
1139 if (!valid_hostname(host)) {
1140 lynx_nsl_status = HT_NOT_ACCEPTABLE;
1141 #ifdef NO_RECOVERY
1142 #ifdef _WINDOWS
1143 WSASetLastError(NO_RECOVERY);
1144 #else
1145 h_errno = NO_RECOVERY;
1146 #endif
1147 #endif
1148 return NULL;
1149 }
1150 #ifdef MVS /* Outstanding problem with crash in MVS gethostbyname */
1151 CTRACE((tfp, "LYGetHostByName: Calling gethostbyname(%s)\n", host));
1152 #endif /* MVS */
1153
1154 CTRACE_FLUSH(tfp); /* so child messages will not mess up parent log */
1155
1156 lynx_nsl_status = HT_INTERNAL; /* should be set to something else below */
1157
1158 #ifdef NSL_FORK
1159 if (!setup_nsl_fork(really_gethostbyname,
1160 read_hostent,
1161 dump_hostent,
1162 host, NULL, (void **) &rehostent)) {
1163 goto failed;
1164 }
1165 result_phost = rehostent;
1166 #else /* Not NSL_FORK: */
1167
1168 #ifdef _WINDOWS_NSL
1169 {
1170 HANDLE hThread;
1171 DWORD dwThreadID;
1172
1173 #ifndef __CYGWIN__
1174 if (!system_is_NT) { /* for Windows9x */
1175 unsigned long t;
1176
1177 t = (unsigned long) inet_addr(host);
1178 if (t != INADDR_NONE)
1179 gbl_phost = gethostbyaddr((char *) &t, sizeof(t), AF_INET);
1180 else
1181 gbl_phost = gethostbyname(host);
1182 } else { /* for Windows NT */
1183 #endif /* !__CYGWIN__ */
1184 gbl_phost = (LYNX_HOSTENT *) NULL;
1185 donelookup = FALSE;
1186
1187 #if defined(__CYGWIN__) || defined(USE_WINSOCK2_H)
1188 SetLastError(WSAHOST_NOT_FOUND);
1189 #else
1190 WSASetLastError(WSAHOST_NOT_FOUND);
1191 #endif
1192
1193 hThread = CreateThread(NULL, 4096UL, _fork_func, host, 0UL,
1194 &dwThreadID);
1195 if (!hThread)
1196 MessageBox(NULL, "CreateThread",
1197 "CreateThread Failed", 0L);
1198
1199 while (!donelookup) {
1200 if (HTCheckForInterrupt()) {
1201 /* Note that host is a character array and is not freed */
1202 /* to avoid possible subthread problems: */
1203 if (!CloseHandle(hThread)) {
1204 MessageBox((void *) NULL,
1205 "CloseHandle", "CloseHandle Failed", 0L);
1206 }
1207 lynx_nsl_status = HT_INTERRUPTED;
1208 return NULL;
1209 }
1210 }
1211 #ifndef __CYGWIN__
1212 }
1213 #endif /* !__CYGWIN__ */
1214 if (gbl_phost) {
1215 lynx_nsl_status = HT_OK;
1216 result_phost = gbl_phost;
1217 } else {
1218 lynx_nsl_status = HT_ERROR;
1219 goto failed;
1220 }
1221 }
1222
1223 #else /* !NSL_FORK, !_WINDOWS_NSL: */
1224 {
1225 LYNX_HOSTENT *phost;
1226
1227 phost = gethostbyname(host); /* See netdb.h */
1228 #ifdef MVS
1229 CTRACE((tfp, "LYGetHostByName: gethostbyname() returned %d\n", phost));
1230 #endif /* MVS */
1231 if (phost) {
1232 lynx_nsl_status = HT_OK;
1233 result_phost = phost;
1234 } else {
1235 lynx_nsl_status = HT_H_ERRNO_VALID;
1236 goto failed;
1237 }
1238 }
1239 #endif /* !NSL_FORK, !_WINDOWS_NSL */
1240 #endif /* !NSL_FORK */
1241
1242 #ifdef DEBUG_HOSTENT
1243 dump_hostent("LYGetHostByName", result_phost);
1244 CTRACE((tfp, "LYGetHostByName: Resolved name to a hostent.\n"));
1245 #endif
1246
1247 return result_phost; /* OK */
1248
1249 failed:
1250 CTRACE((tfp, "LYGetHostByName: Can't find internet node name `%s'.\n",
1251 host));
1252 return NULL;
1253 }
1254
1255 /* Parse a network node address and port
1256 * -------------------------------------
1257 *
1258 * On entry,
1259 * str points to a string with a node name or number,
1260 * with optional trailing colon and port number.
1261 * soc_in points to the binary internet or decnet address field.
1262 *
1263 * On exit,
1264 * *soc_in is filled in. If no port is specified in str, that
1265 * field is left unchanged in *soc_in.
1266 */
1267 #ifndef INET6
HTParseInet(SockA * soc_in,const char * str)1268 static int HTParseInet(SockA * soc_in, const char *str)
1269 {
1270 char *port;
1271 int dotcount_ip = 0; /* for dotted decimal IP addr */
1272 char *strptr;
1273 char *host = NULL;
1274
1275 if (!str) {
1276 CTRACE((tfp, "HTParseInet: Can't parse `NULL'.\n"));
1277 return -1;
1278 }
1279 CTRACE((tfp, "HTParseInet: parsing `%s'.\n", str));
1280 if (HTCheckForInterrupt()) {
1281 CTRACE((tfp, "HTParseInet: INTERRUPTED for '%s'.\n", str));
1282 return -1;
1283 }
1284 StrAllocCopy(host, str); /* Make a copy we can mutilate */
1285 /*
1286 * Parse port number if present.
1287 */
1288 if ((port = strchr(host, ':')) != NULL) {
1289 *port++ = 0; /* Chop off port */
1290 strptr = port;
1291 if (port[0] >= '0' && port[0] <= '9') {
1292 #ifdef UNIX
1293 soc_in->sin_port = (PortNumber) htons(strtol(port, &strptr, 10));
1294 #else /* VMS: */
1295 #ifdef DECNET
1296 soc_in->sdn_objnum = (unsigned char) (strtol(port, &strptr, 10));
1297 #else
1298 soc_in->sin_port = htons((PortNumber) strtol(port, &strptr, 10));
1299 #endif /* Decnet */
1300 #endif /* Unix vs. VMS */
1301 #ifdef SUPPRESS /* 1. crashes!?!. 2. URL syntax has number not name */
1302 } else {
1303 struct servent *serv = getservbyname(port, (char *) 0);
1304
1305 if (serv) {
1306 soc_in->sin_port = serv->s_port;
1307 } else {
1308 CTRACE((tfp, "TCP: Unknown service %s\n", port));
1309 }
1310 #endif /* SUPPRESS */
1311 }
1312 if (strptr && *strptr != '\0') {
1313 FREE(host);
1314 HTAlwaysAlert(NULL, gettext("Address has invalid port"));
1315 return -1;
1316 }
1317 }
1318 #ifdef DECNET
1319 /*
1320 * Read Decnet node name. @@ Should know about DECnet addresses, but it's
1321 * probably worth waiting until the Phase transition from IV to V.
1322 */
1323 soc_in->sdn_nam.n_len = min(DN_MAXNAML, strlen(host)); /* <=6 in phase 4 */
1324 StrNCpy(soc_in->sdn_nam.n_name, host, soc_in->sdn_nam.n_len + 1);
1325 CTRACE((tfp,
1326 "DECnet: Parsed address as object number %d on host %.6s...\n",
1327 soc_in->sdn_objnum, host));
1328 #else /* parse Internet host: */
1329
1330 if (*host >= '0' && *host <= '9') { /* Test for numeric node address: */
1331 strptr = host;
1332 while (*strptr) {
1333 if (*strptr == '.') {
1334 dotcount_ip++;
1335 } else if (!isdigit(UCH(*strptr))) {
1336 break;
1337 }
1338 strptr++;
1339 }
1340 if (*strptr) { /* found non-numeric, assume domain name */
1341 dotcount_ip = 0;
1342 }
1343 }
1344
1345 /*
1346 * Parse host number if present.
1347 */
1348 if (dotcount_ip == 3) /* Numeric node address: */
1349 {
1350 #ifdef DGUX_OLD
1351 soc_in->sin_addr.s_addr = inet_addr(host).s_addr; /* See arpa/inet.h */
1352 #else
1353 #ifdef GUSI
1354 soc_in->sin_addr = inet_addr(host); /* See netinet/in.h */
1355 #else
1356 #ifdef HAVE_INET_ATON
1357 if (!inet_aton(host, &(soc_in->sin_addr))) {
1358 CTRACE((tfp, "inet_aton(%s) returns error\n", host));
1359 FREE(host);
1360 return -1;
1361 }
1362 #else
1363 soc_in->sin_addr.s_addr = inet_addr(host); /* See arpa/inet.h */
1364 #endif /* HAVE_INET_ATON */
1365 #endif /* GUSI */
1366 #endif /* DGUX_OLD */
1367 FREE(host);
1368 } else { /* Alphanumeric node name: */
1369
1370 #ifdef MVS /* Outstanding problem with crash in MVS gethostbyname */
1371 CTRACE((tfp, "HTParseInet: Calling LYGetHostByName(%s)\n", host));
1372 #endif /* MVS */
1373
1374 #ifdef _WINDOWS_NSL
1375 gbl_phost = LYGetHostByName(host); /* See above */
1376 if (!gbl_phost)
1377 goto failed;
1378 MemCpy((void *) &soc_in->sin_addr, gbl_phost->h_addr_list[0], gbl_phost->h_length);
1379 #else /* !_WINDOWS_NSL */
1380 {
1381 LYNX_HOSTENT *phost;
1382
1383 phost = LYGetHostByName(host); /* See above */
1384
1385 if (!phost)
1386 goto failed;
1387 if (!phost)
1388 goto failed;
1389 if (phost->h_length != sizeof soc_in->sin_addr) {
1390 HTAlwaysAlert(host, gettext("Address length looks invalid"));
1391 }
1392 MemCpy((void *) &soc_in->sin_addr, phost->h_addr_list[0], phost->h_length);
1393 }
1394 #endif /* _WINDOWS_NSL */
1395
1396 FREE(host);
1397 } /* Alphanumeric node name */
1398
1399 CTRACE((tfp,
1400 "HTParseInet: Parsed address as port %d, IP address %d.%d.%d.%d\n",
1401 (int) ntohs(soc_in->sin_port),
1402 (int) *((unsigned char *) (&soc_in->sin_addr) + 0),
1403 (int) *((unsigned char *) (&soc_in->sin_addr) + 1),
1404 (int) *((unsigned char *) (&soc_in->sin_addr) + 2),
1405 (int) *((unsigned char *) (&soc_in->sin_addr) + 3)));
1406 #endif /* Internet vs. Decnet */
1407
1408 return 0; /* OK */
1409
1410 failed:
1411 CTRACE((tfp, "HTParseInet: Can't find internet node name `%s'.\n",
1412 host));
1413 FREE(host);
1414 switch (lynx_nsl_status) {
1415 case HT_NOT_ACCEPTABLE:
1416 case HT_INTERRUPTED:
1417 return lynx_nsl_status;
1418 default:
1419 return -1;
1420 }
1421 }
1422 #endif /* !INET6 */
1423
1424 #ifdef INET6
1425
dump_addrinfo(const char * tag,void * data)1426 static void dump_addrinfo(const char *tag, void *data)
1427 {
1428 LYNX_ADDRINFO *res;
1429 int count = 0;
1430
1431 CTRACE((tfp, "dump_addrinfo %s:\n", tag));
1432 for (res = (LYNX_ADDRINFO *) data; res; res = res->ai_next) {
1433 char hostbuf[1024], portbuf[1024];
1434
1435 ++count;
1436 hostbuf[0] = '\0';
1437 portbuf[0] = '\0';
1438 getnameinfo(res->ai_addr, res->ai_addrlen,
1439 hostbuf, (socklen_t) sizeof(hostbuf),
1440 portbuf, (socklen_t) sizeof(portbuf),
1441 NI_NUMERICHOST | NI_NUMERICSERV);
1442
1443 CTRACE((tfp,
1444 "\t[%d] family %d, socktype %d, protocol %d addr %s port %s\n",
1445 count,
1446 res->ai_family,
1447 res->ai_socktype,
1448 res->ai_protocol,
1449 hostbuf,
1450 portbuf));
1451 }
1452 }
1453
1454 #if defined(NSL_FORK)
1455
1456 /*
1457 * Copy the relevant information (on the child-side).
1458 */
fill_addrinfo(void ** buffer,const LYNX_ADDRINFO * phost)1459 static size_t fill_addrinfo(void **buffer,
1460 const LYNX_ADDRINFO *phost)
1461 {
1462 const LYNX_ADDRINFO *q;
1463 LYNX_ADDRINFO *actual;
1464 LYNX_ADDRINFO *result;
1465 int count = 0;
1466 int limit = 0;
1467 size_t need = sizeof(LYNX_ADDRINFO);
1468 char *heap;
1469
1470 CTRACE((tfp, "filladdr_info %p\n", (const void *) phost));
1471 for (q = phost; q != 0; q = q->ai_next) {
1472 ++limit;
1473 need += phost->ai_addrlen;
1474 need += sizeof(LYNX_ADDRINFO);
1475 }
1476 CTRACE((tfp, "...fill_addrinfo %d:%lu\n", limit, (unsigned long) need));
1477
1478 if ((result = (LYNX_ADDRINFO *) calloc(1, need)) == 0)
1479 outofmem(__FILE__, "fill_addrinfo");
1480
1481 *buffer = actual = result;
1482 heap = ((char *) actual) + ((size_t) limit * sizeof(LYNX_ADDRINFO));
1483
1484 for (count = 0; count < limit; ++count) {
1485
1486 /*
1487 * copying the whole structure seems simpler but because it is not
1488 * packed, uninitialized gaps make it hard to analyse with valgrind.
1489 */
1490 /* *INDENT-EQLS* */
1491 actual->ai_flags = phost->ai_flags;
1492 actual->ai_family = phost->ai_family;
1493 actual->ai_socktype = phost->ai_socktype;
1494 actual->ai_protocol = phost->ai_protocol;
1495 actual->ai_addrlen = phost->ai_addrlen;
1496 actual->ai_addr = (struct sockaddr *) (void *) heap;
1497
1498 MemCpy(heap, phost->ai_addr, phost->ai_addrlen);
1499 heap += phost->ai_addrlen;
1500
1501 phost = phost->ai_next;
1502
1503 actual->ai_next = ((count + 1 < limit)
1504 ? (actual + 1)
1505 : 0);
1506 ++actual;
1507 }
1508 return (size_t) (heap - (char *) result);
1509 }
1510
1511 /*
1512 * Read data, repair pointers as done in fill_addrinfo().
1513 */
read_addrinfo(int fd,char * buffer,size_t length)1514 static unsigned read_addrinfo(int fd, char *buffer, size_t length)
1515 {
1516 unsigned result = read_bytes(fd, buffer, length);
1517 LYNX_ADDRINFO *actual = (LYNX_ADDRINFO *) (void *) buffer;
1518 LYNX_ADDRINFO *res;
1519 int count = 0;
1520 int limit;
1521 char *heap;
1522
1523 CTRACE((tfp, "read_addrinfo length %lu\n", (unsigned long) length));
1524 for (limit = 0; actual[limit].ai_next; ++limit) {
1525 }
1526 ++limit;
1527 heap = (char *) (actual + limit);
1528 CTRACE((tfp, "...read_addrinfo %d items\n", limit));
1529
1530 for (res = actual, count = 0; count < limit; ++count) {
1531 res->ai_addr = (struct sockaddr *) (void *) heap;
1532 heap += res->ai_addrlen;
1533 if (count < limit - 1) {
1534 res->ai_next = (res + 1);
1535 ++res;
1536 } else {
1537 res->ai_next = 0;
1538 }
1539 }
1540
1541 #ifdef DEBUG_HOSTENT
1542 dump_addrinfo("read_addrinfo", buffer);
1543 #endif
1544 return result;
1545 }
1546
1547 /*
1548 * This is called via the child-side of the fork.
1549 */
really_getaddrinfo(char * host,char * port,STATUSES * statuses,void ** result)1550 static void really_getaddrinfo(char *host,
1551 char *port,
1552 STATUSES * statuses,
1553 void **result)
1554 {
1555 LYNX_ADDRINFO hints, *res;
1556 int error;
1557
1558 memset(&hints, 0, sizeof(hints));
1559 hints.ai_family = PF_UNSPEC;
1560 hints.ai_socktype = SOCK_STREAM;
1561 error = getaddrinfo(host, port, &hints, &res);
1562 if (error || !res) {
1563 CTRACE((tfp, "HTGetAddrInfo: getaddrinfo(%s, %s): %s\n", host, port,
1564 gai_strerror(error)));
1565 } else {
1566 statuses->child_errno = errno;
1567 statuses->child_h_errno = h_errno;
1568 #ifdef HAVE_H_ERRNO
1569 statuses->h_errno_valid = YES;
1570 #endif
1571
1572 #ifdef DEBUG_HOSTENT_CHILD
1573 dump_addrinfo("CHILD getaddrinfo", res);
1574 #endif
1575 statuses->rehostentlen = fill_addrinfo(result, res);
1576 #ifdef DEBUG_HOSTENT_CHILD
1577 dump_addrinfo("CHILD fill_addrinfo", (LYNX_ADDRINFO *) (*result));
1578 #endif
1579 if (statuses->rehostentlen <= sizeof(LYNX_ADDRINFO)) {
1580 statuses->rehostentlen = 0;
1581 statuses->h_length = 0;
1582 } else {
1583 statuses->h_length = (int) (((LYNX_ADDRINFO *) (*result))->ai_addrlen);
1584 }
1585 }
1586 }
1587 #endif /* NSL_FORK */
1588
HTGetAddrInfo(const char * str,const int defport)1589 static LYNX_ADDRINFO *HTGetAddrInfo(const char *str,
1590 const int defport)
1591 {
1592 #ifdef NSL_FORK
1593 /* for transfer of result between from child to parent: */
1594 void *readdrinfo = 0;
1595
1596 #else
1597 LYNX_ADDRINFO hints;
1598 int error;
1599 #endif /* NSL_FORK */
1600 LYNX_ADDRINFO *res;
1601 char *p;
1602 char *s = NULL;
1603 char *host, *port;
1604 char pbuf[80];
1605
1606 StrAllocCopy(s, str);
1607
1608 if (s[0] == '[' && (p = strchr(s, ']')) != NULL) {
1609 *p++ = '\0';
1610 host = s + 1;
1611 } else {
1612 p = s;
1613 host = &s[0];
1614 }
1615 port = strrchr(p, ':');
1616 if (port) {
1617 *port++ = '\0';
1618 } else {
1619 sprintf(pbuf, "%d", defport);
1620 port = pbuf;
1621 }
1622
1623 #ifdef NSL_FORK
1624 if (setup_nsl_fork(really_getaddrinfo,
1625 read_addrinfo,
1626 dump_addrinfo,
1627 host, port, &readdrinfo)) {
1628 res = readdrinfo;
1629 } else {
1630 res = NULL;
1631 }
1632 #else
1633 memset(&hints, 0, sizeof(hints));
1634 hints.ai_family = PF_UNSPEC;
1635 hints.ai_socktype = SOCK_STREAM;
1636 error = getaddrinfo(host, port, &hints, &res);
1637 if (error || !res) {
1638 CTRACE((tfp, "HTGetAddrInfo: getaddrinfo(%s, %s): %s\n", host, port,
1639 gai_strerror(error)));
1640 res = NULL;
1641 }
1642 #endif
1643
1644 free(s);
1645 #ifdef DEBUG_HOSTENT
1646 dump_addrinfo("HTGetAddrInfo", res);
1647 #endif
1648 return res;
1649 }
1650 #endif /* INET6 */
1651
1652 #ifdef LY_FIND_LEAKS
1653 /* Free our name for the host on which we are - FM
1654 * -------------------------------------------
1655 *
1656 */
free_HTTCP_hostname(void)1657 static void free_HTTCP_hostname(void)
1658 {
1659 FREE(hostname);
1660 }
1661 #endif /* LY_FIND_LEAKS */
1662
1663 /* Derive the name of the host on which we are
1664 * -------------------------------------------
1665 *
1666 */
get_host_details(void)1667 static void get_host_details(void)
1668 {
1669 char name[MAXHOSTNAMELEN + 1]; /* The name of this host */
1670
1671 #ifdef UCX
1672 char *domain_name; /* The name of this host domain */
1673 #endif /* UCX */
1674 #ifdef NEED_HOST_ADDRESS /* no -- needs name server! */
1675 #ifdef INET6
1676 LYNX_ADDRINFO hints, *res;
1677 int error;
1678
1679 #else
1680 LYNX_HOSTENT *phost; /* Pointer to host -- See netdb.h */
1681 #endif /* INET6 */
1682 #endif /* NEED_HOST_ADDRESS */
1683 size_t namelength = sizeof(name);
1684
1685 if (hostname)
1686 return; /* Already done */
1687 gethostname(name, namelength); /* Without domain */
1688 StrAllocCopy(hostname, name);
1689 #ifdef LY_FIND_LEAKS
1690 atexit(free_HTTCP_hostname);
1691 #endif
1692 #ifdef UCX
1693 /*
1694 * UCX doesn't give the complete domain name. Get rest from UCX$BIND_DOM
1695 * logical.
1696 */
1697 if (strchr(hostname, '.') == NULL) { /* Not full address */
1698 domain_name = LYGetEnv("UCX$BIND_DOMAIN");
1699 if (domain_name == NULL)
1700 domain_name = LYGetEnv("TCPIP$BIND_DOMAIN");
1701 if (domain_name != NULL) {
1702 StrAllocCat(hostname, ".");
1703 StrAllocCat(hostname, domain_name);
1704 }
1705 }
1706 #endif /* UCX */
1707 CTRACE((tfp, "TCP: Local host name is %s\n", hostname));
1708
1709 #ifndef DECNET /* Decnet ain't got no damn name server 8#OO */
1710 #ifdef NEED_HOST_ADDRESS /* no -- needs name server! */
1711 #ifdef INET6
1712 memset(&hints, 0, sizeof(hints));
1713 hints.ai_family = PF_UNSPEC;
1714 hints.ai_socktype = SOCK_STREAM;
1715 hints.ai_flags = AI_CANONNAME;
1716 error = getaddrinfo(name, NULL, &hints, &res);
1717 if (error || !res || !res->ai_canonname) {
1718 CTRACE((tfp, "TCP: %s: `%s'\n", gai_strerror(error), name));
1719 if (res)
1720 freeaddrinfo(res);
1721 return; /* Fail! */
1722 }
1723 StrAllocCopy(hostname, res->ai_canonname);
1724 MemCpy(&HTHostAddress, res->ai_addr, res->ai_addrlen);
1725 freeaddrinfo(res);
1726 #else
1727 phost = gethostbyname(name); /* See netdb.h */
1728 if (!OK_HOST(phost)) {
1729 CTRACE((tfp,
1730 "TCP: Can't find my own internet node address for `%s'!!\n",
1731 name));
1732 return; /* Fail! */
1733 }
1734 StrAllocCopy(hostname, phost->h_name);
1735 MemCpy(&HTHostAddress, &phost->h_addr_list[0], phost->h_length);
1736 #endif /* INET6 */
1737 CTRACE((tfp, " Name server says that I am `%s' = %s\n",
1738 hostname, HTInetString(&HTHostAddress)));
1739 #endif /* NEED_HOST_ADDRESS */
1740
1741 #endif /* !DECNET */
1742 }
1743
HTHostName(void)1744 const char *HTHostName(void)
1745 {
1746 get_host_details();
1747 return hostname;
1748 }
1749
1750 #ifdef _WINDOWS
1751 #define SET_EINTR WSASetLastError(EINTR)
1752 #else
1753 #define SET_EINTR SOCKET_ERRNO = EINTR
1754 #endif
1755
HTWasInterrupted(int * status)1756 static BOOL HTWasInterrupted(int *status)
1757 {
1758 BOOL result = FALSE;
1759
1760 if (HTCheckForInterrupt()) {
1761 result = TRUE;
1762 *status = HT_INTERRUPTED;
1763 SET_EINTR;
1764 }
1765 return result;
1766 }
1767
1768 #define TRIES_PER_SECOND 10
1769
1770 /*
1771 * Set the select-timeout to 0.1 seconds.
1772 */
set_timeout(struct timeval * timeoutp)1773 static void set_timeout(struct timeval *timeoutp)
1774 {
1775 timeoutp->tv_sec = 0;
1776 timeoutp->tv_usec = 100000;
1777 }
1778
1779 #ifndef MULTINET /* SOCKET_ERRNO != errno ? */
1780 #if !defined(UCX) || !defined(VAXC) /* errno not modifiable ? */
1781 #define SOCKET_DEBUG_TRACE /* show errno status after some system calls */
1782 #endif /* UCX && VAXC */
1783 #endif /* MULTINET */
1784 /*
1785 * Interruptible connect as implemented for Mosaic by Marc Andreesen
1786 * and hacked in for Lynx years ago by Lou Montulli, and further
1787 * modified over the years by numerous Lynx lovers. - FM
1788 */
HTDoConnect(const char * url,const char * protocol,int default_port,int * s)1789 int HTDoConnect(const char *url,
1790 const char *protocol,
1791 int default_port,
1792 int *s)
1793 {
1794 int status = 0;
1795 char *line = NULL;
1796 char *p1 = NULL;
1797 char *at_sign = NULL;
1798 char *host = NULL;
1799
1800 #ifdef INET6
1801 LYNX_ADDRINFO *res = 0, *res0 = 0;
1802
1803 #else
1804 struct sockaddr_in soc_address;
1805 struct sockaddr_in *soc_in = &soc_address;
1806
1807 /*
1808 * Set up defaults.
1809 */
1810 memset(soc_in, 0, sizeof(*soc_in));
1811 soc_in->sin_family = AF_INET;
1812 soc_in->sin_port = htons((PortNumber) default_port);
1813 #endif /* INET6 */
1814
1815 /*
1816 * Get node name and optional port number.
1817 */
1818 p1 = HTParse(url, "", PARSE_HOST);
1819 if ((at_sign = strchr(p1, '@')) != NULL) {
1820 /*
1821 * If there's an @ then use the stuff after it as a hostname.
1822 */
1823 StrAllocCopy(host, (at_sign + 1));
1824 } else {
1825 StrAllocCopy(host, p1);
1826 }
1827 FREE(p1);
1828
1829 HTSprintf0(&line, "%s%s", WWW_FIND_MESSAGE, host);
1830 _HTProgress(line);
1831 #ifdef INET6
1832 /* HTParseInet() is useless! */
1833 res0 = HTGetAddrInfo(host, default_port);
1834 if (res0 == NULL) {
1835 HTSprintf0(&line, gettext("Unable to locate remote host %s."), host);
1836 _HTProgress(line);
1837 FREE(host);
1838 FREE(line);
1839 return HT_NO_DATA;
1840 }
1841 #else
1842 status = HTParseInet(soc_in, host);
1843 if (status) {
1844 if (status != HT_INTERRUPTED) {
1845 if (status == HT_NOT_ACCEPTABLE) {
1846 /* Not HTProgress, so warning won't be overwritten immediately;
1847 * but not HTAlert, because typically there will be other
1848 * alerts from the callers. - kw
1849 */
1850 HTUserMsg2(gettext("Invalid hostname %s"), host);
1851 } else {
1852 HTSprintf0(&line,
1853 gettext("Unable to locate remote host %s."), host);
1854 _HTProgress(line);
1855 }
1856 status = HT_NO_DATA;
1857 }
1858 FREE(host);
1859 FREE(line);
1860 return status;
1861 }
1862 #endif /* INET6 */
1863
1864 HTSprintf0(&line, gettext("Making %s connection to %s"), protocol, host);
1865 _HTProgress(line);
1866 FREE(host);
1867 FREE(line);
1868
1869 /*
1870 * Now, let's get a socket set up from the server for the data.
1871 */
1872 #ifndef INET6
1873 *s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1874 if (*s == -1) {
1875 HTAlert(gettext("socket failed."));
1876 return HT_NO_DATA;
1877 }
1878 #else
1879 for (res = res0; res; res = res->ai_next) {
1880 *s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
1881 if (*s == -1) {
1882 char hostbuf[1024], portbuf[1024];
1883
1884 getnameinfo(res->ai_addr, res->ai_addrlen,
1885 hostbuf, (socklen_t) sizeof(hostbuf),
1886 portbuf, (socklen_t) sizeof(portbuf),
1887 NI_NUMERICHOST | NI_NUMERICSERV);
1888 HTSprintf0(&line,
1889 gettext("socket failed: family %d addr %s port %s."),
1890 res->ai_family, hostbuf, portbuf);
1891 _HTProgress(line);
1892 FREE(line);
1893 continue;
1894 }
1895 #endif /* INET6 */
1896
1897 #if !defined(DOSPATH) || defined(__DJGPP__)
1898 #if !defined(NO_IOCTL) || defined(USE_FCNTL)
1899 /*
1900 * Make the socket non-blocking, so the connect can be canceled. This
1901 * means that when we issue the connect we should NOT have to wait for
1902 * the accept on the other end.
1903 */
1904 {
1905 #ifdef USE_FCNTL
1906 int ret = fcntl(*s, F_SETFL, O_NONBLOCK);
1907
1908 #else
1909 int val = 1;
1910 int ret = IOCTL(*s, FIONBIO, &val);
1911 #endif /* USE_FCNTL */
1912 if (ret == -1)
1913 _HTProgress(gettext("Could not make connection non-blocking."));
1914 }
1915 #endif /* !NO_IOCTL || USE_FCNTL */
1916 #endif /* !DOSPATH || __DJGPP__ */
1917
1918 /*
1919 * Issue the connect. Since the server can't do an instantaneous
1920 * accept and we are non-blocking, this will almost certainly return a
1921 * negative status.
1922 */
1923 #ifdef SOCKS
1924 if (socks_flag) {
1925 #ifdef INET6
1926 status = Rconnect(*s, res->ai_addr, res->ai_addrlen);
1927 #else
1928 status = Rconnect(*s, (struct sockaddr *) &soc_address,
1929 sizeof(soc_address));
1930 #ifndef SHORTENED_RBIND
1931 socks_bind_remoteAddr = soc_address.sin_addr.s_addr;
1932 #endif
1933 #endif /* INET6 */
1934 } else
1935 #endif /* SOCKS */
1936 #ifdef INET6
1937 status = connect(*s, res->ai_addr, res->ai_addrlen);
1938 #else
1939 status = connect(*s, (struct sockaddr *) &soc_address, sizeof(soc_address));
1940 #endif /* INET6 */
1941
1942 /*
1943 * According to the Sun man page for connect:
1944 * EINPROGRESS The socket is non-blocking and the con-
1945 * nection cannot be completed immediately.
1946 * It is possible to select(2) for comple-
1947 * tion by selecting the socket for writ-
1948 * ing.
1949 * According to the Motorola SVR4 man page for connect:
1950 * EAGAIN The socket is non-blocking and the con-
1951 * nection cannot be completed immediately.
1952 * It is possible to select for completion
1953 * by selecting the socket for writing.
1954 * However, this is only possible if the
1955 * socket STREAMS module is the topmost
1956 * module on the protocol stack with a
1957 * write service procedure. This will be
1958 * the normal case.
1959 */
1960 if ((status < 0) &&
1961 (SOCKET_ERRNO == EINPROGRESS
1962 #ifdef EAGAIN
1963 || SOCKET_ERRNO == EAGAIN
1964 #endif
1965 )) {
1966 struct timeval select_timeout;
1967 int ret;
1968 int tries = 0;
1969
1970 #ifdef SOCKET_DEBUG_TRACE
1971 HTInetStatus("this socket's first connect");
1972 #endif /* SOCKET_DEBUG_TRACE */
1973 ret = 0;
1974 while (ret <= 0) {
1975 fd_set writefds;
1976
1977 /*
1978 * Protect against an infinite loop.
1979 */
1980 if ((tries++ / TRIES_PER_SECOND) >= connect_timeout) {
1981 HTAlert(gettext("Connection failed (too many retries)."));
1982 #ifdef INET6
1983 FREE(line);
1984 #ifndef NSL_FORK
1985 if (res0)
1986 freeaddrinfo(res0);
1987 #endif
1988 #endif /* INET6 */
1989 return HT_NO_DATA;
1990 }
1991 set_timeout(&select_timeout);
1992 FD_ZERO(&writefds);
1993 FD_SET((unsigned) *s, &writefds);
1994 #ifdef SOCKS
1995 if (socks_flag)
1996 ret = Rselect(*s + 1, NULL,
1997 &writefds, NULL, &select_timeout);
1998 else
1999 #endif /* SOCKS */
2000 ret = select(*s + 1,
2001 NULL,
2002 &writefds,
2003 NULL,
2004 &select_timeout);
2005
2006 #ifdef SOCKET_DEBUG_TRACE
2007 if (tries == 1) {
2008 HTInetStatus("this socket's first select");
2009 }
2010 #endif /* SOCKET_DEBUG_TRACE */
2011 /*
2012 * If we suspend, then it is possible that select will be
2013 * interrupted. Allow for this possibility. - JED
2014 */
2015 if ((ret == -1) && (errno == EINTR))
2016 continue;
2017
2018 #ifdef SOCKET_DEBUG_TRACE
2019 if (ret < 0) {
2020 HTInetStatus("failed select");
2021 }
2022 #endif /* SOCKET_DEBUG_TRACE */
2023 /*
2024 * Again according to the Sun and Motorola man pages for
2025 * connect:
2026 * EALREADY The socket is non-blocking and a previ-
2027 * ous connection attempt has not yet been
2028 * completed.
2029 * Thus if the SOCKET_ERRNO is NOT EALREADY we have a real
2030 * error, and should break out here and return that error.
2031 * Otherwise if it is EALREADY keep on trying to complete the
2032 * connection.
2033 */
2034 if ((ret < 0) && (SOCKET_ERRNO != EALREADY)) {
2035 status = ret;
2036 break;
2037 } else if (ret > 0) {
2038 /*
2039 * Extra check here for connection success, if we try to
2040 * connect again, and get EISCONN, it means we have a
2041 * successful connection. But don't check with SOCKS.
2042 */
2043 #ifdef SOCKS
2044 if (socks_flag) {
2045 status = 0;
2046 } else {
2047 #endif /* SOCKS */
2048 #ifdef INET6
2049 status = connect(*s, res->ai_addr, res->ai_addrlen);
2050 #else
2051 status = connect(*s, (struct sockaddr *) &soc_address,
2052 sizeof(soc_address));
2053 #endif /* INET6 */
2054 #ifdef UCX
2055 /*
2056 * A UCX feature: Instead of returning EISCONN UCX
2057 * returns EADDRINUSE. Test for this status also.
2058 */
2059 if ((status < 0) && ((SOCKET_ERRNO == EISCONN) ||
2060 (SOCKET_ERRNO == EADDRINUSE)))
2061 #else
2062 if ((status < 0) && (SOCKET_ERRNO == EISCONN))
2063 #endif /* UCX */
2064 {
2065 status = 0;
2066 }
2067
2068 if (status && (SOCKET_ERRNO == EALREADY)) /* new stuff LJM */
2069 ret = 0; /* keep going */
2070 else {
2071 #ifdef SOCKET_DEBUG_TRACE
2072 if (status < 0) {
2073 HTInetStatus("confirm-ready connect");
2074 }
2075 #endif /* SOCKET_DEBUG_TRACE */
2076 break;
2077 }
2078 #ifdef SOCKS
2079 }
2080 #endif /* SOCKS */
2081 }
2082 #ifdef SOCKS
2083 else if (!socks_flag)
2084 #else
2085 else
2086 #endif /* SOCKS */
2087 {
2088 /*
2089 * The select says we aren't ready yet. Try to connect
2090 * again to make sure. If we don't get EALREADY or
2091 * EISCONN, something has gone wrong. Break out and report
2092 * it.
2093 *
2094 * For some reason, SVR4 returns EAGAIN here instead of
2095 * EALREADY, even though the man page says it should be
2096 * EALREADY.
2097 *
2098 * For some reason, UCX pre 3 apparently returns errno =
2099 * 18242 instead of EALREADY or EISCONN.
2100 */
2101 #ifdef INET6
2102 status = connect(*s, res->ai_addr, res->ai_addrlen);
2103 #else
2104 status = connect(*s, (struct sockaddr *) &soc_address,
2105 sizeof(soc_address));
2106 #endif /* INET6 */
2107 if ((status < 0) &&
2108 (SOCKET_ERRNO != EALREADY
2109 #ifdef EAGAIN
2110 && SOCKET_ERRNO != EAGAIN
2111 #endif
2112 ) &&
2113 #ifdef UCX
2114 (SOCKET_ERRNO != 18242) &&
2115 #endif /* UCX */
2116 (SOCKET_ERRNO != EISCONN)) {
2117 #ifdef SOCKET_DEBUG_TRACE
2118 HTInetStatus("confirm-not-ready connect");
2119 #endif /* SOCKET_DEBUG_TRACE */
2120 break;
2121 }
2122 }
2123 if (HTWasInterrupted(&status)) {
2124 CTRACE((tfp, "*** INTERRUPTED in middle of connect.\n"));
2125 break;
2126 }
2127 }
2128 }
2129 #ifdef SOCKET_DEBUG_TRACE
2130 else if (status < 0) {
2131 HTInetStatus("this socket's first and only connect");
2132 }
2133 #endif /* SOCKET_DEBUG_TRACE */
2134 #ifdef INET6
2135 if (status < 0) {
2136 NETCLOSE(*s);
2137 *s = -1;
2138 continue;
2139 }
2140 break;
2141 }
2142 #endif /* INET6 */
2143
2144 #ifdef INET6
2145 if (*s < 0)
2146 #else
2147 if (status < 0)
2148 #endif /* INET6 */
2149 {
2150 /*
2151 * The connect attempt failed or was interrupted, so close up the
2152 * socket.
2153 */
2154 NETCLOSE(*s);
2155 }
2156 #if !defined(DOSPATH) || defined(__DJGPP__)
2157 #if !defined(NO_IOCTL) || defined(USE_FCNTL)
2158 else {
2159 /*
2160 * Make the socket blocking again on good connect.
2161 */
2162 #ifdef USE_FCNTL
2163 int ret = fcntl(*s, F_SETFL, 0);
2164
2165 #else
2166 int val = 0;
2167 int ret = IOCTL(*s, FIONBIO, &val);
2168 #endif /* USE_FCNTL */
2169 if (ret == -1)
2170 _HTProgress(gettext("Could not restore socket to blocking."));
2171 }
2172 #endif /* !NO_IOCTL || USE_FCNTL */
2173 #endif /* !DOSPATH || __DJGPP__ */
2174
2175 #ifdef INET6
2176 FREE(line);
2177 #ifndef NSL_FORK
2178 if (res0)
2179 freeaddrinfo(res0);
2180 #endif
2181 #endif /* INET6 */
2182 return status;
2183 }
2184
2185 /*
2186 * This is so interruptible reads can be implemented cleanly.
2187 */
HTDoRead(int fildes,void * buf,unsigned nbyte)2188 int HTDoRead(int fildes,
2189 void *buf,
2190 unsigned nbyte)
2191 {
2192 int result;
2193 BOOL ready;
2194
2195 #if !defined(NO_IOCTL)
2196 int ret;
2197 fd_set readfds;
2198 struct timeval select_timeout;
2199 int tries = 0;
2200
2201 #ifdef USE_READPROGRESS
2202 int otries = 0;
2203 time_t otime = time((time_t *) 0);
2204 time_t start = otime;
2205 #endif
2206 #endif /* !NO_IOCTL */
2207
2208 #if defined(UNIX) && !defined(__BEOS__)
2209 if (fildes == 0) {
2210 /*
2211 * 0 can be a valid socket fd, but if it's a tty something must have
2212 * gone wrong. - kw
2213 */
2214 if (isatty(fildes)) {
2215 CTRACE((tfp, "HTDoRead - refusing to read fd 0 which is a tty!\n"));
2216 return -1;
2217 }
2218 } else
2219 #endif
2220 if (fildes <= 0) {
2221 CTRACE((tfp, "HTDoRead - no file descriptor!\n"));
2222 return -1;
2223 }
2224
2225 if (HTWasInterrupted(&result)) {
2226 CTRACE((tfp, "HTDoRead - interrupted before starting!\n"));
2227 return (result);
2228 }
2229 #if defined(NO_IOCTL)
2230 ready = TRUE;
2231 #else
2232 ready = FALSE;
2233 while (!ready) {
2234 /*
2235 * Protect against an infinite loop.
2236 */
2237 if ((tries++ / TRIES_PER_SECOND) >= reading_timeout) {
2238 HTAlert(gettext("Socket read failed (too many tries)."));
2239 SET_EINTR;
2240 result = HT_INTERRUPTED;
2241 break;
2242 }
2243 #ifdef USE_READPROGRESS
2244 if (tries - otries > TRIES_PER_SECOND) {
2245 time_t t = time((time_t *) 0);
2246
2247 otries = tries;
2248 if (t - otime >= 5) {
2249 otime = t;
2250 HTReadProgress((off_t) (-1), (off_t) 0); /* Put "stalled" message */
2251 }
2252 }
2253 #endif
2254
2255 /*
2256 * If we suspend, then it is possible that select will be interrupted.
2257 * Allow for this possibility. - JED
2258 */
2259 do {
2260 set_timeout(&select_timeout);
2261 FD_ZERO(&readfds);
2262 FD_SET((unsigned) fildes, &readfds);
2263 #ifdef SOCKS
2264 if (socks_flag)
2265 ret = Rselect(fildes + 1,
2266 &readfds, NULL, NULL, &select_timeout);
2267 else
2268 #endif /* SOCKS */
2269 ret = select(fildes + 1,
2270 &readfds, NULL, NULL, &select_timeout);
2271 } while ((ret == -1) && (errno == EINTR));
2272
2273 if (ret < 0) {
2274 result = -1;
2275 break;
2276 } else if (ret > 0) {
2277 ready = TRUE;
2278 } else if (HTWasInterrupted(&result)) {
2279 break;
2280 }
2281 }
2282 #endif /* !NO_IOCTL */
2283
2284 if (ready) {
2285 #if defined(UCX) && defined(VAXC)
2286 /*
2287 * VAXC and UCX problem only.
2288 */
2289 errno = vaxc$errno = 0;
2290 result = SOCKET_READ(fildes, buf, nbyte);
2291 CTRACE((tfp,
2292 "Read - result,errno,vaxc$errno: %d %d %d\n", result, errno, vaxc$errno));
2293 if ((result <= 0) && TRACE)
2294 perror("HTTCP.C:HTDoRead:read"); /* RJF */
2295 /*
2296 * An errno value of EPIPE and result < 0 indicates end-of-file on VAXC.
2297 */
2298 if ((result <= 0) && (errno == EPIPE)) {
2299 result = 0;
2300 set_errno(0);
2301 }
2302 #else
2303 #ifdef UNIX
2304 while ((result = (int) SOCKET_READ(fildes, buf, nbyte)) == -1) {
2305 if (errno == EINTR)
2306 continue;
2307 #ifdef ERESTARTSYS
2308 if (errno == ERESTARTSYS)
2309 continue;
2310 #endif /* ERESTARTSYS */
2311 HTInetStatus("read");
2312 break;
2313 }
2314 #else /* UNIX */
2315 result = SOCKET_READ(fildes, buf, nbyte);
2316 #endif /* !UNIX */
2317 #endif /* UCX && VAXC */
2318 }
2319 #ifdef USE_READPROGRESS
2320 CTRACE2(TRACE_TIMING, (tfp, "...HTDoRead returns %d (%" PRI_time_t
2321 " seconds)\n",
2322 result, CAST_time_t (time((time_t *)0) - start)));
2323 #endif
2324 return result;
2325 }
2326
2327 #ifdef SVR4_BSDSELECT
2328 /*
2329 * This is a fix for the difference between BSD's select() and
2330 * SVR4's select(). SVR4's select() can never return a value larger
2331 * than the total number of file descriptors being checked. So, if
2332 * you select for read and write on one file descriptor, and both
2333 * are true, SVR4 select() will only return 1. BSD select in the
2334 * same situation will return 2.
2335 *
2336 * Additionally, BSD select() on timing out, will zero the masks,
2337 * while SVR4 does not. This is fixed here as well.
2338 *
2339 * Set your tabstops to 4 characters to have this code nicely formatted.
2340 *
2341 * Jerry Whelan, guru@bradley.edu, June 12th, 1993
2342 */
2343 #ifdef select
2344 #undef select
2345 #endif /* select */
2346
2347 #ifdef SOCKS
2348 #ifdef Rselect
2349 #undef Rselect
2350 #endif /* Rselect */
2351 #endif /* SOCKS */
2352
2353 #include <sys/types.h>
2354 #include <sys/time.h>
2355 #include <sys/select.h>
2356
BSDselect(int nfds,fd_set * readfds,fd_set * writefds,fd_set * exceptfds,struct timeval * select_timeout)2357 int BSDselect(int nfds,
2358 fd_set * readfds,
2359 fd_set * writefds,
2360 fd_set * exceptfds,
2361 struct timeval *select_timeout)
2362 {
2363 int rval, i;
2364
2365 #ifdef SOCKS
2366 if (socks_flag)
2367 rval = Rselect(nfds, readfds, writefds, exceptfds, select_timeout);
2368 else
2369 #endif /* SOCKS */
2370 rval = select(nfds, readfds, writefds, exceptfds, select_timeout);
2371
2372 switch (rval) {
2373 case -1:
2374 return (rval);
2375
2376 case 0:
2377 if (readfds != NULL)
2378 FD_ZERO(readfds);
2379 if (writefds != NULL)
2380 FD_ZERO(writefds);
2381 if (exceptfds != NULL)
2382 FD_ZERO(exceptfds);
2383 return (rval);
2384
2385 default:
2386 for (i = 0, rval = 0; i < nfds; i++) {
2387 if ((readfds != NULL) && FD_ISSET(i, readfds))
2388 rval++;
2389 if ((writefds != NULL) && FD_ISSET(i, writefds))
2390 rval++;
2391 if ((exceptfds != NULL) && FD_ISSET(i, exceptfds))
2392 rval++;
2393
2394 }
2395 return (rval);
2396 }
2397 /* Should never get here */
2398 }
2399 #endif /* SVR4_BSDSELECT */
2400