2011-04-21 00:28:57 +04:00
/*
Unix SMB / CIFS implementation .
Common server globals
Copyright ( C ) Simo Sorce < idra @ samba . org > 2011
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include "includes.h"
2011-08-17 23:21:12 +04:00
# include "serverid.h"
# include "messages.h"
2011-04-21 00:28:57 +04:00
# include "system/time.h"
# include "system/shmem.h"
# include "system/filesys.h"
# include "server_prefork.h"
2011-09-21 01:26:36 +04:00
# include "../lib/util/samba_util.h"
2011-05-04 02:55:25 +04:00
# include "../lib/util/tevent_unix.h"
2011-04-21 00:28:57 +04:00
struct prefork_pool {
2011-05-10 16:39:14 +04:00
int listen_fd_size ;
int * listen_fds ;
2011-04-21 00:28:57 +04:00
prefork_main_fn_t * main_fn ;
void * private_data ;
int pool_size ;
struct pf_worker_data * pool ;
2011-05-06 01:56:31 +04:00
int allowed_clients ;
2011-05-20 07:56:02 +04:00
prefork_sigchld_fn_t * sigchld_fn ;
void * sigchld_data ;
2011-04-21 00:28:57 +04:00
} ;
2011-05-20 07:56:02 +04:00
static bool prefork_setup_sigchld_handler ( struct tevent_context * ev_ctx ,
struct prefork_pool * pfp ) ;
static int prefork_pool_destructor ( struct prefork_pool * pfp )
2011-04-21 00:28:57 +04:00
{
2011-08-15 02:11:18 +04:00
anonymous_shared_free ( pfp - > pool ) ;
2011-04-21 00:28:57 +04:00
return 0 ;
}
2011-07-18 18:39:50 +04:00
bool prefork_create_pool ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev_ctx ,
struct messaging_context * msg_ctx ,
2011-05-10 16:39:14 +04:00
int listen_fd_size , int * listen_fds ,
2011-04-21 00:28:57 +04:00
int min_children , int max_children ,
prefork_main_fn_t * main_fn , void * private_data ,
struct prefork_pool * * pf_pool )
{
struct prefork_pool * pfp ;
pid_t pid ;
time_t now = time ( NULL ) ;
size_t data_size ;
int ret ;
int i ;
2011-05-20 07:56:02 +04:00
bool ok ;
2011-04-21 00:28:57 +04:00
2011-05-20 07:56:02 +04:00
pfp = talloc_zero ( mem_ctx , struct prefork_pool ) ;
2011-04-21 00:28:57 +04:00
if ( ! pfp ) {
DEBUG ( 1 , ( " Out of memory! \n " ) ) ;
return false ;
}
2011-05-10 16:39:14 +04:00
pfp - > listen_fd_size = listen_fd_size ;
pfp - > listen_fds = talloc_array ( pfp , int , listen_fd_size ) ;
if ( ! pfp - > listen_fds ) {
DEBUG ( 1 , ( " Out of memory! \n " ) ) ;
return false ;
}
for ( i = 0 ; i < listen_fd_size ; i + + ) {
pfp - > listen_fds [ i ] = listen_fds [ i ] ;
2011-08-18 20:35:02 +04:00
/* force sockets in non-blocking mode */
set_blocking ( listen_fds [ i ] , false ) ;
2011-05-10 16:39:14 +04:00
}
2011-04-21 00:28:57 +04:00
pfp - > main_fn = main_fn ;
pfp - > private_data = private_data ;
pfp - > pool_size = max_children ;
data_size = sizeof ( struct pf_worker_data ) * max_children ;
2011-09-30 12:07:30 +04:00
pfp - > pool = ( struct pf_worker_data * ) anonymous_shared_allocate (
data_size ) ;
2011-08-15 02:11:18 +04:00
if ( pfp - > pool = = NULL ) {
2011-04-21 00:28:57 +04:00
DEBUG ( 1 , ( " Failed to mmap memory for prefork pool! \n " ) ) ;
talloc_free ( pfp ) ;
return false ;
}
talloc_set_destructor ( pfp , prefork_pool_destructor ) ;
for ( i = 0 ; i < min_children ; i + + ) {
2011-05-06 01:56:31 +04:00
pfp - > pool [ i ] . allowed_clients = 1 ;
pfp - > pool [ i ] . started = now ;
2012-03-24 23:17:08 +04:00
pid = fork ( ) ;
2011-04-21 00:28:57 +04:00
switch ( pid ) {
case - 1 :
DEBUG ( 1 , ( " Failed to prefork child n. %d ! \n " , i ) ) ;
break ;
case 0 : /* THE CHILD */
2011-08-16 19:37:41 +04:00
pfp - > pool [ i ] . status = PF_WORKER_ALIVE ;
2011-07-18 18:39:50 +04:00
ret = pfp - > main_fn ( ev_ctx , msg_ctx ,
2011-08-10 00:44:52 +04:00
& pfp - > pool [ i ] , i + 1 ,
2011-05-10 16:39:14 +04:00
pfp - > listen_fd_size ,
pfp - > listen_fds ,
2011-04-21 00:28:57 +04:00
pfp - > private_data ) ;
exit ( ret ) ;
default : /* THE PARENT */
pfp - > pool [ i ] . pid = pid ;
break ;
}
}
2011-05-20 07:56:02 +04:00
ok = prefork_setup_sigchld_handler ( ev_ctx , pfp ) ;
if ( ! ok ) {
DEBUG ( 1 , ( " Failed to setup SIGCHLD Handler! \n " ) ) ;
talloc_free ( pfp ) ;
return false ;
}
2011-04-21 00:28:57 +04:00
* pf_pool = pfp ;
return true ;
}
2011-05-09 12:51:47 +04:00
/* Provide the new max children number in new_max
* ( must be larger than current max ) .
* Returns : 0 if all fine
* ENOSPC if mremap fails to expand
* EINVAL if new_max is invalid
*/
int prefork_expand_pool ( struct prefork_pool * pfp , int new_max )
{
2011-08-15 02:11:18 +04:00
struct prefork_pool * pool ;
2011-05-09 12:51:47 +04:00
size_t old_size ;
size_t new_size ;
2011-08-15 02:11:18 +04:00
int ret ;
2011-05-09 12:51:47 +04:00
if ( new_max < = pfp - > pool_size ) {
return EINVAL ;
}
old_size = sizeof ( struct pf_worker_data ) * pfp - > pool_size ;
new_size = sizeof ( struct pf_worker_data ) * new_max ;
2011-09-30 12:07:35 +04:00
pool = ( struct prefork_pool * ) anonymous_shared_resize (
& pfp - > pool , new_size , false ) ;
2011-08-15 02:11:18 +04:00
if ( pool = = NULL ) {
ret = errno ;
DEBUG ( 3 , ( " Failed to mremap memory (%d: %s)! \n " ,
ret , strerror ( ret ) ) ) ;
return ret ;
2011-05-09 12:51:47 +04:00
}
memset ( & pool [ pfp - > pool_size ] , 0 , new_size - old_size ) ;
pfp - > pool_size = new_max ;
return 0 ;
}
2011-04-21 00:28:57 +04:00
int prefork_add_children ( struct tevent_context * ev_ctx ,
2011-07-18 18:39:50 +04:00
struct messaging_context * msg_ctx ,
2011-04-21 00:28:57 +04:00
struct prefork_pool * pfp ,
int num_children )
{
pid_t pid ;
time_t now = time ( NULL ) ;
int ret ;
int i , j ;
for ( i = 0 , j = 0 ; i < pfp - > pool_size & & j < num_children ; i + + ) {
if ( pfp - > pool [ i ] . status ! = PF_WORKER_NONE ) {
continue ;
}
2011-05-06 01:56:31 +04:00
pfp - > pool [ i ] . allowed_clients = 1 ;
pfp - > pool [ i ] . started = now ;
2012-03-24 23:17:08 +04:00
pid = fork ( ) ;
2011-04-21 00:28:57 +04:00
switch ( pid ) {
case - 1 :
DEBUG ( 1 , ( " Failed to prefork child n. %d ! \n " , j ) ) ;
break ;
case 0 : /* THE CHILD */
2011-08-16 19:37:41 +04:00
pfp - > pool [ i ] . status = PF_WORKER_ALIVE ;
2011-07-18 18:39:50 +04:00
ret = pfp - > main_fn ( ev_ctx , msg_ctx ,
2011-08-10 00:44:52 +04:00
& pfp - > pool [ i ] , i + 1 ,
2011-05-10 16:39:14 +04:00
pfp - > listen_fd_size ,
pfp - > listen_fds ,
2011-04-21 00:28:57 +04:00
pfp - > private_data ) ;
pfp - > pool [ i ] . status = PF_WORKER_EXITING ;
exit ( ret ) ;
default : /* THE PARENT */
pfp - > pool [ i ] . pid = pid ;
j + + ;
break ;
}
}
DEBUG ( 5 , ( " Added %d children! \n " , j ) ) ;
return j ;
}
struct prefork_oldest {
int num ;
time_t started ;
} ;
/* sort in inverse order */
static int prefork_sort_oldest ( const void * ap , const void * bp )
{
2011-07-20 16:24:15 +04:00
const struct prefork_oldest * a = ( const struct prefork_oldest * ) ap ;
const struct prefork_oldest * b = ( const struct prefork_oldest * ) bp ;
2011-04-21 00:28:57 +04:00
if ( a - > started = = b - > started ) {
return 0 ;
}
if ( a - > started < b - > started ) {
return 1 ;
}
return - 1 ;
}
2011-08-18 18:31:36 +04:00
int prefork_retire_children ( struct messaging_context * msg_ctx ,
struct prefork_pool * pfp ,
2011-04-21 00:28:57 +04:00
int num_children , time_t age_limit )
{
2011-08-18 18:31:36 +04:00
const DATA_BLOB ping = data_blob_null ;
2011-04-21 00:28:57 +04:00
time_t now = time ( NULL ) ;
struct prefork_oldest * oldest ;
int i , j ;
oldest = talloc_array ( pfp , struct prefork_oldest , pfp - > pool_size ) ;
if ( ! oldest ) {
return - 1 ;
}
for ( i = 0 ; i < pfp - > pool_size ; i + + ) {
oldest [ i ] . num = i ;
2011-08-16 19:37:41 +04:00
if ( pfp - > pool [ i ] . status = = PF_WORKER_ALIVE | |
pfp - > pool [ i ] . status = = PF_WORKER_ACCEPTING ) {
2011-04-21 00:28:57 +04:00
oldest [ i ] . started = pfp - > pool [ i ] . started ;
} else {
oldest [ i ] . started = now ;
}
}
qsort ( oldest , pfp - > pool_size ,
sizeof ( struct prefork_oldest ) ,
prefork_sort_oldest ) ;
for ( i = 0 , j = 0 ; i < pfp - > pool_size & & j < num_children ; i + + ) {
2011-08-18 18:31:36 +04:00
if ( ( ( pfp - > pool [ i ] . status = = PF_WORKER_ALIVE ) & &
( pfp - > pool [ i ] . num_clients < 1 ) ) & &
( pfp - > pool [ i ] . started < = age_limit ) ) {
2011-04-21 00:28:57 +04:00
/* tell the child it's time to give up */
2013-03-14 13:36:34 +04:00
DEBUG ( 5 , ( " Retiring pid %u! \n " , ( unsigned int ) pfp - > pool [ i ] . pid ) ) ;
2011-04-21 00:28:57 +04:00
pfp - > pool [ i ] . cmds = PF_SRV_MSG_EXIT ;
2011-08-18 18:31:36 +04:00
messaging_send ( msg_ctx ,
pid_to_procid ( pfp - > pool [ i ] . pid ) ,
MSG_PREFORK_PARENT_EVENT , & ping ) ;
2011-04-21 00:28:57 +04:00
j + + ;
}
}
return j ;
}
2011-08-17 02:20:51 +04:00
int prefork_count_children ( struct prefork_pool * pfp , int * active )
2011-04-21 00:28:57 +04:00
{
int i , a , t ;
a = 0 ;
t = 0 ;
for ( i = 0 ; i < pfp - > pool_size ; i + + ) {
if ( pfp - > pool [ i ] . status = = PF_WORKER_NONE ) {
continue ;
}
t + + ;
2011-08-17 02:20:51 +04:00
if ( ( pfp - > pool [ i ] . status = = PF_WORKER_EXITING ) | |
( pfp - > pool [ i ] . num_clients < = 0 ) ) {
2011-04-21 00:28:57 +04:00
continue ;
}
a + + ;
}
2011-08-17 02:20:51 +04:00
if ( active ) {
* active = a ;
}
return t ;
2011-04-21 00:28:57 +04:00
}
2011-05-20 07:56:02 +04:00
static void prefork_cleanup_loop ( struct prefork_pool * pfp )
2011-04-21 00:28:57 +04:00
{
2011-05-16 18:46:35 +04:00
int status ;
pid_t pid ;
2011-04-21 00:28:57 +04:00
int i ;
2011-05-16 18:46:35 +04:00
/* TODO: should we use a process group id wait instead of looping ? */
2011-04-21 00:28:57 +04:00
for ( i = 0 ; i < pfp - > pool_size ; i + + ) {
2011-05-16 18:46:35 +04:00
if ( pfp - > pool [ i ] . status = = PF_WORKER_NONE | |
pfp - > pool [ i ] . pid = = 0 ) {
continue ;
}
2016-02-16 17:46:06 +03:00
pid = waitpid ( pfp - > pool [ i ] . pid , & status , WNOHANG ) ;
2011-05-16 18:46:35 +04:00
if ( pid > 0 ) {
2011-04-21 00:28:57 +04:00
if ( pfp - > pool [ i ] . status ! = PF_WORKER_EXITING ) {
2011-05-16 18:46:35 +04:00
DEBUG ( 3 , ( " Child (%d) terminated abnormally: "
" %d \n " , ( int ) pid , status ) ) ;
} else {
DEBUG ( 10 , ( " Child (%d) terminated with status: "
" %d \n " , ( int ) pid , status ) ) ;
2011-04-21 00:28:57 +04:00
}
/* reset all fields,
* this makes status = PF_WORK_NONE */
memset ( & pfp - > pool [ i ] , 0 ,
sizeof ( struct pf_worker_data ) ) ;
}
}
}
2011-08-12 20:24:13 +04:00
int prefork_count_allowed_connections ( struct prefork_pool * pfp )
{
int c ;
int i ;
c = 0 ;
for ( i = 0 ; i < pfp - > pool_size ; i + + ) {
2011-08-16 19:07:27 +04:00
if ( pfp - > pool [ i ] . status = = PF_WORKER_NONE | |
pfp - > pool [ i ] . status = = PF_WORKER_EXITING ) {
continue ;
}
if ( pfp - > pool [ i ] . num_clients < 0 ) {
2011-08-12 20:24:13 +04:00
continue ;
}
c + = pfp - > pool [ i ] . allowed_clients - pfp - > pool [ i ] . num_clients ;
}
return c ;
}
2011-05-06 01:56:31 +04:00
void prefork_increase_allowed_clients ( struct prefork_pool * pfp , int max )
{
int i ;
for ( i = 0 ; i < pfp - > pool_size ; i + + ) {
2011-08-16 19:07:27 +04:00
if ( pfp - > pool [ i ] . status = = PF_WORKER_NONE | |
pfp - > pool [ i ] . status = = PF_WORKER_EXITING ) {
continue ;
}
if ( pfp - > pool [ i ] . num_clients < 0 ) {
2011-05-06 01:56:31 +04:00
continue ;
}
if ( pfp - > pool [ i ] . allowed_clients < max ) {
pfp - > pool [ i ] . allowed_clients + + ;
}
}
}
2011-08-12 20:24:13 +04:00
void prefork_decrease_allowed_clients ( struct prefork_pool * pfp )
{
int i ;
for ( i = 0 ; i < pfp - > pool_size ; i + + ) {
2011-08-16 19:07:27 +04:00
if ( pfp - > pool [ i ] . status = = PF_WORKER_NONE | |
pfp - > pool [ i ] . status = = PF_WORKER_EXITING ) {
continue ;
}
if ( pfp - > pool [ i ] . num_clients < 0 ) {
2011-08-12 20:24:13 +04:00
continue ;
}
if ( pfp - > pool [ i ] . allowed_clients > 1 ) {
pfp - > pool [ i ] . allowed_clients - - ;
}
}
}
2011-05-06 01:56:31 +04:00
void prefork_reset_allowed_clients ( struct prefork_pool * pfp )
{
int i ;
for ( i = 0 ; i < pfp - > pool_size ; i + + ) {
pfp - > pool [ i ] . allowed_clients = 1 ;
}
}
2011-05-09 16:49:50 +04:00
void prefork_send_signal_to_all ( struct prefork_pool * pfp , int signal_num )
{
int i ;
for ( i = 0 ; i < pfp - > pool_size ; i + + ) {
if ( pfp - > pool [ i ] . status = = PF_WORKER_NONE ) {
continue ;
}
kill ( pfp - > pool [ i ] . pid , signal_num ) ;
}
}
2011-08-17 23:21:12 +04:00
void prefork_warn_active_children ( struct messaging_context * msg_ctx ,
struct prefork_pool * pfp )
{
const DATA_BLOB ping = data_blob_null ;
int i ;
for ( i = 0 ; i < pfp - > pool_size ; i + + ) {
if ( pfp - > pool [ i ] . status = = PF_WORKER_NONE ) {
continue ;
}
messaging_send ( msg_ctx ,
pid_to_procid ( pfp - > pool [ i ] . pid ) ,
MSG_PREFORK_PARENT_EVENT , & ping ) ;
}
}
2011-05-20 07:56:02 +04:00
static void prefork_sigchld_handler ( struct tevent_context * ev_ctx ,
struct tevent_signal * se ,
int signum , int count ,
void * siginfo , void * pvt )
{
struct prefork_pool * pfp ;
pfp = talloc_get_type_abort ( pvt , struct prefork_pool ) ;
/* run the cleanup function to make sure all dead children are
* properly and timely retired . */
prefork_cleanup_loop ( pfp ) ;
if ( pfp - > sigchld_fn ) {
pfp - > sigchld_fn ( ev_ctx , pfp , pfp - > sigchld_data ) ;
}
}
static bool prefork_setup_sigchld_handler ( struct tevent_context * ev_ctx ,
struct prefork_pool * pfp )
{
struct tevent_signal * se ;
se = tevent_add_signal ( ev_ctx , pfp , SIGCHLD , 0 ,
prefork_sigchld_handler , pfp ) ;
if ( ! se ) {
DEBUG ( 0 , ( " Failed to setup SIGCHLD handler! \n " ) ) ;
return false ;
}
return true ;
}
void prefork_set_sigchld_callback ( struct prefork_pool * pfp ,
prefork_sigchld_fn_t * sigchld_fn ,
void * private_data )
{
pfp - > sigchld_fn = sigchld_fn ;
pfp - > sigchld_data = private_data ;
}
2011-05-09 16:49:50 +04:00
2011-04-21 00:28:57 +04:00
/* ==== Functions used by children ==== */
2011-05-04 02:55:25 +04:00
struct pf_listen_state {
struct tevent_context * ev ;
struct pf_worker_data * pf ;
2011-05-10 16:39:14 +04:00
int listen_fd_size ;
int * listen_fds ;
2011-05-04 02:55:25 +04:00
int accept_fd ;
2011-07-19 23:07:42 +04:00
struct tsocket_address * srv_addr ;
struct tsocket_address * cli_addr ;
2011-05-04 02:55:25 +04:00
int error ;
} ;
2011-08-16 17:30:28 +04:00
struct pf_listen_ctx {
TALLOC_CTX * fde_ctx ;
struct tevent_req * req ;
int listen_fd ;
} ;
2011-05-04 02:55:25 +04:00
static void prefork_listen_accept_handler ( struct tevent_context * ev ,
struct tevent_fd * fde ,
uint16_t flags , void * pvt ) ;
struct tevent_req * prefork_listen_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct pf_worker_data * pf ,
2011-05-10 16:39:14 +04:00
int listen_fd_size ,
2011-08-16 17:30:28 +04:00
int * listen_fds )
2011-05-04 02:55:25 +04:00
{
2011-08-16 17:30:28 +04:00
struct tevent_req * req ;
2011-05-04 02:55:25 +04:00
struct pf_listen_state * state ;
2011-08-16 17:30:28 +04:00
struct pf_listen_ctx * ctx ;
struct tevent_fd * fde ;
TALLOC_CTX * fde_ctx ;
int i ;
2011-05-04 02:55:25 +04:00
req = tevent_req_create ( mem_ctx , & state , struct pf_listen_state ) ;
if ( ! req ) {
return NULL ;
}
state - > ev = ev ;
state - > pf = pf ;
2011-05-10 16:39:14 +04:00
state - > listen_fd_size = listen_fd_size ;
state - > listen_fds = listen_fds ;
2011-05-04 02:55:25 +04:00
state - > accept_fd = - 1 ;
state - > error = 0 ;
2011-05-10 16:39:14 +04:00
fde_ctx = talloc_new ( state ) ;
if ( tevent_req_nomem ( fde_ctx , req ) ) {
2011-08-16 17:30:28 +04:00
return tevent_req_post ( req , ev ) ;
2011-05-10 16:39:14 +04:00
}
2011-08-16 17:30:28 +04:00
/* race on accept */
2011-05-10 16:39:14 +04:00
for ( i = 0 ; i < state - > listen_fd_size ; i + + ) {
ctx = talloc ( fde_ctx , struct pf_listen_ctx ) ;
if ( tevent_req_nomem ( ctx , req ) ) {
2011-08-16 17:30:28 +04:00
return tevent_req_post ( req , ev ) ;
2011-05-10 16:39:14 +04:00
}
ctx - > fde_ctx = fde_ctx ;
ctx - > req = req ;
ctx - > listen_fd = state - > listen_fds [ i ] ;
fde = tevent_add_fd ( state - > ev , fde_ctx ,
ctx - > listen_fd , TEVENT_FD_READ ,
prefork_listen_accept_handler , ctx ) ;
if ( tevent_req_nomem ( fde , req ) ) {
2011-08-16 17:30:28 +04:00
return tevent_req_post ( req , ev ) ;
2011-05-10 16:39:14 +04:00
}
}
2011-08-16 17:30:28 +04:00
2011-08-16 19:37:41 +04:00
pf - > status = PF_WORKER_ACCEPTING ;
2011-08-16 17:30:28 +04:00
return req ;
2011-05-04 02:55:25 +04:00
}
static void prefork_listen_accept_handler ( struct tevent_context * ev ,
struct tevent_fd * fde ,
uint16_t flags , void * pvt )
{
struct pf_listen_state * state ;
2011-08-16 17:30:28 +04:00
struct tevent_req * req ;
2011-05-10 16:39:14 +04:00
struct pf_listen_ctx * ctx ;
2011-07-19 23:07:42 +04:00
struct sockaddr_storage addr ;
socklen_t addrlen ;
2011-08-17 18:53:38 +04:00
int soerr = 0 ;
socklen_t solen = sizeof ( soerr ) ;
2011-05-04 02:55:25 +04:00
int sd = - 1 ;
2011-07-19 23:07:42 +04:00
int ret ;
2011-05-04 02:55:25 +04:00
2011-05-10 16:39:14 +04:00
ctx = talloc_get_type_abort ( pvt , struct pf_listen_ctx ) ;
2011-08-16 17:30:28 +04:00
req = ctx - > req ;
2011-05-10 16:39:14 +04:00
state = tevent_req_data ( ctx - > req , struct pf_listen_state ) ;
2011-05-04 02:55:25 +04:00
2011-08-18 18:31:36 +04:00
if ( ( state - > pf - > cmds = = PF_SRV_MSG_EXIT ) & &
( state - > pf - > num_clients < = 0 ) ) {
2011-08-16 19:37:41 +04:00
/* We have been asked to exit, so drop here and the next
* child will pick it up */
2011-08-18 18:31:36 +04:00
state - > pf - > status = PF_WORKER_EXITING ;
2011-08-16 19:37:41 +04:00
state - > error = EINTR ;
goto done ;
}
2011-08-17 18:53:38 +04:00
/* before proceeding check that the listening fd is ok */
ret = getsockopt ( ctx - > listen_fd , SOL_SOCKET , SO_ERROR , & soerr , & solen ) ;
if ( ret = = - 1 ) {
/* this is a fatal error, we cannot continue listening */
state - > error = EBADF ;
goto done ;
}
if ( soerr ! = 0 ) {
/* this is a fatal error, we cannot continue listening */
state - > error = soerr ;
goto done ;
}
2011-07-19 23:07:42 +04:00
ZERO_STRUCT ( addr ) ;
addrlen = sizeof ( addr ) ;
sd = accept ( ctx - > listen_fd , ( struct sockaddr * ) & addr , & addrlen ) ;
2011-05-04 02:55:25 +04:00
if ( sd = = - 1 ) {
2011-08-17 18:53:38 +04:00
state - > error = errno ;
DEBUG ( 6 , ( " Accept failed! (%d, %s) \n " ,
state - > error , strerror ( state - > error ) ) ) ;
2011-07-19 23:07:42 +04:00
goto done ;
2011-05-04 02:55:25 +04:00
}
2017-12-10 23:46:07 +03:00
smb_set_close_on_exec ( sd ) ;
2011-05-04 02:55:25 +04:00
state - > accept_fd = sd ;
2011-07-19 23:07:42 +04:00
ret = tsocket_address_bsd_from_sockaddr ( state ,
( struct sockaddr * ) ( void * ) & addr ,
addrlen , & state - > cli_addr ) ;
if ( ret < 0 ) {
state - > error = errno ;
goto done ;
}
ZERO_STRUCT ( addr ) ;
addrlen = sizeof ( addr ) ;
ret = getsockname ( sd , ( struct sockaddr * ) ( void * ) & addr , & addrlen ) ;
if ( ret < 0 ) {
state - > error = errno ;
goto done ;
}
ret = tsocket_address_bsd_from_sockaddr ( state ,
( struct sockaddr * ) ( void * ) & addr ,
addrlen , & state - > srv_addr ) ;
if ( ret < 0 ) {
state - > error = errno ;
goto done ;
}
done :
2011-08-17 18:53:38 +04:00
/* do not track the listen fds anymore */
talloc_free ( ctx - > fde_ctx ) ;
2011-05-04 02:55:25 +04:00
tevent_req_done ( req ) ;
}
2011-07-19 23:07:42 +04:00
int prefork_listen_recv ( struct tevent_req * req ,
TALLOC_CTX * mem_ctx , int * fd ,
struct tsocket_address * * srv_addr ,
struct tsocket_address * * cli_addr )
2011-05-04 02:55:25 +04:00
{
struct pf_listen_state * state ;
2011-07-19 23:07:42 +04:00
int ret = 0 ;
2011-05-04 02:55:25 +04:00
state = tevent_req_data ( req , struct pf_listen_state ) ;
2011-07-19 23:07:42 +04:00
if ( state - > error ) {
ret = state - > error ;
} else {
2012-12-13 17:18:02 +04:00
if ( ! tevent_req_is_unix_error ( req , & ret ) ) {
ret = 0 ;
}
2011-07-19 23:07:42 +04:00
}
if ( ret ) {
2011-05-04 02:55:25 +04:00
if ( state - > accept_fd ! = - 1 ) {
close ( state - > accept_fd ) ;
}
} else {
* fd = state - > accept_fd ;
2011-07-19 23:07:42 +04:00
* srv_addr = talloc_move ( mem_ctx , & state - > srv_addr ) ;
* cli_addr = talloc_move ( mem_ctx , & state - > cli_addr ) ;
2011-05-04 02:55:25 +04:00
state - > pf - > num_clients + + ;
}
2011-08-16 19:37:41 +04:00
if ( state - > pf - > status = = PF_WORKER_ACCEPTING ) {
state - > pf - > status = PF_WORKER_ALIVE ;
}
2011-05-04 02:55:25 +04:00
tevent_req_received ( req ) ;
return ret ;
}