<NONE>

Sonya Rikhtverchik (rikhtver@OpenMarket.com)
Wed, 18 Jun 1997 15:50:54 -0400

Message-Id: <199706181950.PAA10669@u4-138.openmarket.com>
To: fastcgi-developers@OpenMarket.com
Date: Wed, 18 Jun 1997 15:50:54 -0400
From: Sonya Rikhtverchik <rikhtver@OpenMarket.com>
Subject: <NONE>


------- Forwarded Message

Received: (from majordom@localhost) by relay.openmarket.com (8.6.10/8.6.6) id 
PAA01371; Wed, 18 Jun 1997 15:28:46 -0400
Date: Wed, 18 Jun 1997 15:28:46 -0400
From: owner-fastcgi-developers@OpenMarket.com
Message-Id: <199706181928.PAA01371@relay.openmarket.com>
To: owner-fastcgi-developers@OpenMarket.com
Subject: BOUNCE fastcgi-developers@OpenMarket.com:   Earlier I submitted a 
patch that protected the accept() call in
  

>From rikhtver@OpenMarket.com  Wed Jun 18 15:28:42 1997
Received: from berlin.atlantic.net (berlin.atlantic.net [204.215.255.12]) by 
relay.openmarket.com (8.6.10/8.6.6) with ESMTP id PAA01363 for 
<fastcgi-developers@OpenMarket.com>; Wed, 18 Jun 1997 15:28:38 -0400
Received: from rio.atlantic.net (chip@rio.atlantic.net [204.215.255.3]) by 
berlin.atlantic.net (8.8.6/8.8.5) with ESMTP id PAA25098 for 
<fastcgi-developers@OpenMarket.com>; Wed, 18 Jun 1997 15:30:57 -0400
Received: (from chip@localhost) by rio.atlantic.net (8.8.6/8.8.5) id PAA11638 
for fastcgi-developers@OpenMarket.com; Wed, 18 Jun 1997 15:28:31 -0400
From: Chip Salzenberg <chip@rio.atlantic.net>
Message-Id: <199706181928.PAA11638@rio.atlantic.net>
Subject: Better patch for protecting accept()
To: fastcgi-developers@OpenMarket.com
Date: Wed, 18 Jun 1997 15:28:31 -0400 (EDT)
Reply-To: chip@pobox.com
Content-Type: text

Earlier I submitted a patch that protected the accept() call in
FCGX_IsCGI().  However, that patch had the unfortunate side effect of
causing premature exits during startup of competing FCGI processes.
(After a few race conditions were satisfied, though, things settled
down, which initially disguised the problem.)

This improved patch has been tested not to cause that problem, while
still protecting against the multiple simultaneous accept() calls that
are so lethal under Solaris and Irix.

Index: fcgiapp.c
*************** union u_sockaddr {
*** 1881,1884 ****
- --- 1881,1955 ----
  static int fcgiClilen;
  
+ 
+ /*
+  *----------------------------------------------------------------------
+  *
+  * AcquireLock --
+  *
+  *      On platforms that implement concurrent calls to accept
+  *      on a shared listening socket, returns 0.  On other platforms,
+  *      acquires an exclusive lock across all processes sharing a
+  *      listening socket.  If "blocking" parameter is true, blocks
+  *      until the lock has been acquired, otherwise does not.
+  *
+  * Results:
+  *      0 for successful call, -1 in case of system error.
+  *
+  * Side effects:
+  *      This process now has the exclusive lock.
+  *
+  *----------------------------------------------------------------------
+  */
+ static int AcquireLock(int blocking)
+ {
+ #ifdef USE_LOCKING
+     struct flock lock;
+     lock.l_type = F_WRLCK;
+     lock.l_start = 0;
+     lock.l_whence = SEEK_SET;
+     lock.l_len = 0;
+ 
+     while (fcntl(FCGI_LISTENSOCK_FILENO,
+                  blocking ? F_SETLKW : F_SETLK, &lock) < 0) {
+         if (errno != EINTR)
+             return -1;
+     }
+ #endif /* USE_LOCKING */
+     return 0;
+ }
+ 
+ /*
+  *----------------------------------------------------------------------
+  *
+  * ReleaseLock --
+  *
+  *      On platforms that implement concurrent calls to accept
+  *      on a shared listening socket, does nothing.  On other platforms,
+  *	releases an exclusive lock acquired by AcquireLock.
+  *
+  * Results:
+  *      0 for successful call, -1 in case of system error (fatal).
+  *
+  * Side effects:
+  *      This process no longer holds the lock.
+  *
+  *----------------------------------------------------------------------
+  */
+ static int ReleaseLock(void)
+ {
+ #ifdef USE_LOCKING
+     struct flock lock;
+     lock.l_type = F_UNLCK;
+     lock.l_start = 0;
+     lock.l_whence = SEEK_SET;
+     lock.l_len = 0;
+ 
+     if(fcntl(FCGI_LISTENSOCK_FILENO, F_SETLK, &lock) < 0) {
+         return -1;
+     }
+ #endif /* USE_LOCKING */
+     return 0;
+ }
+ 
  /*
   *----------------------------------------------------------------------
*************** int FCGX_IsCGI(void)
*** 1912,1929 ****
      }
      
- -     fcgiClilen = sizeof(fcgiSa);
- -     
      /*
!      * Put the file descriptor into non-blocking mode.
       */
!     flags = fcntl(FCGI_LISTENSOCK_FILENO, F_GETFL, 0);
!     flags |= O_NONBLOCK;
!     if( (fcntl(FCGI_LISTENSOCK_FILENO, F_SETFL, flags)) == -1 ) {
          /*
           * XXX: The reason for the assert is that this call is not
!          *      supposed to return an error unless the 
!          *      FCGI_LISTENSOCK_FILENO is closed.  If it is closed
!          *      then we have an unexpected error which should cause 
!          *      the assert to pop.  The same is true for the following
           *      asserts in this function.
           */
- --- 1983,2010 ----
      }
      
      /*
!      * Lock the file descriptor.
       */
!     if(AcquireLock(FALSE) == -1) {
!         /*
!          * If errno == EWOULDBLOCK then this is a valid FastCGI listener 
!          * socket that is already locked because there's an accept() pending.
!          * NOTE: hp-ux can also return EAGAIN.
!          */
!         if(errno == EACCES || errno == EWOULDBLOCK
! #if (EAGAIN != EWOULDBLOCK)
!            || errno == EAGAIN
! #endif
!           ) {
!             isCGI = FALSE;
!             return isCGI;
!         }
! 
          /*
           * XXX: The reason for the assert is that this call is not
!          *      supposed to return errors other than EWOULDBLOCK unless
!          *      the FCGI_LISTENSOCK_FILENO is closed.  If it is closed
!          *      then we have an unexpected error which should cause the
!          *      assert to pop.  The same is true for the following
           *      asserts in this function.
           */
*************** int FCGX_IsCGI(void)
*** 1932,1941 ****
  
      /*
       * Perform an accept() on the file descriptor.  If this is not a
       * listener socket we will get an error.  Typically this will be
       * ENOTSOCK but it differs from platform to platform.
       */
!     fcgiSocket = accept(FCGI_LISTENSOCK_FILENO, (struct sockaddr *) 
&fcgiSa.un,
!                         &fcgiClilen);
      if(fcgiSocket >= 0) {
          /*
- --- 2013,2032 ----
  
      /*
+      * Put the file descriptor into non-blocking mode.
+      */
+     flags = fcntl(FCGI_LISTENSOCK_FILENO, F_GETFL, 0);
+     flags |= O_NONBLOCK;
+     if( (fcntl(FCGI_LISTENSOCK_FILENO, F_SETFL, flags)) == -1 ) {
+         assert(errno == 0);
+     }
+ 
+     /*
       * Perform an accept() on the file descriptor.  If this is not a
       * listener socket we will get an error.  Typically this will be
       * ENOTSOCK but it differs from platform to platform.
       */
!     fcgiClilen = sizeof(fcgiSa);
!     fcgiSocket = accept(FCGI_LISTENSOCK_FILENO,
!                         (struct sockaddr *) &fcgiSa.un, &fcgiClilen);
      if(fcgiSocket >= 0) {
          /*
*************** int FCGX_IsCGI(void)
*** 1958,1970 ****
           * If errno == EWOULDBLOCK then this is a valid FastCGI listener 
           * socket without any connection pending at this time.
! 	 *
! 	 * NOTE: hp-ux can also return EAGAIN for listener sockets in
! 	 * non-blocking mode when no connections are present.
           */
  #if (EAGAIN != EWOULDBLOCK)
!         if((errno == EWOULDBLOCK) || (errno == EAGAIN)) {
! #else
!         if(errno == EWOULDBLOCK) {
  #endif
              isCGI = FALSE;
          } else {
- --- 2049,2061 ----
           * If errno == EWOULDBLOCK then this is a valid FastCGI listener 
           * socket without any connection pending at this time.
!          *
!          * NOTE: hp-ux can also return EAGAIN for listener sockets in
!          * non-blocking mode when no connections are present.
           */
+         if(errno == EACCES || errno == EWOULDBLOCK
  #if (EAGAIN != EWOULDBLOCK)
!            || errno == EAGAIN
  #endif
+           ) {
              isCGI = FALSE;
          } else {
*************** int FCGX_IsCGI(void)
*** 1980,2051 ****
          assert(errno == 0);
      }
- -     return isCGI;
- - }
- - 
- - /*
- -  *----------------------------------------------------------------------
- -  *
- -  * AcquireLock --
- -  *
- -  *      On platforms that implement concurrent calls to accept
- -  *      on a shared listening socket, returns 0.  On other platforms,
- -  *	acquires an exclusive lock across all processes sharing a
- -  *      listening socket, blocking until the lock has been acquired.
- -  *
- -  * Results:
- -  *      0 for successful call, -1 in case of system error (fatal).
- -  *
- -  * Side effects:
- -  *      This process now has the exclusive lock.
- -  *
- -  *----------------------------------------------------------------------
- -  */
- - static int AcquireLock(void)
- - {
- - #ifdef USE_LOCKING
- -     struct flock lock;
- -     lock.l_type = F_WRLCK;
- -     lock.l_start = 0;
- -     lock.l_whence = SEEK_SET;
- -     lock.l_len = 0;
  
!     if(fcntl(FCGI_LISTENSOCK_FILENO, F_SETLKW, &lock) < 0) {
!         return -1;
!     }
! #endif /* USE_LOCKING */
!     return 0;
! }
! 
! /*
!  *----------------------------------------------------------------------
!  *
!  * ReleaseLock --
!  *
!  *      On platforms that implement concurrent calls to accept
!  *      on a shared listening socket, does nothing.  On other platforms,
!  *	releases an exclusive lock acquired by AcquireLock.
!  *
!  * Results:
!  *      0 for successful call, -1 in case of system error (fatal).
!  *
!  * Side effects:
!  *      This process no longer holds the lock.
!  *
!  *----------------------------------------------------------------------
!  */
! static int ReleaseLock(void)
! {
! #ifdef USE_LOCKING
!     struct flock lock;
!     lock.l_type = F_UNLCK;
!     lock.l_start = 0;
!     lock.l_whence = SEEK_SET;
!     lock.l_len = 0;
  
!     if(fcntl(FCGI_LISTENSOCK_FILENO, F_SETLK, &lock) < 0) {
!         return -1;
!     }
! #endif /* USE_LOCKING */
!     return 0;
  }
  
- --- 2071,2081 ----
          assert(errno == 0);
      }
  
!     /*
!      * Unlock the file descriptor.
!      */
!     (void)ReleaseLock();
  
!     return isCGI;
  }
  
*************** static int ReleaseLock(void)
*** 2058,2062 ****
   *
   * Results:
!  *	TRUE if address list is empty or client address is present
   *      in the list, FALSE otherwise.
   *
- --- 2088,2092 ----
   *
   * Results:
!  *      TRUE if address list is empty or client address is present
   *      in the list, FALSE otherwise.
   *
*************** int FCGX_Accept(
*** 2204,2208 ****
  	    } sa;
              int clilen = sizeof(sa);
!             if(AcquireLock() < 0) {
                  return -1;
  	    }
- --- 2234,2238 ----
  	    } sa;
              int clilen = sizeof(sa);
!             if(AcquireLock(TRUE) == -1) {
                  return -1;
  	    }

- -- 
Chip Salzenberg         - a.k.a. -           <chip@pobox.com>
 (as character touches fingertips while hypnotizing a girl)
      "Here is the church; here is the steeple;
       now open the door and go - to - sleeple."  // MST3K

------- End of Forwarded Message