2007-04-10 00:03:39 +04:00
/*
ctdb daemon code
Copyright ( C ) Andrew Tridgell 2006
This library is free software ; you can redistribute it and / or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation ; either
version 2 of the License , or ( at your option ) any later version .
This library 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
Lesser General Public License for more details .
You should have received a copy of the GNU Lesser General Public
License along with this library ; if not , write to the Free Software
Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# include "includes.h"
# include "db_wrap.h"
# include "lib/tdb/include/tdb.h"
# include "lib/events/events.h"
# include "lib/util/dlinklist.h"
# include "system/network.h"
# include "system/filesys.h"
2007-04-17 09:33:20 +04:00
# include "system/wait.h"
2007-04-10 00:03:39 +04:00
# include "../include/ctdb.h"
# include "../include/ctdb_private.h"
2007-04-19 10:27:56 +04:00
/*
structure describing a connected client in the daemon
*/
struct ctdb_client {
struct ctdb_context * ctdb ;
int fd ;
struct ctdb_queue * queue ;
} ;
static void daemon_incoming_packet ( void * , uint8_t * , uint32_t ) ;
2007-04-10 00:03:39 +04:00
static void ctdb_main_loop ( struct ctdb_context * ctdb )
{
2007-04-26 17:28:13 +04:00
int ret = - 1 ;
if ( strcmp ( ctdb - > transport , " tcp " ) = = 0 ) {
int ctdb_tcp_init ( struct ctdb_context * ) ;
ret = ctdb_tcp_init ( ctdb ) ;
}
2007-04-26 17:33:17 +04:00
# ifdef USE_INFINIBAND
2007-04-26 17:28:13 +04:00
if ( strcmp ( ctdb - > transport , " ib " ) = = 0 ) {
int ctdb_ibw_init ( struct ctdb_context * ) ;
ret = ctdb_ibw_init ( ctdb ) ;
}
# endif
if ( ret ! = 0 ) {
DEBUG ( 0 , ( " Failed to initialise transport '%s' \n " , ctdb - > transport ) ) ;
return ;
2007-04-20 16:26:19 +04:00
}
2007-04-26 17:28:13 +04:00
/* start the transport running */
2007-04-10 00:03:39 +04:00
ctdb - > methods - > start ( ctdb ) ;
/* go into a wait loop to allow other nodes to complete */
event_loop_wait ( ctdb - > ev ) ;
2007-04-17 16:27:17 +04:00
DEBUG ( 0 , ( " event_loop_wait() returned. this should not happen \n " ) ) ;
2007-04-10 00:03:39 +04:00
exit ( 1 ) ;
}
static void set_non_blocking ( int fd )
{
unsigned v ;
v = fcntl ( fd , F_GETFL , 0 ) ;
fcntl ( fd , F_SETFL , v | O_NONBLOCK ) ;
}
2007-04-17 09:33:20 +04:00
static void block_signal ( int signum )
{
struct sigaction act ;
memset ( & act , 0 , sizeof ( act ) ) ;
act . sa_handler = SIG_IGN ;
sigemptyset ( & act . sa_mask ) ;
sigaddset ( & act . sa_mask , signum ) ;
sigaction ( signum , & act , NULL ) ;
}
2007-04-10 00:03:39 +04:00
2007-04-20 14:07:47 +04:00
/*
send a packet to a client
*/
static int daemon_queue_send ( struct ctdb_client * client , struct ctdb_req_header * hdr )
{
client - > ctdb - > status . client_packets_sent + + ;
return ctdb_queue_send ( client - > queue , ( uint8_t * ) hdr , hdr - > length ) ;
}
2007-04-11 05:58:28 +04:00
/*
message handler for when we are in daemon mode . This redirects the message
to the right client
*/
2007-04-27 18:31:45 +04:00
static void daemon_message_handler ( struct ctdb_context * ctdb , uint64_t srvid ,
2007-04-13 14:38:24 +04:00
TDB_DATA data , void * private_data )
2007-04-11 05:58:28 +04:00
{
2007-04-13 14:38:24 +04:00
struct ctdb_client * client = talloc_get_type ( private_data , struct ctdb_client ) ;
2007-04-11 05:58:28 +04:00
struct ctdb_req_message * r ;
int len ;
/* construct a message to send to the client containing the data */
len = offsetof ( struct ctdb_req_message , data ) + data . dsize ;
2007-04-28 12:50:32 +04:00
r = ctdbd_allocate_pkt ( ctdb , ctdb , CTDB_REQ_MESSAGE ,
len , struct ctdb_req_message ) ;
CTDB_NO_MEMORY_VOID ( ctdb , r ) ;
2007-04-11 07:43:15 +04:00
2007-04-11 05:58:28 +04:00
talloc_set_name_const ( r , " req_message packet " ) ;
r - > srvid = srvid ;
r - > datalen = data . dsize ;
memcpy ( & r - > data [ 0 ] , data . dptr , data . dsize ) ;
2007-04-17 04:15:44 +04:00
2007-04-20 14:07:47 +04:00
daemon_queue_send ( client , & r - > hdr ) ;
2007-04-11 05:58:28 +04:00
talloc_free ( r ) ;
}
/*
this is called when the ctdb daemon received a ctdb request to
set the srvid from the client
*/
static void daemon_request_register_message_handler ( struct ctdb_client * client ,
struct ctdb_req_register * c )
{
int res ;
res = ctdb_register_message_handler ( client - > ctdb , client ,
c - > srvid , daemon_message_handler ,
client ) ;
if ( res ! = 0 ) {
2007-04-27 18:31:45 +04:00
DEBUG ( 0 , ( __location__ " Failed to register handler %llu in daemon \n " ,
2007-04-17 16:27:17 +04:00
c - > srvid ) ) ;
2007-04-20 01:47:37 +04:00
} else {
2007-04-27 18:31:45 +04:00
DEBUG ( 2 , ( __location__ " Registered message handler for srvid=%llu \n " ,
2007-04-20 01:47:37 +04:00
c - > srvid ) ) ;
2007-04-11 05:58:28 +04:00
}
}
2007-04-18 06:39:03 +04:00
/*
called when the daemon gets a shutdown request from a client
*/
static void daemon_request_shutdown ( struct ctdb_client * client ,
struct ctdb_req_shutdown * f )
{
2007-04-18 08:08:45 +04:00
struct ctdb_context * ctdb = talloc_get_type ( client - > ctdb , struct ctdb_context ) ;
2007-04-18 06:39:03 +04:00
int len ;
uint32_t node ;
2007-04-18 08:08:45 +04:00
/* we dont send to ourself so we can already count one daemon as
exiting */
ctdb - > num_finished + + ;
2007-04-18 06:39:03 +04:00
/* loop over all nodes of the cluster */
2007-04-18 08:08:45 +04:00
for ( node = 0 ; node < ctdb - > num_nodes ; node + + ) {
struct ctdb_req_finished * rf ;
/* dont send a message to ourself */
if ( ctdb - > vnn = = node ) {
continue ;
}
len = sizeof ( struct ctdb_req_finished ) ;
2007-04-28 12:50:32 +04:00
rf = ctdb_transport_allocate ( ctdb , ctdb , CTDB_REQ_FINISHED , len ,
struct ctdb_req_finished ) ;
2007-04-18 08:08:45 +04:00
CTDB_NO_MEMORY_FATAL ( ctdb , rf ) ;
2007-04-28 12:50:32 +04:00
2007-04-18 08:08:45 +04:00
rf - > hdr . destnode = node ;
ctdb_queue_packet ( ctdb , & ( rf - > hdr ) ) ;
talloc_free ( rf ) ;
2007-04-18 06:39:03 +04:00
}
2007-04-18 08:08:45 +04:00
/* wait until all nodes have are prepared to shutdown */
while ( ctdb - > num_finished ! = ctdb - > num_nodes ) {
event_loop_once ( ctdb - > ev ) ;
}
2007-04-18 06:39:03 +04:00
2007-04-18 08:08:45 +04:00
/* all daemons have requested to finish - we now exit */
DEBUG ( 1 , ( " All daemons finished - exiting \n " ) ) ;
_exit ( 0 ) ;
2007-04-18 06:39:03 +04:00
}
2007-04-18 12:39:02 +04:00
2007-04-12 09:46:50 +04:00
2007-04-11 08:54:47 +04:00
/*
called when the daemon gets a connect wait request from a client
*/
static void daemon_request_connect_wait ( struct ctdb_client * client ,
struct ctdb_req_connect_wait * c )
{
2007-04-27 19:10:47 +04:00
struct ctdb_reply_connect_wait * r ;
2007-04-11 08:54:47 +04:00
int res ;
/* first wait - in the daemon */
ctdb_daemon_connect_wait ( client - > ctdb ) ;
/* now send the reply */
2007-04-28 12:50:32 +04:00
r = ctdbd_allocate_pkt ( client - > ctdb , client , CTDB_REPLY_CONNECT_WAIT , sizeof ( * r ) ,
struct ctdb_reply_connect_wait ) ;
CTDB_NO_MEMORY_VOID ( client - > ctdb , r ) ;
2007-04-27 19:10:47 +04:00
r - > vnn = ctdb_get_vnn ( client - > ctdb ) ;
r - > num_connected = client - > ctdb - > num_connected ;
2007-04-11 08:54:47 +04:00
2007-04-27 19:10:47 +04:00
res = daemon_queue_send ( client , & r - > hdr ) ;
talloc_free ( r ) ;
2007-04-20 14:07:47 +04:00
if ( res ! = 0 ) {
DEBUG ( 0 , ( __location__ " Failed to queue a connect wait response \n " ) ) ;
return ;
}
}
2007-04-10 00:03:39 +04:00
/*
destroy a ctdb_client
*/
static int ctdb_client_destructor ( struct ctdb_client * client )
{
2007-04-28 17:15:21 +04:00
client - > ctdb - > num_clients - - ;
2007-04-10 00:03:39 +04:00
close ( client - > fd ) ;
client - > fd = - 1 ;
return 0 ;
}
2007-04-11 07:43:15 +04:00
/*
this is called when the ctdb daemon received a ctdb request message
from a local client over the unix domain socket
*/
static void daemon_request_message_from_client ( struct ctdb_client * client ,
2007-04-11 08:05:01 +04:00
struct ctdb_req_message * c )
2007-04-11 07:43:15 +04:00
{
2007-04-11 08:05:01 +04:00
TDB_DATA data ;
int res ;
/* maybe the message is for another client on this node */
2007-04-11 07:43:15 +04:00
if ( ctdb_get_vnn ( client - > ctdb ) = = c - > hdr . destnode ) {
ctdb_request_message ( client - > ctdb , ( struct ctdb_req_header * ) c ) ;
2007-04-11 08:05:01 +04:00
return ;
}
2007-04-27 17:16:17 +04:00
2007-04-11 08:05:01 +04:00
/* its for a remote node */
data . dptr = & c - > data [ 0 ] ;
data . dsize = c - > datalen ;
res = ctdb_daemon_send_message ( client - > ctdb , c - > hdr . destnode ,
c - > srvid , data ) ;
if ( res ! = 0 ) {
2007-04-17 16:27:17 +04:00
DEBUG ( 0 , ( __location__ " Failed to send message to remote node %u \n " ,
c - > hdr . destnode ) ) ;
2007-04-11 07:43:15 +04:00
}
}
2007-04-19 04:37:44 +04:00
struct daemon_call_state {
struct ctdb_client * client ;
uint32_t reqid ;
struct ctdb_call * call ;
2007-04-20 14:07:47 +04:00
struct timeval start_time ;
2007-04-19 04:37:44 +04:00
} ;
/*
complete a call from a client
*/
static void daemon_call_from_client_callback ( struct ctdb_call_state * state )
2007-04-10 00:03:39 +04:00
{
2007-04-19 04:37:44 +04:00
struct daemon_call_state * dstate = talloc_get_type ( state - > async . private_data ,
struct daemon_call_state ) ;
2007-04-11 05:01:42 +04:00
struct ctdb_reply_call * r ;
2007-04-10 00:03:39 +04:00
int res ;
2007-04-11 05:01:42 +04:00
uint32_t length ;
2007-04-19 04:37:44 +04:00
struct ctdb_client * client = dstate - > client ;
2007-04-10 00:03:39 +04:00
2007-04-19 04:37:44 +04:00
talloc_steal ( client , dstate ) ;
talloc_steal ( dstate , dstate - > call ) ;
2007-04-10 00:03:39 +04:00
2007-04-19 04:37:44 +04:00
res = ctdb_daemon_call_recv ( state , dstate - > call ) ;
2007-04-10 00:03:39 +04:00
if ( res ! = 0 ) {
2007-04-17 16:27:17 +04:00
DEBUG ( 0 , ( __location__ " ctdbd_call_recv() returned error \n " ) ) ;
2007-04-20 14:07:47 +04:00
client - > ctdb - > status . pending_calls - - ;
ctdb_latency ( & client - > ctdb - > status . max_call_latency , dstate - > start_time ) ;
2007-04-19 04:37:44 +04:00
return ;
2007-04-10 00:03:39 +04:00
}
2007-04-19 04:37:44 +04:00
length = offsetof ( struct ctdb_reply_call , data ) + dstate - > call - > reply_data . dsize ;
2007-04-28 12:50:32 +04:00
r = ctdbd_allocate_pkt ( client - > ctdb , dstate , CTDB_REPLY_CALL ,
length , struct ctdb_reply_call ) ;
2007-04-11 05:01:42 +04:00
if ( r = = NULL ) {
2007-04-17 16:27:17 +04:00
DEBUG ( 0 , ( __location__ " Failed to allocate reply_call in ctdb daemon \n " ) ) ;
2007-04-20 14:07:47 +04:00
client - > ctdb - > status . pending_calls - - ;
ctdb_latency ( & client - > ctdb - > status . max_call_latency , dstate - > start_time ) ;
2007-04-11 05:01:42 +04:00
return ;
}
2007-04-19 04:37:44 +04:00
r - > hdr . reqid = dstate - > reqid ;
r - > datalen = dstate - > call - > reply_data . dsize ;
memcpy ( & r - > data [ 0 ] , dstate - > call - > reply_data . dptr , r - > datalen ) ;
2007-04-11 05:01:42 +04:00
2007-04-20 14:07:47 +04:00
res = daemon_queue_send ( client , & r - > hdr ) ;
2007-04-11 05:01:42 +04:00
if ( res ! = 0 ) {
2007-04-17 16:27:17 +04:00
DEBUG ( 0 , ( __location__ " Failed to queue packet from daemon to client \n " ) ) ;
2007-04-10 00:03:39 +04:00
}
2007-04-21 07:08:22 +04:00
ctdb_latency ( & client - > ctdb - > status . max_call_latency , dstate - > start_time ) ;
2007-04-19 04:37:44 +04:00
talloc_free ( dstate ) ;
2007-04-20 14:07:47 +04:00
client - > ctdb - > status . pending_calls - - ;
2007-04-10 00:03:39 +04:00
}
2007-04-19 10:27:56 +04:00
2007-04-19 04:37:44 +04:00
/*
this is called when the ctdb daemon received a ctdb request call
from a local client over the unix domain socket
*/
static void daemon_request_call_from_client ( struct ctdb_client * client ,
struct ctdb_req_call * c )
{
struct ctdb_call_state * state ;
struct ctdb_db_context * ctdb_db ;
struct daemon_call_state * dstate ;
struct ctdb_call * call ;
2007-04-19 10:27:56 +04:00
struct ctdb_ltdb_header header ;
TDB_DATA key , data ;
int ret ;
struct ctdb_context * ctdb = client - > ctdb ;
2007-04-19 04:37:44 +04:00
2007-04-20 14:07:47 +04:00
ctdb - > status . total_calls + + ;
ctdb - > status . pending_calls + + ;
2007-04-19 04:37:44 +04:00
ctdb_db = find_ctdb_db ( client - > ctdb , c - > db_id ) ;
if ( ! ctdb_db ) {
DEBUG ( 0 , ( __location__ " Unknown database in request. db_id==0x%08x " ,
c - > db_id ) ) ;
2007-04-20 14:07:47 +04:00
ctdb - > status . pending_calls - - ;
2007-04-19 04:37:44 +04:00
return ;
}
2007-04-19 10:27:56 +04:00
key . dptr = c - > data ;
key . dsize = c - > keylen ;
ret = ctdb_ltdb_lock_fetch_requeue ( ctdb_db , key , & header ,
( struct ctdb_req_header * ) c , & data ,
daemon_incoming_packet , client ) ;
if ( ret = = - 2 ) {
/* will retry later */
2007-04-20 14:07:47 +04:00
ctdb - > status . pending_calls - - ;
2007-04-19 10:27:56 +04:00
return ;
}
if ( ret ! = 0 ) {
DEBUG ( 0 , ( __location__ " Unable to fetch record \n " ) ) ;
2007-04-20 14:07:47 +04:00
ctdb - > status . pending_calls - - ;
2007-04-19 10:27:56 +04:00
return ;
}
2007-04-19 04:37:44 +04:00
dstate = talloc ( client , struct daemon_call_state ) ;
if ( dstate = = NULL ) {
2007-04-19 10:27:56 +04:00
ctdb_ltdb_unlock ( ctdb_db , key ) ;
2007-04-19 04:37:44 +04:00
DEBUG ( 0 , ( __location__ " Unable to allocate dstate \n " ) ) ;
2007-04-20 14:07:47 +04:00
ctdb - > status . pending_calls - - ;
2007-04-19 04:37:44 +04:00
return ;
}
2007-04-20 14:07:47 +04:00
dstate - > start_time = timeval_current ( ) ;
2007-04-19 04:37:44 +04:00
dstate - > client = client ;
dstate - > reqid = c - > hdr . reqid ;
2007-04-19 10:27:56 +04:00
talloc_steal ( dstate , data . dptr ) ;
2007-04-19 04:37:44 +04:00
call = dstate - > call = talloc_zero ( dstate , struct ctdb_call ) ;
if ( call = = NULL ) {
2007-04-19 10:27:56 +04:00
ctdb_ltdb_unlock ( ctdb_db , key ) ;
2007-04-19 04:37:44 +04:00
DEBUG ( 0 , ( __location__ " Unable to allocate call \n " ) ) ;
2007-04-20 14:07:47 +04:00
ctdb - > status . pending_calls - - ;
ctdb_latency ( & ctdb - > status . max_call_latency , dstate - > start_time ) ;
2007-04-19 04:37:44 +04:00
return ;
}
call - > call_id = c - > callid ;
2007-04-19 10:27:56 +04:00
call - > key = key ;
2007-04-19 04:37:44 +04:00
call - > call_data . dptr = c - > data + c - > keylen ;
call - > call_data . dsize = c - > calldatalen ;
2007-04-19 19:44:45 +04:00
call - > flags = c - > flags ;
2007-04-19 04:37:44 +04:00
2007-04-19 10:27:56 +04:00
if ( header . dmaster = = ctdb - > vnn & & ! ( ctdb - > flags & CTDB_FLAG_SELF_CONNECT ) ) {
state = ctdb_call_local_send ( ctdb_db , call , & header , & data ) ;
} else {
state = ctdb_daemon_call_send_remote ( ctdb_db , call , & header ) ;
}
ctdb_ltdb_unlock ( ctdb_db , key ) ;
2007-04-19 04:37:44 +04:00
if ( state = = NULL ) {
DEBUG ( 0 , ( __location__ " Unable to setup call send \n " ) ) ;
2007-04-20 14:07:47 +04:00
ctdb - > status . pending_calls - - ;
ctdb_latency ( & ctdb - > status . max_call_latency , dstate - > start_time ) ;
2007-04-19 04:37:44 +04:00
return ;
}
talloc_steal ( state , dstate ) ;
talloc_steal ( client , state ) ;
state - > async . fn = daemon_call_from_client_callback ;
state - > async . private_data = dstate ;
}
2007-04-10 00:03:39 +04:00
2007-04-26 16:27:49 +04:00
static void daemon_request_control_from_client ( struct ctdb_client * client ,
struct ctdb_req_control * c ) ;
2007-04-10 00:03:39 +04:00
/* data contains a packet from the client */
2007-04-19 10:27:56 +04:00
static void daemon_incoming_packet ( void * p , uint8_t * data , uint32_t nread )
2007-04-10 00:03:39 +04:00
{
2007-04-19 10:27:56 +04:00
struct ctdb_req_header * hdr = ( struct ctdb_req_header * ) data ;
struct ctdb_client * client = talloc_get_type ( p , struct ctdb_client ) ;
2007-04-18 05:20:24 +04:00
TALLOC_CTX * tmp_ctx ;
2007-04-20 15:02:53 +04:00
struct ctdb_context * ctdb = client - > ctdb ;
2007-04-18 05:20:24 +04:00
/* place the packet as a child of a tmp_ctx. We then use
talloc_free ( ) below to free it . If any of the calls want
to keep it , then they will steal it somewhere else , and the
talloc_free ( ) will be a no - op */
tmp_ctx = talloc_new ( client ) ;
talloc_steal ( tmp_ctx , hdr ) ;
2007-04-10 00:03:39 +04:00
if ( hdr - > ctdb_magic ! = CTDB_MAGIC ) {
2007-04-17 04:15:44 +04:00
ctdb_set_error ( client - > ctdb , " Non CTDB packet rejected in daemon \n " ) ;
2007-04-11 08:05:01 +04:00
goto done ;
2007-04-10 00:03:39 +04:00
}
if ( hdr - > ctdb_version ! = CTDB_VERSION ) {
2007-04-17 04:15:44 +04:00
ctdb_set_error ( client - > ctdb , " Bad CTDB version 0x%x rejected in daemon \n " , hdr - > ctdb_version ) ;
2007-04-11 08:05:01 +04:00
goto done ;
2007-04-10 00:03:39 +04:00
}
switch ( hdr - > operation ) {
case CTDB_REQ_CALL :
2007-04-20 15:02:53 +04:00
ctdb - > status . client . req_call + + ;
2007-04-11 05:01:42 +04:00
daemon_request_call_from_client ( client , ( struct ctdb_req_call * ) hdr ) ;
2007-04-10 00:03:39 +04:00
break ;
2007-04-11 05:58:28 +04:00
case CTDB_REQ_REGISTER :
2007-04-20 15:02:53 +04:00
ctdb - > status . client . req_register + + ;
2007-04-11 05:58:28 +04:00
daemon_request_register_message_handler ( client ,
( struct ctdb_req_register * ) hdr ) ;
break ;
2007-04-26 16:27:49 +04:00
2007-04-11 07:43:15 +04:00
case CTDB_REQ_MESSAGE :
2007-04-20 15:02:53 +04:00
ctdb - > status . client . req_message + + ;
2007-04-11 07:43:15 +04:00
daemon_request_message_from_client ( client , ( struct ctdb_req_message * ) hdr ) ;
break ;
2007-04-11 08:54:47 +04:00
case CTDB_REQ_CONNECT_WAIT :
2007-04-20 15:02:53 +04:00
ctdb - > status . client . req_connect_wait + + ;
2007-04-11 08:54:47 +04:00
daemon_request_connect_wait ( client , ( struct ctdb_req_connect_wait * ) hdr ) ;
break ;
2007-04-19 04:03:20 +04:00
2007-04-18 06:39:03 +04:00
case CTDB_REQ_SHUTDOWN :
2007-04-20 15:02:53 +04:00
ctdb - > status . client . req_shutdown + + ;
2007-04-18 06:39:03 +04:00
daemon_request_shutdown ( client , ( struct ctdb_req_shutdown * ) hdr ) ;
break ;
2007-04-19 04:03:20 +04:00
2007-04-26 16:27:49 +04:00
case CTDB_REQ_CONTROL :
ctdb - > status . client . req_control + + ;
daemon_request_control_from_client ( client , ( struct ctdb_req_control * ) hdr ) ;
break ;
2007-04-13 03:41:15 +04:00
default :
2007-04-17 16:27:17 +04:00
DEBUG ( 0 , ( __location__ " daemon: unrecognized operation %d \n " ,
hdr - > operation ) ) ;
2007-04-10 00:03:39 +04:00
}
2007-04-11 08:05:01 +04:00
done :
2007-04-18 05:20:24 +04:00
talloc_free ( tmp_ctx ) ;
2007-04-10 00:03:39 +04:00
}
2007-04-20 14:07:47 +04:00
/*
called when the daemon gets a incoming packet
*/
2007-04-17 08:52:51 +04:00
static void ctdb_daemon_read_cb ( uint8_t * data , size_t cnt , void * args )
2007-04-10 00:03:39 +04:00
{
2007-04-10 02:38:29 +04:00
struct ctdb_client * client = talloc_get_type ( args , struct ctdb_client ) ;
struct ctdb_req_header * hdr ;
2007-04-11 15:17:36 +04:00
if ( cnt = = 0 ) {
talloc_free ( client ) ;
return ;
}
2007-04-20 14:07:47 +04:00
client - > ctdb - > status . client_packets_recv + + ;
2007-04-10 02:38:29 +04:00
if ( cnt < sizeof ( * hdr ) ) {
2007-04-28 13:35:49 +04:00
ctdb_set_error ( client - > ctdb , " Bad packet length %u in daemon \n " ,
( unsigned ) cnt ) ;
2007-04-10 00:03:39 +04:00
return ;
}
2007-04-10 02:38:29 +04:00
hdr = ( struct ctdb_req_header * ) data ;
if ( cnt ! = hdr - > length ) {
2007-04-26 20:31:13 +04:00
ctdb_set_error ( client - > ctdb , " Bad header length %u expected %u \n in daemon " ,
2007-04-28 13:35:49 +04:00
( unsigned ) hdr - > length , ( unsigned ) cnt ) ;
2007-04-10 00:03:39 +04:00
return ;
}
2007-04-10 02:38:29 +04:00
if ( hdr - > ctdb_magic ! = CTDB_MAGIC ) {
ctdb_set_error ( client - > ctdb , " Non CTDB packet rejected \n " ) ;
2007-04-10 00:03:39 +04:00
return ;
}
2007-04-10 02:38:29 +04:00
if ( hdr - > ctdb_version ! = CTDB_VERSION ) {
2007-04-17 04:15:44 +04:00
ctdb_set_error ( client - > ctdb , " Bad CTDB version 0x%x rejected in daemon \n " , hdr - > ctdb_version ) ;
2007-04-10 00:03:39 +04:00
return ;
}
2007-04-20 14:07:47 +04:00
DEBUG ( 3 , ( __location__ " client request %d of type %d length %d from "
" node %d to %d \n " , hdr - > reqid , hdr - > operation , hdr - > length ,
hdr - > srcnode , hdr - > destnode ) ) ;
2007-04-10 02:38:29 +04:00
/* it is the responsibility of the incoming packet function to free 'data' */
2007-04-17 08:52:51 +04:00
daemon_incoming_packet ( client , data , cnt ) ;
2007-04-10 02:38:29 +04:00
}
2007-04-10 00:03:39 +04:00
static void ctdb_accept_client ( struct event_context * ev , struct fd_event * fde ,
2007-04-13 14:38:24 +04:00
uint16_t flags , void * private_data )
2007-04-10 00:03:39 +04:00
{
struct sockaddr_in addr ;
socklen_t len ;
int fd ;
2007-04-13 14:38:24 +04:00
struct ctdb_context * ctdb = talloc_get_type ( private_data , struct ctdb_context ) ;
2007-04-10 00:03:39 +04:00
struct ctdb_client * client ;
memset ( & addr , 0 , sizeof ( addr ) ) ;
len = sizeof ( addr ) ;
fd = accept ( ctdb - > daemon . sd , ( struct sockaddr * ) & addr , & len ) ;
if ( fd = = - 1 ) {
return ;
}
set_non_blocking ( fd ) ;
client = talloc_zero ( ctdb , struct ctdb_client ) ;
client - > ctdb = ctdb ;
client - > fd = fd ;
2007-04-28 17:15:21 +04:00
ctdb - > num_clients + + ;
2007-04-10 00:03:39 +04:00
2007-04-10 13:33:21 +04:00
client - > queue = ctdb_queue_setup ( ctdb , client , fd , CTDB_DS_ALIGNMENT ,
2007-04-17 08:52:51 +04:00
ctdb_daemon_read_cb , client ) ;
2007-04-10 00:03:39 +04:00
talloc_set_destructor ( client , ctdb_client_destructor ) ;
}
static void ctdb_read_from_parent ( struct event_context * ev , struct fd_event * fde ,
2007-04-13 14:38:24 +04:00
uint16_t flags , void * private_data )
2007-04-10 00:03:39 +04:00
{
2007-04-13 14:38:24 +04:00
int * fd = private_data ;
2007-04-10 00:03:39 +04:00
int cnt ;
char buf ;
/* XXX this is a good place to try doing some cleaning up before exiting */
cnt = read ( * fd , & buf , 1 ) ;
if ( cnt = = 0 ) {
2007-04-18 05:33:16 +04:00
DEBUG ( 2 , ( __location__ " parent process exited. filedescriptor dissappeared \n " ) ) ;
2007-04-10 00:03:39 +04:00
exit ( 1 ) ;
} else {
2007-04-17 16:27:17 +04:00
DEBUG ( 0 , ( __location__ " ctdb: did not expect data from parent process \n " ) ) ;
2007-04-10 00:03:39 +04:00
exit ( 1 ) ;
}
}
/*
create a unix domain socket and bind it
return a file descriptor open on the socket
*/
static int ux_socket_bind ( struct ctdb_context * ctdb )
{
struct sockaddr_un addr ;
ctdb - > daemon . sd = socket ( AF_UNIX , SOCK_STREAM , 0 ) ;
if ( ctdb - > daemon . sd = = - 1 ) {
ctdb - > daemon . sd = - 1 ;
return - 1 ;
}
set_non_blocking ( ctdb - > daemon . sd ) ;
memset ( & addr , 0 , sizeof ( addr ) ) ;
addr . sun_family = AF_UNIX ;
strncpy ( addr . sun_path , ctdb - > daemon . name , sizeof ( addr . sun_path ) ) ;
if ( bind ( ctdb - > daemon . sd , ( struct sockaddr * ) & addr , sizeof ( addr ) ) = = - 1 ) {
close ( ctdb - > daemon . sd ) ;
ctdb - > daemon . sd = - 1 ;
return - 1 ;
}
listen ( ctdb - > daemon . sd , 1 ) ;
return 0 ;
}
2007-04-11 05:01:42 +04:00
/*
delete the socket on exit - called on destruction of autofree context
*/
static int unlink_destructor ( const char * name )
2007-04-10 02:47:39 +04:00
{
2007-04-11 05:01:42 +04:00
unlink ( name ) ;
return 0 ;
2007-04-10 02:47:39 +04:00
}
2007-04-10 00:03:39 +04:00
/*
start the protocol going
*/
2007-04-17 08:52:51 +04:00
int ctdb_start ( struct ctdb_context * ctdb )
2007-04-10 00:03:39 +04:00
{
pid_t pid ;
static int fd [ 2 ] ;
int res ;
struct fd_event * fde ;
2007-04-11 05:01:42 +04:00
const char * domain_socket_name ;
2007-04-10 00:03:39 +04:00
/* get rid of any old sockets */
unlink ( ctdb - > daemon . name ) ;
/* create a unix domain stream socket to listen to */
res = ux_socket_bind ( ctdb ) ;
if ( res ! = 0 ) {
2007-04-17 16:27:17 +04:00
DEBUG ( 0 , ( __location__ " Failed to open CTDB unix domain socket \n " ) ) ;
2007-04-10 00:03:39 +04:00
exit ( 10 ) ;
}
res = pipe ( & fd [ 0 ] ) ;
if ( res ) {
2007-04-17 16:27:17 +04:00
DEBUG ( 0 , ( __location__ " Failed to open pipe for CTDB \n " ) ) ;
2007-04-10 00:03:39 +04:00
exit ( 1 ) ;
}
pid = fork ( ) ;
if ( pid = = - 1 ) {
2007-04-17 16:27:17 +04:00
DEBUG ( 0 , ( __location__ " Failed to fork CTDB daemon \n " ) ) ;
2007-04-10 00:03:39 +04:00
exit ( 1 ) ;
}
if ( pid ) {
close ( fd [ 0 ] ) ;
close ( ctdb - > daemon . sd ) ;
ctdb - > daemon . sd = - 1 ;
2007-05-02 05:02:04 +04:00
ctdb_ctrl_get_config ( ctdb ) ;
2007-04-10 00:03:39 +04:00
return 0 ;
}
2007-04-17 09:33:20 +04:00
block_signal ( SIGPIPE ) ;
2007-04-11 05:01:42 +04:00
/* ensure the socket is deleted on exit of the daemon */
domain_socket_name = talloc_strdup ( talloc_autofree_context ( ) , ctdb - > daemon . name ) ;
talloc_set_destructor ( domain_socket_name , unlink_destructor ) ;
2007-04-10 00:03:39 +04:00
close ( fd [ 1 ] ) ;
2007-04-17 08:52:51 +04:00
2007-04-27 12:43:52 +04:00
2007-04-10 00:03:39 +04:00
ctdb - > ev = event_context_init ( NULL ) ;
fde = event_add_fd ( ctdb - > ev , ctdb , fd [ 0 ] , EVENT_FD_READ , ctdb_read_from_parent , & fd [ 0 ] ) ;
fde = event_add_fd ( ctdb - > ev , ctdb , ctdb - > daemon . sd , EVENT_FD_READ , ctdb_accept_client , ctdb ) ;
ctdb_main_loop ( ctdb ) ;
return 0 ;
}
2007-04-29 18:19:40 +04:00
/*
start the protocol going as a daemon
*/
int ctdb_start_daemon ( struct ctdb_context * ctdb )
{
int res ;
struct fd_event * fde ;
const char * domain_socket_name ;
/* get rid of any old sockets */
unlink ( ctdb - > daemon . name ) ;
/* create a unix domain stream socket to listen to */
res = ux_socket_bind ( ctdb ) ;
if ( res ! = 0 ) {
DEBUG ( 0 , ( __location__ " Failed to open CTDB unix domain socket \n " ) ) ;
exit ( 10 ) ;
}
if ( fork ( ) ) {
return 0 ;
}
tdb_reopen_all ( False ) ;
setsid ( ) ;
block_signal ( SIGPIPE ) ;
block_signal ( SIGCHLD ) ;
/* ensure the socket is deleted on exit of the daemon */
domain_socket_name = talloc_strdup ( talloc_autofree_context ( ) , ctdb - > daemon . name ) ;
talloc_set_destructor ( domain_socket_name , unlink_destructor ) ;
ctdb - > ev = event_context_init ( NULL ) ;
fde = event_add_fd ( ctdb - > ev , ctdb , ctdb - > daemon . sd , EVENT_FD_READ ,
ctdb_accept_client , ctdb ) ;
ctdb_main_loop ( ctdb ) ;
return 0 ;
}
2007-04-10 00:03:39 +04:00
/*
2007-04-11 05:01:42 +04:00
allocate a packet for use in client < - > daemon communication
*/
2007-04-28 12:50:32 +04:00
struct ctdb_req_header * _ctdbd_allocate_pkt ( struct ctdb_context * ctdb ,
TALLOC_CTX * mem_ctx ,
enum ctdb_operation operation ,
size_t length , size_t slength ,
const char * type )
2007-04-10 00:03:39 +04:00
{
int size ;
2007-04-28 12:50:32 +04:00
struct ctdb_req_header * hdr ;
size = ( ( length + 1 ) + ( CTDB_DS_ALIGNMENT - 1 ) ) & ~ ( CTDB_DS_ALIGNMENT - 1 ) ;
2007-04-29 18:19:40 +04:00
2007-04-28 12:50:32 +04:00
hdr = ( struct ctdb_req_header * ) talloc_size ( mem_ctx , size ) ;
if ( hdr = = NULL ) {
DEBUG ( 0 , ( " Unable to allocate packet for operation %u of length %u \n " ,
operation , length ) ) ;
return NULL ;
}
talloc_set_name_const ( hdr , type ) ;
2007-04-29 18:19:40 +04:00
memset ( hdr , 0 , size ) ;
2007-04-28 12:50:32 +04:00
hdr - > operation = operation ;
2007-04-29 18:19:40 +04:00
hdr - > length = size ;
2007-04-28 12:50:32 +04:00
hdr - > ctdb_magic = CTDB_MAGIC ;
hdr - > ctdb_version = CTDB_VERSION ;
2007-04-29 18:19:40 +04:00
hdr - > srcnode = ctdb - > vnn ;
2007-04-28 14:01:46 +04:00
if ( ctdb - > vnn_map ) {
hdr - > generation = ctdb - > vnn_map - > generation ;
}
2007-04-28 12:50:32 +04:00
return hdr ;
}
2007-04-10 00:03:39 +04:00
2007-04-28 12:50:32 +04:00
/*
allocate a packet for use in daemon < - > daemon communication
*/
struct ctdb_req_header * _ctdb_transport_allocate ( struct ctdb_context * ctdb ,
TALLOC_CTX * mem_ctx ,
enum ctdb_operation operation ,
size_t length , size_t slength ,
const char * type )
{
int size ;
struct ctdb_req_header * hdr ;
size = ( ( length + 1 ) + ( CTDB_DS_ALIGNMENT - 1 ) ) & ~ ( CTDB_DS_ALIGNMENT - 1 ) ;
hdr = ( struct ctdb_req_header * ) ctdb - > methods - > allocate_pkt ( mem_ctx , size ) ;
if ( hdr = = NULL ) {
DEBUG ( 0 , ( " Unable to allocate transport packet for operation %u of length %u \n " ,
operation , length ) ) ;
return NULL ;
}
talloc_set_name_const ( hdr , type ) ;
2007-04-29 18:19:40 +04:00
memset ( hdr , 0 , size ) ;
2007-04-28 12:50:32 +04:00
hdr - > operation = operation ;
2007-04-29 18:19:40 +04:00
hdr - > length = size ;
2007-04-28 12:50:32 +04:00
hdr - > ctdb_magic = CTDB_MAGIC ;
hdr - > ctdb_version = CTDB_VERSION ;
hdr - > generation = ctdb - > vnn_map - > generation ;
hdr - > srcnode = ctdb - > vnn ;
return hdr ;
2007-04-10 00:03:39 +04:00
}
2007-04-18 05:55:54 +04:00
/*
called when a CTDB_REQ_FINISHED packet comes in
*/
void ctdb_request_finished ( struct ctdb_context * ctdb , struct ctdb_req_header * hdr )
{
ctdb - > num_finished + + ;
}
2007-04-26 16:27:49 +04:00
struct daemon_control_state {
struct ctdb_client * client ;
struct ctdb_req_control * c ;
2007-04-26 21:27:07 +04:00
uint32_t reqid ;
2007-04-26 16:27:49 +04:00
} ;
/*
callback when a control reply comes in
*/
static void daemon_control_callback ( struct ctdb_context * ctdb ,
uint32_t status , TDB_DATA data ,
void * private_data )
{
struct daemon_control_state * state = talloc_get_type ( private_data ,
struct daemon_control_state ) ;
struct ctdb_client * client = state - > client ;
struct ctdb_reply_control * r ;
size_t len ;
/* construct a message to send to the client containing the data */
2007-04-27 01:10:35 +04:00
len = offsetof ( struct ctdb_reply_control , data ) + data . dsize ;
2007-05-02 23:51:46 +04:00
r = ctdbd_allocate_pkt ( ctdb , state , CTDB_REPLY_CONTROL , len ,
2007-04-28 12:50:32 +04:00
struct ctdb_reply_control ) ;
CTDB_NO_MEMORY_VOID ( ctdb , r ) ;
2007-04-26 16:27:49 +04:00
2007-04-26 21:27:07 +04:00
r - > hdr . reqid = state - > reqid ;
2007-04-26 16:27:49 +04:00
r - > status = status ;
r - > datalen = data . dsize ;
memcpy ( & r - > data [ 0 ] , data . dptr , data . dsize ) ;
daemon_queue_send ( client , & r - > hdr ) ;
talloc_free ( state ) ;
}
/*
this is called when the ctdb daemon received a ctdb request control
from a local client over the unix domain socket
*/
static void daemon_request_control_from_client ( struct ctdb_client * client ,
struct ctdb_req_control * c )
{
TDB_DATA data ;
int res ;
struct daemon_control_state * state ;
2007-04-26 21:27:07 +04:00
if ( c - > hdr . destnode = = CTDB_CURRENT_NODE ) {
c - > hdr . destnode = client - > ctdb - > vnn ;
}
2007-04-26 16:27:49 +04:00
state = talloc ( client , struct daemon_control_state ) ;
CTDB_NO_MEMORY_VOID ( client - > ctdb , state ) ;
state - > client = client ;
state - > c = talloc_steal ( state , c ) ;
2007-04-26 21:27:07 +04:00
state - > reqid = c - > hdr . reqid ;
2007-04-26 16:27:49 +04:00
data . dptr = & c - > data [ 0 ] ;
data . dsize = c - > datalen ;
res = ctdb_daemon_send_control ( client - > ctdb , c - > hdr . destnode ,
2007-04-30 17:31:40 +04:00
c - > srvid , c - > opcode , c - > flags ,
data , daemon_control_callback ,
2007-04-26 16:27:49 +04:00
state ) ;
if ( res ! = 0 ) {
DEBUG ( 0 , ( __location__ " Failed to send control to remote node %u \n " ,
c - > hdr . destnode ) ) ;
}
}
2007-04-30 17:31:40 +04:00
/*
register a call function
*/
int ctdb_daemon_set_call ( struct ctdb_context * ctdb , uint32_t db_id ,
ctdb_fn_t fn , int id )
{
struct ctdb_registered_call * call ;
struct ctdb_db_context * ctdb_db ;
ctdb_db = find_ctdb_db ( ctdb , db_id ) ;
if ( ctdb_db = = NULL ) {
return - 1 ;
}
call = talloc ( ctdb_db , struct ctdb_registered_call ) ;
call - > fn = fn ;
call - > id = id ;
DLIST_ADD ( ctdb_db - > calls , call ) ;
return 0 ;
}