Esempio n. 1
0
static status_e set_fd_modes( struct service *sp )
{
   int sd = SVC_FD( sp ) ;
   const char *func = "set_fd_modes" ;

   /*
    * There is a possibility of blocking on a send/write if
    *
    * the service does not require forking (==> is internal) AND
    * it does not accept connections
    *
    * To avoid this, we put the descriptor in FNDELAY mode.
    * (if the service accepts connections, we still need to put the
    * 'accepted' connection in FNDELAY mode but this is done elsewhere)
    */
   if ( ! SVC_FORKS( sp ) && ! SVC_ACCEPTS_CONNECTIONS( sp ) &&
                              fcntl( sd, F_SETFL, FNDELAY ) == -1 )
   {
      msg( LOG_ERR, func,
         "fcntl failed (%m) for FNDELAY. service = %s", SVC_ID( sp ) ) ;
      return( FAILED ) ;
   }

   /*
    * Always set the close-on-exec flag
    */
   if ( fcntl( sd, F_SETFD, FD_CLOEXEC ) == -1 )
   {
      msg( LOG_ERR, func,
         "fcntl failed (%m) for close-on-exec. service = %s", SVC_ID( sp ) ) ;
      return( FAILED ) ;
   }
   return( OK ) ;
}
Esempio n. 2
0
/*
 * Check that the counts of running and retry servers stored in struct service
 * are accurate
 */
static unsigned service_count_check( struct service *sp, 
                                      unsigned running_servers, 
                                      unsigned retry_servers )
{
   char *sid = SVC_ID( sp ) ;
   int error_count = 0 ;
   const char *func = "service_count_check" ;

   if ( SVC_RUNNING_SERVERS( sp ) != running_servers )
   {
      msg( LOG_ERR, func,
         "service %s: actual running servers = %d, known running servers = %d",
            sid, running_servers, SVC_RUNNING_SERVERS( sp ) ) ;
      error_count++ ;
   }
   if ( SVC_RETRIES( sp ) != retry_servers )
   {
      msg( LOG_ERR, func,
         "service %s: actual retry servers = %d, known retry servers = %d",
            sid, retry_servers, SVC_RETRIES( sp ) ) ;
      error_count++ ;
   }

   if ( error_count && debug.on )
      msg( LOG_DEBUG, func, "%s: %d errors detected", sid, error_count ) ;

   return( error_count ) ;
}
Esempio n. 3
0
/*
 * Steps:
 *      1. Deactivate the service
 *      2. Free all memory used by the service and free the service itself
 *
 * Since this function may free all memory associated with the service as
 * well as the memory pointed by sp, only the value of sp should be used
 * after this call if the return value is 0 (i.e. no dereferencing of sp).
 *
 * Special services are never deactivated.
 */
int svc_release( struct service *sp )
{
   char *sid = SVC_ID( sp ) ;
   const char *func = "svc_release" ;

   if ( SVC_REFCOUNT(sp) == 0 )
   {
      msg( LOG_ERR, func, "%s: svc_release with 0 count", sid ) ;
      return( 0 ) ;
   }
   
   SVC_REFCOUNT(sp)-- ;
   if ( SVC_REFCOUNT(sp) == 0 )
   {
      if ( debug.on )
         msg( LOG_DEBUG, func, "ref count of service %s dropped to 0", sid ) ;
      if ( ! SC_IS_SPECIAL( SVC_CONF( sp ) ) )
      {
         if ( SVC_LOG(sp) )
            log_end( SC_LOG( SVC_CONF( sp ) ), SVC_LOG(sp) ) ;
         svc_deactivate( sp ) ;
         svc_free( sp ) ;
         sp = NULL;
      }
      else      /* this shouldn't happen */
         msg( LOG_WARNING, func,
            "ref count of special service %s dropped to 0", sid ) ;
      return( 0 ) ;
   }
   else
      return( SVC_REFCOUNT(sp) ) ;
}
Esempio n. 4
0
/*
 * Suspend a service
 */
void svc_suspend( struct service *sp )
{
   const char *func = "svc_suspend" ;

   if ( ! SVC_IS_ACTIVE( sp ) )
   {
      msg( LOG_ERR, func, "service %s is not active", SVC_ID( sp ) ) ;
      return ;
   }

   FD_CLR( SVC_FD( sp ), &ps.rws.socket_mask ) ;
   ps.rws.active_services-- ;
   if ( debug.on )
      msg( LOG_DEBUG, func, "Suspended service %s", SVC_ID( sp ) ) ;
   
   SUSPEND( sp ) ;
}
Esempio n. 5
0
/*
 * Resume a suspended service.
 */
void svc_resume( struct service *sp )
{
   const char *func = "svc_resume" ;

   FD_SET( SVC_FD( sp ), &ps.rws.socket_mask ) ;
   ps.rws.active_services++ ;
   if ( debug.on )
      msg( LOG_DEBUG, func, "Resumed service %s", SVC_ID( sp ) ) ;
   RESUME( sp ) ;
}
Esempio n. 6
0
static int banner_fail( const struct service *sp, const connection_s *cp )
{
   const char *func = "banner_fail";
   const struct service_config *scp = SVC_CONF( sp ) ;


   if ( SC_BANNER_FAIL(scp) != NULL )
   {
      char tmpbuf[TMPSIZE];
      int retval;
      int bannerfd = open(SC_BANNER_FAIL(scp), O_RDONLY);

      if( bannerfd < 0 )
      {
         msg( LOG_ERR, func, "service = %s, open of banner %s failed", 
            SVC_ID( sp ), SC_BANNER_FAIL(scp));
         return(-1);
      }

      while( (retval = read(bannerfd, tmpbuf, sizeof(tmpbuf))) ) {
         if (retval == -1)
         {
            if (errno == EINTR)
               continue;
            else
            {
               msg(LOG_ERR, func, "service %s, Error %m reading banner %s", 
			       SVC_ID( sp ), SC_BANNER(scp));
               break;
            }
         }
         Swrite(cp->co_descriptor, tmpbuf, retval);
      }

      Sclose(bannerfd);
      Sflush ( cp->co_descriptor );
   }

   return(0);
}
Esempio n. 7
0
void conn_dump( const connection_s *cp, int fd )
{
   const char *name = conn_addrstr( cp );

   tabprint( fd, 1, "service = %s\n", SVC_ID( cp->co_sp ) ) ;
   tabprint( fd, 1, "descriptor = %d\n", cp->co_descriptor ) ;
#if defined(__GNUC__) && !defined(__arch64__) && !defined(__alpha__)
   tabprint( fd, 1, "flags = %#llx\n", cp->co_flags ) ;
#else
   tabprint( fd, 1, "flags = %#lx\n", cp->co_flags ) ;
#endif
   tabprint( fd, 1, "remote_address = %s,%d\n", name,
                              ntohs( cp->co_remote_address.sa_in.sin_port ) ) ;
}
Esempio n. 8
0
/*
 * Check for reference counting errors.
 * Returns number of errors found.
 * Always set the number of running and retry servers.
 */
static unsigned refcount_check( struct service *sp, 
                                 unsigned *running_servers, 
                                 unsigned *retry_servers )
{
   char *sid = SVC_ID( sp ) ;
   unsigned errors = 0 ;
   int refs ;
   int refcount = SVC_REFCOUNT( sp ) ;
   const char *func = "refcount_check" ;

   if ( refcount <= 0 )
   {
      msg( LOG_ERR, func, "%s service has bad refcount: %d",
               sid, refcount ) ;
      errors++ ;
   }

   /*
    * The service table holds a reference to the service. The remaining
    * references must be from servers and connections.
    */
   refcount-- ;

   refs = count_refs( sp, SERVERS( ps ), running_servers ) ;
   if ( ! errors && refs > refcount )
   {
      msg( LOG_ERR, func,
         "running servers: too many references for %s (%d with max=%d)",
            sid, refs, refcount ) ;
      errors++ ;
   }

   refs = count_refs( sp, RETRIES( ps ), retry_servers ) ;
   if ( ! errors && refs > refcount )
   {
      msg( LOG_ERR, func,
         "retry servers: too many references for %s (%d with max=%d)",
            sid, refs, refcount ) ;
      errors++ ;
   }

   if ( errors && debug.on )
      msg( LOG_DEBUG, func, "%s: %d errors detected", sid, errors ) ;

   return( errors ) ;
}
Esempio n. 9
0
/*
 * Invoked when a server of the specified service dies
 */
void svc_postmortem( struct service *sp, struct server *serp )
{
   struct service  *co_sp   = SERVER_CONNSERVICE( serp ) ;
   connection_s    *cp      = SERVER_CONNECTION( serp ) ;
   const char      *func    = "svc_postmortem" ;

   SVC_DEC_RUNNING_SERVERS( sp ) ;

   /*
    * Log information about the server that died
    */
   if ( SVC_IS_LOGGING( sp ) )
   {
      if ( SERVER_WRITES_TO_LOG(serp) )
      {
         if ( debug.on )
            msg( LOG_DEBUG, func,
                        "Checking log size of %s service", SVC_ID( sp ) ) ;
         xlog_control( SVC_LOG( sp ), XLOG_SIZECHECK ) ;
      }
      svc_log_exit( sp, serp ) ;
   }

   /*
    * Now check if we have to check the log size of the service that owns
    * the connection
    */
   if ( co_sp != sp && SVC_IS_LOGGING( co_sp ) )
      xlog_control( SVC_LOG( co_sp ), XLOG_SIZECHECK ) ;

   if (!SVC_WAITS(sp)) {
      conn_free( cp, 1 ) ;
      cp = NULL;
   } else {
      if (cp) {
         if ( SVC_SOCKET_TYPE( sp ) == SOCK_DGRAM )
            drain( cp->co_descriptor ) ;
         free(cp);
         cp = NULL;
         if( SVC_RELE( sp ) == 0 )
            svc_release( sp ); /* shouldn't be 0, but should remove from
                                * pset if it is... */
      }
      svc_resume(sp);
   }
}
Esempio n. 10
0
/*
 * If the service is single-threaded:
 *         if the descriptor is set in the socket mask, there must
 *         be a server running (or to be retried)
 *   If the service is multi-threaded:
 *         the descriptor must be always set
 */
static unsigned thread_check( struct service *sp, 
                               unsigned running_servers, 
                               unsigned retry_servers )
{
   unsigned error_count = 0 ;
   int sd = SVC_FD( sp ) ;
   char *sid = SVC_ID( sp ) ;
   const char *func = "thread_check" ;

   if ( SVC_WAITS( sp ) )
   {
      bool_int has_servers = ( running_servers + retry_servers != 0 ) ;

      if ( has_servers && FD_ISSET( sd, &ps.rws.socket_mask ) )
      {
         msg( LOG_ERR, func,
"Active single-threaded service %s: server running, descriptor set", sid ) ;
         error_count++ ;
      }
      if ( !has_servers && !FD_ISSET( sd, &ps.rws.socket_mask ) )
      {
         msg( LOG_ERR, func,
"Active single-threaded service %s: no server running, descriptor not set",
            sid ) ;
         error_count++ ;
      }
   }
   else
      if ( ! FD_ISSET( sd, &ps.rws.socket_mask ) )
      {
         msg( LOG_ERR, func,
            "Active multi-threaded service %s: descriptor not set", sid ) ;
         error_count++ ;
      }

   if ( error_count && debug.on )
      msg( LOG_DEBUG, func, "%s: %d errors detected", sid, error_count ) ;

   return( error_count ) ;
}
Esempio n. 11
0
static void consistency_check( enum check_type type )
{
   int         fd ;
   fd_set      socket_mask_copy ;
   unsigned    u ;
   int         errors ;
   unsigned    total_running_servers        = 0 ;
   unsigned    total_retry_servers          = 0 ;
   unsigned    error_count                  = 0 ;
   bool_int    service_count_check_failed   = FALSE ;
   const char  *func                        = "consistency_check" ;

   socket_mask_copy = ps.rws.socket_mask ;

   for ( u = 0 ; u < pset_count( SERVICES( ps ) ) ; u++ )
   {
      register struct service *sp = SP( pset_pointer( SERVICES( ps ), u ) ) ;
      char *sid = SVC_ID( sp ) ;
      unsigned   running_servers ;
      unsigned   retry_servers ;

      error_count += refcount_check( sp, &running_servers, &retry_servers ) ;

      if ( SVC_IS_AVAILABLE( sp ) || SVC_IS_DISABLED ( sp ) )
      {
         /*
          * In this case, there may be some servers running
          */
         if ( FD_ISSET( SVC_FD( sp ), &socket_mask_copy ) )
         {
            if ( SVC_IS_DISABLED( sp ) )
            {
               msg( LOG_ERR, func,
                  "fd of disabled service %s still in socket mask", sid ) ;
               error_count++ ;
            }
            FD_CLR( SVC_FD( sp ), &socket_mask_copy ) ;
         }
         error_count += thread_check( sp, running_servers, retry_servers ) ;

         errors = service_count_check( sp, running_servers, retry_servers ) ;
         if ( ! errors && ! service_count_check_failed )
         {
            total_retry_servers += retry_servers ;
            total_running_servers += running_servers ;
         }
         if ( errors )
         {
            service_count_check_failed = TRUE ;
            error_count += errors ;
         }

         if ( SVC_IS_DISABLED( sp ) && SVC_RUNNING_SERVERS( sp ) == 0 )
         {
            msg( LOG_ERR, func,
               "disabled service %s has 0 running servers\n", sid ) ;
            error_count++ ;
            continue ;
         }
      }
      else
      {
         msg( LOG_ERR, func, "service %s not started", SVC_ID( sp ) ) ;
         error_count++ ;
      }
   }

   if ( ! service_count_check_failed )
   {
      if ( total_running_servers != pset_count( SERVERS( ps ) ) )
      {
         msg( LOG_ERR, func,
            "total running servers (%d) != number of running servers (%d)",
               total_running_servers, pset_count( SERVERS( ps ) ) ) ;
         error_count++ ;
      }
      if ( total_retry_servers != pset_count( RETRIES( ps ) ) )
      {
         msg( LOG_ERR, func,
            "total retry servers (%d) != number of retry servers (%d)",
               total_retry_servers, pset_count( RETRIES( ps ) ) ) ;
         error_count++ ;
      }
   }

   /*
    * Check if there are any descriptors set in socket_mask_copy
    */
   for ( fd = 0 ; fd < ps.ros.max_descriptors ; fd++ )
      if ( FD_ISSET( fd, &socket_mask_copy ) && ((fd != signals_pending[0]) && fd != signals_pending[1]))
      {
         msg( LOG_ERR, func,
            "descriptor %d set in socket mask but there is no service for it",
               fd ) ;
         error_count++ ;
      }

   if ( error_count != 0 )
      msg( LOG_WARNING, func,
            "Consistency check detected %d errors", error_count ) ;
   else
      if ( type == USER_REQUESTED || debug.on )
         msg( LOG_INFO, func, "Consistency check passed" ) ;

   if( type == PERIODIC ) 
      if ( xtimer_add( periodic_check, ps.ros.cc_interval ) == -1 )
         msg( LOG_ERR, func, "Failed to start consistency timer" ) ;
}
Esempio n. 12
0
/*
 * Get a new connection request and initialize 'cp' appropriately
 */
static status_e get_connection( struct service *sp, connection_s *cp )
{
   struct service_config *scp = SVC_CONF( sp );
   socklen_t sin_len;
   const char *func = "get_connection" ;
   int on = 1;

   if( SC_IPV4(scp) ) sin_len = sizeof(struct sockaddr_in);
   if( SC_IPV6(scp) ) sin_len = sizeof(struct sockaddr_in6);

   if ( SVC_SOCKET_TYPE( sp ) == SOCK_STREAM ) {
      /* If it's a TCP socket, and we're set to wait, the accept is
       * done by the child process.  Don't set NEW_DESCRIPTOR, since
       * there isn't one.  The descriptor will be/was removed from
       * the descriptor set in svc_suspend and re-enabled in svc_resume.
       */
      if( SC_WAITS( scp ) ) {
         cp->co_descriptor = SVC_FD( sp );
      } else {
         cp->co_descriptor = accept( SVC_FD( sp ), &(cp->co_remote_address.sa),
                                     &sin_len ) ;
	 if (cp->co_descriptor != -1)
             M_SET( cp->co_flags, COF_NEW_DESCRIPTOR ) ;
      }

      if ( cp->co_descriptor == -1 )
      {
	 if ((errno == EMFILE) || (errno == ENFILE))
	     cps_service_stop(sp, "no available descriptors");
	 else
             msg( LOG_ERR, func, "service %s, accept: %m", SVC_ID( sp ) ) ;
         return( FAILED ) ;
      }

      if( SC_NODELAY( scp ) && (SC_PROTOVAL( scp ) == IPPROTO_TCP) )
         if( setsockopt(SVC_FD(sp), IPPROTO_TCP, TCP_NODELAY, 
                        (char *)&on, sizeof( on ) ) < 0 )
            msg( LOG_WARNING, func, "service %s, setsockopt: %m", SVC_ID(sp));

      if( SC_KEEPALIVE( scp ) && (SC_PROTOVAL( scp ) == IPPROTO_TCP) )
      {
         if( setsockopt(SVC_FD(sp), SOL_SOCKET, SO_KEEPALIVE, 
                        (char *)&on, sizeof( on ) ) < 0 )
            msg( LOG_WARNING, func, "service %s, setsockopt: %m", SVC_ID(sp));
      }
      
      if( SC_IPV6(scp) && !(SC_V6ONLY( scp ))  && 
         (IN6_IS_ADDR_V4MAPPED(&cp->co_remote_address.sa_in6.sin6_addr) || 
	  IN6_IS_ADDR_V4COMPAT(&cp->co_remote_address.sa_in6.sin6_addr)) ) 
      {
         int af = AF_INET;
         if( setsockopt(cp->co_descriptor, IPPROTO_IPV6,
               IPV6_ADDRFORM, &af, sizeof( af ) ) ) {
            if( debug.on ) msg( LOG_WARNING, func, "service %s, IPV6_ADDRFORM setsockopt() failed: %m", SVC_ID( sp) );
         }
      }

      M_SET( cp->co_flags, COF_HAVE_ADDRESS ) ;
   }
   else
   {
      if ( SVC_SOCKET_TYPE( sp ) == SOCK_DGRAM )
      {
         char t_ch ;
	 ssize_t val;

         /*
          * This trick is done to get the remote address.
          * select(2) guaranteed that we won't block on the recvfrom
          */
	 val = recvfrom( SVC_FD( sp ), &t_ch, 1, MSG_PEEK,
                              &cp->co_remote_address.sa, &sin_len );
         if ( val == (ssize_t)-1 )
         {
            msg( LOG_ERR, func, "service %s, recvfrom: %m", SVC_ID( sp ) ) ;
            return( FAILED ) ;
         }
         M_SET( cp->co_flags, COF_HAVE_ADDRESS ) ;
      }

      cp->co_descriptor = SVC_FD( sp ) ;
   }

   return( OK ) ;
}