2016-09-03 16:27:23 +03:00
/*
A server based on unix domain socket
Copyright ( C ) Amitay Isaacs 2016
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 "replace.h"
# include "system/filesys.h"
# include "system/network.h"
# include "system/wait.h"
# include <talloc.h>
# include <tevent.h>
# include "lib/async_req/async_sock.h"
# include "lib/util/debug.h"
# include "lib/util/blocking.h"
# include "lib/util/dlinklist.h"
# include "lib/util/tevent_unix.h"
2017-08-16 06:52:08 +03:00
# include "lib/util/become_daemon.h"
2018-08-24 07:44:12 +03:00
# include "lib/util/sys_rw.h"
2016-09-03 16:27:23 +03:00
# include "common/logging.h"
# include "common/reqid.h"
# include "common/comm.h"
# include "common/pidfile.h"
2018-02-06 08:42:39 +03:00
# include "common/system.h"
2016-09-03 16:27:23 +03:00
# include "common/sock_daemon.h"
struct sock_socket {
struct sock_socket * prev , * next ;
const char * sockpath ;
struct sock_socket_funcs * funcs ;
void * private_data ;
int fd ;
struct tevent_req * req ;
} ;
struct sock_client {
struct sock_client * prev , * next ;
struct tevent_req * req ;
struct sock_client_context * client_ctx ;
} ;
struct sock_client_context {
struct tevent_context * ev ;
struct sock_socket * sock ;
int fd ;
struct comm_context * comm ;
struct sock_client * client ;
} ;
struct sock_daemon_context {
struct sock_daemon_funcs * funcs ;
void * private_data ;
struct pidfile_context * pid_ctx ;
struct sock_socket * socket_list ;
2018-08-24 07:44:12 +03:00
int startup_fd ;
2016-09-03 16:27:23 +03:00
} ;
/*
* Process a single client
*/
static void sock_client_read_handler ( uint8_t * buf , size_t buflen ,
void * private_data ) ;
static void sock_client_read_done ( struct tevent_req * subreq ) ;
static void sock_client_dead_handler ( void * private_data ) ;
static int sock_client_context_destructor (
struct sock_client_context * client_ctx ) ;
static int sock_client_context_init ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct sock_socket * sock ,
int client_fd ,
struct sock_client * client ,
struct sock_client_context * * result )
{
struct sock_client_context * client_ctx ;
int ret ;
client_ctx = talloc_zero ( mem_ctx , struct sock_client_context ) ;
if ( client_ctx = = NULL ) {
return ENOMEM ;
}
client_ctx - > ev = ev ;
client_ctx - > sock = sock ;
client_ctx - > fd = client_fd ;
client_ctx - > client = client ;
ret = comm_setup ( client_ctx , ev , client_fd ,
sock_client_read_handler , client_ctx ,
sock_client_dead_handler , client_ctx ,
& client_ctx - > comm ) ;
if ( ret ! = 0 ) {
talloc_free ( client_ctx ) ;
return ret ;
}
if ( sock - > funcs - > connect ! = NULL ) {
2018-02-06 08:42:39 +03:00
pid_t pid ;
2016-09-03 16:27:23 +03:00
bool status ;
2018-02-06 08:42:39 +03:00
( void ) ctdb_get_peer_pid ( client_fd , & pid ) ;
status = sock - > funcs - > connect ( client_ctx ,
pid ,
sock - > private_data ) ;
2016-09-03 16:27:23 +03:00
if ( ! status ) {
talloc_free ( client_ctx ) ;
close ( client_fd ) ;
return 0 ;
}
}
talloc_set_destructor ( client_ctx , sock_client_context_destructor ) ;
* result = client_ctx ;
return 0 ;
}
static void sock_client_read_handler ( uint8_t * buf , size_t buflen ,
void * private_data )
{
struct sock_client_context * client_ctx = talloc_get_type_abort (
private_data , struct sock_client_context ) ;
struct sock_socket * sock = client_ctx - > sock ;
struct tevent_req * subreq ;
subreq = sock - > funcs - > read_send ( client_ctx , client_ctx - > ev ,
client_ctx , buf , buflen ,
sock - > private_data ) ;
if ( subreq = = NULL ) {
talloc_free ( client_ctx ) ;
return ;
}
tevent_req_set_callback ( subreq , sock_client_read_done , client_ctx ) ;
}
static void sock_client_read_done ( struct tevent_req * subreq )
{
struct sock_client_context * client_ctx = tevent_req_callback_data (
subreq , struct sock_client_context ) ;
struct sock_socket * sock = client_ctx - > sock ;
int ret ;
bool status ;
status = sock - > funcs - > read_recv ( subreq , & ret ) ;
if ( ! status ) {
D_ERR ( " client read failed with ret=%d \n " , ret ) ;
talloc_free ( client_ctx ) ;
}
}
static void sock_client_dead_handler ( void * private_data )
{
struct sock_client_context * client_ctx = talloc_get_type_abort (
private_data , struct sock_client_context ) ;
struct sock_socket * sock = client_ctx - > sock ;
if ( sock - > funcs - > disconnect ! = NULL ) {
sock - > funcs - > disconnect ( client_ctx , sock - > private_data ) ;
}
talloc_free ( client_ctx ) ;
}
static int sock_client_context_destructor (
struct sock_client_context * client_ctx )
{
TALLOC_FREE ( client_ctx - > client ) ;
TALLOC_FREE ( client_ctx - > comm ) ;
if ( client_ctx - > fd ! = - 1 ) {
close ( client_ctx - > fd ) ;
client_ctx - > fd = - 1 ;
}
return 0 ;
}
/*
* Process a single listening socket
*/
static int socket_setup ( const char * sockpath , bool remove_before_use )
{
struct sockaddr_un addr ;
size_t len ;
int ret , fd ;
memset ( & addr , 0 , sizeof ( addr ) ) ;
addr . sun_family = AF_UNIX ;
len = strlcpy ( addr . sun_path , sockpath , sizeof ( addr . sun_path ) ) ;
if ( len > = sizeof ( addr . sun_path ) ) {
D_ERR ( " socket path too long: %s \n " , sockpath ) ;
return - 1 ;
}
fd = socket ( AF_UNIX , SOCK_STREAM , 0 ) ;
if ( fd = = - 1 ) {
D_ERR ( " socket create failed - %s \n " , sockpath ) ;
return - 1 ;
}
ret = set_blocking ( fd , false ) ;
if ( ret ! = 0 ) {
D_ERR ( " socket set nonblocking failed - %s \n " , sockpath ) ;
close ( fd ) ;
return - 1 ;
}
if ( remove_before_use ) {
unlink ( sockpath ) ;
}
ret = bind ( fd , ( struct sockaddr * ) & addr , sizeof ( addr ) ) ;
if ( ret ! = 0 ) {
D_ERR ( " socket bind failed - %s \n " , sockpath ) ;
close ( fd ) ;
return - 1 ;
}
ret = listen ( fd , 10 ) ;
if ( ret ! = 0 ) {
D_ERR ( " socket listen failed - %s \n " , sockpath ) ;
close ( fd ) ;
return - 1 ;
}
2017-11-03 08:00:04 +03:00
D_NOTICE ( " listening on %s \n " , sockpath ) ;
2016-09-03 16:27:23 +03:00
return fd ;
}
static int sock_socket_destructor ( struct sock_socket * sock ) ;
static int sock_socket_init ( TALLOC_CTX * mem_ctx , const char * sockpath ,
struct sock_socket_funcs * funcs ,
void * private_data ,
struct sock_socket * * result )
{
struct sock_socket * sock ;
if ( funcs = = NULL ) {
return EINVAL ;
}
if ( funcs - > read_send = = NULL | | funcs - > read_recv = = NULL ) {
return EINVAL ;
}
sock = talloc_zero ( mem_ctx , struct sock_socket ) ;
if ( sock = = NULL ) {
return ENOMEM ;
}
2017-11-17 04:31:16 +03:00
sock - > sockpath = talloc_strdup ( sock , sockpath ) ;
if ( sock - > sockpath = = NULL ) {
talloc_free ( sock ) ;
return ENOMEM ;
}
2016-09-03 16:27:23 +03:00
sock - > funcs = funcs ;
sock - > private_data = private_data ;
2017-11-03 08:00:04 +03:00
sock - > fd = - 1 ;
2016-09-03 16:27:23 +03:00
talloc_set_destructor ( sock , sock_socket_destructor ) ;
* result = sock ;
return 0 ;
}
static int sock_socket_destructor ( struct sock_socket * sock )
{
2017-11-20 03:52:55 +03:00
TALLOC_FREE ( sock - > req ) ;
2016-12-27 13:47:10 +03:00
if ( sock - > fd ! = - 1 ) {
2016-09-03 16:27:23 +03:00
close ( sock - > fd ) ;
sock - > fd = - 1 ;
}
unlink ( sock - > sockpath ) ;
return 0 ;
}
struct sock_socket_start_state {
struct tevent_context * ev ;
struct sock_socket * sock ;
struct sock_client * client_list ;
} ;
static int sock_socket_start_state_destructor (
struct sock_socket_start_state * state ) ;
static void sock_socket_start_new_client ( struct tevent_req * subreq ) ;
static int sock_socket_start_client_destructor ( struct sock_client * client ) ;
static struct tevent_req * sock_socket_start_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
2017-11-03 08:00:04 +03:00
struct sock_socket * sock ,
bool remove_before_use )
2016-09-03 16:27:23 +03:00
{
struct tevent_req * req , * subreq ;
struct sock_socket_start_state * state ;
req = tevent_req_create ( mem_ctx , & state ,
struct sock_socket_start_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > ev = ev ;
state - > sock = sock ;
2017-11-03 08:00:04 +03:00
sock - > fd = socket_setup ( sock - > sockpath , remove_before_use ) ;
if ( sock - > fd = = - 1 ) {
tevent_req_error ( req , EIO ) ;
return tevent_req_post ( req , ev ) ;
}
2016-09-03 16:27:23 +03:00
talloc_set_destructor ( state , sock_socket_start_state_destructor ) ;
subreq = accept_send ( state , ev , sock - > fd ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , sock_socket_start_new_client , req ) ;
2017-11-20 03:52:55 +03:00
sock - > req = req ;
2016-09-03 16:27:23 +03:00
return req ;
}
static int sock_socket_start_state_destructor (
struct sock_socket_start_state * state )
{
struct sock_client * client ;
while ( ( client = state - > client_list ) ! = NULL ) {
talloc_free ( client ) ;
}
return 0 ;
}
static void sock_socket_start_new_client ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct sock_socket_start_state * state = tevent_req_data (
req , struct sock_socket_start_state ) ;
struct sock_client * client ;
int client_fd , ret ;
client_fd = accept_recv ( subreq , NULL , NULL , & ret ) ;
TALLOC_FREE ( subreq ) ;
if ( client_fd = = - 1 ) {
D_ERR ( " failed to accept new connection \n " ) ;
}
subreq = accept_send ( state , state - > ev , state - > sock - > fd ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , sock_socket_start_new_client , req ) ;
if ( client_fd = = - 1 ) {
return ;
}
client = talloc_zero ( state , struct sock_client ) ;
if ( tevent_req_nomem ( client , req ) ) {
close ( client_fd ) ;
return ;
}
client - > req = req ;
ret = sock_client_context_init ( client , state - > ev , state - > sock ,
client_fd , client , & client - > client_ctx ) ;
if ( ret ! = 0 ) {
talloc_free ( client ) ;
return ;
}
talloc_set_destructor ( client , sock_socket_start_client_destructor ) ;
DLIST_ADD ( state - > client_list , client ) ;
}
static int sock_socket_start_client_destructor ( struct sock_client * client )
{
struct sock_socket_start_state * state = tevent_req_data (
client - > req , struct sock_socket_start_state ) ;
DLIST_REMOVE ( state - > client_list , client ) ;
TALLOC_FREE ( client - > client_ctx ) ;
return 0 ;
}
2017-11-17 04:31:16 +03:00
static bool sock_socket_start_recv ( struct tevent_req * req , int * perr ,
TALLOC_CTX * mem_ctx , const char * * sockpath )
2016-09-03 16:27:23 +03:00
{
struct sock_socket_start_state * state = tevent_req_data (
req , struct sock_socket_start_state ) ;
int ret ;
state - > sock - > req = NULL ;
if ( tevent_req_is_unix_error ( req , & ret ) ) {
if ( perr ! = NULL ) {
* perr = ret ;
}
return false ;
}
2017-11-17 04:31:16 +03:00
if ( sockpath ! = NULL ) {
* sockpath = talloc_steal ( mem_ctx , state - > sock - > sockpath ) ;
}
2016-09-03 16:27:23 +03:00
return true ;
}
/*
* Send message to a client
*/
struct tevent_req * sock_socket_write_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct sock_client_context * client_ctx ,
uint8_t * buf , size_t buflen )
{
2017-01-04 08:20:17 +03:00
struct tevent_req * req ;
2016-09-03 16:27:23 +03:00
2017-01-04 08:20:17 +03:00
req = comm_write_send ( mem_ctx , ev , client_ctx - > comm , buf , buflen ) ;
2016-09-03 16:27:23 +03:00
return req ;
}
2017-01-04 08:20:17 +03:00
bool sock_socket_write_recv ( struct tevent_req * req , int * perr )
2016-09-03 16:27:23 +03:00
{
int ret ;
bool status ;
2017-01-04 08:20:17 +03:00
status = comm_write_recv ( req , & ret ) ;
2016-09-03 16:27:23 +03:00
if ( ! status ) {
if ( perr ! = NULL ) {
* perr = ret ;
}
}
2017-01-04 08:20:17 +03:00
return status ;
2016-09-03 16:27:23 +03:00
}
2017-01-04 08:20:17 +03:00
2016-09-03 16:27:23 +03:00
/*
* Socket daemon
*/
int sock_daemon_setup ( TALLOC_CTX * mem_ctx , const char * daemon_name ,
const char * logging , const char * debug_level ,
struct sock_daemon_funcs * funcs ,
void * private_data ,
struct sock_daemon_context * * out )
{
struct sock_daemon_context * sockd ;
int ret ;
sockd = talloc_zero ( mem_ctx , struct sock_daemon_context ) ;
if ( sockd = = NULL ) {
return ENOMEM ;
}
sockd - > funcs = funcs ;
sockd - > private_data = private_data ;
2018-08-24 07:44:12 +03:00
sockd - > startup_fd = - 1 ;
2016-09-03 16:27:23 +03:00
ret = logging_init ( sockd , logging , debug_level , daemon_name ) ;
if ( ret ! = 0 ) {
fprintf ( stderr ,
" Failed to initialize logging, logging=%s, debug=%s \n " ,
logging , debug_level ) ;
return ret ;
}
* out = sockd ;
return 0 ;
}
int sock_daemon_add_unix ( struct sock_daemon_context * sockd ,
const char * sockpath ,
struct sock_socket_funcs * funcs ,
void * private_data )
{
struct sock_socket * sock ;
int ret ;
2017-11-03 08:00:04 +03:00
ret = sock_socket_init ( sockd , sockpath , funcs , private_data , & sock ) ;
2016-09-03 16:27:23 +03:00
if ( ret ! = 0 ) {
return ret ;
}
DLIST_ADD ( sockd - > socket_list , sock ) ;
return 0 ;
}
2018-08-24 07:44:12 +03:00
void sock_daemon_set_startup_fd ( struct sock_daemon_context * sockd , int fd )
{
sockd - > startup_fd = fd ;
}
2016-09-03 16:27:23 +03:00
/*
* Run socket daemon
*/
2017-01-11 11:50:34 +03:00
struct sock_daemon_run_state {
2016-09-03 16:27:23 +03:00
struct tevent_context * ev ;
struct sock_daemon_context * sockd ;
pid_t pid_watch ;
int fd ;
2017-11-17 04:38:47 +03:00
int exit_code ;
2016-09-03 16:27:23 +03:00
} ;
2017-01-13 02:40:43 +03:00
static void sock_daemon_run_started ( struct tevent_req * subreq ) ;
2017-11-17 04:36:29 +03:00
static void sock_daemon_run_startup_done ( struct tevent_req * subreq ) ;
2017-01-13 02:40:43 +03:00
static void sock_daemon_run_signal_handler ( struct tevent_context * ev ,
struct tevent_signal * se ,
int signum , int count , void * siginfo ,
void * private_data ) ;
2017-01-13 02:43:44 +03:00
static void sock_daemon_run_reconfigure ( struct tevent_req * req ) ;
2017-11-17 04:38:18 +03:00
static void sock_daemon_run_reconfigure_done ( struct tevent_req * subreq ) ;
2017-01-13 02:43:44 +03:00
static void sock_daemon_run_shutdown ( struct tevent_req * req ) ;
2017-11-17 04:38:47 +03:00
static void sock_daemon_run_shutdown_done ( struct tevent_req * subreq ) ;
static void sock_daemon_run_exit ( struct tevent_req * req ) ;
2017-11-10 04:15:45 +03:00
static bool sock_daemon_run_socket_listen ( struct tevent_req * req ) ;
2017-01-13 02:40:43 +03:00
static void sock_daemon_run_socket_fail ( struct tevent_req * subreq ) ;
static void sock_daemon_run_watch_pid ( struct tevent_req * subreq ) ;
2017-11-17 02:52:57 +03:00
static void sock_daemon_run_wait ( struct tevent_req * req ) ;
2017-01-11 12:37:00 +03:00
static void sock_daemon_run_wait_done ( struct tevent_req * subreq ) ;
2018-08-24 07:44:12 +03:00
static void sock_daemon_startup_notify ( struct sock_daemon_context * sockd ) ;
2016-09-03 16:27:23 +03:00
struct tevent_req * sock_daemon_run_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct sock_daemon_context * sockd ,
2017-08-28 11:39:40 +03:00
const char * pidfile ,
2017-08-16 06:52:08 +03:00
bool do_fork , bool create_session ,
2016-09-03 16:27:23 +03:00
pid_t pid_watch )
{
struct tevent_req * req , * subreq ;
2017-01-11 11:50:34 +03:00
struct sock_daemon_run_state * state ;
2016-09-03 16:27:23 +03:00
struct tevent_signal * se ;
req = tevent_req_create ( mem_ctx , & state ,
2017-01-11 11:50:34 +03:00
struct sock_daemon_run_state ) ;
2016-09-03 16:27:23 +03:00
if ( req = = NULL ) {
return NULL ;
}
2017-08-16 06:52:08 +03:00
become_daemon ( do_fork , ! create_session , false ) ;
2017-08-28 11:39:40 +03:00
if ( pidfile ! = NULL ) {
int ret = pidfile_context_create ( sockd , pidfile ,
& sockd - > pid_ctx ) ;
if ( ret ! = 0 ) {
tevent_req_error ( req , EEXIST ) ;
return tevent_req_post ( req , ev ) ;
}
}
2016-09-03 16:27:23 +03:00
state - > ev = ev ;
state - > sockd = sockd ;
state - > pid_watch = pid_watch ;
state - > fd = - 1 ;
subreq = tevent_wakeup_send ( state , ev ,
tevent_timeval_current_ofs ( 0 , 0 ) ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
2017-01-13 02:40:43 +03:00
tevent_req_set_callback ( subreq , sock_daemon_run_started , req ) ;
2016-09-03 16:27:23 +03:00
se = tevent_add_signal ( ev , state , SIGHUP , 0 ,
2017-01-13 02:40:43 +03:00
sock_daemon_run_signal_handler , req ) ;
2016-09-03 16:27:23 +03:00
if ( tevent_req_nomem ( se , req ) ) {
return tevent_req_post ( req , ev ) ;
}
se = tevent_add_signal ( ev , state , SIGUSR1 , 0 ,
2017-01-13 02:40:43 +03:00
sock_daemon_run_signal_handler , req ) ;
2016-09-03 16:27:23 +03:00
if ( tevent_req_nomem ( se , req ) ) {
return tevent_req_post ( req , ev ) ;
}
se = tevent_add_signal ( ev , state , SIGINT , 0 ,
2017-01-13 02:40:43 +03:00
sock_daemon_run_signal_handler , req ) ;
2016-09-03 16:27:23 +03:00
if ( tevent_req_nomem ( se , req ) ) {
return tevent_req_post ( req , ev ) ;
}
se = tevent_add_signal ( ev , state , SIGTERM , 0 ,
2017-01-13 02:40:43 +03:00
sock_daemon_run_signal_handler , req ) ;
2016-09-03 16:27:23 +03:00
if ( tevent_req_nomem ( se , req ) ) {
return tevent_req_post ( req , ev ) ;
}
if ( pid_watch > 1 ) {
subreq = tevent_wakeup_send ( state , ev ,
tevent_timeval_current_ofs ( 1 , 0 ) ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
2017-01-13 02:40:43 +03:00
tevent_req_set_callback ( subreq , sock_daemon_run_watch_pid ,
req ) ;
2016-09-03 16:27:23 +03:00
}
return req ;
}
2017-01-13 02:40:43 +03:00
static void sock_daemon_run_started ( struct tevent_req * subreq )
2016-09-03 16:27:23 +03:00
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
2017-01-11 11:50:34 +03:00
struct sock_daemon_run_state * state = tevent_req_data (
req , struct sock_daemon_run_state ) ;
2016-09-03 16:27:23 +03:00
struct sock_daemon_context * sockd = state - > sockd ;
2017-11-10 04:18:01 +03:00
bool status ;
status = tevent_wakeup_recv ( subreq ) ;
TALLOC_FREE ( subreq ) ;
if ( ! status ) {
tevent_req_error ( req , EIO ) ;
return ;
}
2016-09-03 16:27:23 +03:00
D_NOTICE ( " daemon started, pid=%u \n " , getpid ( ) ) ;
2017-11-17 04:36:29 +03:00
if ( sockd - > funcs ! = NULL & & sockd - > funcs - > startup_send ! = NULL & &
sockd - > funcs - > startup_recv ! = NULL ) {
subreq = sockd - > funcs - > startup_send ( state , state - > ev ,
sockd - > private_data ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , sock_daemon_run_startup_done ,
req ) ;
return ;
}
2016-09-03 16:27:23 +03:00
if ( sockd - > funcs ! = NULL & & sockd - > funcs - > startup ! = NULL ) {
2017-11-10 04:10:05 +03:00
int ret ;
ret = sockd - > funcs - > startup ( sockd - > private_data ) ;
if ( ret ! = 0 ) {
D_ERR ( " startup failed, ret=%d \n " , ret ) ;
tevent_req_error ( req , EIO ) ;
return ;
}
D_NOTICE ( " startup completed successfully \n " ) ;
2016-09-03 16:27:23 +03:00
}
2017-11-17 02:52:57 +03:00
2017-11-10 04:15:45 +03:00
status = sock_daemon_run_socket_listen ( req ) ;
if ( ! status ) {
return ;
}
2017-11-17 02:52:57 +03:00
sock_daemon_run_wait ( req ) ;
2018-08-24 07:44:12 +03:00
sock_daemon_startup_notify ( sockd ) ;
2016-09-03 16:27:23 +03:00
}
2017-11-17 04:36:29 +03:00
static void sock_daemon_run_startup_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct sock_daemon_run_state * state = tevent_req_data (
req , struct sock_daemon_run_state ) ;
struct sock_daemon_context * sockd = state - > sockd ;
int ret ;
bool status ;
status = sockd - > funcs - > startup_recv ( subreq , & ret ) ;
TALLOC_FREE ( subreq ) ;
if ( ! status ) {
D_ERR ( " startup failed, ret=%d \n " , ret ) ;
tevent_req_error ( req , EIO ) ;
return ;
}
2018-05-04 23:24:00 +03:00
D_NOTICE ( " startup completed successfully \n " ) ;
2017-11-17 04:36:29 +03:00
status = sock_daemon_run_socket_listen ( req ) ;
if ( ! status ) {
return ;
}
sock_daemon_run_wait ( req ) ;
2018-08-24 07:44:12 +03:00
sock_daemon_startup_notify ( sockd ) ;
2017-11-17 04:36:29 +03:00
}
2017-01-13 02:40:43 +03:00
static void sock_daemon_run_signal_handler ( struct tevent_context * ev ,
struct tevent_signal * se ,
int signum , int count , void * siginfo ,
void * private_data )
2016-09-03 16:27:23 +03:00
{
struct tevent_req * req = talloc_get_type_abort (
private_data , struct tevent_req ) ;
2017-11-17 04:38:47 +03:00
struct sock_daemon_run_state * state = tevent_req_data (
req , struct sock_daemon_run_state ) ;
2016-09-03 16:27:23 +03:00
D_NOTICE ( " Received signal %d \n " , signum ) ;
if ( signum = = SIGHUP | | signum = = SIGUSR1 ) {
2017-01-13 02:43:44 +03:00
sock_daemon_run_reconfigure ( req ) ;
2016-09-03 16:27:23 +03:00
return ;
}
if ( signum = = SIGINT | | signum = = SIGTERM ) {
2017-11-17 04:38:47 +03:00
state - > exit_code = EINTR ;
2017-01-13 02:43:44 +03:00
sock_daemon_run_shutdown ( req ) ;
2016-09-03 16:27:23 +03:00
}
}
2017-01-13 02:43:44 +03:00
static void sock_daemon_run_reconfigure ( struct tevent_req * req )
2016-09-03 16:27:23 +03:00
{
2017-11-17 04:38:18 +03:00
struct tevent_req * subreq ;
2017-01-13 02:43:44 +03:00
struct sock_daemon_run_state * state = tevent_req_data (
req , struct sock_daemon_run_state ) ;
2016-09-03 16:27:23 +03:00
struct sock_daemon_context * sockd = state - > sockd ;
2017-11-17 04:38:18 +03:00
if ( sockd - > funcs ! = NULL & & sockd - > funcs - > reconfigure_send ! = NULL & &
sockd - > funcs - > reconfigure_recv ! = NULL ) {
subreq = sockd - > funcs - > reconfigure_send ( state , state - > ev ,
sockd - > private_data ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq ,
sock_daemon_run_reconfigure_done , req ) ;
return ;
}
2016-09-03 16:27:23 +03:00
if ( sockd - > funcs ! = NULL & & sockd - > funcs - > reconfigure ! = NULL ) {
2017-11-10 04:10:05 +03:00
int ret ;
ret = sockd - > funcs - > reconfigure ( sockd - > private_data ) ;
if ( ret ! = 0 ) {
D_ERR ( " reconfigure failed, ret=%d \n " , ret ) ;
return ;
}
D_NOTICE ( " reconfigure completed successfully \n " ) ;
2016-09-03 16:27:23 +03:00
}
}
2017-11-17 04:38:18 +03:00
static void sock_daemon_run_reconfigure_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct sock_daemon_run_state * state = tevent_req_data (
req , struct sock_daemon_run_state ) ;
struct sock_daemon_context * sockd = state - > sockd ;
int ret ;
bool status ;
status = sockd - > funcs - > reconfigure_recv ( subreq , & ret ) ;
TALLOC_FREE ( subreq ) ;
if ( ! status ) {
D_ERR ( " reconfigure failed, ret=%d \n " , ret ) ;
return ;
}
D_NOTICE ( " reconfigure completed successfully \n " ) ;
}
2017-01-13 02:43:44 +03:00
static void sock_daemon_run_shutdown ( struct tevent_req * req )
2016-09-03 16:27:23 +03:00
{
2017-11-17 04:38:47 +03:00
struct tevent_req * subreq ;
2017-01-13 02:43:44 +03:00
struct sock_daemon_run_state * state = tevent_req_data (
req , struct sock_daemon_run_state ) ;
2016-09-03 16:27:23 +03:00
struct sock_daemon_context * sockd = state - > sockd ;
struct sock_socket * sock ;
D_NOTICE ( " Shutting down \n " ) ;
while ( ( sock = sockd - > socket_list ) ! = NULL ) {
DLIST_REMOVE ( sockd - > socket_list , sock ) ;
TALLOC_FREE ( sock ) ;
}
2017-11-17 04:38:47 +03:00
if ( sockd - > funcs ! = NULL & & sockd - > funcs - > shutdown_send ! = NULL & &
sockd - > funcs - > shutdown_recv ! = NULL ) {
subreq = sockd - > funcs - > shutdown_send ( state , state - > ev ,
sockd - > private_data ) ;
if ( subreq = = NULL ) {
sock_daemon_run_exit ( req ) ;
return ;
}
tevent_req_set_callback ( subreq , sock_daemon_run_shutdown_done ,
req ) ;
return ;
}
2016-09-03 16:27:23 +03:00
if ( sockd - > funcs ! = NULL & & sockd - > funcs - > shutdown ! = NULL ) {
sockd - > funcs - > shutdown ( sockd - > private_data ) ;
}
2017-11-17 04:38:47 +03:00
sock_daemon_run_exit ( req ) ;
}
static void sock_daemon_run_shutdown_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct sock_daemon_run_state * state = tevent_req_data (
req , struct sock_daemon_run_state ) ;
struct sock_daemon_context * sockd = state - > sockd ;
sockd - > funcs - > shutdown_recv ( subreq ) ;
TALLOC_FREE ( subreq ) ;
sock_daemon_run_exit ( req ) ;
}
static void sock_daemon_run_exit ( struct tevent_req * req )
{
struct sock_daemon_run_state * state = tevent_req_data (
req , struct sock_daemon_run_state ) ;
struct sock_daemon_context * sockd = state - > sockd ;
2016-09-03 16:27:23 +03:00
TALLOC_FREE ( sockd - > pid_ctx ) ;
2017-11-17 04:38:47 +03:00
if ( state - > exit_code = = 0 ) {
tevent_req_done ( req ) ;
} else {
tevent_req_error ( req , state - > exit_code ) ;
}
2016-09-03 16:27:23 +03:00
}
2017-11-10 04:15:45 +03:00
static bool sock_daemon_run_socket_listen ( struct tevent_req * req )
{
struct tevent_req * subreq ;
struct sock_daemon_run_state * state = tevent_req_data (
req , struct sock_daemon_run_state ) ;
struct sock_daemon_context * sockd = state - > sockd ;
struct sock_socket * sock ;
bool remove_before_use = false ;
if ( sockd - > pid_ctx ! = NULL ) {
remove_before_use = true ;
}
for ( sock = sockd - > socket_list ; sock ! = NULL ; sock = sock - > next ) {
subreq = sock_socket_start_send ( state , state - > ev , sock ,
remove_before_use ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return false ;
}
tevent_req_set_callback ( subreq , sock_daemon_run_socket_fail ,
req ) ;
}
return true ;
}
2017-01-13 02:40:43 +03:00
static void sock_daemon_run_socket_fail ( struct tevent_req * subreq )
2016-09-03 16:27:23 +03:00
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
2017-11-17 04:31:16 +03:00
struct sock_daemon_run_state * state = tevent_req_data (
req , struct sock_daemon_run_state ) ;
const char * sockpath = NULL ;
2016-09-03 16:27:23 +03:00
int ret = 0 ;
bool status ;
2017-11-17 04:31:16 +03:00
status = sock_socket_start_recv ( subreq , & ret , state , & sockpath ) ;
2016-09-03 16:27:23 +03:00
TALLOC_FREE ( subreq ) ;
if ( ! status ) {
2017-11-17 04:31:16 +03:00
D_ERR ( " socket %s closed unexpectedly \n " , sockpath ) ;
2017-11-17 04:38:47 +03:00
state - > exit_code = ret ;
2016-09-03 16:27:23 +03:00
} else {
2017-11-17 04:38:47 +03:00
state - > exit_code = 0 ;
2016-09-03 16:27:23 +03:00
}
2017-11-17 04:38:47 +03:00
sock_daemon_run_shutdown ( req ) ;
2016-09-03 16:27:23 +03:00
}
2017-01-13 02:40:43 +03:00
static void sock_daemon_run_watch_pid ( struct tevent_req * subreq )
2016-09-03 16:27:23 +03:00
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
2017-01-11 11:50:34 +03:00
struct sock_daemon_run_state * state = tevent_req_data (
req , struct sock_daemon_run_state ) ;
2016-09-03 16:27:23 +03:00
int ret ;
bool status ;
status = tevent_wakeup_recv ( subreq ) ;
TALLOC_FREE ( subreq ) ;
if ( ! status ) {
tevent_req_error ( req , EIO ) ;
return ;
}
ret = kill ( state - > pid_watch , 0 ) ;
if ( ret = = - 1 ) {
if ( errno = = ESRCH ) {
D_ERR ( " PID %d gone away, exiting \n " , state - > pid_watch ) ;
2017-11-17 04:38:47 +03:00
state - > exit_code = ESRCH ;
2017-01-13 02:43:44 +03:00
sock_daemon_run_shutdown ( req ) ;
2016-09-03 16:27:23 +03:00
return ;
} else {
D_ERR ( " Failed to check PID status %d, ret=%d \n " ,
state - > pid_watch , errno ) ;
}
}
subreq = tevent_wakeup_send ( state , state - > ev ,
tevent_timeval_current_ofs ( 5 , 0 ) ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
2017-01-13 02:40:43 +03:00
tevent_req_set_callback ( subreq , sock_daemon_run_watch_pid , req ) ;
2016-09-03 16:27:23 +03:00
}
2017-11-17 02:52:57 +03:00
static void sock_daemon_run_wait ( struct tevent_req * req )
{
struct tevent_req * subreq ;
struct sock_daemon_run_state * state = tevent_req_data (
req , struct sock_daemon_run_state ) ;
struct sock_daemon_context * sockd = state - > sockd ;
if ( sockd - > funcs ! = NULL & & sockd - > funcs - > wait_send ! = NULL & &
sockd - > funcs - > wait_recv ! = NULL ) {
subreq = sockd - > funcs - > wait_send ( state , state - > ev ,
sockd - > private_data ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , sock_daemon_run_wait_done ,
req ) ;
}
}
2017-01-11 12:37:00 +03:00
static void sock_daemon_run_wait_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct sock_daemon_run_state * state = tevent_req_data (
req , struct sock_daemon_run_state ) ;
struct sock_daemon_context * sockd = state - > sockd ;
2017-11-17 04:38:47 +03:00
int ret = 0 ;
2017-01-11 12:37:00 +03:00
bool status ;
status = sockd - > funcs - > wait_recv ( subreq , & ret ) ;
TALLOC_FREE ( subreq ) ;
if ( ! status ) {
2017-11-17 04:38:47 +03:00
state - > exit_code = ret ;
2017-01-11 12:37:00 +03:00
} else {
2017-11-17 04:38:47 +03:00
state - > exit_code = 0 ;
2017-01-11 12:37:00 +03:00
}
2017-11-17 04:38:47 +03:00
sock_daemon_run_shutdown ( req ) ;
2017-01-11 12:37:00 +03:00
}
2018-08-24 07:44:12 +03:00
static void sock_daemon_startup_notify ( struct sock_daemon_context * sockd )
{
if ( sockd - > startup_fd ! = - 1 ) {
unsigned int zero = 0 ;
ssize_t num ;
num = sys_write ( sockd - > startup_fd , & zero , sizeof ( zero ) ) ;
if ( num ! = sizeof ( zero ) ) {
D_WARNING ( " Failed to write zero to pipe FD \n " ) ;
}
}
}
2016-09-03 16:27:23 +03:00
bool sock_daemon_run_recv ( struct tevent_req * req , int * perr )
{
int ret ;
if ( tevent_req_is_unix_error ( req , & ret ) ) {
if ( perr ! = NULL ) {
* perr = ret ;
}
return false ;
}
return true ;
}
int sock_daemon_run ( struct tevent_context * ev ,
struct sock_daemon_context * sockd ,
2017-08-28 11:39:40 +03:00
const char * pidfile ,
2017-08-16 06:52:08 +03:00
bool do_fork , bool create_session ,
2016-09-03 16:27:23 +03:00
pid_t pid_watch )
{
struct tevent_req * req ;
int ret ;
bool status ;
2017-08-16 06:52:08 +03:00
req = sock_daemon_run_send ( ev , ev , sockd ,
pidfile , do_fork , create_session , pid_watch ) ;
2016-09-03 16:27:23 +03:00
if ( req = = NULL ) {
return ENOMEM ;
}
tevent_req_poll ( req , ev ) ;
status = sock_daemon_run_recv ( req , & ret ) ;
TALLOC_FREE ( req ) ;
if ( ! status ) {
return ret ;
}
return 0 ;
}