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 ) ; }
/* * 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 ) ; }
void svc_dump( const struct service *sp, int fd ) { tabprint( fd, 0, "Service = %s\n", SC_NAME( SVC_CONF( sp ) ) ) ; tabprint( fd, 1, "State = %s\n", nv_get_name( service_states, (int) SVC_STATE(sp) ) ) ; sc_dump( SVC_CONF( sp ), fd, 1, FALSE ) ; if ( SVC_IS_ACTIVE(sp) ) { tabprint( fd, 1, "running servers = %d\n", SVC_RUNNING_SERVERS(sp) ) ; tabprint( fd, 1, "retry servers = %d\n", SVC_RETRIES(sp) ) ; tabprint( fd, 1, "attempts = %d\n", SVC_ATTEMPTS(sp) ) ; tabprint( fd, 1, "service fd = %d\n", SVC_FD(sp) ) ; } Sputchar( fd, '\n' ) ; }
/* * 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 ) ; }
/* * This function closes all service descriptors. This should be called * for all child processes that fork, but do not exec. This includes * redirect, builtins, and tcpmux. The close on exec flag takes care of * child processes that call exec. Without calling this, the listening * fd's are not closed and reconfig will fail. */ void close_all_svc_descriptors(void) { psi_h iter ; struct service *osp ; /* Have to close all other descriptors here */ iter = psi_create( SERVICES( ps ) ) ; if ( iter == NULL ) { out_of_memory( "close_all_svc_descriptors" ) ; exit( 1 ); } for ( osp = SP( psi_start( iter ) ) ; osp ; osp = SP( psi_next( iter ) ) ) (void) Sclose( SVC_FD( osp ) ) ; psi_destroy( iter ) ; }
/* * Close the service descriptor. * If this is an RPC service, deregister it. * Close the log. */ void svc_deactivate( struct service *sp ) { if ( ! SVC_IS_AVAILABLE( sp ) ) return ; deactivate( sp ) ; ps.rws.descriptors_free++ ; if ( SVC_IS_ACTIVE( sp ) ) { FD_CLR( SVC_FD( sp ), &ps.rws.socket_mask ) ; ps.rws.active_services-- ; } ps.rws.available_services-- ; DISABLE( sp ) ; }
/* * 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 ) ; }
static void deactivate( const struct service *sp ) { (void) Sclose( SVC_FD( sp ) ) ; #ifdef HAVE_MDNS xinetd_mdns_deregister(SVC_CONF(sp)); #endif if (debug.on) msg(LOG_DEBUG, "deactivate", "%d Service %s deactivated", getpid(), SC_NAME( SVC_CONF(sp) ) ); #ifndef NO_RPC if ( SC_IS_RPC( SVC_CONF( sp ) ) ) { unsigned long vers ; const struct rpc_data *rdp = SC_RPCDATA( SVC_CONF( sp ) ) ; for ( vers = RD_MINVERS( rdp ) ; vers <= RD_MAXVERS( rdp ) ; vers++ ) { (void) pmap_unset( RD_PROGNUM( rdp ), vers ) ; } } #endif /* ! NO_RPC */ }
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" ) ; }
/* * 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 ) ; }
/* * Activate a service. */ status_e svc_activate( struct service *sp ) { struct service_config *scp = SVC_CONF( sp ) ; status_e status ; const char *func = "svc_activate" ; /* No activation for MUXCLIENTS. */ if (SC_IS_MUXCLIENT( scp )) { return( OK ); } if( SC_IPV4( scp ) ) { SVC_FD(sp) = socket( AF_INET, SC_SOCKET_TYPE( scp ), SC_PROTOVAL( scp ) ) ; } else if( SC_IPV6( scp ) ) { SVC_FD(sp) = socket( AF_INET6, SC_SOCKET_TYPE( scp ), SC_PROTOVAL( scp ) ) ; } if ( SVC_FD(sp) == -1 ) { msg( LOG_ERR, func, "socket creation failed (%m). service = %s", SC_ID( scp ) ) ; return( FAILED ) ; } if ( set_fd_modes( sp ) == FAILED ) { (void) Sclose( SVC_FD(sp) ) ; return( FAILED ) ; } #ifndef NO_RPC if ( SC_IS_RPC( scp ) ) status = activate_rpc( sp ) ; else #endif /* ! NO_RPC */ status = activate_normal( sp ) ; if ( status == FAILED ) { (void) Sclose( SVC_FD(sp) ) ; return( FAILED ) ; } #ifdef HAVE_MDNS xinetd_mdns_register(scp); #endif if ( log_start( sp, &SVC_LOG(sp) ) == FAILED ) { deactivate( sp ) ; return( FAILED ) ; } /* * Initialize the service data */ SVC_RUNNING_SERVERS(sp) = SVC_RETRIES(sp) = 0 ; if ( SC_MUST_LISTEN( scp ) ) (void) listen( SVC_FD(sp), LISTEN_BACKLOG ) ; ps.rws.descriptors_free-- ; SVC_STATE(sp) = SVC_ACTIVE ; FD_SET( SVC_FD(sp), &ps.rws.socket_mask ) ; if ( SVC_FD(sp) > ps.rws.mask_max ) ps.rws.mask_max = SVC_FD(sp) ; ps.rws.active_services++ ; ps.rws.available_services++ ; return( OK ) ; }
static status_e activate_normal( struct service *sp ) { union xsockaddr tsin; int sd = SVC_FD( sp ) ; struct service_config *scp = SVC_CONF( sp ) ; uint16_t service_port = SC_PORT( scp ) ; char *sid = SC_ID( scp ) ; const char *func = "activate_normal" ; unsigned int sin_len = sizeof(tsin); int on = 1; #ifdef IPV6_V6ONLY int v6on = 0; #endif if( SC_BIND_ADDR(scp) != NULL ) memcpy(&tsin, SC_BIND_ADDR(scp), sin_len); else memset(&tsin, 0, sin_len); if( SC_IPV4( scp ) ) { tsin.sa_in.sin_family = AF_INET ; tsin.sa_in.sin_port = htons( service_port ) ; sin_len = sizeof(struct sockaddr_in); } else if( SC_IPV6( scp ) ) { tsin.sa_in6.sin6_family = AF_INET6; tsin.sa_in6.sin6_port = htons( service_port ); sin_len = sizeof(struct sockaddr_in6); } #ifdef IPV6_V6ONLY if( SC_IPV6(scp) ) { if( SC_SPECIFIED(scp, A_V6ONLY) ) { v6on = 1; } else { v6on = 0; } if( setsockopt(sd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&v6on, sizeof(v6on)) < 0 ) { msg( LOG_ERR, func, "Setting IPV6_V6ONLY option failed (%m)" ); } } #endif if ( setsockopt( sd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof( on ) ) == -1 ) msg( LOG_WARNING, func, "setsockopt SO_REUSEADDR failed (%m). service = %s", sid ) ; if( SC_NODELAY( scp ) && (SC_PROTOVAL(scp) == IPPROTO_TCP) ) { if ( setsockopt( sd, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof( on ) ) == -1 ) msg( LOG_WARNING, func, "setsockopt TCP_NODELAY failed (%m). service = %s", sid ) ; } if( SC_KEEPALIVE( scp ) && (SC_PROTOVAL(scp) == IPPROTO_TCP) ) { if( setsockopt(sd, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof( on ) ) < 0 ) msg( LOG_WARNING, func, "setsockopt SO_KEEPALIVE failed (%m). service = %s", sid ) ; } if ( bind( sd, &tsin.sa, sin_len ) == -1 ) { msg( LOG_ERR, func, "bind failed (%m). service = %s", sid ) ; return( FAILED ) ; } #ifdef IN_MULTICAST if( SC_IPV4(scp) && IN_MULTICAST( ntohl(tsin.sa_in.sin_addr.s_addr) ) ) { struct ifaddrs *addrs, *addr; struct ip_mreq mreq; if (getifaddrs(&addrs) == 0) { addr = addrs; while (addr) { if (addr->ifa_addr && (addr->ifa_flags & IFF_MULTICAST)) { mreq.imr_multiaddr.s_addr = tsin.sa_in.sin_addr.s_addr; mreq.imr_interface.s_addr = ((struct sockaddr_in *)addr->ifa_addr)->sin_addr.s_addr; setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); } addr = addr->ifa_next; } freeifaddrs(addrs); if ( debug.on ) msg( LOG_DEBUG, func, "Adding multicast membership." ); } else { msg( LOG_ERR, func, "getifaddrs failed (%m). service = %s", sid ); } } #endif return( OK ) ; }
static status_e activate_rpc( struct service *sp ) { union xsockaddr tsin; socklen_t sin_len = sizeof(tsin); unsigned long vers ; struct service_config *scp = SVC_CONF( sp ) ; struct rpc_data *rdp = SC_RPCDATA( scp ) ; char *sid = SC_ID( scp ) ; unsigned registered_versions = 0 ; int sd = SVC_FD( sp ) ; const char *func = "activate_rpc" ; if( SC_BIND_ADDR(scp) != 0 ) memcpy( &tsin, SC_BIND_ADDR(scp), sizeof(tsin) ); else memset( &tsin, 0, sizeof(tsin)); if ( SC_PROTOVAL ( scp ) == IPPROTO_TCP ) { M_SET ( scp->sc_xflags, SF_NOLIBWRAP ); } if( SC_IPV4( scp ) ) { tsin.sa_in.sin_family = AF_INET ; sin_len = sizeof(struct sockaddr_in); } else if( SC_IPV6( scp ) ) { tsin.sa_in6.sin6_family = AF_INET6 ; sin_len = sizeof(struct sockaddr_in6); } if ( bind( sd, &tsin.sa, sin_len ) == -1 ) { msg( LOG_ERR, func, "bind failed (%m). service = %s", sid ) ; return( FAILED ) ; } /* * Find the port number that was assigned to the socket */ if ( getsockname( sd, &tsin.sa, &sin_len ) == -1 ) { msg( LOG_ERR, func, "getsockname failed (%m). service = %s", sid ) ; return( FAILED ) ; } if( tsin.sa.sa_family == AF_INET ) SC_SET_PORT( scp, ntohs( tsin.sa_in.sin_port ) ) ; else if( tsin.sa.sa_family == AF_INET6 ) SC_SET_PORT( scp, ntohs( tsin.sa_in6.sin6_port ) ) ; /* * Try to register as many versions as possible */ for ( vers = RD_MINVERS( rdp ) ; vers <= RD_MAXVERS( rdp ) ; vers++ ) { /* Is this right? For instance, if we have both tcp and udp services, * this will unregister the previously registered protocol. * pmap_unset(RD_PROGNUM(rdp), vers); */ if ( pmap_set( RD_PROGNUM( rdp ), vers, SC_PROTOVAL( scp ), SC_PORT( scp ) ) ) registered_versions++ ; else msg( LOG_ERR, func, "pmap_set failed. service=%s program=%ld version=%ld", sid, RD_PROGNUM( rdp ), vers ) ; sleep(1); } if ( debug.on ) msg( LOG_DEBUG, func, "Registered %d versions of %s", registered_versions, sid ) ; return( ( registered_versions == 0 ) ? FAILED : OK ) ; }