lynx-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

lynx-dev NSL_FORK fixes


From: Bela Lubkin
Subject: lynx-dev NSL_FORK fixes
Date: Tue, 8 Sep 1998 23:06:35 -0700

This resurrects changes I submitted in November 1996 -- modified for
today's Lynx source, and further enhanced:

  - Make URL guessing (www.huh.com? www.huh.org? www.huh.net?)
    interruptible.

  - Make URL guessing from the command line interruptible.

  - Use select() instead of FIONREAD.  This makes it work on OSes where
    previously it only *looked* like it was working.

  - select() on stdin as well as the child pipe, when using [n]curses
    (not SLANG).  This allows interrupt to be processed instantly,
    without up-to-1-second delay.

  - While looping, 1 second at a time, bail out after "too many"
    (currently 50) loops: just in case something weird happens, like
    select() returning some unexpected error that we ignore.

  - Make sure child processes are always killed and reaped.

  - Close pipe ends as soon as possible.

  - Now write the length down the pipe (using a known-to-the-program
    length of sizeof(int)) first -- this both helps workaround old
    CMU TCP bugs and the fact that select() doesn't let us get number of
    bytes ready, like FIONREAD does.

Patch is against 2.8.1dev25.

Tom, please check this into dev26 or 27.  I'm specifically asking you to
do this *because* I've changed so much code having to do with OSes I
don't have.  The #ifdef tangle for DJGPP, _WINDOWS_NSL, etc., may have
confused me -- I want the code to reach out and bite people with those
OSes so that my mistakes can be fixed -- instead of just sitting on the
changes and having them not get in for another 2 years...

>Bela<

=============================================================================

*** ./src/LYUtils.c.orig        Mon Sep  7 03:02:16 1998
--- ./src/LYUtils.c     Tue Sep  8 22:32:10 1998
***************
*** 4147,4153 ****
      char *Host = NULL, *HostColon = NULL, *host = NULL;
      char *Path = NULL;
      char *Fragment = NULL;
!     struct hostent  *phost;
      BOOLEAN GotHost = FALSE;
      BOOLEAN Startup = (helpfilepath == NULL);
  
--- 4147,4154 ----
      char *Host = NULL, *HostColon = NULL, *host = NULL;
      char *Path = NULL;
      char *Fragment = NULL;
!     int hoststat;
!     SockA sock;
      BOOLEAN GotHost = FALSE;
      BOOLEAN Startup = (helpfilepath == NULL);
  
***************
*** 4222,4228 ****
        fprintf(stdout, "Looking up '%s' first.\n", host);
      }
  #ifndef DJGPP
!     if ((phost = gethostbyname(host)) != NULL)
  #else
      if (resolve(host) != 0)
  #endif /* DJGPP */
--- 4223,4230 ----
        fprintf(stdout, "Looking up '%s' first.\n", host);
      }
  #ifndef DJGPP
!     sock.sin_port = htons(80);
!     if ((hoststat = HTParseInet(&sock, host)) == 0)
  #else
      if (resolve(host) != 0)
  #endif /* DJGPP */
***************
*** 4243,4249 ****
--- 4245,4255 ----
        FREE(Str);
        FREE(MsgStr);
        return GotHost;
+ #ifndef DJGPP
+     } else if (LYCursesON && ((hoststat == HT_INTERRUPTED) || 
HTCheckForInterrupt())) {
+ #else /* DJGPP */
      } else if (LYCursesON && HTCheckForInterrupt()) {
+ #endif /* DJGPP */
        /*
         *  Give the user chance to interrupt lookup cycles. - KW & FM
         */
***************
*** 4339,4345 ****
                fprintf(stdout, "Looking up '%s', guessing...\n", host);
            }
  #ifndef DJGPP
!           GotHost = ((phost = gethostbyname(host)) != NULL);
  #else
            GotHost = (resolve(host) != 0);
  #endif /* DJGPP */
--- 4345,4352 ----
                fprintf(stdout, "Looking up '%s', guessing...\n", host);
            }
  #ifndef DJGPP
!           sock.sin_port = htons(80);
!           GotHost = ((hoststat = HTParseInet(&sock, host)) == 0);
  #else
            GotHost = (resolve(host) != 0);
  #endif /* DJGPP */
***************
*** 4350,4356 ****
                /*
                 *  Give the user chance to interrupt lookup cycles. - KW
                 */
!               if (LYCursesON && HTCheckForInterrupt()) {
                    CTRACE(tfp, "LYExpandHostForURL: Interrupted while '%s' 
failed to resolve.\n",
                                host);
                    FREE(Str);
--- 4357,4368 ----
                /*
                 *  Give the user chance to interrupt lookup cycles. - KW
                 */
! #ifndef DJGPP
!               if (LYCursesON && ((hoststat == HT_INTERRUPTED) || 
HTCheckForInterrupt()))
! #else /* DJGPP */
!               if (LYCursesON && HTCheckForInterrupt())
! #endif /* DJGPP */
!               {
                    CTRACE(tfp, "LYExpandHostForURL: Interrupted while '%s' 
failed to resolve.\n",
                                host);
                    FREE(Str);
*** ./src/LYMain.c.orig Mon Sep  7 03:02:16 1998
--- ./src/LYMain.c      Tue Sep  8 22:20:39 1998
***************
*** 1534,1539 ****
--- 1534,1555 ----
      LYLoadCookies(LYCookieFile);
  #endif
  
+ #ifdef SIGTSTP
+     /*
+      *        Block Control-Z suspending if requested. - FM
+      */
+     if (no_suspend)
+       (void) signal(SIGTSTP,SIG_IGN);
+ #endif /* SIGTSTP */
+ 
+     /*
+      *  Finish setting up for an INTERACTIVE session.
+      *  Done here so that URL guessing in LYEnsureAbsoluteURL() can be
+      *  interruptible (terminal is in raw mode, select() works).  -BL
+      */
+     if (!dump_output_immediately) {
+       setup(terminal);
+     }
      /*
       *        If startfile is a file URL and the host is defaulted,
       *        force in "//localhost", and if it's not an absolute URL,
***************
*** 1587,1600 ****
        rlogin_ok = !no_outside_rlogin && rlogin_ok;
      }
  
- #ifdef SIGTSTP
-     /*
-      *        Block Control-Z suspending if requested. - FM
-      */
-     if (no_suspend)
-       (void) signal(SIGTSTP,SIG_IGN);
- #endif /* SIGTSTP */
- 
      /*
       *        Check for a valid HEAD request. - FM
       */
--- 1603,1608 ----
***************
*** 1722,1738 ****
  #endif /* SIGTSTP */
      } else {
        /*
!        *  Finish setting up and start an
!        *  INTERACTIVE session. - FM
         */
!       if (setup(terminal)) {
!           if (x_display != NULL && *x_display != '\0') {
!               LYisConfiguredForX = TRUE;
!           }
!           ena_csi((LYlowest_eightbit[current_char_set] > 155));
!           status = mainloop();
!           cleanup();
        }
      }
  
      exit(status);
--- 1730,1743 ----
  #endif /* SIGTSTP */
      } else {
        /*
!        *  Start an INTERACTIVE session. - FM
         */
!       if (x_display != NULL && *x_display != '\0') {
!           LYisConfiguredForX = TRUE;
        }
+       ena_csi((LYlowest_eightbit[current_char_set] > 155));
+       status = mainloop();
+       cleanup();
      }
  
      exit(status);
*** ./WWW/Library/Implementation/HTTCP.c.orig   Thu Aug  6 05:28:22 1998
--- ./WWW/Library/Implementation/HTTCP.c        Tue Sep  8 22:51:45 1998
***************
*** 324,338 ****
  {
      char *port;
      int dotcount_ip = 0;      /* for dotted decimal IP addr */
  #ifndef _WINDOWS_NSL
      char *host = NULL;
-     struct hostent  *phost;   /* Pointer to host - See netdb.h */
  #endif /* _WINDOWS_NSL */
  
      if (!str) {
        CTRACE(tfp, "HTParseInet: Can't parse `NULL'.\n");
        return -1;
      }
      if (HTCheckForInterrupt()) {
        CTRACE (tfp, "HTParseInet: INTERRUPTED for '%s'.\n", str);
        return -1;
--- 324,339 ----
  {
      char *port;
      int dotcount_ip = 0;      /* for dotted decimal IP addr */
+     int success = 0;
  #ifndef _WINDOWS_NSL
      char *host = NULL;
  #endif /* _WINDOWS_NSL */
  
      if (!str) {
        CTRACE(tfp, "HTParseInet: Can't parse `NULL'.\n");
        return -1;
      }
+     CTRACE(tfp, "HTParseInet: parsing `%s'.\n", str);
      if (HTCheckForInterrupt()) {
        CTRACE (tfp, "HTParseInet: INTERRUPTED for '%s'.\n", str);
        return -1;
***************
*** 428,475 ****
        */
        {
            /*
!           **  Pipe, child pid, and status buffers.
            */
            pid_t fpid, waitret = (pid_t)0;
!           int pfd[2], cstat, cst1 = 0;
  
            pipe(pfd);
  
            if ((fpid = fork()) == 0 ) {
                /*
                **  Child - for the long call.
                */
                phost = gethostbyname(host);
!               cst1 = 0;
                /*
!               **  Return value (or nulls).
                */
!               if (OK_HOST(phost)) {
                    write(pfd[1], phost->h_addr, phost->h_length);
                    _exit(0);
                } else {
!                   write(pfd[1], &cst1, 4);
!                   _exit(1);   /* return an error code */
                }
            }
  
            /*
!           **  (parent) Wait until lookup finishes, or interrupt.
            */
!           cstat = 0;
!           while (cstat <= 0) {
                /*
!               **  Exit when data sent.
                */
!               IOCTL(pfd[0], FIONREAD, &cstat);
!               if (cstat > 0)
                    break;
                /*
!               **  Exit if child exited.
                */
!               if ((waitret = waitpid(fpid, &cst1, WNOHANG)) > 0) {
                    break;
!               }
                /*
                **  Abort if interrupt key pressed.
                */
--- 429,548 ----
        */
        {
            /*
!           **  Pipe, child pid, status buffers, cycle count, select()
!           **  control variables.
            */
            pid_t fpid, waitret = (pid_t)0;
!           int pfd[2], cstat, cst1 = 0, cycle = 0;
!           fd_set readfds;
!           struct timeval timeout;
  
            pipe(pfd);
  
            if ((fpid = fork()) == 0 ) {
+               struct hostent  *phost; /* Pointer to host - See netdb.h */
                /*
                **  Child - for the long call.
+               **  Child won't use read side.  -BL
                */
+               close(pfd[0]);
                phost = gethostbyname(host);
! #ifdef MVS
!               CTRACE(tfp, "HTParseInet: gethostbyname() returned %d\n", 
phost);
! #endif /* MVS */
! 
                /*
!               **  Send length of subsequent value to parent (as a
!               **  native int).
                */
!               if (OK_HOST(phost))
!                       cstat = phost->h_length;
!               else
!                       cstat = 0;
!               write(pfd[1], &cstat, sizeof cstat);
! 
!               if (cstat) {
!                   /*
!                   **  Return value through pipe...
!                   */
                    write(pfd[1], phost->h_addr, phost->h_length);
                    _exit(0);
                } else {
!                   /*
!                   **  ... or return error as exit code.
!                   */
!                   _exit(1);
                }
            }
  
            /*
!           **  (parent) Wait until lookup finishes, or interrupt,
!           **  or cycled too many times (just in case) -BL
            */
! 
!           close(pfd[1]);      /* parent won't use write side -BL */
! 
!           while (cycle < 50) {
!               /*
!               **  Avoid infinite loop in the face of the unexpected.  -BL
!               */
!               cycle++;
! 
!               timeout.tv_sec = 1;
!               timeout.tv_usec = 0;
!               FD_ZERO(&readfds);
!               FD_SET(pfd[0], &readfds);
! #ifndef USE_SLANG
!               /*
!               **  This allows us to abort immediately, not after 1-second
!               **  timeout, when user hits abort key.  Can't do this when
!               **  using SLANG (or at least I don't know how), so SLANG
!               **  users must live with up-to-1s timeout.  -BL
!               */
!               FD_SET(0, &readfds);    /* stdin -BL */
! #endif /* USE_SLANG */
! 
                /*
!               **  Return when data received, interrupted, or failed.
!               **  If nothing is waiting, we sleep for 1 second in
!               **  select(), to be nice to the system.  -BL
                */
! #ifdef SOCKS
!               if (socks_flag)
!                   cst1 = Rselect(pfd[0] + 1, (void *)&readfds, NULL, NULL, 
&timeout);
!               else
! #endif /* SOCKS */
!                   cst1 = select(pfd[0] + 1, (void *)&readfds, NULL, NULL, 
&timeout);
! 
!               if ((cst1 > 0) && FD_ISSET(pfd[0], &readfds)) {
!                   /*
!                   **  First get length of address.  -BL
!                   */
!                   cst1 = read(pfd[0], (void *)&cstat, sizeof cstat);
!                   if (cstat == sizeof soc_in->sin_addr) {
!                       /*
!                       **  Then get address itself.  -BL
!                       */
!                       cst1 = read(pfd[0], (void *)&soc_in->sin_addr, cstat);
!                       if (cst1 == cstat) success = 1;
!                   }
!                   /*
!                   **  Make sure child is cleaned up.  -BL
!                   */
!                   waitret = waitpid(fpid, &cst1, WNOHANG);
!                   if (!WIFEXITED(cst1) && !WIFSIGNALED(cst1)) {
!                       kill(fpid, SIGKILL);
!                       waitret = waitpid(fpid, &cst1, WNOHANG);
!                   }
                    break;
+               }
+ 
                /*
!               **  End loop if child exited.
                */
!               if ((waitret = waitpid(fpid, &cst1, WNOHANG)) > 0)
                    break;
! 
                /*
                **  Abort if interrupt key pressed.
                */
***************
*** 479,561 ****
                    waitpid(fpid, NULL, 0);
                    FREE(host);
                    close(pfd[0]);
-                   close(pfd[1]);
                    return HT_INTERRUPTED;
                }
-               /*
-               **  Be nice to the system.
-               */
-               sleep(1);
            }
            if (waitret <= 0) {
                waitret = waitpid(fpid, &cst1, WNOHANG);
            }
!           if (WIFEXITED(cst1)) {
!               CTRACE(tfp, "HTParseInet: NSL_FORK child %d exited, status 
0x%x.\n",
!                           (int)waitret, cst1);
!           } else if (WIFSIGNALED(cst1)) {
!               CTRACE(tfp, "HTParseInet: NSL_FORK child %d got signal, status 
0x%x!\n",
!                           (int)waitret, cst1);
  #ifdef WCOREDUMP
!               if (WCOREDUMP(cst1)) {
!                   CTRACE(tfp, "HTParseInet: NSL_FORK child %d dumped core!\n",
!                               (int)waitret);
                    }
  #endif /* WCOREDUMP */
!           } else if (WIFSTOPPED(cst1)) {
!               CTRACE(tfp, "HTParseInet: NSL_FORK child %d is stopped, status 
0x%x!\n",
!                           (int)waitret, cst1);
!           }
!           /*
!           **  Read as much as we can - should be the address.
!           */
!           IOCTL(pfd[0], FIONREAD, &cstat);
!           if (cstat < 4) {
!               CTRACE(tfp, "HTParseInet: NSL_FORK child returns only %d 
bytes.\n",
!                           cstat);
!               CTRACE(tfp, "             Trying again without forking.\n");
!               phost = gethostbyname(host);    /* See netdb.h */
!               if (!OK_HOST(phost)) {
!                   CTRACE(tfp, "HTParseInet: Can't find internet node name 
`%s'.\n",
!                               host);
!                   memset((void *)&soc_in->sin_addr, 0, 
sizeof(soc_in->sin_addr));
!               } else {
!                   memcpy((void *)&soc_in->sin_addr,
!                          phost->h_addr, phost->h_length);
                }
- #ifdef NOTDEFINED
-               cstat = read(pfd[0], (void *)&soc_in->sin_addr , 4);
- #endif /* NOTDEFINED */
-           } else {
-               cstat = read(pfd[0], (void *)&soc_in->sin_addr , cstat);
            }
!           close(pfd[0]);
!           close(pfd[1]);
!       }
!       if (soc_in->sin_addr.s_addr == 0) {
!           CTRACE(tfp, "HTParseInet: Can't find internet node name `%s'.\n",
!                       host);
! #ifndef _WINDOWS_NSL
!           FREE(host);
! #endif /* _WINDOWS_NSL */
!           return -1;
        }
- #ifndef _WINDOWS_NSL
-       FREE(host);
- #endif /* _WINDOWS_NSL */
- #ifdef MVS
-       CTRACE(tfp, "HTParseInet: gethostbyname() returned %d\n", phost);
- #endif /* MVS */
- 
  #else /* Not NSL_FORK: */
  #ifdef DJGPP
        soc_in->sin_addr.s_addr = htonl(resolve(host));
-       FREE(host);
        if (soc_in->sin_addr.s_addr == 0) {
!           CTRACE(tfp, "HTTPAccess: Can't find internet node name 
`%s'.\n",host);
!           return -1;  /* Fail? */
        }
! #else
  #ifdef _WINDOWS_NSL
        {
  #ifdef __BORLANDC__
--- 552,594 ----
                    waitpid(fpid, NULL, 0);
                    FREE(host);
                    close(pfd[0]);
                    return HT_INTERRUPTED;
                }
            }
+           close(pfd[0]);
            if (waitret <= 0) {
                waitret = waitpid(fpid, &cst1, WNOHANG);
            }
!           if (waitret > 0) {
!               if (WIFEXITED(cst1)) {
!                   CTRACE(tfp, "HTParseInet: NSL_FORK child %d exited, status 
0x%x.\n",
!                               (int)waitret, cst1);
!               } else if (WIFSIGNALED(cst1)) {
!                   CTRACE(tfp, "HTParseInet: NSL_FORK child %d got signal, 
status 0x%x!\n",
!                               (int)waitret, cst1);
  #ifdef WCOREDUMP
!                   if (WCOREDUMP(cst1)) {
!                       CTRACE(tfp, "HTParseInet: NSL_FORK child %d dumped 
core!\n",
!                                   (int)waitret);
                    }
  #endif /* WCOREDUMP */
!               } else if (WIFSTOPPED(cst1)) {
!                   CTRACE(tfp, "HTParseInet: NSL_FORK child %d is stopped, 
status 0x%x!\n",
!                               (int)waitret, cst1);
                }
            }
!           if (!success) {
!               memset((void *)&soc_in->sin_addr, 0, sizeof(soc_in->sin_addr));
!               goto failed;
!           }
        }
  #else /* Not NSL_FORK: */
  #ifdef DJGPP
        soc_in->sin_addr.s_addr = htonl(resolve(host));
        if (soc_in->sin_addr.s_addr == 0) {
!           goto failed;
        }
! #else /* !NSL_FORK, !DJGPP: */
  #ifdef _WINDOWS_NSL
        {
  #ifdef __BORLANDC__
***************
*** 585,622 ****
                          return HT_INTERRUPTED;
                        };
        };
! #else /* !_WINDOWS_NSL */
!       phost = gethostbyname(host);    /* See netdb.h */
! #endif /* _WINDOWS_NSL */
  #ifdef MVS
!       CTRACE(tfp, "HTParseInet: gethostbyname() returned %d\n", phost);
  #endif /* MVS */
!       if (!phost) {
!           CTRACE(tfp, "HTParseInet: Can't find internet node name `%s'.\n",
!                       host);
! #ifndef _WINDOWS_NSL
!           FREE(host);
! #endif /* _WINDOWS_NSL */
!           return -1;  /* Fail? */
        }
  #ifndef _WINDOWS_NSL
        FREE(host);
  #endif /* _WINDOWS_NSL */
! #if defined(VMS) && defined(CMU_TCP)
!       /*
!       **  In LIBCMU, phost->h_length contains not the length of one address
!       **  (four bytes) but the number of bytes in *h_addr, i.e. some multiple
!       **  of four. Thus we need to hard code the value here, and remember to
!       **  change it if/when IP addresses change in size. :-(  LIBCMU is no
!       **  longer supported, and CMU users are encouraged to obtain and use
!       **  SOCKETSHR/NETLIB instead. - S. Bjorndahl
!       */
!       memcpy((void *)&soc_in->sin_addr, phost->h_addr, 4);
! #else
!       memcpy((void *)&soc_in->sin_addr, phost->h_addr, phost->h_length);
! #endif /* VMS && CMU_TCP */
! #endif /* DJGPP */
! #endif /* NSL_FORK */
      }
  
      CTRACE(tfp, "HTParseInet: Parsed address as port %d, IP address 
%d.%d.%d.%d\n",
--- 618,652 ----
                          return HT_INTERRUPTED;
                        };
        };
! #else /* !NSL_FORK, !DJGPP, !_WINDOWS_NSL: */
!       {
!           struct hostent  *phost;
!           phost = gethostbyname(host);        /* See netdb.h */
  #ifdef MVS
!           CTRACE(tfp, "HTParseInet: gethostbyname() returned %d\n", phost);
  #endif /* MVS */
!           if (!phost) goto failed;
! #if defined(VMS) && defined(CMU_TCP)
!           /*
!           **  In LIBCMU, phost->h_length contains not the length of one 
address
!           **  (four bytes) but the number of bytes in *h_addr, i.e. some 
multiple
!           **  of four. Thus we need to hard code the value here, and remember 
to
!           **  change it if/when IP addresses change in size. :-(      LIBCMU 
is no
!           **  longer supported, and CMU users are encouraged to obtain and use
!           **  SOCKETSHR/NETLIB instead. - S. Bjorndahl
!           */
!           memcpy((void *)&soc_in->sin_addr, phost->h_addr, 4);
! #else
!           memcpy((void *)&soc_in->sin_addr, phost->h_addr, phost->h_length);
! #endif /* VMS && CMU_TCP */
        }
+ #endif /* !NSL_FORK, !DJGPP, !_WINDOWS_NSL */
+ #endif /* !NSL_FORK, !DJGPP */
+ #endif /* !NSL_FORK */
  #ifndef _WINDOWS_NSL
        FREE(host);
  #endif /* _WINDOWS_NSL */
! 
      }
  
      CTRACE(tfp, "HTParseInet: Parsed address as port %d, IP address 
%d.%d.%d.%d\n",
***************
*** 628,633 ****
--- 658,671 ----
  #endif        /* Internet vs. Decnet */
  
      return 0; /* OK */
+ 
+ failed:
+     CTRACE(tfp, "HTParseInet: Can't find internet node name `%s'.\n",
+               host);
+ #ifndef _WINDOWS_NSL
+     FREE(host);
+ #endif /* _WINDOWS_NSL */
+     return -1;
  }
  
  /*    Free our name for the host on which we are - FM

reply via email to

[Prev in Thread] Current Thread [Next in Thread]