service.c (xinetd-2.3.15) | : | service.c (xinetd-2.3.15.4.tar.xz) | ||
---|---|---|---|---|
skipping to change at line 23 | skipping to change at line 23 | |||
#include <syslog.h> | #include <syslog.h> | |||
#include <fcntl.h> | #include <fcntl.h> | |||
#include <netinet/tcp.h> | #include <netinet/tcp.h> | |||
#include <stdlib.h> | #include <stdlib.h> | |||
#include <unistd.h> | #include <unistd.h> | |||
#include <signal.h> | #include <signal.h> | |||
#include <time.h> | #include <time.h> | |||
#include <errno.h> | #include <errno.h> | |||
#include <netinet/in.h> | #include <netinet/in.h> | |||
#include <stdio.h> | #include <stdio.h> | |||
#ifdef HAVE_MDNS | ||||
#include "xmdns.h" | ||||
#endif | ||||
#ifndef NO_RPC | #ifndef NO_RPC | |||
#ifdef HAVE_RPC_PMAP_CLNT_H | ||||
#ifdef __sun | #ifdef __sun | |||
#include <rpc/types.h> | #include <rpc/types.h> | |||
#include <rpc/auth.h> | #include <rpc/auth.h> | |||
#endif | #endif | |||
#include <rpc/types.h> | #include <rpc/types.h> | |||
#include <rpc/xdr.h> | #include <rpc/xdr.h> | |||
#include <rpc/auth.h> | #include <rpc/auth.h> | |||
#include <rpc/clnt.h> | #include <rpc/clnt.h> | |||
#include <rpc/pmap_clnt.h> | #include <rpc/pmap_clnt.h> | |||
#endif | ||||
#include <rpc/rpc.h> | #include <rpc/rpc.h> | |||
#endif | #endif | |||
#ifdef HAVE_SYS_FILE_H | ||||
#include <sys/file.h> | #include <sys/file.h> | |||
#endif | ||||
#include "sio.h" | #include "sio.h" | |||
#include "service.h" | #include "service.h" | |||
#include "util.h" | #include "util.h" | |||
#include "main.h" | #include "main.h" | |||
#include "sconf.h" | #include "sconf.h" | |||
#include "msg.h" | #include "msg.h" | |||
#include "logctl.h" | #include "logctl.h" | |||
#include "xconfig.h" | #include "xconfig.h" | |||
#include "special.h" | #include "special.h" | |||
skipping to change at line 90 | skipping to change at line 82 | |||
sp = NEW_SVC() ; | sp = NEW_SVC() ; | |||
if ( sp == NULL ) | if ( sp == NULL ) | |||
{ | { | |||
out_of_memory( func ) ; | out_of_memory( func ) ; | |||
return( NULL ) ; | return( NULL ) ; | |||
} | } | |||
CLEAR( *sp ) ; | CLEAR( *sp ) ; | |||
SVC_CONF(sp) = scp ; | SVC_CONF(sp) = scp ; | |||
sp->svc_pfd_index = -1; | ||||
return( sp ) ; | return( sp ) ; | |||
} | } | |||
struct service *svc_make_special( struct service_config *scp ) | struct service *svc_make_special( struct service_config *scp ) | |||
{ | { | |||
struct service *sp ; | struct service *sp ; | |||
const char *func = "svc_make_special" ; | const char *func = "svc_make_special" ; | |||
if ( ( sp = svc_new( scp ) ) == NULL ) | if ( ( sp = svc_new( scp ) ) == NULL ) | |||
{ | { | |||
skipping to change at line 231 | skipping to change at line 224 | |||
if ( debug.on ) | if ( debug.on ) | |||
msg( LOG_DEBUG, func, | msg( LOG_DEBUG, func, | |||
"Registered %d versions of %s", registered_versions, sid ) ; | "Registered %d versions of %s", registered_versions, sid ) ; | |||
return( ( registered_versions == 0 ) ? FAILED : OK ) ; | return( ( registered_versions == 0 ) ? FAILED : OK ) ; | |||
} | } | |||
#endif /* ! NO_RPC */ | #endif /* ! NO_RPC */ | |||
#define MAX_BIND_ATTEMPTS 10 | ||||
static status_e activate_normal( struct service *sp ) | static status_e activate_normal( struct service *sp ) | |||
{ | { | |||
union xsockaddr tsin; | union xsockaddr tsin; | |||
int sd = SVC_FD( sp ) ; | int sd = SVC_FD( sp ) ; | |||
struct service_config *scp = SVC_CONF( sp ) ; | struct service_config *scp = SVC_CONF( sp ) ; | |||
uint16_t service_port = SC_PORT( scp ) ; | uint16_t service_port = SC_PORT( scp ) ; | |||
char *sid = SC_ID( scp ) ; | char *sid = SC_ID( scp ) ; | |||
const char *func = "activate_normal" ; | const char *func = "activate_normal" ; | |||
unsigned int sin_len = sizeof(tsin); | unsigned int sin_len = sizeof(tsin); | |||
int on = 1; | int on = 1; | |||
int retries = MAX_BIND_ATTEMPTS; | ||||
useconds_t bind_retry_delay= 0; | ||||
char *brd_str = NULL; | ||||
#ifdef IPV6_V6ONLY | #ifdef IPV6_V6ONLY | |||
int v6on = 0; | int v6on = 0; | |||
#endif | #endif | |||
brd_str = getenv("XINETD_BIND_DELAY"); | ||||
if (brd_str) { | ||||
bind_retry_delay = atoi(brd_str); | ||||
if (bind_retry_delay > 500000) { | ||||
bind_retry_delay = 0; | ||||
} | ||||
} | ||||
if( SC_BIND_ADDR(scp) != NULL ) | if( SC_BIND_ADDR(scp) != NULL ) | |||
memcpy(&tsin, SC_BIND_ADDR(scp), sin_len); | memcpy(&tsin, SC_BIND_ADDR(scp), sin_len); | |||
else | else | |||
memset(&tsin, 0, sin_len); | memset(&tsin, 0, sin_len); | |||
if( SC_IPV4( scp ) ) { | if( SC_IPV4( scp ) ) { | |||
tsin.sa_in.sin_family = AF_INET ; | tsin.sa_in.sin_family = AF_INET ; | |||
tsin.sa_in.sin_port = htons( service_port ) ; | tsin.sa_in.sin_port = htons( service_port ) ; | |||
sin_len = sizeof(struct sockaddr_in); | sin_len = sizeof(struct sockaddr_in); | |||
} else if( SC_IPV6( scp ) ) { | } else if( SC_IPV6( scp ) ) { | |||
skipping to change at line 294 | skipping to change at line 300 | |||
} | } | |||
if( SC_KEEPALIVE( scp ) && (SC_PROTOVAL(scp) == IPPROTO_TCP) ) | if( SC_KEEPALIVE( scp ) && (SC_PROTOVAL(scp) == IPPROTO_TCP) ) | |||
{ | { | |||
if( setsockopt(sd, SOL_SOCKET, SO_KEEPALIVE, | if( setsockopt(sd, SOL_SOCKET, SO_KEEPALIVE, | |||
(char *)&on, sizeof( on ) ) < 0 ) | (char *)&on, sizeof( on ) ) < 0 ) | |||
msg( LOG_WARNING, func, | msg( LOG_WARNING, func, | |||
"setsockopt SO_KEEPALIVE failed (%m). service = %s", sid ) ; | "setsockopt SO_KEEPALIVE failed (%m). service = %s", sid ) ; | |||
} | } | |||
if ( bind( sd, &tsin.sa, sin_len ) == -1 ) | while ( bind( sd, &tsin.sa, sin_len ) == -1 ) | |||
{ | { | |||
msg( LOG_ERR, func, "bind failed (%m). service = %s", sid ) ; | msg( LOG_ERR, func, "bind failed (%m). service = %s", sid ) ; | |||
return( FAILED ) ; | if (retries-- > 0) { | |||
msg( LOG_NOTICE, func, | ||||
"bind retry attempt %i", MAX_BIND_ATTEMPTS - retries); | ||||
if (bind_retry_delay) { | ||||
usleep(bind_retry_delay); | ||||
} | ||||
} else { | ||||
return( FAILED ) ; | ||||
} | ||||
} | } | |||
#ifdef IN_MULTICAST | #ifdef IN_MULTICAST | |||
if( SC_IPV4(scp) && IN_MULTICAST(tsin.sa_in.sin_addr.s_addr) ) { | if( SC_IPV4(scp) && IN_MULTICAST(tsin.sa_in.sin_addr.s_addr) ) { | |||
struct ip_mreq mreq; | struct ip_mreq mreq; | |||
mreq.imr_multiaddr.s_addr = tsin.sa_in.sin_addr.s_addr; | mreq.imr_multiaddr.s_addr = tsin.sa_in.sin_addr.s_addr; | |||
mreq.imr_interface.s_addr = htonl(INADDR_ANY); | mreq.imr_interface.s_addr = htonl(INADDR_ANY); | |||
setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); | setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); | |||
if ( debug.on ) | if ( debug.on ) | |||
msg( LOG_DEBUG, func, "Adding multicast membership." ); | msg( LOG_DEBUG, func, "Adding multicast membership." ); | |||
skipping to change at line 331 | skipping to change at line 345 | |||
const char *func = "svc_activate" ; | const char *func = "svc_activate" ; | |||
/* No activation for MUXCLIENTS. | /* No activation for MUXCLIENTS. | |||
*/ | */ | |||
if (SC_IS_MUXCLIENT( scp )) | if (SC_IS_MUXCLIENT( scp )) | |||
{ | { | |||
return( OK ); | return( OK ); | |||
} | } | |||
#ifdef HAVE_POLL | ||||
if ( ps.rws.descriptors_free <= 0 ) | ||||
{ | ||||
msg(LOG_ERR, func, "Maximum number of services reached") ; | ||||
return( FAILED ) ; | ||||
} | ||||
if ( sp->svc_pfd_index >= 0 ) | ||||
{ | ||||
SVC_POLLFD( sp ) = &ps.rws.pfd_array[sp->svc_pfd_index] ; | ||||
} | ||||
else | ||||
{ | ||||
sp->svc_pfd_index = ps.rws.pfds_last ; | ||||
SVC_POLLFD( sp ) = &ps.rws.pfd_array[ps.rws.pfds_last++] ; | ||||
} | ||||
#endif /* HAVE_POLL */ | ||||
if( SC_IPV4( scp ) ) { | if( SC_IPV4( scp ) ) { | |||
SVC_FD(sp) = socket( AF_INET, | SVC_FD(sp) = socket( AF_INET, | |||
SC_SOCKET_TYPE( scp ), SC_PROTOVAL( scp ) ) ; | SC_SOCKET_TYPE( scp ), SC_PROTOVAL( scp ) ) ; | |||
} else if( SC_IPV6( scp ) ) { | } else if( SC_IPV6( scp ) ) { | |||
SVC_FD(sp) = socket( AF_INET6, | SVC_FD(sp) = socket( AF_INET6, | |||
SC_SOCKET_TYPE( scp ), SC_PROTOVAL( scp ) ) ; | SC_SOCKET_TYPE( scp ), SC_PROTOVAL( scp ) ) ; | |||
} | } | |||
if ( SVC_FD(sp) == -1 ) | if ( SVC_FD(sp) == -1 ) | |||
{ | { | |||
if (SC_BIND_ADDR(scp) == NULL && SC_IPV6( scp )) | ||||
{ | ||||
/* there was no bind address configured and IPv6 fails. Try IPv4 */ | ||||
msg( LOG_NOTICE, func, "IPv6 socket creation failed for service %s, try | ||||
ing IPv4", SC_ID( scp ) ) ; | ||||
M_CLEAR(SC_XFLAGS(scp), SF_IPV6); | ||||
M_SET(SC_XFLAGS(scp), SF_IPV4); | ||||
return svc_activate(sp); | ||||
} | ||||
msg( LOG_ERR, func, | msg( LOG_ERR, func, | |||
"socket creation failed (%m). service = %s", SC_ID( scp ) ) ; | "socket creation failed (%m). service = %s", SC_ID( scp ) ) ; | |||
#ifdef HAVE_POLL | ||||
SVC_EVENTS( sp ) = 0; | ||||
SVC_FD( sp ) = 0; | ||||
#else | ||||
FD_CLR( SVC_FD( sp ), &ps.rws.socket_mask ) ; | ||||
#endif /* HAVE_POLL */ | ||||
return( FAILED ) ; | return( FAILED ) ; | |||
} | } | |||
if ( set_fd_modes( sp ) == FAILED ) | if ( set_fd_modes( sp ) == FAILED ) | |||
{ | { | |||
(void) Sclose( SVC_FD(sp) ) ; | (void) Sclose( SVC_FD(sp) ) ; | |||
#ifdef HAVE_POLL | ||||
SVC_EVENTS( sp ) = 0; | ||||
SVC_FD( sp ) = 0; | ||||
#else | ||||
FD_CLR( SVC_FD( sp ), &ps.rws.socket_mask ) ; | ||||
#endif /* HAVE_POLL */ | ||||
return( FAILED ) ; | return( FAILED ) ; | |||
} | } | |||
#ifndef NO_RPC | #ifndef NO_RPC | |||
if ( SC_IS_RPC( scp ) ) | if ( SC_IS_RPC( scp ) ) | |||
status = activate_rpc( sp ) ; | status = activate_rpc( sp ) ; | |||
else | else | |||
#endif /* ! NO_RPC */ | #endif /* ! NO_RPC */ | |||
status = activate_normal( sp ) ; | status = activate_normal( sp ) ; | |||
if ( status == FAILED ) | if ( status == FAILED ) | |||
{ | { | |||
(void) Sclose( SVC_FD(sp) ) ; | (void) Sclose( SVC_FD(sp) ) ; | |||
#ifdef HAVE_POLL | ||||
SVC_EVENTS( sp ) = 0; | ||||
SVC_FD( sp ) = 0; | ||||
#else | ||||
FD_CLR( SVC_FD( sp ), &ps.rws.socket_mask ) ; | ||||
#endif /* HAVE_POLL */ | ||||
return( FAILED ) ; | return( FAILED ) ; | |||
} | } | |||
#ifdef HAVE_MDNS | ||||
xinetd_mdns_register(scp); | ||||
#endif | ||||
if ( log_start( sp, &SVC_LOG(sp) ) == FAILED ) | if ( log_start( sp, &SVC_LOG(sp) ) == FAILED ) | |||
{ | { | |||
deactivate( sp ) ; | deactivate( sp ) ; | |||
return( FAILED ) ; | return( FAILED ) ; | |||
} | } | |||
/* | /* | |||
* Initialize the service data | * Initialize the service data | |||
*/ | */ | |||
SVC_RUNNING_SERVERS(sp) = SVC_RETRIES(sp) = 0 ; | SVC_RUNNING_SERVERS(sp) = SVC_RETRIES(sp) = 0 ; | |||
if ( SC_MUST_LISTEN( scp ) ) | if ( SC_MUST_LISTEN( scp ) ) | |||
(void) listen( SVC_FD(sp), LISTEN_BACKLOG ) ; | (void) listen( SVC_FD(sp), LISTEN_BACKLOG ) ; | |||
ps.rws.descriptors_free-- ; | ps.rws.descriptors_free-- ; | |||
SVC_STATE(sp) = SVC_ACTIVE ; | SVC_STATE(sp) = SVC_ACTIVE ; | |||
#ifdef HAVE_POLL | ||||
SVC_EVENTS( sp ) = POLLIN ; | ||||
#else | ||||
FD_SET( SVC_FD(sp), &ps.rws.socket_mask ) ; | FD_SET( SVC_FD(sp), &ps.rws.socket_mask ) ; | |||
if ( SVC_FD(sp) > ps.rws.mask_max ) | if ( SVC_FD(sp) > ps.rws.mask_max ) | |||
ps.rws.mask_max = SVC_FD(sp) ; | ps.rws.mask_max = SVC_FD(sp) ; | |||
#endif /* HAVE_POLL */ | ||||
ps.rws.active_services++ ; | ps.rws.active_services++ ; | |||
ps.rws.available_services++ ; | ps.rws.available_services++ ; | |||
return( OK ) ; | return( OK ) ; | |||
} | } | |||
static void deactivate( const struct service *sp ) | static void deactivate( const struct service *sp ) | |||
{ | { | |||
(void) Sclose( SVC_FD( sp ) ) ; | (void) Sclose( SVC_FD( sp ) ) ; | |||
#ifdef HAVE_POLL | ||||
#ifdef HAVE_MDNS | SVC_FD( sp ) = 0; | |||
xinetd_mdns_deregister(SVC_CONF(sp)); | #else | |||
FD_CLR( SVC_FD( sp ), &ps.rws.socket_mask ) ; | ||||
#endif | #endif | |||
if (debug.on) | if (debug.on) | |||
msg(LOG_DEBUG, "deactivate", "%d Service %s deactivated", | msg(LOG_DEBUG, "deactivate", "%d Service %s deactivated", | |||
getpid(), SC_NAME( SVC_CONF(sp) ) ); | getpid(), SC_NAME( SVC_CONF(sp) ) ); | |||
#ifndef NO_RPC | #ifndef NO_RPC | |||
if ( SC_IS_RPC( SVC_CONF( sp ) ) ) | if ( SC_IS_RPC( SVC_CONF( sp ) ) ) | |||
{ | { | |||
unsigned long vers ; | unsigned long vers ; | |||
skipping to change at line 437 | skipping to change at line 498 | |||
void svc_deactivate( struct service *sp ) | void svc_deactivate( struct service *sp ) | |||
{ | { | |||
if ( ! SVC_IS_AVAILABLE( sp ) ) | if ( ! SVC_IS_AVAILABLE( sp ) ) | |||
return ; | return ; | |||
deactivate( sp ) ; | deactivate( sp ) ; | |||
ps.rws.descriptors_free++ ; | ps.rws.descriptors_free++ ; | |||
if ( SVC_IS_ACTIVE( sp ) ) | if ( SVC_IS_ACTIVE( sp ) ) | |||
{ | { | |||
#ifdef HAVE_POLL | ||||
SVC_EVENTS( sp ) = 0; | ||||
SVC_FD( sp ) = 0; | ||||
#else | ||||
FD_CLR( SVC_FD( sp ), &ps.rws.socket_mask ) ; | FD_CLR( SVC_FD( sp ), &ps.rws.socket_mask ) ; | |||
#endif /* HAVE_POLL */ | ||||
ps.rws.active_services-- ; | ps.rws.active_services-- ; | |||
} | } | |||
ps.rws.available_services-- ; | ps.rws.available_services-- ; | |||
DISABLE( sp ) ; | DISABLE( sp ) ; | |||
} | } | |||
/* | /* | |||
* Suspend a service | * Suspend a service | |||
skipping to change at line 459 | skipping to change at line 525 | |||
void svc_suspend( struct service *sp ) | void svc_suspend( struct service *sp ) | |||
{ | { | |||
const char *func = "svc_suspend" ; | const char *func = "svc_suspend" ; | |||
if ( ! SVC_IS_ACTIVE( sp ) ) | if ( ! SVC_IS_ACTIVE( sp ) ) | |||
{ | { | |||
msg( LOG_ERR, func, "service %s is not active", SVC_ID( sp ) ) ; | msg( LOG_ERR, func, "service %s is not active", SVC_ID( sp ) ) ; | |||
return ; | return ; | |||
} | } | |||
#ifdef HAVE_POLL | ||||
/* | ||||
* don't reap the pfd from pfd_array, since we must have it allocated for | ||||
* SVC_FD( sp ) | ||||
*/ | ||||
SVC_EVENTS( sp ) = 0; | ||||
#else | ||||
FD_CLR( SVC_FD( sp ), &ps.rws.socket_mask ) ; | FD_CLR( SVC_FD( sp ), &ps.rws.socket_mask ) ; | |||
#endif | ||||
ps.rws.active_services-- ; | ps.rws.active_services-- ; | |||
if ( debug.on ) | if ( debug.on ) | |||
msg( LOG_DEBUG, func, "Suspended service %s", SVC_ID( sp ) ) ; | msg( LOG_DEBUG, func, "Suspended service %s", SVC_ID( sp ) ) ; | |||
SUSPEND( sp ) ; | SUSPEND( sp ) ; | |||
} | } | |||
/* | /* | |||
* Resume a suspended service. | * Resume a suspended service. | |||
*/ | */ | |||
void svc_resume( struct service *sp ) | void svc_resume( struct service *sp ) | |||
{ | { | |||
const char *func = "svc_resume" ; | const char *func = "svc_resume" ; | |||
#ifdef HAVE_POLL | ||||
SVC_EVENTS( sp ) = POLLIN ; | ||||
#else | ||||
FD_SET( SVC_FD( sp ), &ps.rws.socket_mask ) ; | FD_SET( SVC_FD( sp ), &ps.rws.socket_mask ) ; | |||
#endif | ||||
ps.rws.active_services++ ; | ps.rws.active_services++ ; | |||
if ( debug.on ) | if ( debug.on ) | |||
msg( LOG_DEBUG, func, "Resumed service %s", SVC_ID( sp ) ) ; | msg( LOG_DEBUG, func, "Resumed service %s", SVC_ID( sp ) ) ; | |||
RESUME( sp ) ; | RESUME( sp ) ; | |||
} | } | |||
/* | /* | |||
* Steps: | * Steps: | |||
* 1. Deactivate the service | * 1. Deactivate the service | |||
* 2. Free all memory used by the service and free the service itself | * 2. Free all memory used by the service and free the service itself | |||
skipping to change at line 894 | skipping to change at line 973 | |||
* fd's are not closed and reconfig will fail. | * fd's are not closed and reconfig will fail. | |||
*/ | */ | |||
void close_all_svc_descriptors(void) | void close_all_svc_descriptors(void) | |||
{ | { | |||
psi_h iter ; | psi_h iter ; | |||
struct service *osp ; | struct service *osp ; | |||
/* Have to close all other descriptors here */ | /* Have to close all other descriptors here */ | |||
iter = psi_create( SERVICES( ps ) ) ; | iter = psi_create( SERVICES( ps ) ) ; | |||
if ( iter == NULL ) | if ( iter == NULL ) | |||
{ | ||||
out_of_memory( "close_all_svc_descriptors" ) ; | out_of_memory( "close_all_svc_descriptors" ) ; | |||
exit( 1 ); | ||||
} | ||||
for ( osp = SP( psi_start( iter ) ) ; osp ; osp = SP( psi_next( iter ) ) ) | for ( osp = SP( psi_start( iter ) ) ; osp ; osp = SP( psi_next( iter ) ) ) | |||
(void) Sclose( SVC_FD( osp ) ) ; | { | |||
#ifdef HAVE_POLL | ||||
if ( osp && SVC_POLLFD( osp ) ) | ||||
#endif | ||||
(void) Sclose( SVC_FD( osp ) ) ; | ||||
} | ||||
psi_destroy( iter ) ; | psi_destroy( iter ) ; | |||
} | } | |||
End of changes. 30 change blocks. | ||||
18 lines changed or deleted | 106 lines changed or added |