2007-06-10 21:02:09 +04:00
/*
Unix SMB / CIFS implementation .
Samba internal messaging functions
Copyright ( C ) 2007 by Volker Lendecke
Copyright ( C ) 2007 by Andrew Tridgell
2009-08-07 14:09:21 +04:00
2007-06-10 21:02:09 +04:00
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
2007-07-09 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
2007-06-10 21:02:09 +04:00
( at your option ) any later version .
2009-08-07 14:09:21 +04:00
2007-06-10 21:02:09 +04:00
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 .
2009-08-07 14:09:21 +04:00
2007-06-10 21:02:09 +04:00
You should have received a copy of the GNU General Public License
2007-07-10 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2007-06-10 21:02:09 +04:00
*/
# include "includes.h"
2011-05-05 13:25:29 +04:00
# include "util_tdb.h"
2007-06-10 21:02:09 +04:00
# ifdef CLUSTER_SUPPORT
2010-08-26 12:14:07 +04:00
# include "ctdbd_conn.h"
2011-05-02 05:38:41 +04:00
# include "ctdb_packet.h"
2011-03-24 17:31:06 +03:00
# include "messages.h"
2007-06-10 21:02:09 +04:00
2011-08-30 19:02:54 +04:00
/*
* It is not possible to include ctdb . h and tdb_compat . h ( included via
* some other include above ) without warnings . This fixes those
* warnings .
*/
# ifdef typesafe_cb
# undef typesafe_cb
# endif
# ifdef typesafe_cb_preargs
# undef typesafe_cb_preargs
# endif
# ifdef typesafe_cb_postargs
# undef typesafe_cb_postargs
# endif
2007-06-10 21:02:09 +04:00
/* paths to these include files come from --with-ctdb= in configure */
2011-08-30 19:02:54 +04:00
2007-06-10 21:02:09 +04:00
# include "ctdb.h"
# include "ctdb_private.h"
struct ctdbd_connection {
struct messaging_context * msg_ctx ;
uint32 reqid ;
uint32 our_vnn ;
uint64 rand_srvid ;
2011-05-02 05:38:41 +04:00
struct ctdb_packet_context * pkt ;
2007-06-10 21:02:09 +04:00
struct fd_event * fde ;
2009-08-07 14:09:21 +04:00
2007-06-10 21:02:09 +04:00
void ( * release_ip_handler ) ( const char * ip_addr , void * private_data ) ;
void * release_ip_priv ;
} ;
2011-10-26 12:56:32 +04:00
static uint32_t ctdbd_next_reqid ( struct ctdbd_connection * conn )
{
conn - > reqid + = 1 ;
if ( conn - > reqid = = 0 ) {
conn - > reqid + = 1 ;
}
return conn - > reqid ;
}
2007-06-10 21:02:09 +04:00
static NTSTATUS ctdbd_control ( struct ctdbd_connection * conn ,
uint32_t vnn , uint32 opcode ,
2008-08-07 10:20:05 +04:00
uint64_t srvid , uint32_t flags , TDB_DATA data ,
2007-06-10 21:02:09 +04:00
TALLOC_CTX * mem_ctx , TDB_DATA * outdata ,
int * cstatus ) ;
/*
* exit on fatal communications errors with the ctdbd daemon
*/
static void cluster_fatal ( const char * why )
{
DEBUG ( 0 , ( " cluster fatal event: %s - exiting immediately \n " , why ) ) ;
/* we don't use smb_panic() as we don't want to delay to write
a core file . We need to release this process id immediately
so that someone else can take over without getting sharing
violations */
2009-10-22 15:03:20 +04:00
_exit ( 1 ) ;
2007-06-10 21:02:09 +04:00
}
2007-08-29 15:46:44 +04:00
/*
*
*/
static void ctdb_packet_dump ( struct ctdb_req_header * hdr )
{
if ( DEBUGLEVEL < 10 ) {
return ;
}
DEBUGADD ( 10 , ( " len=%d, magic=%x, vers=%d, gen=%d, op=%d, reqid=%d \n " ,
( int ) hdr - > length , ( int ) hdr - > ctdb_magic ,
( int ) hdr - > ctdb_version , ( int ) hdr - > generation ,
( int ) hdr - > operation , ( int ) hdr - > reqid ) ) ;
}
2007-06-10 21:02:09 +04:00
/*
* Register a srvid with ctdbd
*/
static NTSTATUS register_with_ctdbd ( struct ctdbd_connection * conn ,
uint64_t srvid )
{
int cstatus ;
return ctdbd_control ( conn , CTDB_CURRENT_NODE ,
2008-08-07 10:20:05 +04:00
CTDB_CONTROL_REGISTER_SRVID , srvid , 0 ,
2007-06-10 21:02:09 +04:00
tdb_null , NULL , NULL , & cstatus ) ;
}
/*
* get our vnn from the cluster
*/
static NTSTATUS get_cluster_vnn ( struct ctdbd_connection * conn , uint32 * vnn )
{
int32_t cstatus = - 1 ;
NTSTATUS status ;
status = ctdbd_control ( conn ,
2008-08-07 10:20:05 +04:00
CTDB_CURRENT_NODE , CTDB_CONTROL_GET_PNN , 0 , 0 ,
2007-06-10 21:02:09 +04:00
tdb_null , NULL , NULL , & cstatus ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
cluster_fatal ( " ctdbd_control failed \n " ) ;
}
* vnn = ( uint32_t ) cstatus ;
return status ;
}
2009-11-16 14:03:24 +03:00
/*
* Are we active ( i . e . not banned or stopped ? )
*/
static bool ctdbd_working ( struct ctdbd_connection * conn , uint32_t vnn )
{
int32_t cstatus = - 1 ;
NTSTATUS status ;
TDB_DATA outdata ;
struct ctdb_node_map * m ;
uint32_t failure_flags ;
bool ret = false ;
int i ;
status = ctdbd_control ( conn , CTDB_CURRENT_NODE ,
CTDB_CONTROL_GET_NODEMAP , 0 , 0 ,
tdb_null , talloc_tos ( ) , & outdata , & cstatus ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
cluster_fatal ( " ctdbd_control failed \n " ) ;
}
if ( ( cstatus ! = 0 ) | | ( outdata . dptr = = NULL ) ) {
DEBUG ( 2 , ( " Received invalid ctdb data \n " ) ) ;
return false ;
}
m = ( struct ctdb_node_map * ) outdata . dptr ;
for ( i = 0 ; i < m - > num ; i + + ) {
if ( vnn = = m - > nodes [ i ] . pnn ) {
break ;
}
}
if ( i = = m - > num ) {
DEBUG ( 2 , ( " Did not find ourselves (node %d) in nodemap \n " ,
( int ) vnn ) ) ;
goto fail ;
}
failure_flags = NODE_FLAGS_BANNED | NODE_FLAGS_DISCONNECTED
| NODE_FLAGS_PERMANENTLY_DISABLED | NODE_FLAGS_STOPPED ;
if ( ( m - > nodes [ i ] . flags & failure_flags ) ! = 0 ) {
DEBUG ( 2 , ( " Node has status %x, not active \n " ,
( int ) m - > nodes [ i ] . flags ) ) ;
goto fail ;
}
ret = true ;
fail :
TALLOC_FREE ( outdata . dptr ) ;
2011-02-02 14:50:42 +03:00
return ret ;
2009-11-16 14:03:24 +03:00
}
2007-06-10 21:02:09 +04:00
uint32 ctdbd_vnn ( const struct ctdbd_connection * conn )
{
return conn - > our_vnn ;
}
/*
* Get us a ctdb connection
*/
static NTSTATUS ctdbd_connect ( TALLOC_CTX * mem_ctx ,
2011-05-02 05:38:41 +04:00
struct ctdb_packet_context * * presult )
2007-06-10 21:02:09 +04:00
{
2011-05-02 05:38:41 +04:00
struct ctdb_packet_context * result ;
2007-06-10 21:02:09 +04:00
const char * sockname = lp_ctdbd_socket ( ) ;
struct sockaddr_un addr ;
int fd ;
if ( ! sockname | | ! * sockname ) {
sockname = CTDB_PATH ;
}
fd = socket ( AF_UNIX , SOCK_STREAM , 0 ) ;
if ( fd = = - 1 ) {
DEBUG ( 3 , ( " Could not create socket: %s \n " , strerror ( errno ) ) ) ;
return map_nt_error_from_unix ( errno ) ;
}
ZERO_STRUCT ( addr ) ;
addr . sun_family = AF_UNIX ;
strncpy ( addr . sun_path , sockname , sizeof ( addr . sun_path ) ) ;
2010-07-04 22:49:43 +04:00
if ( sys_connect ( fd , ( struct sockaddr * ) ( void * ) & addr ) = = - 1 ) {
2008-06-24 17:09:37 +04:00
DEBUG ( 1 , ( " connect(%s) failed: %s \n " , sockname ,
2007-06-10 21:02:09 +04:00
strerror ( errno ) ) ) ;
close ( fd ) ;
return map_nt_error_from_unix ( errno ) ;
}
2011-05-02 05:38:41 +04:00
if ( ! ( result = ctdb_packet_init ( mem_ctx , fd ) ) ) {
2007-06-10 21:02:09 +04:00
close ( fd ) ;
return NT_STATUS_NO_MEMORY ;
}
* presult = result ;
return NT_STATUS_OK ;
}
/*
* Do we have a complete ctdb packet in the queue ?
*/
2008-12-20 12:44:29 +03:00
static bool ctdb_req_complete ( const uint8_t * buf , size_t available ,
2007-06-10 21:02:09 +04:00
size_t * length ,
void * private_data )
{
uint32 msglen ;
2008-12-20 12:44:29 +03:00
if ( available < sizeof ( msglen ) ) {
2007-06-10 21:02:09 +04:00
return False ;
}
2008-12-20 12:44:29 +03:00
msglen = * ( ( uint32 * ) buf ) ;
2007-06-10 21:02:09 +04:00
DEBUG ( 10 , ( " msglen = %d \n " , msglen ) ) ;
if ( msglen < sizeof ( struct ctdb_req_header ) ) {
DEBUG ( 0 , ( " Got invalid msglen: %d, expected at least %d for "
2007-07-24 15:45:29 +04:00
" the req_header \n " , ( int ) msglen ,
( int ) sizeof ( struct ctdb_req_header ) ) ) ;
2007-06-10 21:02:09 +04:00
cluster_fatal ( " ctdbd protocol error \n " ) ;
}
2008-12-20 12:44:29 +03:00
if ( available < msglen ) {
return false ;
2007-06-10 21:02:09 +04:00
}
2008-12-20 12:44:29 +03:00
* length = msglen ;
return true ;
2007-06-10 21:02:09 +04:00
}
/*
* State necessary to defer an incoming message while we are waiting for a
* ctdb reply .
*/
struct deferred_msg_state {
struct messaging_context * msg_ctx ;
struct messaging_rec * rec ;
} ;
/*
* Timed event handler for the deferred message
*/
static void deferred_message_dispatch ( struct event_context * event_ctx ,
struct timed_event * te ,
2009-01-05 12:22:50 +03:00
struct timeval now ,
2007-06-10 21:02:09 +04:00
void * private_data )
{
struct deferred_msg_state * state = talloc_get_type_abort (
private_data , struct deferred_msg_state ) ;
messaging_dispatch_rec ( state - > msg_ctx , state - > rec ) ;
TALLOC_FREE ( state ) ;
TALLOC_FREE ( te ) ;
}
struct req_pull_state {
TALLOC_CTX * mem_ctx ;
DATA_BLOB req ;
} ;
/*
2011-05-02 05:38:41 +04:00
* Pull a ctdb request out of the incoming ctdb_packet queue
2007-06-10 21:02:09 +04:00
*/
2008-12-20 12:44:29 +03:00
static NTSTATUS ctdb_req_pull ( uint8_t * buf , size_t length ,
2007-06-10 21:02:09 +04:00
void * private_data )
{
struct req_pull_state * state = ( struct req_pull_state * ) private_data ;
2008-12-20 12:44:29 +03:00
state - > req . data = talloc_move ( state - > mem_ctx , & buf ) ;
state - > req . length = length ;
2007-06-10 21:02:09 +04:00
return NT_STATUS_OK ;
}
/*
* Fetch a messaging_rec from an incoming ctdb style message
*/
static struct messaging_rec * ctdb_pull_messaging_rec ( TALLOC_CTX * mem_ctx ,
size_t overall_length ,
struct ctdb_req_message * msg )
{
struct messaging_rec * result ;
DATA_BLOB blob ;
2007-11-11 01:15:40 +03:00
enum ndr_err_code ndr_err ;
2007-06-10 21:02:09 +04:00
if ( ( overall_length < offsetof ( struct ctdb_req_message , data ) )
| | ( overall_length
< offsetof ( struct ctdb_req_message , data ) + msg - > datalen ) ) {
cluster_fatal ( " got invalid msg length " ) ;
}
2011-06-07 05:38:41 +04:00
if ( ! ( result = talloc ( mem_ctx , struct messaging_rec ) ) ) {
2007-06-10 21:02:09 +04:00
DEBUG ( 0 , ( " talloc failed \n " ) ) ;
return NULL ;
}
blob = data_blob_const ( msg - > data , msg - > datalen ) ;
2007-11-11 01:15:40 +03:00
ndr_err = ndr_pull_struct_blob (
2010-05-18 14:26:52 +04:00
& blob , result , result ,
2007-06-10 21:02:09 +04:00
( ndr_pull_flags_fn_t ) ndr_pull_messaging_rec ) ;
2007-11-11 01:15:40 +03:00
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
2007-06-10 21:02:09 +04:00
DEBUG ( 0 , ( " ndr_pull_struct_blob failed: %s \n " ,
2007-11-11 01:15:40 +03:00
ndr_errstr ( ndr_err ) ) ) ;
2007-06-10 21:02:09 +04:00
TALLOC_FREE ( result ) ;
return NULL ;
}
2007-11-11 01:15:40 +03:00
if ( DEBUGLEVEL > = 10 ) {
DEBUG ( 10 , ( " ctdb_pull_messaging_rec: \n " ) ) ;
NDR_PRINT_DEBUG ( messaging_rec , result ) ;
}
2007-06-10 21:02:09 +04:00
return result ;
}
2011-05-02 05:38:41 +04:00
static NTSTATUS ctdb_packet_fd_read_sync ( struct ctdb_packet_context * ctx )
2009-11-03 07:41:02 +03:00
{
2011-02-07 18:59:38 +03:00
int timeout = lp_ctdb_timeout ( ) ;
2009-11-03 07:41:02 +03:00
2011-02-07 18:59:38 +03:00
if ( timeout = = 0 ) {
timeout = - 1 ;
}
2011-05-03 13:11:38 +04:00
return ctdb_packet_fd_read_sync_timeout ( ctx , timeout ) ;
2009-11-03 07:41:02 +03:00
}
2007-06-10 21:02:09 +04:00
/*
* Read a full ctdbd request . If we have a messaging context , defer incoming
* messages that might come in between .
*/
static NTSTATUS ctdb_read_req ( struct ctdbd_connection * conn , uint32 reqid ,
TALLOC_CTX * mem_ctx , void * result )
{
struct ctdb_req_header * hdr ;
struct req_pull_state state ;
NTSTATUS status ;
again :
2009-11-03 07:41:02 +03:00
status = ctdb_packet_fd_read_sync ( conn - > pkt ) ;
2007-06-10 21:02:09 +04:00
if ( NT_STATUS_EQUAL ( status , NT_STATUS_NETWORK_BUSY ) ) {
/* EAGAIN */
goto again ;
2007-07-13 14:40:53 +04:00
} else if ( NT_STATUS_EQUAL ( status , NT_STATUS_RETRY ) ) {
/* EAGAIN */
goto again ;
2007-06-10 21:02:09 +04:00
}
if ( ! NT_STATUS_IS_OK ( status ) ) {
2011-05-02 05:38:41 +04:00
DEBUG ( 0 , ( " ctdb_packet_fd_read failed: %s \n " , nt_errstr ( status ) ) ) ;
2007-06-10 21:02:09 +04:00
cluster_fatal ( " ctdbd died \n " ) ;
}
2007-08-29 15:46:44 +04:00
next_pkt :
2007-06-10 21:02:09 +04:00
ZERO_STRUCT ( state ) ;
state . mem_ctx = mem_ctx ;
2011-05-02 05:38:41 +04:00
if ( ! ctdb_packet_handler ( conn - > pkt , ctdb_req_complete , ctdb_req_pull ,
2007-06-10 21:02:09 +04:00
& state , & status ) ) {
/*
* Not enough data
*/
2007-08-29 15:46:44 +04:00
DEBUG ( 10 , ( " not enough data from ctdb socket, retrying \n " ) ) ;
2007-06-10 21:02:09 +04:00
goto again ;
}
if ( ! NT_STATUS_IS_OK ( status ) ) {
2011-05-02 05:38:41 +04:00
DEBUG ( 0 , ( " Could not read ctdb_packet: %s \n " , nt_errstr ( status ) ) ) ;
2007-06-10 21:02:09 +04:00
cluster_fatal ( " ctdbd died \n " ) ;
}
hdr = ( struct ctdb_req_header * ) state . req . data ;
2007-08-29 15:46:44 +04:00
DEBUG ( 10 , ( " Received ctdb packet \n " ) ) ;
ctdb_packet_dump ( hdr ) ;
2007-06-10 21:02:09 +04:00
if ( hdr - > operation = = CTDB_REQ_MESSAGE ) {
struct timed_event * evt ;
struct deferred_msg_state * msg_state ;
struct ctdb_req_message * msg = ( struct ctdb_req_message * ) hdr ;
if ( conn - > msg_ctx = = NULL ) {
DEBUG ( 1 , ( " Got a message without having a msg ctx, "
2007-07-24 15:45:29 +04:00
" dropping msg %llu \n " ,
( long long unsigned ) msg - > srvid ) ) ;
2007-08-29 15:46:44 +04:00
goto next_pkt ;
2007-06-10 21:02:09 +04:00
}
2009-08-07 14:09:21 +04:00
2007-06-10 21:02:09 +04:00
if ( ( conn - > release_ip_handler ! = NULL )
& & ( msg - > srvid = = CTDB_SRVID_RELEASE_IP ) ) {
/* must be dispatched immediately */
DEBUG ( 10 , ( " received CTDB_SRVID_RELEASE_IP \n " ) ) ;
conn - > release_ip_handler ( ( const char * ) msg - > data ,
conn - > release_ip_priv ) ;
TALLOC_FREE ( hdr ) ;
2007-08-29 15:46:44 +04:00
goto next_pkt ;
2007-06-10 21:02:09 +04:00
}
2009-10-25 18:12:12 +03:00
if ( ( msg - > srvid = = CTDB_SRVID_RECONFIGURE )
| | ( msg - > srvid = = CTDB_SRVID_SAMBA_NOTIFY ) ) {
DEBUG ( 1 , ( " ctdb_read_req: Got %s message \n " ,
( msg - > srvid = = CTDB_SRVID_RECONFIGURE )
? " cluster reconfigure " : " SAMBA_NOTIFY " ) ) ;
2010-07-04 22:50:11 +04:00
messaging_send ( conn - > msg_ctx ,
messaging_server_id ( conn - > msg_ctx ) ,
2008-08-08 14:31:03 +04:00
MSG_SMB_BRL_VALIDATE , & data_blob_null ) ;
2010-07-04 22:50:11 +04:00
messaging_send ( conn - > msg_ctx ,
messaging_server_id ( conn - > msg_ctx ) ,
2009-10-25 18:12:12 +03:00
MSG_DBWRAP_G_LOCK_RETRY ,
& data_blob_null ) ;
2008-08-08 14:31:03 +04:00
TALLOC_FREE ( hdr ) ;
goto next_pkt ;
}
2011-06-07 05:38:41 +04:00
msg_state = talloc ( NULL , struct deferred_msg_state ) ;
2010-09-26 02:50:33 +04:00
if ( msg_state = = NULL ) {
2007-06-10 21:02:09 +04:00
DEBUG ( 0 , ( " talloc failed \n " ) ) ;
TALLOC_FREE ( hdr ) ;
2007-08-29 15:46:44 +04:00
goto next_pkt ;
2007-06-10 21:02:09 +04:00
}
if ( ! ( msg_state - > rec = ctdb_pull_messaging_rec (
msg_state , state . req . length , msg ) ) ) {
DEBUG ( 0 , ( " ctdbd_pull_messaging_rec failed \n " ) ) ;
TALLOC_FREE ( msg_state ) ;
TALLOC_FREE ( hdr ) ;
2007-08-29 15:46:44 +04:00
goto next_pkt ;
2007-06-10 21:02:09 +04:00
}
TALLOC_FREE ( hdr ) ;
msg_state - > msg_ctx = conn - > msg_ctx ;
2009-08-07 14:09:21 +04:00
2007-06-10 21:02:09 +04:00
/*
* We ' re waiting for a call reply , but an async message has
* crossed . Defer dispatching to the toplevel event loop .
*/
evt = event_add_timed ( conn - > msg_ctx - > event_ctx ,
conn - > msg_ctx - > event_ctx ,
timeval_zero ( ) ,
deferred_message_dispatch ,
msg_state ) ;
if ( evt = = NULL ) {
DEBUG ( 0 , ( " event_add_timed failed \n " ) ) ;
TALLOC_FREE ( msg_state ) ;
TALLOC_FREE ( hdr ) ;
2007-08-29 15:46:44 +04:00
goto next_pkt ;
2007-06-10 21:02:09 +04:00
}
2009-08-07 14:09:21 +04:00
2007-08-29 15:46:44 +04:00
goto next_pkt ;
2007-06-10 21:02:09 +04:00
}
if ( hdr - > reqid ! = reqid ) {
/* we got the wrong reply */
DEBUG ( 0 , ( " Discarding mismatched ctdb reqid %u should have "
" been %u \n " , hdr - > reqid , reqid ) ) ;
TALLOC_FREE ( hdr ) ;
goto again ;
}
* ( ( void * * ) result ) = talloc_move ( mem_ctx , & hdr ) ;
return NT_STATUS_OK ;
}
/*
* Get us a ctdbd connection
*/
2010-08-31 18:11:10 +04:00
static NTSTATUS ctdbd_init_connection ( TALLOC_CTX * mem_ctx ,
struct ctdbd_connection * * pconn )
2007-06-10 21:02:09 +04:00
{
struct ctdbd_connection * conn ;
NTSTATUS status ;
2011-06-07 05:44:43 +04:00
if ( ! ( conn = talloc_zero ( mem_ctx , struct ctdbd_connection ) ) ) {
2007-06-10 21:02:09 +04:00
DEBUG ( 0 , ( " talloc failed \n " ) ) ;
return NT_STATUS_NO_MEMORY ;
}
status = ctdbd_connect ( conn , & conn - > pkt ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 10 , ( " ctdbd_connect failed: %s \n " , nt_errstr ( status ) ) ) ;
goto fail ;
}
status = get_cluster_vnn ( conn , & conn - > our_vnn ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 10 , ( " get_cluster_vnn failed: %s \n " , nt_errstr ( status ) ) ) ;
goto fail ;
}
2009-11-16 14:03:24 +03:00
if ( ! ctdbd_working ( conn , conn - > our_vnn ) ) {
DEBUG ( 2 , ( " Node is not working, can not connect \n " ) ) ;
2009-12-03 03:55:52 +03:00
status = NT_STATUS_INTERNAL_DB_ERROR ;
2009-11-16 14:03:24 +03:00
goto fail ;
}
2007-06-10 21:02:09 +04:00
generate_random_buffer ( ( unsigned char * ) & conn - > rand_srvid ,
sizeof ( conn - > rand_srvid ) ) ;
status = register_with_ctdbd ( conn , conn - > rand_srvid ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 5 , ( " Could not register random srvid: %s \n " ,
nt_errstr ( status ) ) ) ;
goto fail ;
}
* pconn = conn ;
return NT_STATUS_OK ;
fail :
TALLOC_FREE ( conn ) ;
return status ;
}
/*
* Get us a ctdbd connection and register us as a process
*/
NTSTATUS ctdbd_messaging_connection ( TALLOC_CTX * mem_ctx ,
struct ctdbd_connection * * pconn )
{
struct ctdbd_connection * conn ;
NTSTATUS status ;
status = ctdbd_init_connection ( mem_ctx , & conn ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
status = register_with_ctdbd ( conn , ( uint64_t ) sys_getpid ( ) ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
status = register_with_ctdbd ( conn , MSG_SRVID_SAMBA ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
2009-10-25 18:12:12 +03:00
status = register_with_ctdbd ( conn , CTDB_SRVID_SAMBA_NOTIFY ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
2007-06-10 21:02:09 +04:00
* pconn = conn ;
return NT_STATUS_OK ;
fail :
TALLOC_FREE ( conn ) ;
return status ;
}
2009-12-04 15:22:30 +03:00
struct messaging_context * ctdb_conn_msg_ctx ( struct ctdbd_connection * conn )
{
return conn - > msg_ctx ;
}
2010-01-23 02:05:15 +03:00
int ctdbd_conn_get_fd ( struct ctdbd_connection * conn )
{
2011-05-02 05:38:41 +04:00
return ctdb_packet_get_fd ( conn - > pkt ) ;
2010-01-23 02:05:15 +03:00
}
2007-06-10 21:02:09 +04:00
/*
* Packet handler to receive and handle a ctdb message
*/
2008-12-20 12:44:29 +03:00
static NTSTATUS ctdb_handle_message ( uint8_t * buf , size_t length ,
2007-06-10 21:02:09 +04:00
void * private_data )
{
struct ctdbd_connection * conn = talloc_get_type_abort (
private_data , struct ctdbd_connection ) ;
struct ctdb_req_message * msg ;
struct messaging_rec * msg_rec ;
2008-12-20 12:44:29 +03:00
msg = ( struct ctdb_req_message * ) buf ;
2007-06-10 21:02:09 +04:00
if ( msg - > hdr . operation ! = CTDB_REQ_MESSAGE ) {
DEBUG ( 0 , ( " Received async msg of type %u, discarding \n " ,
msg - > hdr . operation ) ) ;
2008-12-20 12:44:29 +03:00
TALLOC_FREE ( buf ) ;
2007-06-10 21:02:09 +04:00
return NT_STATUS_INVALID_PARAMETER ;
}
if ( ( conn - > release_ip_handler ! = NULL )
& & ( msg - > srvid = = CTDB_SRVID_RELEASE_IP ) ) {
/* must be dispatched immediately */
DEBUG ( 10 , ( " received CTDB_SRVID_RELEASE_IP \n " ) ) ;
conn - > release_ip_handler ( ( const char * ) msg - > data ,
conn - > release_ip_priv ) ;
2008-12-20 12:44:29 +03:00
TALLOC_FREE ( buf ) ;
2007-06-10 21:02:09 +04:00
return NT_STATUS_OK ;
}
SMB_ASSERT ( conn - > msg_ctx ! = NULL ) ;
2009-10-25 18:12:12 +03:00
if ( ( msg - > srvid = = CTDB_SRVID_RECONFIGURE )
| | ( msg - > srvid = = CTDB_SRVID_SAMBA_NOTIFY ) ) {
2007-06-10 21:02:09 +04:00
DEBUG ( 0 , ( " Got cluster reconfigure message \n " ) ) ;
/*
2009-10-25 18:12:12 +03:00
* when the cluster is reconfigured or someone of the
* family has passed away ( SAMBA_NOTIFY ) , we need to
* clean the brl database
2007-06-10 21:02:09 +04:00
*/
2010-07-04 22:50:11 +04:00
messaging_send ( conn - > msg_ctx ,
messaging_server_id ( conn - > msg_ctx ) ,
2007-06-10 21:02:09 +04:00
MSG_SMB_BRL_VALIDATE , & data_blob_null ) ;
2010-07-04 22:50:11 +04:00
messaging_send ( conn - > msg_ctx ,
messaging_server_id ( conn - > msg_ctx ) ,
2009-10-25 18:12:12 +03:00
MSG_DBWRAP_G_LOCK_RETRY ,
& data_blob_null ) ;
2008-12-20 12:44:29 +03:00
TALLOC_FREE ( buf ) ;
2007-06-10 21:02:09 +04:00
return NT_STATUS_OK ;
}
/* only messages to our pid or the broadcast are valid here */
if ( msg - > srvid ! = sys_getpid ( ) & & msg - > srvid ! = MSG_SRVID_SAMBA ) {
DEBUG ( 0 , ( " Got unexpected message with srvid=%llu \n " ,
( unsigned long long ) msg - > srvid ) ) ;
2008-12-20 12:44:29 +03:00
TALLOC_FREE ( buf ) ;
2007-06-10 21:02:09 +04:00
return NT_STATUS_OK ;
}
2008-12-20 12:44:29 +03:00
if ( ! ( msg_rec = ctdb_pull_messaging_rec ( NULL , length , msg ) ) ) {
2007-06-10 21:02:09 +04:00
DEBUG ( 10 , ( " ctdb_pull_messaging_rec failed \n " ) ) ;
2008-12-20 12:44:29 +03:00
TALLOC_FREE ( buf ) ;
2007-06-10 21:02:09 +04:00
return NT_STATUS_NO_MEMORY ;
}
messaging_dispatch_rec ( conn - > msg_ctx , msg_rec ) ;
TALLOC_FREE ( msg_rec ) ;
2008-12-20 12:44:29 +03:00
TALLOC_FREE ( buf ) ;
2007-06-10 21:02:09 +04:00
return NT_STATUS_OK ;
}
/*
* The ctdbd socket is readable asynchronuously
*/
static void ctdbd_socket_handler ( struct event_context * event_ctx ,
struct fd_event * event ,
uint16 flags ,
void * private_data )
{
struct ctdbd_connection * conn = talloc_get_type_abort (
private_data , struct ctdbd_connection ) ;
NTSTATUS status ;
2011-05-02 05:38:41 +04:00
status = ctdb_packet_fd_read ( conn - > pkt ) ;
2007-06-10 21:02:09 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " packet_fd_read failed: %s \n " , nt_errstr ( status ) ) ) ;
cluster_fatal ( " ctdbd died \n " ) ;
}
2011-05-02 05:38:41 +04:00
while ( ctdb_packet_handler ( conn - > pkt , ctdb_req_complete ,
2007-06-10 21:02:09 +04:00
ctdb_handle_message , conn , & status ) ) {
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 10 , ( " could not handle incoming message: %s \n " ,
nt_errstr ( status ) ) ) ;
}
}
}
/*
* Prepare a ctdbd connection to receive messages
*/
NTSTATUS ctdbd_register_msg_ctx ( struct ctdbd_connection * conn ,
struct messaging_context * msg_ctx )
{
SMB_ASSERT ( conn - > msg_ctx = = NULL ) ;
SMB_ASSERT ( conn - > fde = = NULL ) ;
if ( ! ( conn - > fde = event_add_fd ( msg_ctx - > event_ctx , conn ,
2011-05-02 05:38:41 +04:00
ctdb_packet_get_fd ( conn - > pkt ) ,
2007-06-10 21:02:09 +04:00
EVENT_FD_READ ,
ctdbd_socket_handler ,
conn ) ) ) {
DEBUG ( 0 , ( " event_add_fd failed \n " ) ) ;
return NT_STATUS_NO_MEMORY ;
}
conn - > msg_ctx = msg_ctx ;
return NT_STATUS_OK ;
}
/*
* Send a messaging message across a ctdbd
*/
NTSTATUS ctdbd_messaging_send ( struct ctdbd_connection * conn ,
uint32 dst_vnn , uint64 dst_srvid ,
struct messaging_rec * msg )
{
struct ctdb_req_message r ;
TALLOC_CTX * mem_ctx ;
DATA_BLOB blob ;
NTSTATUS status ;
2007-11-11 01:15:40 +03:00
enum ndr_err_code ndr_err ;
2007-06-10 21:02:09 +04:00
if ( ! ( mem_ctx = talloc_init ( " ctdbd_messaging_send " ) ) ) {
DEBUG ( 0 , ( " talloc failed \n " ) ) ;
return NT_STATUS_NO_MEMORY ;
}
2007-11-11 01:15:40 +03:00
ndr_err = ndr_push_struct_blob (
2010-05-18 14:26:52 +04:00
& blob , mem_ctx , msg ,
2007-06-10 21:02:09 +04:00
( ndr_push_flags_fn_t ) ndr_push_messaging_rec ) ;
2007-11-11 01:15:40 +03:00
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
2007-06-10 21:02:09 +04:00
DEBUG ( 0 , ( " ndr_push_struct_blob failed: %s \n " ,
2007-11-11 01:15:40 +03:00
ndr_errstr ( ndr_err ) ) ) ;
2007-11-12 19:36:34 +03:00
status = ndr_map_error2ntstatus ( ndr_err ) ;
2007-06-10 21:02:09 +04:00
goto fail ;
}
r . hdr . length = offsetof ( struct ctdb_req_message , data ) + blob . length ;
r . hdr . ctdb_magic = CTDB_MAGIC ;
r . hdr . ctdb_version = CTDB_VERSION ;
r . hdr . generation = 1 ;
r . hdr . operation = CTDB_REQ_MESSAGE ;
r . hdr . destnode = dst_vnn ;
r . hdr . srcnode = conn - > our_vnn ;
r . hdr . reqid = 0 ;
r . srvid = dst_srvid ;
r . datalen = blob . length ;
2007-08-29 15:46:44 +04:00
DEBUG ( 10 , ( " ctdbd_messaging_send: Sending ctdb packet \n " ) ) ;
ctdb_packet_dump ( & r . hdr ) ;
2011-05-02 05:38:41 +04:00
status = ctdb_packet_send (
2007-06-10 21:02:09 +04:00
conn - > pkt , 2 ,
data_blob_const ( & r , offsetof ( struct ctdb_req_message , data ) ) ,
blob ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2011-05-02 05:38:41 +04:00
DEBUG ( 0 , ( " ctdb_packet_send failed: %s \n " , nt_errstr ( status ) ) ) ;
2007-06-10 21:02:09 +04:00
goto fail ;
}
2011-05-02 05:38:41 +04:00
status = ctdb_packet_flush ( conn - > pkt ) ;
2007-06-10 21:02:09 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 3 , ( " write to ctdbd failed: %s \n " , nt_errstr ( status ) ) ) ;
cluster_fatal ( " cluster dispatch daemon msg write error \n " ) ;
}
status = NT_STATUS_OK ;
fail :
TALLOC_FREE ( mem_ctx ) ;
return status ;
}
/*
* send / recv a generic ctdb control message
*/
static NTSTATUS ctdbd_control ( struct ctdbd_connection * conn ,
uint32_t vnn , uint32 opcode ,
2008-08-07 10:20:05 +04:00
uint64_t srvid , uint32_t flags ,
TDB_DATA data ,
2007-06-10 21:02:09 +04:00
TALLOC_CTX * mem_ctx , TDB_DATA * outdata ,
int * cstatus )
{
struct ctdb_req_control req ;
struct ctdb_reply_control * reply = NULL ;
struct ctdbd_connection * new_conn = NULL ;
NTSTATUS status ;
if ( conn = = NULL ) {
status = ctdbd_init_connection ( NULL , & new_conn ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 10 , ( " Could not init temp connection: %s \n " ,
nt_errstr ( status ) ) ) ;
goto fail ;
}
conn = new_conn ;
}
ZERO_STRUCT ( req ) ;
req . hdr . length = offsetof ( struct ctdb_req_control , data ) + data . dsize ;
req . hdr . ctdb_magic = CTDB_MAGIC ;
req . hdr . ctdb_version = CTDB_VERSION ;
req . hdr . operation = CTDB_REQ_CONTROL ;
2011-10-26 12:56:32 +04:00
req . hdr . reqid = ctdbd_next_reqid ( conn ) ;
2007-06-10 21:02:09 +04:00
req . hdr . destnode = vnn ;
req . opcode = opcode ;
req . srvid = srvid ;
req . datalen = data . dsize ;
2011-03-08 18:26:34 +03:00
req . flags = flags ;
2007-06-10 21:02:09 +04:00
2007-08-29 15:46:44 +04:00
DEBUG ( 10 , ( " ctdbd_control: Sending ctdb packet \n " ) ) ;
ctdb_packet_dump ( & req . hdr ) ;
2011-05-02 05:38:41 +04:00
status = ctdb_packet_send (
2007-06-10 21:02:09 +04:00
conn - > pkt , 2 ,
data_blob_const ( & req , offsetof ( struct ctdb_req_control , data ) ) ,
2007-07-24 13:47:26 +04:00
data_blob_const ( data . dptr , data . dsize ) ) ;
2007-06-10 21:02:09 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2011-05-02 05:38:41 +04:00
DEBUG ( 3 , ( " ctdb_packet_send failed: %s \n " , nt_errstr ( status ) ) ) ;
2007-06-10 21:02:09 +04:00
goto fail ;
}
2011-05-02 05:38:41 +04:00
status = ctdb_packet_flush ( conn - > pkt ) ;
2007-06-10 21:02:09 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 3 , ( " write to ctdbd failed: %s \n " , nt_errstr ( status ) ) ) ;
cluster_fatal ( " cluster dispatch daemon control write error \n " ) ;
}
2008-08-07 10:20:05 +04:00
if ( flags & CTDB_CTRL_FLAG_NOREPLY ) {
TALLOC_FREE ( new_conn ) ;
2010-12-23 18:43:55 +03:00
if ( cstatus ) {
* cstatus = 0 ;
}
2008-08-07 10:20:05 +04:00
return NT_STATUS_OK ;
}
2007-06-10 21:02:09 +04:00
status = ctdb_read_req ( conn , req . hdr . reqid , NULL , ( void * ) & reply ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 10 , ( " ctdb_read_req failed: %s \n " , nt_errstr ( status ) ) ) ;
goto fail ;
}
if ( reply - > hdr . operation ! = CTDB_REPLY_CONTROL ) {
DEBUG ( 0 , ( " received invalid reply \n " ) ) ;
goto fail ;
}
if ( outdata ) {
if ( ! ( outdata - > dptr = ( uint8 * ) talloc_memdup (
mem_ctx , reply - > data , reply - > datalen ) ) ) {
TALLOC_FREE ( reply ) ;
return NT_STATUS_NO_MEMORY ;
}
outdata - > dsize = reply - > datalen ;
}
if ( cstatus ) {
( * cstatus ) = reply - > status ;
}
status = NT_STATUS_OK ;
fail :
TALLOC_FREE ( new_conn ) ;
TALLOC_FREE ( reply ) ;
return status ;
}
/*
* see if a remote process exists
*/
2007-10-19 04:40:25 +04:00
bool ctdbd_process_exists ( struct ctdbd_connection * conn , uint32 vnn , pid_t pid )
2007-06-10 21:02:09 +04:00
{
NTSTATUS status ;
TDB_DATA data ;
int32_t cstatus ;
data . dptr = ( uint8_t * ) & pid ;
data . dsize = sizeof ( pid ) ;
2008-08-07 10:20:05 +04:00
status = ctdbd_control ( conn , vnn , CTDB_CONTROL_PROCESS_EXISTS , 0 , 0 ,
2007-06-10 21:02:09 +04:00
data , NULL , NULL , & cstatus ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( __location__ " ctdb_control for process_exists "
" failed \n " ) ) ;
return False ;
}
return cstatus = = 0 ;
}
/*
* Get a db path
*/
char * ctdbd_dbpath ( struct ctdbd_connection * conn ,
TALLOC_CTX * mem_ctx , uint32_t db_id )
{
NTSTATUS status ;
TDB_DATA data ;
int32_t cstatus ;
data . dptr = ( uint8_t * ) & db_id ;
data . dsize = sizeof ( db_id ) ;
status = ctdbd_control ( conn , CTDB_CURRENT_NODE ,
2008-08-07 10:20:05 +04:00
CTDB_CONTROL_GETDBPATH , 0 , 0 , data ,
2007-06-10 21:02:09 +04:00
mem_ctx , & data , & cstatus ) ;
if ( ! NT_STATUS_IS_OK ( status ) | | cstatus ! = 0 ) {
DEBUG ( 0 , ( __location__ " ctdb_control for getdbpath failed \n " ) ) ;
return NULL ;
}
return ( char * ) data . dptr ;
}
/*
* attach to a ctdb database
*/
NTSTATUS ctdbd_db_attach ( struct ctdbd_connection * conn ,
const char * name , uint32_t * db_id , int tdb_flags )
{
NTSTATUS status ;
TDB_DATA data ;
int32_t cstatus ;
2008-03-17 16:12:10 +03:00
bool persistent = ( tdb_flags & TDB_CLEAR_IF_FIRST ) = = 0 ;
2007-06-10 21:02:09 +04:00
data . dptr = ( uint8_t * ) name ;
data . dsize = strlen ( name ) + 1 ;
status = ctdbd_control ( conn , CTDB_CURRENT_NODE ,
2008-03-17 16:12:10 +03:00
persistent
? CTDB_CONTROL_DB_ATTACH_PERSISTENT
: CTDB_CONTROL_DB_ATTACH ,
2010-10-25 13:07:36 +04:00
tdb_flags , 0 , data , NULL , & data , & cstatus ) ;
2007-06-10 21:02:09 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( __location__ " ctdb_control for db_attach "
" failed: %s \n " , nt_errstr ( status ) ) ) ;
return status ;
}
if ( cstatus ! = 0 | | data . dsize ! = sizeof ( uint32_t ) ) {
DEBUG ( 0 , ( __location__ " ctdb_control for db_attach failed \n " ) ) ;
return NT_STATUS_INTERNAL_ERROR ;
}
* db_id = * ( uint32_t * ) data . dptr ;
talloc_free ( data . dptr ) ;
if ( ! ( tdb_flags & TDB_SEQNUM ) ) {
return NT_STATUS_OK ;
}
data . dptr = ( uint8_t * ) db_id ;
data . dsize = sizeof ( * db_id ) ;
status = ctdbd_control ( conn , CTDB_CURRENT_NODE ,
2008-08-07 10:20:05 +04:00
CTDB_CONTROL_ENABLE_SEQNUM , 0 , 0 , data ,
2007-06-10 21:02:09 +04:00
NULL , NULL , & cstatus ) ;
if ( ! NT_STATUS_IS_OK ( status ) | | cstatus ! = 0 ) {
DEBUG ( 0 , ( __location__ " ctdb_control for enable seqnum "
" failed \n " ) ) ;
return NT_STATUS_IS_OK ( status ) ? NT_STATUS_INTERNAL_ERROR :
status ;
}
return NT_STATUS_OK ;
}
/*
* force the migration of a record to this node
*/
NTSTATUS ctdbd_migrate ( struct ctdbd_connection * conn , uint32 db_id ,
TDB_DATA key )
{
struct ctdb_req_call req ;
struct ctdb_reply_call * reply ;
NTSTATUS status ;
ZERO_STRUCT ( req ) ;
2009-08-07 14:09:21 +04:00
2007-06-10 21:02:09 +04:00
req . hdr . length = offsetof ( struct ctdb_req_call , data ) + key . dsize ;
req . hdr . ctdb_magic = CTDB_MAGIC ;
req . hdr . ctdb_version = CTDB_VERSION ;
req . hdr . operation = CTDB_REQ_CALL ;
2011-10-26 12:56:32 +04:00
req . hdr . reqid = ctdbd_next_reqid ( conn ) ;
2007-06-10 21:02:09 +04:00
req . flags = CTDB_IMMEDIATE_MIGRATION ;
req . callid = CTDB_NULL_FUNC ;
req . db_id = db_id ;
req . keylen = key . dsize ;
2007-08-29 15:46:44 +04:00
DEBUG ( 10 , ( " ctdbd_migrate: Sending ctdb packet \n " ) ) ;
ctdb_packet_dump ( & req . hdr ) ;
2011-05-02 05:38:41 +04:00
status = ctdb_packet_send (
2007-06-10 21:02:09 +04:00
conn - > pkt , 2 ,
data_blob_const ( & req , offsetof ( struct ctdb_req_call , data ) ) ,
2007-07-24 13:47:26 +04:00
data_blob_const ( key . dptr , key . dsize ) ) ;
2007-06-10 21:02:09 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2011-05-02 05:38:41 +04:00
DEBUG ( 3 , ( " ctdb_packet_send failed: %s \n " , nt_errstr ( status ) ) ) ;
2007-06-10 21:02:09 +04:00
return status ;
}
2011-05-02 05:38:41 +04:00
status = ctdb_packet_flush ( conn - > pkt ) ;
2007-06-10 21:02:09 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 3 , ( " write to ctdbd failed: %s \n " , nt_errstr ( status ) ) ) ;
cluster_fatal ( " cluster dispatch daemon control write error \n " ) ;
}
status = ctdb_read_req ( conn , req . hdr . reqid , NULL , ( void * ) & reply ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " ctdb_read_req failed: %s \n " , nt_errstr ( status ) ) ) ;
goto fail ;
}
if ( reply - > hdr . operation ! = CTDB_REPLY_CALL ) {
DEBUG ( 0 , ( " received invalid reply \n " ) ) ;
status = NT_STATUS_INTERNAL_ERROR ;
goto fail ;
}
status = NT_STATUS_OK ;
fail :
TALLOC_FREE ( reply ) ;
return status ;
}
/*
* remotely fetch a record without locking it or forcing a migration
*/
NTSTATUS ctdbd_fetch ( struct ctdbd_connection * conn , uint32 db_id ,
TDB_DATA key , TALLOC_CTX * mem_ctx , TDB_DATA * data )
{
struct ctdb_req_call req ;
struct ctdb_reply_call * reply ;
NTSTATUS status ;
ZERO_STRUCT ( req ) ;
2009-08-07 14:09:21 +04:00
2007-06-10 21:02:09 +04:00
req . hdr . length = offsetof ( struct ctdb_req_call , data ) + key . dsize ;
req . hdr . ctdb_magic = CTDB_MAGIC ;
req . hdr . ctdb_version = CTDB_VERSION ;
req . hdr . operation = CTDB_REQ_CALL ;
2011-10-26 12:56:32 +04:00
req . hdr . reqid = ctdbd_next_reqid ( conn ) ;
2007-06-10 21:02:09 +04:00
req . flags = 0 ;
req . callid = CTDB_FETCH_FUNC ;
req . db_id = db_id ;
req . keylen = key . dsize ;
2011-05-02 05:38:41 +04:00
status = ctdb_packet_send (
2007-06-10 21:02:09 +04:00
conn - > pkt , 2 ,
data_blob_const ( & req , offsetof ( struct ctdb_req_call , data ) ) ,
2007-07-24 13:47:26 +04:00
data_blob_const ( key . dptr , key . dsize ) ) ;
2007-06-10 21:02:09 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2011-05-02 05:38:41 +04:00
DEBUG ( 3 , ( " ctdb_packet_send failed: %s \n " , nt_errstr ( status ) ) ) ;
2007-06-10 21:02:09 +04:00
return status ;
}
2011-05-02 05:38:41 +04:00
status = ctdb_packet_flush ( conn - > pkt ) ;
2007-06-10 21:02:09 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 3 , ( " write to ctdbd failed: %s \n " , nt_errstr ( status ) ) ) ;
cluster_fatal ( " cluster dispatch daemon control write error \n " ) ;
}
status = ctdb_read_req ( conn , req . hdr . reqid , NULL , ( void * ) & reply ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " ctdb_read_req failed: %s \n " , nt_errstr ( status ) ) ) ;
goto fail ;
}
if ( reply - > hdr . operation ! = CTDB_REPLY_CALL ) {
DEBUG ( 0 , ( " received invalid reply \n " ) ) ;
status = NT_STATUS_INTERNAL_ERROR ;
goto fail ;
}
data - > dsize = reply - > datalen ;
if ( data - > dsize = = 0 ) {
data - > dptr = NULL ;
goto done ;
}
data - > dptr = ( uint8 * ) talloc_memdup ( mem_ctx , & reply - > data [ 0 ] ,
reply - > datalen ) ;
if ( data - > dptr = = NULL ) {
DEBUG ( 0 , ( " talloc failed \n " ) ) ;
status = NT_STATUS_NO_MEMORY ;
goto fail ;
}
done :
status = NT_STATUS_OK ;
fail :
TALLOC_FREE ( reply ) ;
return status ;
}
struct ctdbd_traverse_state {
void ( * fn ) ( TDB_DATA key , TDB_DATA data , void * private_data ) ;
void * private_data ;
} ;
/*
* Handle a traverse record coming in on the ctdbd connection
*/
2008-12-20 12:44:29 +03:00
static NTSTATUS ctdb_traverse_handler ( uint8_t * buf , size_t length ,
2007-06-10 21:02:09 +04:00
void * private_data )
{
struct ctdbd_traverse_state * state =
( struct ctdbd_traverse_state * ) private_data ;
struct ctdb_req_message * m ;
struct ctdb_rec_data * d ;
TDB_DATA key , data ;
2008-12-20 12:44:29 +03:00
m = ( struct ctdb_req_message * ) buf ;
2007-06-10 21:02:09 +04:00
2008-12-20 12:44:29 +03:00
if ( length < sizeof ( * m ) | | m - > hdr . length ! = length ) {
DEBUG ( 0 , ( " Got invalid message of length %d \n " , ( int ) length ) ) ;
TALLOC_FREE ( buf ) ;
2007-06-10 21:02:09 +04:00
return NT_STATUS_UNEXPECTED_IO_ERROR ;
}
d = ( struct ctdb_rec_data * ) & m - > data [ 0 ] ;
if ( m - > datalen < sizeof ( uint32_t ) | | m - > datalen ! = d - > length ) {
DEBUG ( 0 , ( " Got invalid traverse data of length %d \n " ,
( int ) m - > datalen ) ) ;
2008-12-20 12:44:29 +03:00
TALLOC_FREE ( buf ) ;
2007-06-10 21:02:09 +04:00
return NT_STATUS_UNEXPECTED_IO_ERROR ;
}
key . dsize = d - > keylen ;
key . dptr = & d - > data [ 0 ] ;
data . dsize = d - > datalen ;
data . dptr = & d - > data [ d - > keylen ] ;
if ( key . dsize = = 0 & & data . dsize = = 0 ) {
/* end of traverse */
return NT_STATUS_END_OF_FILE ;
}
if ( data . dsize < sizeof ( struct ctdb_ltdb_header ) ) {
DEBUG ( 0 , ( " Got invalid ltdb header length %d \n " ,
( int ) data . dsize ) ) ;
2008-12-20 12:44:29 +03:00
TALLOC_FREE ( buf ) ;
2007-06-10 21:02:09 +04:00
return NT_STATUS_UNEXPECTED_IO_ERROR ;
}
data . dsize - = sizeof ( struct ctdb_ltdb_header ) ;
data . dptr + = sizeof ( struct ctdb_ltdb_header ) ;
if ( state - > fn ) {
state - > fn ( key , data , state - > private_data ) ;
}
2008-12-20 12:44:29 +03:00
TALLOC_FREE ( buf ) ;
2007-06-10 21:02:09 +04:00
return NT_STATUS_OK ;
}
/*
Traverse a ctdb database . This uses a kind - of hackish way to open a second
connection to ctdbd to avoid the hairy recursive and async problems with
everything in - line .
*/
NTSTATUS ctdbd_traverse ( uint32 db_id ,
void ( * fn ) ( TDB_DATA key , TDB_DATA data ,
void * private_data ) ,
void * private_data )
{
struct ctdbd_connection * conn ;
NTSTATUS status ;
TDB_DATA data ;
struct ctdb_traverse_start t ;
int cstatus ;
struct ctdbd_traverse_state state ;
status = ctdbd_init_connection ( NULL , & conn ) ;
2009-05-04 16:39:56 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " ctdbd_init_connection failed: %s \n " ,
nt_errstr ( status ) ) ) ;
return status ;
}
2007-06-10 21:02:09 +04:00
t . db_id = db_id ;
t . srvid = conn - > rand_srvid ;
2011-10-26 12:56:32 +04:00
t . reqid = ctdbd_next_reqid ( conn ) ;
2007-06-10 21:02:09 +04:00
data . dptr = ( uint8_t * ) & t ;
data . dsize = sizeof ( t ) ;
status = ctdbd_control ( conn , CTDB_CURRENT_NODE ,
2008-08-07 10:20:05 +04:00
CTDB_CONTROL_TRAVERSE_START , conn - > rand_srvid , 0 ,
2007-06-10 21:02:09 +04:00
data , NULL , NULL , & cstatus ) ;
if ( ! NT_STATUS_IS_OK ( status ) | | ( cstatus ! = 0 ) ) {
DEBUG ( 0 , ( " ctdbd_control failed: %s, %d \n " , nt_errstr ( status ) ,
cstatus ) ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
/*
* We need a mapping here
*/
status = NT_STATUS_UNSUCCESSFUL ;
}
goto done ;
}
state . fn = fn ;
state . private_data = private_data ;
while ( True ) {
status = NT_STATUS_OK ;
2011-05-02 05:38:41 +04:00
if ( ctdb_packet_handler ( conn - > pkt , ctdb_req_complete ,
2007-06-10 21:02:09 +04:00
ctdb_traverse_handler , & state , & status ) ) {
if ( NT_STATUS_EQUAL ( status , NT_STATUS_END_OF_FILE ) ) {
status = NT_STATUS_OK ;
break ;
}
/*
* There might be more in the queue
*/
continue ;
}
if ( ! NT_STATUS_IS_OK ( status ) ) {
break ;
}
2009-11-03 07:41:02 +03:00
status = ctdb_packet_fd_read_sync ( conn - > pkt ) ;
2007-06-10 21:02:09 +04:00
2007-07-13 14:40:53 +04:00
if ( NT_STATUS_EQUAL ( status , NT_STATUS_RETRY ) ) {
/*
* There might be more in the queue
*/
continue ;
}
2007-06-10 21:02:09 +04:00
if ( NT_STATUS_EQUAL ( status , NT_STATUS_END_OF_FILE ) ) {
status = NT_STATUS_OK ;
2009-11-02 18:59:15 +03:00
break ;
2007-06-10 21:02:09 +04:00
}
if ( ! NT_STATUS_IS_OK ( status ) ) {
2011-05-02 05:38:41 +04:00
DEBUG ( 0 , ( " ctdb_packet_fd_read_sync failed: %s \n " , nt_errstr ( status ) ) ) ;
2007-06-10 21:02:09 +04:00
cluster_fatal ( " ctdbd died \n " ) ;
}
}
done :
TALLOC_FREE ( conn ) ;
return status ;
}
2009-01-28 20:55:13 +03:00
/*
This is used to canonicalize a ctdb_sock_addr structure .
*/
static void smbd_ctdb_canonicalize_ip ( const struct sockaddr_storage * in ,
struct sockaddr_storage * out )
{
memcpy ( out , in , sizeof ( * out ) ) ;
# ifdef HAVE_IPV6
if ( in - > ss_family = = AF_INET6 ) {
const char prefix [ 12 ] = { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xff , 0xff } ;
const struct sockaddr_in6 * in6 = ( struct sockaddr_in6 * ) in ;
struct sockaddr_in * out4 = ( struct sockaddr_in * ) out ;
if ( memcmp ( & in6 - > sin6_addr , prefix , 12 ) = = 0 ) {
memset ( out , 0 , sizeof ( * out ) ) ;
# ifdef HAVE_SOCK_SIN_LEN
out4 - > sin_len = sizeof ( * out ) ;
# endif
out4 - > sin_family = AF_INET ;
out4 - > sin_port = in6 - > sin6_port ;
memcpy ( & out4 - > sin_addr , & in6 - > sin6_addr . s6_addr32 [ 3 ] , 4 ) ;
}
}
# endif
}
2007-06-10 21:02:09 +04:00
/*
* Register us as a server for a particular tcp connection
*/
NTSTATUS ctdbd_register_ips ( struct ctdbd_connection * conn ,
2009-01-28 20:55:13 +03:00
const struct sockaddr_storage * _server ,
const struct sockaddr_storage * _client ,
2007-06-10 21:02:09 +04:00
void ( * release_ip_handler ) ( const char * ip_addr ,
void * private_data ) ,
void * private_data )
{
2009-01-14 14:09:46 +03:00
/*
* we still use ctdb_control_tcp for ipv4
* because we want to work against older ctdb
* versions at runtime
*/
struct ctdb_control_tcp p4 ;
2009-01-28 20:55:13 +03:00
# ifdef HAVE_STRUCT_CTDB_CONTROL_TCP_ADDR
2009-01-14 14:09:46 +03:00
struct ctdb_control_tcp_addr p ;
# endif
2007-06-10 21:02:09 +04:00
TDB_DATA data ;
NTSTATUS status ;
2009-01-28 20:55:13 +03:00
struct sockaddr_storage client ;
struct sockaddr_storage server ;
2007-06-10 21:02:09 +04:00
/*
* Only one connection so far
*/
SMB_ASSERT ( conn - > release_ip_handler = = NULL ) ;
2009-01-28 20:55:13 +03:00
smbd_ctdb_canonicalize_ip ( _client , & client ) ;
smbd_ctdb_canonicalize_ip ( _server , & server ) ;
switch ( client . ss_family ) {
2008-12-18 17:02:42 +03:00
case AF_INET :
2011-10-21 14:04:59 +04:00
memcpy ( & p4 . dest , & server , sizeof ( p4 . dest ) ) ;
memcpy ( & p4 . src , & client , sizeof ( p4 . src ) ) ;
2009-01-14 14:09:46 +03:00
data . dptr = ( uint8_t * ) & p4 ;
data . dsize = sizeof ( p4 ) ;
2008-12-18 17:02:42 +03:00
break ;
2009-01-28 20:55:13 +03:00
# ifdef HAVE_STRUCT_CTDB_CONTROL_TCP_ADDR
2008-12-18 17:02:42 +03:00
case AF_INET6 :
2011-10-21 14:04:59 +04:00
memcpy ( & p . dest . ip6 , & server , sizeof ( p . dest . ip6 ) ) ;
memcpy ( & p . src . ip6 , & client , sizeof ( p . src . ip6 ) ) ;
2009-01-14 14:09:46 +03:00
data . dptr = ( uint8_t * ) & p ;
data . dsize = sizeof ( p ) ;
2008-12-18 17:02:42 +03:00
break ;
# endif
default :
return NT_STATUS_INTERNAL_ERROR ;
}
2008-08-08 15:11:56 +04:00
conn - > release_ip_handler = release_ip_handler ;
2011-05-19 20:13:40 +04:00
conn - > release_ip_priv = private_data ;
2008-08-08 15:11:56 +04:00
2007-06-10 21:02:09 +04:00
/*
* We want to be told about IP releases
*/
status = register_with_ctdbd ( conn , CTDB_SRVID_RELEASE_IP ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
/*
* inform ctdb of our tcp connection , so if IP takeover happens ctdb
* can send an extra ack to trigger a reset for our client , so it
* immediately reconnects
*/
return ctdbd_control ( conn , CTDB_CURRENT_NODE ,
2009-01-14 14:09:46 +03:00
CTDB_CONTROL_TCP_CLIENT , 0 ,
2007-06-10 21:02:09 +04:00
CTDB_CTRL_FLAG_NOREPLY , data , NULL , NULL , NULL ) ;
}
/*
* We want to handle reconfigure events
*/
NTSTATUS ctdbd_register_reconfigure ( struct ctdbd_connection * conn )
{
return register_with_ctdbd ( conn , CTDB_SRVID_RECONFIGURE ) ;
}
2008-08-07 10:20:05 +04:00
/*
call a control on the local node
*/
NTSTATUS ctdbd_control_local ( struct ctdbd_connection * conn , uint32 opcode ,
uint64_t srvid , uint32_t flags , TDB_DATA data ,
TALLOC_CTX * mem_ctx , TDB_DATA * outdata ,
int * cstatus )
{
return ctdbd_control ( conn , CTDB_CURRENT_NODE , opcode , srvid , flags , data , mem_ctx , outdata , cstatus ) ;
}
2009-10-25 18:12:12 +03:00
NTSTATUS ctdb_watch_us ( struct ctdbd_connection * conn )
{
struct ctdb_client_notify_register reg_data ;
size_t struct_len ;
NTSTATUS status ;
int cstatus ;
reg_data . srvid = CTDB_SRVID_SAMBA_NOTIFY ;
reg_data . len = 1 ;
reg_data . notify_data [ 0 ] = 0 ;
struct_len = offsetof ( struct ctdb_client_notify_register ,
notify_data ) + reg_data . len ;
status = ctdbd_control_local (
conn , CTDB_CONTROL_REGISTER_NOTIFY , conn - > rand_srvid , 0 ,
make_tdb_data ( ( uint8_t * ) & reg_data , struct_len ) ,
NULL , NULL , & cstatus ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " ctdbd_control_local failed: %s \n " ,
nt_errstr ( status ) ) ) ;
}
return status ;
}
NTSTATUS ctdb_unwatch ( struct ctdbd_connection * conn )
{
struct ctdb_client_notify_deregister dereg_data ;
NTSTATUS status ;
int cstatus ;
dereg_data . srvid = CTDB_SRVID_SAMBA_NOTIFY ;
status = ctdbd_control_local (
conn , CTDB_CONTROL_DEREGISTER_NOTIFY , conn - > rand_srvid , 0 ,
make_tdb_data ( ( uint8_t * ) & dereg_data , sizeof ( dereg_data ) ) ,
NULL , NULL , & cstatus ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " ctdbd_control_local failed: %s \n " ,
nt_errstr ( status ) ) ) ;
}
return status ;
}
2007-06-10 21:02:09 +04:00
# endif