main.c (xinetd-2.3.15) | : | main.c (xinetd-2.3.15.4.tar.xz) | ||
---|---|---|---|---|
skipping to change at line 26 | skipping to change at line 26 | |||
#include "main.h" | #include "main.h" | |||
#include "init.h" | #include "init.h" | |||
#include "msg.h" | #include "msg.h" | |||
#include "internals.h" | #include "internals.h" | |||
#include "signals.h" | #include "signals.h" | |||
#include "service.h" | #include "service.h" | |||
#include "sconf.h" | #include "sconf.h" | |||
#include "xtimer.h" | #include "xtimer.h" | |||
#include "sensor.h" | #include "sensor.h" | |||
#include "xmdns.h" | #ifdef HAVE_POLL | |||
#include "xpoll.h" | ||||
#endif | ||||
#ifdef __GNUC__ | #ifdef __GNUC__ | |||
__attribute__ ((noreturn)) | __attribute__ ((noreturn)) | |||
#endif | #endif | |||
static void main_loop(void); | static void main_loop(void); | |||
static void find_bad_fd(void) ; | static void find_bad_fd(void) ; | |||
/* | /* | |||
* The following are the only global variables of this program | * The following are the only global variables of this program | |||
*/ | */ | |||
struct program_state ps ; | struct program_state ps ; | |||
struct debug debug ; | struct debug debug ; | |||
char program_version[] = XINETD_VERSION ; | char program_version[] = VERSION ; | |||
int signals_pending[2] = {-1, -1} ; | int signals_pending[2] = {-1, -1} ; | |||
/* | /* | |||
* This is where the story starts... | * This is where the story starts... | |||
*/ | */ | |||
int main( int argc, char *argv[] ) | int main( int argc, char *argv[] ) | |||
{ | { | |||
const char *func = "main" ; | const char *func = "main" ; | |||
init_daemon( argc, argv ) ; | init_daemon( argc, argv ) ; | |||
#ifdef HAVE_MDNS | ||||
xinetd_mdns_init(); | ||||
#endif | ||||
init_services() ; | init_services() ; | |||
/* Do the chdir after reading the config file. Relative path names | /* Do the chdir after reading the config file. Relative path names | |||
* will work better. | * will work better. | |||
*/ | */ | |||
if (chdir("/") < 0) { | if (chdir("/") < 0) { | |||
msg(LOG_ERR, func, "Can't chdir to /: %m"); | msg(LOG_ERR, func, "Can't chdir to /: %m"); | |||
} | } | |||
/* Print out all the options we're compiled with. Makes support | /* Print out all the options we're compiled with. Makes support | |||
* a tad easier. | * a tad easier. | |||
* Also, try to get them all into one syslog message for atomicity | * Also, try to get them all into one syslog message for atomicity | |||
*/ | */ | |||
msg( LOG_NOTICE, func, "%s started with " | msg( LOG_NOTICE, func, "%s started with " | |||
#ifdef LIBWRAP | #ifdef LIBWRAP | |||
"libwrap " | "libwrap " | |||
#endif | #endif | |||
#ifdef HAVE_LOADAVG | #ifdef HAVE_LOADAVG | |||
"loadavg " | "loadavg " | |||
#endif | #endif | |||
#ifdef HAVE_MDNS | ||||
"mdns " | ||||
#endif | ||||
#ifdef HAVE_HOWL | ||||
"howl " | ||||
#endif | ||||
#ifdef HAVE_DNSREGISTRATION | ||||
"rendezvous " | ||||
#endif | ||||
#ifdef LABELED_NET | #ifdef LABELED_NET | |||
"labeled-networking " | "labeled-networking " | |||
#endif | #endif | |||
#if !defined(LIBWRAP) && !defined(HAVE_LOADAVG) && !defined(HAVE_MDNS) && !defin ed(HAVE_HOWL) && !defined(HAVE_DNSREGISTRATION) && !defined(LABELED_NET) | #if !defined(LIBWRAP) && !defined(HAVE_LOADAVG) && !defined(LABELED_NET) | |||
"no " | "no " | |||
#endif | #endif | |||
"options compiled in." | "options compiled in." | |||
, XINETD_VERSION ); | , VERSION ); | |||
msg( LOG_NOTICE, func, "Started working: %d available service%s", | msg( LOG_NOTICE, func, "Started working: %d available service%s", | |||
ps.rws.available_services, | ps.rws.available_services, | |||
( ps.rws.available_services != 1 ) ? "s" : "" ) ; | ( ps.rws.available_services != 1 ) ? "s" : "" ) ; | |||
/* | /* | |||
* The reason for doing the setjmp here instead of in main_loop is | * The reason for doing the setjmp here instead of in main_loop is | |||
* that setjmp is not guaranteed to restore register values which | * that setjmp is not guaranteed to restore register values which | |||
* can cause a problem for register variables | * can cause a problem for register variables | |||
*/ | */ | |||
skipping to change at line 120 | skipping to change at line 110 | |||
* What main_loop does: | * What main_loop does: | |||
* | * | |||
* select on all active services | * select on all active services | |||
* for each socket where a request is pending | * for each socket where a request is pending | |||
* try to start a server | * try to start a server | |||
*/ | */ | |||
static void main_loop(void) | static void main_loop(void) | |||
{ | { | |||
const char *func = "main_loop" ; | const char *func = "main_loop" ; | |||
struct timeval tv, *tvptr = NULL; | struct timeval tv, *tvptr = NULL; | |||
#ifdef HAVE_POLL | ||||
struct pollfd *signal_pfd; | ||||
FD_SET(signals_pending[0], &ps.rws.socket_mask); | ps.rws.pfd_array[ps.rws.pfds_last].fd = signals_pending[0] ; | |||
ps.rws.pfd_array[ps.rws.pfds_last].events = POLLIN ; | ||||
signal_pfd = &ps.rws.pfd_array[ps.rws.pfds_last] ; | ||||
ps.rws.pfds_last++; | ||||
#else | ||||
FD_SET(signals_pending[0], &ps.rws.socket_mask) ; | ||||
if ( signals_pending[0] > ps.rws.mask_max ) | if ( signals_pending[0] > ps.rws.mask_max ) | |||
ps.rws.mask_max = signals_pending[0] ; | ps.rws.mask_max = signals_pending[0] ; | |||
if ( signals_pending[1] > ps.rws.mask_max ) | #endif /* HAVE_POLL */ | |||
ps.rws.mask_max = signals_pending[1] ; | ||||
for ( ;; ) | for ( ;; ) | |||
{ | { | |||
#ifndef HAVE_POLL | ||||
fd_set read_mask ; | fd_set read_mask ; | |||
#endif | ||||
int n_active ; | int n_active ; | |||
unsigned u ; | unsigned u ; | |||
if ( debug.on ) | if ( debug.on ) | |||
msg( LOG_DEBUG, func, | msg( LOG_DEBUG, func, | |||
"active_services = %d", ps.rws.active_services ) ; | "active_services = %d", ps.rws.active_services ) ; | |||
/* get the next timer value, if there is one, and select for that time */ | /* get the next timer value, if there is one, and select for that time */ | |||
if( (tv.tv_sec = xtimer_nexttime()) >= 0 ) { | if( (tv.tv_sec = xtimer_nexttime()) >= 0 ) { | |||
tv.tv_usec = 0; | tv.tv_usec = 0; | |||
tvptr = &tv; | tvptr = &tv; | |||
} else { | } else { | |||
tvptr = NULL; | tvptr = NULL; | |||
} | } | |||
#ifdef HAVE_POLL | ||||
n_active = poll( ps.rws.pfd_array, ps.rws.pfds_last, | ||||
tvptr == NULL ? -1 : tvptr->tv_sec*1000 ) ; | ||||
#else | ||||
read_mask = ps.rws.socket_mask ; | read_mask = ps.rws.socket_mask ; | |||
n_active = select( ps.rws.mask_max+1, &read_mask, | n_active = select( ps.rws.mask_max+1, &read_mask, | |||
FD_SET_NULL, FD_SET_NULL, tvptr ) ; | FD_SET_NULL, FD_SET_NULL, tvptr ) ; | |||
#endif | ||||
if ( n_active == -1 ) | if ( n_active == -1 ) | |||
{ | { | |||
if ( errno == EINTR ) { | if ( errno == EINTR ) { | |||
continue ; | continue ; | |||
} else if ( errno == EBADF ) | } else if ( errno == EBADF ) | |||
find_bad_fd() ; | find_bad_fd() ; | |||
continue ; | continue ; | |||
} | } | |||
else if ( n_active == 0 ) { | else if ( n_active == 0 ) { | |||
xtimer_poll(); | xtimer_poll(); | |||
continue ; | continue ; | |||
} | } | |||
if ( debug.on ) | if ( debug.on ) | |||
msg( LOG_DEBUG, func, "select returned %d", n_active ) ; | msg( LOG_DEBUG, func, "select returned %d", n_active ) ; | |||
xtimer_poll(); | xtimer_poll(); | |||
if( FD_ISSET(signals_pending[0], &read_mask) ) { | #ifdef HAVE_POLL | |||
if ( POLLFD_REVENTS( signal_pfd ) ) | ||||
{ | ||||
if ( POLLFD_REVENTS( signal_pfd ) & (POLLERR | POLLHUP | | ||||
POLLNVAL) ) | ||||
find_bad_fd(); | ||||
else | ||||
{ | ||||
check_pipe(); | ||||
if ( --n_active == 0 ) | ||||
continue ; | ||||
} | ||||
} | ||||
#else | ||||
if( FD_ISSET(signals_pending[0], &read_mask) ) | ||||
{ | ||||
check_pipe(); | check_pipe(); | |||
if ( --n_active == 0 ) | if ( --n_active == 0 ) | |||
continue ; | continue ; | |||
} | } | |||
#ifdef HAVE_MDNS | ||||
if( xinetd_mdns_poll() == 0 ) | ||||
if ( --n_active == 0 ) | ||||
continue ; | ||||
#endif | #endif | |||
for ( u = 0 ; u < pset_count( SERVICES( ps ) ) ; u++ ) | for ( u = 0 ; u < pset_count( SERVICES( ps ) ) ; u++ ) | |||
{ | { | |||
struct service *sp ; | struct service *sp ; | |||
sp = SP( pset_pointer( SERVICES( ps ), u ) ) ; | sp = SP( pset_pointer( SERVICES( ps ), u ) ) ; | |||
if ( ! SVC_IS_ACTIVE( sp ) ) | if ( ! SVC_IS_ACTIVE( sp ) ) | |||
continue ; | continue ; | |||
#ifdef HAVE_POLL | ||||
if ( SVC_REVENTS( sp ) ) | ||||
{ | ||||
if ( SVC_REVENTS( sp ) & (POLLERR | POLLHUP | | ||||
POLLNVAL) ) | ||||
find_bad_fd(); | ||||
else | ||||
{ | ||||
svc_request( sp ) ; | ||||
if ( --n_active == 0 ) | ||||
break ; | ||||
} | ||||
} | ||||
#else | ||||
if ( FD_ISSET( SVC_FD( sp ), &read_mask ) ) | if ( FD_ISSET( SVC_FD( sp ), &read_mask ) ) | |||
{ | { | |||
svc_request( sp ) ; | svc_request( sp ) ; | |||
if ( --n_active == 0 ) | if ( --n_active == 0 ) | |||
break ; | break ; | |||
} | } | |||
#endif | ||||
} | } | |||
if ( n_active > 0 ) | if ( n_active > 0 ) | |||
msg( LOG_ERR, func, "%d descriptors still set", n_active ) ; | msg( LOG_ERR, func, "%d descriptors still set", n_active ) ; | |||
} | } | |||
} | } | |||
/* | /* | |||
* This function identifies if any of the fd's in the socket mask | * This function identifies if any of the fd's in the socket mask | |||
* is bad. We use it in case select(2) returns EBADF | * is bad. We use it in case select(2) returns EBADF | |||
* When we identify such a bad fd, we remove it from the mask | * When we identify such a bad fd, we remove it from the mask | |||
* and deactivate the service. | * and deactivate the service. | |||
*/ | */ | |||
static void find_bad_fd(void) | static void find_bad_fd(void) | |||
{ | { | |||
int fd ; | int fd ; | |||
#ifndef HAVE_POLL | ||||
struct stat st ; | struct stat st ; | |||
#endif | ||||
unsigned bad_fd_count = 0 ; | unsigned bad_fd_count = 0 ; | |||
const char *func = "find_bad_fd" ; | const char *func = "find_bad_fd" ; | |||
#ifdef HAVE_POLL | ||||
for ( fd = 0 ; fd < ps.rws.pfds_last ; fd++ ) | ||||
if ( ps.rws.pfd_array[fd].revents & ( POLLHUP|POLLNVAL|POLLERR ) ) | ||||
{ | ||||
#else | ||||
for ( fd = 0 ; (unsigned)fd < ps.ros.max_descriptors ; fd++ ) | for ( fd = 0 ; (unsigned)fd < ps.ros.max_descriptors ; fd++ ) | |||
if ( FD_ISSET( fd, &ps.rws.socket_mask ) && fstat( fd, &st ) == -1 ) | if ( FD_ISSET( fd, &ps.rws.socket_mask ) && fstat( fd, &st ) == -1 ) | |||
{ | { | |||
#endif | ||||
int found = FALSE ; | int found = FALSE ; | |||
unsigned u ; | unsigned u ; | |||
for ( u = 0 ; u < pset_count( SERVICES( ps ) ) ; u++ ) | for ( u = 0 ; u < pset_count( SERVICES( ps ) ) ; u++ ) | |||
{ | { | |||
register struct service *sp ; | register struct service *sp ; | |||
sp = SP( pset_pointer( SERVICES( ps ), u ) ) ; | sp = SP( pset_pointer( SERVICES( ps ), u ) ) ; | |||
if ( ! SVC_IS_AVAILABLE( sp ) ) | if ( ! SVC_IS_AVAILABLE( sp ) ) | |||
continue ; | continue ; | |||
if ( SVC_FD( sp ) == fd ) | if ( SVC_FD( sp ) == fd ) | |||
{ | { | |||
msg( LOG_ERR, func, | msg( LOG_ERR, func, | |||
"file descriptor of service %s has been closed", | "file descriptor of service %s has been closed", | |||
SVC_ID( sp ) ) ; | SVC_ID( sp ) ) ; | |||
svc_deactivate( sp ) ; | svc_deactivate( sp ) ; | |||
found = TRUE ; | found = TRUE ; | |||
bad_fd_count++ ; | ||||
break ; | break ; | |||
} | } | |||
} | } | |||
if ( ! found ) | if ( ! found ) | |||
{ | { | |||
#ifdef HAVE_POLL | ||||
ps.rws.pfd_array[fd].events = 0; | ||||
ps.rws.pfd_array[fd].fd = -1; | ||||
#else | ||||
FD_CLR( fd, &ps.rws.socket_mask ) ; | FD_CLR( fd, &ps.rws.socket_mask ) ; | |||
#endif | ||||
msg( LOG_ERR, func, | msg( LOG_ERR, func, | |||
"No active service for file descriptor %d\n", fd ) ; | "No active service for file descriptor %d\n", fd ) ; | |||
bad_fd_count++ ; | bad_fd_count++ ; | |||
} | } | |||
} | } | |||
if ( bad_fd_count == 0 ) | if ( bad_fd_count == 0 ) | |||
msg( LOG_NOTICE, func, | msg( LOG_NOTICE, func, | |||
"select reported EBADF but no bad file descriptors were found" ) ; | "select reported EBADF but no bad file descriptors were found" ) ; | |||
} | } | |||
End of changes. 24 change blocks. | ||||
25 lines changed or deleted | 67 lines changed or added |