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"
2012-02-15 14:22:45 +04:00
# include "serverid.h"
2012-04-04 13:56:06 +04:00
# include "ctdbd_conn.h"
2014-05-06 14:21:42 +04:00
# include "system/select.h"
2014-11-19 17:25:56 +03:00
# include "lib/sys_rw_data.h"
2015-05-25 09:50:35 +03:00
# include "lib/util/iov_buf.h"
2007-06-10 21:02:09 +04:00
2011-03-24 17:31:06 +03:00
# include "messages.h"
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"
2015-05-19 08:01:55 +03:00
struct ctdbd_srvid_cb {
uint64_t srvid ;
2015-06-23 17:55:09 +03:00
int ( * cb ) ( uint32_t src_vnn , uint32_t dst_vnn ,
uint64_t dst_srvid ,
const uint8_t * msg , size_t msglen ,
void * private_data ) ;
2015-05-19 08:01:55 +03:00
void * private_data ;
} ;
2007-06-10 21:02:09 +04:00
struct ctdbd_connection {
2015-09-26 01:49:16 +03:00
const char * sockname ; /* Needed in ctdbd_traverse */
2007-06-10 21:02:09 +04:00
struct messaging_context * msg_ctx ;
2012-07-30 17:31:59 +04:00
uint32_t reqid ;
uint32_t our_vnn ;
uint64_t rand_srvid ;
2015-05-19 08:01:55 +03:00
struct ctdbd_srvid_cb * callbacks ;
2014-05-06 14:21:42 +04:00
int fd ;
2013-02-18 13:24:12 +04:00
struct tevent_fd * fde ;
2015-09-26 00:36:35 +03:00
int timeout ;
2007-06-10 21:02:09 +04:00
} ;
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 ,
2012-07-30 17:31:59 +04:00
uint32_t vnn , uint32_t opcode ,
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 )
{
2012-02-07 19:41:25 +04:00
if ( DEBUGLEVEL < 11 ) {
2007-08-29 15:46:44 +04:00
return ;
}
2012-02-07 19:41:25 +04:00
DEBUGADD ( 11 , ( " len=%d, magic=%x, vers=%d, gen=%d, op=%d, reqid=%d \n " ,
2007-08-29 15:46:44 +04:00
( 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
*/
2015-05-19 08:05:24 +03:00
NTSTATUS register_with_ctdbd ( struct ctdbd_connection * conn , uint64_t srvid ,
2015-06-23 17:55:09 +03:00
int ( * cb ) ( uint32_t src_vnn , uint32_t dst_vnn ,
uint64_t dst_srvid ,
const uint8_t * msg , size_t msglen ,
void * private_data ) ,
2015-05-19 08:05:24 +03:00
void * private_data )
2007-06-10 21:02:09 +04:00
{
2014-11-21 18:20:10 +03:00
NTSTATUS status ;
2007-06-10 21:02:09 +04:00
int cstatus ;
2015-05-19 08:01:55 +03:00
size_t num_callbacks ;
struct ctdbd_srvid_cb * tmp ;
2014-11-21 18:20:10 +03:00
status = ctdbd_control ( conn , CTDB_CURRENT_NODE ,
CTDB_CONTROL_REGISTER_SRVID , srvid , 0 ,
tdb_null , NULL , NULL , & cstatus ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2015-05-19 08:01:55 +03:00
num_callbacks = talloc_array_length ( conn - > callbacks ) ;
2014-11-21 18:20:10 +03:00
2015-05-19 08:01:55 +03:00
tmp = talloc_realloc ( conn , conn - > callbacks , struct ctdbd_srvid_cb ,
num_callbacks + 1 ) ;
2014-11-21 18:20:10 +03:00
if ( tmp = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2015-05-19 08:01:55 +03:00
conn - > callbacks = tmp ;
conn - > callbacks [ num_callbacks ] = ( struct ctdbd_srvid_cb ) {
2015-05-19 08:05:24 +03:00
. srvid = srvid , . cb = cb , . private_data = private_data
2015-05-19 08:01:55 +03:00
} ;
2014-11-21 18:20:10 +03:00
return NT_STATUS_OK ;
}
2015-06-23 17:59:00 +03:00
static int ctdbd_msg_call_back ( struct ctdbd_connection * conn ,
struct ctdb_req_message * msg )
2015-05-19 16:07:33 +03:00
{
2015-06-02 23:30:06 +03:00
size_t msg_len ;
2015-05-19 16:07:33 +03:00
size_t i , num_callbacks ;
2015-06-02 23:30:06 +03:00
msg_len = msg - > hdr . length ;
if ( msg_len < offsetof ( struct ctdb_req_message , data ) ) {
DEBUG ( 10 , ( " %s: len %u too small \n " , __func__ ,
( unsigned ) msg_len ) ) ;
2015-06-23 17:59:00 +03:00
return 0 ;
2015-06-02 23:30:06 +03:00
}
msg_len - = offsetof ( struct ctdb_req_message , data ) ;
if ( msg_len < msg - > datalen ) {
DEBUG ( 10 , ( " %s: msg_len=%u < msg->datalen=%u \n " , __func__ ,
( unsigned ) msg_len , ( unsigned ) msg - > datalen ) ) ;
2015-06-23 17:59:00 +03:00
return 0 ;
2015-06-02 23:30:06 +03:00
}
2015-05-19 16:07:33 +03:00
num_callbacks = talloc_array_length ( conn - > callbacks ) ;
for ( i = 0 ; i < num_callbacks ; i + + ) {
struct ctdbd_srvid_cb * cb = & conn - > callbacks [ i ] ;
if ( ( cb - > srvid = = msg - > srvid ) & & ( cb - > cb ! = NULL ) ) {
2015-06-23 17:59:00 +03:00
int ret ;
ret = cb - > cb ( msg - > hdr . srcnode , msg - > hdr . destnode ,
msg - > srvid , msg - > data , msg - > datalen ,
cb - > private_data ) ;
if ( ret ! = 0 ) {
return ret ;
}
2015-05-19 16:07:33 +03:00
}
}
2015-06-23 17:59:00 +03:00
return 0 ;
2015-05-19 16:07:33 +03:00
}
2007-06-10 21:02:09 +04:00
/*
* get our vnn from the cluster
*/
2012-07-30 17:31:59 +04:00
static NTSTATUS get_cluster_vnn ( struct ctdbd_connection * conn , uint32_t * vnn )
2007-06-10 21:02:09 +04:00
{
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 ) ) {
2013-01-31 13:54:48 +04:00
DEBUG ( 1 , ( " ctdbd_control failed: %s \n " , nt_errstr ( status ) ) ) ;
return status ;
2007-06-10 21:02:09 +04:00
}
* 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 ) ) {
2013-01-31 14:02:52 +04:00
DEBUG ( 1 , ( " ctdbd_control failed: %s \n " , nt_errstr ( status ) ) ) ;
return false ;
2009-11-16 14:03:24 +03:00
}
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
}
2012-07-30 17:31:59 +04:00
uint32_t ctdbd_vnn ( const struct ctdbd_connection * conn )
2007-06-10 21:02:09 +04:00
{
return conn - > our_vnn ;
}
/*
* Get us a ctdb connection
*/
2015-09-26 00:32:09 +03:00
static int ctdbd_connect ( const char * sockname , int * pfd )
2007-06-10 21:02:09 +04:00
{
2013-08-13 14:50:15 +04:00
struct sockaddr_un addr = { 0 , } ;
2007-06-10 21:02:09 +04:00
int fd ;
2012-03-24 17:48:56 +04:00
socklen_t salen ;
2014-08-19 13:20:49 +04:00
size_t namelen ;
2007-06-10 21:02:09 +04:00
fd = socket ( AF_UNIX , SOCK_STREAM , 0 ) ;
if ( fd = = - 1 ) {
2014-05-06 14:21:42 +04:00
int err = errno ;
DEBUG ( 3 , ( " Could not create socket: %s \n " , strerror ( err ) ) ) ;
return err ;
2007-06-10 21:02:09 +04:00
}
addr . sun_family = AF_UNIX ;
2014-08-19 13:20:49 +04:00
namelen = strlcpy ( addr . sun_path , sockname , sizeof ( addr . sun_path ) ) ;
if ( namelen > = sizeof ( addr . sun_path ) ) {
DEBUG ( 3 , ( " %s: Socket name too long: %s \n " , __func__ ,
sockname ) ) ;
close ( fd ) ;
return ENAMETOOLONG ;
}
2007-06-10 21:02:09 +04:00
2012-03-24 17:48:56 +04:00
salen = sizeof ( struct sockaddr_un ) ;
2014-05-06 14:21:42 +04:00
2012-03-24 17:48:56 +04:00
if ( connect ( fd , ( struct sockaddr * ) ( void * ) & addr , salen ) = = - 1 ) {
2014-05-06 14:21:42 +04:00
int err = errno ;
2008-06-24 17:09:37 +04:00
DEBUG ( 1 , ( " connect(%s) failed: %s \n " , sockname ,
2014-05-06 14:21:42 +04:00
strerror ( err ) ) ) ;
2007-06-10 21:02:09 +04:00
close ( fd ) ;
2014-05-06 14:21:42 +04:00
return err ;
2007-06-10 21:02:09 +04:00
}
2014-05-06 14:21:42 +04:00
* pfd = fd ;
return 0 ;
2007-06-10 21:02:09 +04:00
}
2015-09-26 00:36:35 +03:00
static int ctdb_read_packet ( int fd , int timeout , TALLOC_CTX * mem_ctx ,
2015-07-11 13:23:22 +03:00
struct ctdb_req_header * * result )
2009-11-03 07:41:02 +03:00
{
2014-05-06 14:21:42 +04:00
struct ctdb_req_header * req ;
int ret , revents ;
uint32_t msglen ;
2015-05-17 21:23:35 +03:00
ssize_t nread ;
2009-11-03 07:41:02 +03:00
2014-07-21 16:35:39 +04:00
if ( timeout ! = - 1 ) {
ret = poll_one_fd ( fd , POLLIN , timeout , & revents ) ;
if ( ret = = - 1 ) {
2015-07-11 13:23:22 +03:00
return errno ;
2014-07-21 16:35:39 +04:00
}
if ( ret = = 0 ) {
2015-07-11 13:23:22 +03:00
return ETIMEDOUT ;
2014-07-21 16:35:39 +04:00
}
if ( ret ! = 1 ) {
2015-07-11 13:23:22 +03:00
return EIO ;
2014-07-21 16:35:39 +04:00
}
2014-05-06 14:21:42 +04:00
}
2015-05-17 21:23:35 +03:00
nread = read_data ( fd , & msglen , sizeof ( msglen ) ) ;
if ( nread = = - 1 ) {
2015-07-11 13:23:22 +03:00
return errno ;
2015-05-17 21:23:35 +03:00
}
if ( nread = = 0 ) {
2015-07-11 13:23:22 +03:00
return EIO ;
2014-05-06 14:21:42 +04:00
}
if ( msglen < sizeof ( struct ctdb_req_header ) ) {
2015-07-11 13:23:22 +03:00
return EIO ;
2014-05-06 14:21:42 +04:00
}
req = talloc_size ( mem_ctx , msglen ) ;
if ( req = = NULL ) {
2015-07-11 13:23:22 +03:00
return ENOMEM ;
2014-05-06 14:21:42 +04:00
}
talloc_set_name_const ( req , " struct ctdb_req_header " ) ;
req - > length = msglen ;
2015-05-17 21:23:35 +03:00
nread = read_data ( fd , ( ( char * ) req ) + sizeof ( msglen ) ,
msglen - sizeof ( msglen ) ) ;
if ( nread = = - 1 ) {
2015-07-11 13:23:22 +03:00
return errno ;
2015-05-17 21:23:35 +03:00
}
if ( nread = = 0 ) {
2015-07-11 13:23:22 +03:00
return EIO ;
2014-05-06 14:21:42 +04:00
}
* result = req ;
2015-07-11 13:23:22 +03:00
return 0 ;
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 .
*/
2015-06-19 12:47:01 +03:00
static int ctdb_read_req ( struct ctdbd_connection * conn , uint32_t reqid ,
TALLOC_CTX * mem_ctx , struct ctdb_req_header * * result )
2007-06-10 21:02:09 +04:00
{
struct ctdb_req_header * hdr ;
2015-07-11 13:23:22 +03:00
int ret ;
2007-06-10 21:02:09 +04:00
2007-08-29 15:46:44 +04:00
next_pkt :
2007-06-10 21:02:09 +04:00
2015-09-26 00:36:35 +03:00
ret = ctdb_read_packet ( conn - > fd , conn - > timeout , mem_ctx , & hdr ) ;
2015-07-11 13:23:22 +03:00
if ( ret ! = 0 ) {
DEBUG ( 0 , ( " ctdb_read_packet failed: %s \n " , strerror ( ret ) ) ) ;
2007-06-10 21:02:09 +04:00
cluster_fatal ( " ctdbd died \n " ) ;
}
2012-02-07 19:41:25 +04:00
DEBUG ( 11 , ( " Received ctdb packet \n " ) ) ;
2007-08-29 15:46:44 +04:00
ctdb_packet_dump ( hdr ) ;
2007-06-10 21:02:09 +04:00
if ( hdr - > operation = = CTDB_REQ_MESSAGE ) {
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 ) ) ;
2015-07-01 18:00:43 +03:00
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
2015-06-23 18:04:59 +03:00
ret = ctdbd_msg_call_back ( conn , msg ) ;
if ( ret ! = 0 ) {
TALLOC_FREE ( hdr ) ;
return ret ;
}
2007-06-10 21:02:09 +04:00
TALLOC_FREE ( hdr ) ;
2007-08-29 15:46:44 +04:00
goto next_pkt ;
2007-06-10 21:02:09 +04:00
}
2011-10-26 12:58:25 +04:00
if ( ( reqid ! = 0 ) & & ( hdr - > reqid ! = reqid ) ) {
2007-06-10 21:02:09 +04:00
/* we got the wrong reply */
DEBUG ( 0 , ( " Discarding mismatched ctdb reqid %u should have "
" been %u \n " , hdr - > reqid , reqid ) ) ;
TALLOC_FREE ( hdr ) ;
2011-10-27 17:21:29 +04:00
goto next_pkt ;
2007-06-10 21:02:09 +04:00
}
2014-05-06 14:21:42 +04:00
* result = talloc_move ( mem_ctx , & hdr ) ;
2007-06-10 21:02:09 +04:00
2015-06-19 12:47:01 +03:00
return 0 ;
2007-06-10 21:02:09 +04:00
}
2014-05-06 14:21:42 +04:00
static int ctdbd_connection_destructor ( struct ctdbd_connection * c )
{
close ( c - > fd ) ;
return 0 ;
}
2007-06-10 21:02:09 +04:00
/*
* Get us a ctdbd connection
*/
2010-08-31 18:11:10 +04:00
static NTSTATUS ctdbd_init_connection ( TALLOC_CTX * mem_ctx ,
2015-09-26 02:09:23 +03:00
const char * sockname , int timeout ,
2010-08-31 18:11:10 +04:00
struct ctdbd_connection * * pconn )
2007-06-10 21:02:09 +04:00
{
struct ctdbd_connection * conn ;
2014-05-06 14:21:42 +04:00
int ret ;
2007-06-10 21:02:09 +04:00
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 ;
}
2015-09-26 02:09:23 +03:00
conn - > sockname = talloc_strdup ( conn , sockname ) ;
2015-09-26 01:49:16 +03:00
if ( conn - > sockname = = NULL ) {
DBG_ERR ( " %s: talloc failed \n " , __func__ ) ;
status = NT_STATUS_NO_MEMORY ;
goto fail ;
}
2015-09-26 02:09:23 +03:00
conn - > timeout = timeout ;
2015-09-26 00:36:35 +03:00
if ( conn - > timeout = = 0 ) {
conn - > timeout = - 1 ;
}
2015-09-26 01:49:16 +03:00
ret = ctdbd_connect ( conn - > sockname , & conn - > fd ) ;
2014-05-06 14:21:42 +04:00
if ( ret ! = 0 ) {
2015-06-26 14:17:01 +03:00
status = map_nt_error_from_unix ( ret ) ;
DEBUG ( 1 , ( " ctdbd_connect failed: %s \n " , strerror ( ret ) ) ) ;
2007-06-10 21:02:09 +04:00
goto fail ;
}
2014-05-06 14:21:42 +04:00
talloc_set_destructor ( conn , ctdbd_connection_destructor ) ;
2007-06-10 21:02:09 +04:00
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 ) ) ;
2015-05-19 08:05:24 +03:00
status = register_with_ctdbd ( conn , conn - > rand_srvid , NULL , NULL ) ;
2007-06-10 21:02:09 +04:00
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 ,
2015-09-26 02:49:33 +03:00
const char * sockname , int timeout ,
2007-06-10 21:02:09 +04:00
struct ctdbd_connection * * pconn )
{
struct ctdbd_connection * conn ;
NTSTATUS status ;
2015-09-26 02:49:33 +03:00
status = ctdbd_init_connection ( mem_ctx , sockname , timeout , & conn ) ;
2007-06-10 21:02:09 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2015-05-19 08:05:24 +03:00
status = register_with_ctdbd ( conn , MSG_SRVID_SAMBA , NULL , NULL ) ;
2007-06-10 21:02:09 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
* 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 )
{
2014-05-06 14:21:42 +04:00
return conn - > fd ;
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
*/
2015-06-19 12:47:01 +03:00
static int ctdb_handle_message ( struct ctdbd_connection * conn ,
struct ctdb_req_header * hdr )
2007-06-10 21:02:09 +04:00
{
struct ctdb_req_message * msg ;
2014-05-06 14:21:42 +04:00
if ( hdr - > operation ! = CTDB_REQ_MESSAGE ) {
2007-06-10 21:02:09 +04:00
DEBUG ( 0 , ( " Received async msg of type %u, discarding \n " ,
2014-05-06 14:21:42 +04:00
hdr - > operation ) ) ;
2015-06-19 12:47:01 +03:00
return EINVAL ;
2007-06-10 21:02:09 +04:00
}
2014-05-06 14:21:42 +04:00
msg = ( struct ctdb_req_message * ) hdr ;
2015-05-19 16:07:33 +03:00
ctdbd_msg_call_back ( conn , msg ) ;
2015-06-19 12:47:01 +03:00
return 0 ;
2007-06-10 21:02:09 +04:00
}
/*
* The ctdbd socket is readable asynchronuously
*/
2013-02-18 13:00:26 +04:00
static void ctdbd_socket_handler ( struct tevent_context * event_ctx ,
2013-02-18 13:24:12 +04:00
struct tevent_fd * event ,
2015-05-10 02:33:10 +03:00
uint16_t flags ,
2007-06-10 21:02:09 +04:00
void * private_data )
{
struct ctdbd_connection * conn = talloc_get_type_abort (
private_data , struct ctdbd_connection ) ;
2015-03-03 10:48:00 +03:00
struct ctdb_req_header * hdr = NULL ;
2015-07-11 13:23:22 +03:00
int ret ;
2007-06-10 21:02:09 +04:00
2015-09-26 00:36:35 +03:00
ret = ctdb_read_packet ( conn - > fd , conn - > timeout , talloc_tos ( ) , & hdr ) ;
2015-07-11 13:23:22 +03:00
if ( ret ! = 0 ) {
DEBUG ( 0 , ( " ctdb_read_packet failed: %s \n " , strerror ( ret ) ) ) ;
2007-06-10 21:02:09 +04:00
cluster_fatal ( " ctdbd died \n " ) ;
}
2015-06-19 12:47:01 +03:00
ret = ctdb_handle_message ( conn , hdr ) ;
2015-06-15 17:47:50 +03:00
TALLOC_FREE ( hdr ) ;
2015-06-19 12:47:01 +03:00
if ( ret ! = 0 ) {
2014-05-06 14:21:42 +04:00
DEBUG ( 10 , ( " could not handle incoming message: %s \n " ,
2015-06-19 12:47:01 +03:00
strerror ( ret ) ) ) ;
2007-06-10 21:02:09 +04:00
}
}
/*
* 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 ) ;
2014-05-29 18:44:32 +04:00
if ( ! ( conn - > fde = tevent_add_fd ( messaging_tevent_context ( msg_ctx ) ,
conn ,
2014-05-06 14:21:42 +04:00
conn - > fd ,
2013-02-18 13:53:02 +04:00
TEVENT_FD_READ ,
2007-06-10 21:02:09 +04:00
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 ;
}
2015-05-25 09:50:35 +03:00
NTSTATUS ctdbd_messaging_send_iov ( struct ctdbd_connection * conn ,
uint32_t dst_vnn , uint64_t dst_srvid ,
const struct iovec * iov , int iovlen )
2012-03-30 13:10:47 +04:00
{
struct ctdb_req_message r ;
2015-05-25 09:50:35 +03:00
struct iovec iov2 [ iovlen + 1 ] ;
size_t buflen = iov_buflen ( iov , iovlen ) ;
2014-05-06 14:21:42 +04:00
ssize_t nwritten ;
2012-03-30 13:10:47 +04:00
r . hdr . length = offsetof ( struct ctdb_req_message , data ) + buflen ;
2007-06-10 21:02:09 +04:00
r . hdr . ctdb_magic = CTDB_MAGIC ;
2014-10-21 04:53:29 +04:00
r . hdr . ctdb_version = CTDB_PROTOCOL ;
2007-06-10 21:02:09 +04:00
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 ;
2012-03-30 13:10:47 +04:00
r . datalen = buflen ;
2007-06-10 21:02:09 +04:00
2007-08-29 15:46:44 +04:00
DEBUG ( 10 , ( " ctdbd_messaging_send: Sending ctdb packet \n " ) ) ;
ctdb_packet_dump ( & r . hdr ) ;
2015-05-25 09:50:35 +03:00
iov2 [ 0 ] . iov_base = & r ;
iov2 [ 0 ] . iov_len = offsetof ( struct ctdb_req_message , data ) ;
memcpy ( & iov2 [ 1 ] , iov , iovlen * sizeof ( struct iovec ) ) ;
2007-06-10 21:02:09 +04:00
2015-05-25 09:50:35 +03:00
nwritten = write_data_iov ( conn - > fd , iov2 , iovlen + 1 ) ;
2014-05-06 14:21:42 +04:00
if ( nwritten = = - 1 ) {
DEBUG ( 3 , ( " write_data_iov failed: %s \n " , strerror ( errno ) ) ) ;
2007-06-10 21:02:09 +04:00
cluster_fatal ( " cluster dispatch daemon msg write error \n " ) ;
}
2014-05-06 14:21:42 +04:00
2012-03-30 13:10:47 +04:00
return NT_STATUS_OK ;
2007-06-10 21:02:09 +04:00
}
/*
* send / recv a generic ctdb control message
*/
static NTSTATUS ctdbd_control ( struct ctdbd_connection * conn ,
2012-07-30 17:31:59 +04:00
uint32_t vnn , uint32_t opcode ,
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 ;
2014-05-06 14:21:42 +04:00
struct ctdb_req_header * hdr ;
2007-06-10 21:02:09 +04:00
struct ctdb_reply_control * reply = NULL ;
2014-05-06 14:21:42 +04:00
struct iovec iov [ 2 ] ;
ssize_t nwritten ;
2007-06-10 21:02:09 +04:00
NTSTATUS status ;
2015-06-19 12:47:01 +03:00
int ret ;
2007-06-10 21:02:09 +04:00
ZERO_STRUCT ( req ) ;
req . hdr . length = offsetof ( struct ctdb_req_control , data ) + data . dsize ;
req . hdr . ctdb_magic = CTDB_MAGIC ;
2014-10-21 04:53:29 +04:00
req . hdr . ctdb_version = CTDB_PROTOCOL ;
2007-06-10 21:02:09 +04:00
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 ) ;
2014-05-06 14:21:42 +04:00
iov [ 0 ] . iov_base = & req ;
iov [ 0 ] . iov_len = offsetof ( struct ctdb_req_control , data ) ;
iov [ 1 ] . iov_base = data . dptr ;
iov [ 1 ] . iov_len = data . dsize ;
2007-06-10 21:02:09 +04:00
2014-05-06 14:21:42 +04:00
nwritten = write_data_iov ( conn - > fd , iov , ARRAY_SIZE ( iov ) ) ;
if ( nwritten = = - 1 ) {
DEBUG ( 3 , ( " write_data_iov failed: %s \n " , strerror ( errno ) ) ) ;
cluster_fatal ( " cluster dispatch daemon msg write error \n " ) ;
2007-06-10 21:02:09 +04:00
}
2008-08-07 10:20:05 +04:00
if ( flags & CTDB_CTRL_FLAG_NOREPLY ) {
2010-12-23 18:43:55 +03:00
if ( cstatus ) {
* cstatus = 0 ;
}
2008-08-07 10:20:05 +04:00
return NT_STATUS_OK ;
}
2015-06-19 12:47:01 +03:00
ret = ctdb_read_req ( conn , req . hdr . reqid , NULL , & hdr ) ;
if ( ret ! = 0 ) {
DEBUG ( 10 , ( " ctdb_read_req failed: %s \n " , strerror ( ret ) ) ) ;
status = map_nt_error_from_unix ( ret ) ;
2007-06-10 21:02:09 +04:00
goto fail ;
}
2014-05-06 14:21:42 +04:00
if ( hdr - > operation ! = CTDB_REPLY_CONTROL ) {
2007-06-10 21:02:09 +04:00
DEBUG ( 0 , ( " received invalid reply \n " ) ) ;
goto fail ;
}
2014-05-06 14:21:42 +04:00
reply = ( struct ctdb_reply_control * ) hdr ;
2007-06-10 21:02:09 +04:00
if ( outdata ) {
2015-05-10 02:33:10 +03:00
if ( ! ( outdata - > dptr = ( uint8_t * ) talloc_memdup (
2007-06-10 21:02:09 +04:00
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 ( reply ) ;
return status ;
}
/*
* see if a remote process exists
*/
2012-07-30 17:31:59 +04:00
bool ctdbd_process_exists ( struct ctdbd_connection * conn , uint32_t vnn , pid_t pid )
2007-06-10 21:02:09 +04:00
{
2011-10-26 13:36:21 +04:00
struct server_id id ;
bool result ;
2007-06-10 21:02:09 +04:00
2011-10-26 13:36:21 +04:00
id . pid = pid ;
id . vnn = vnn ;
2007-06-10 21:02:09 +04:00
2011-10-26 13:36:21 +04:00
if ( ! ctdb_processes_exist ( conn , & id , 1 , & result ) ) {
DEBUG ( 10 , ( " ctdb_processes_exist failed \n " ) ) ;
return false ;
2007-06-10 21:02:09 +04:00
}
2011-10-26 13:36:21 +04:00
return result ;
2007-06-10 21:02:09 +04:00
}
2011-10-23 23:38:54 +04:00
bool ctdb_processes_exist ( struct ctdbd_connection * conn ,
const struct server_id * pids , int num_pids ,
bool * results )
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
int i , num_received ;
uint32_t * reqids ;
bool result = false ;
reqids = talloc_array ( talloc_tos ( ) , uint32_t , num_pids ) ;
if ( reqids = = NULL ) {
goto fail ;
}
for ( i = 0 ; i < num_pids ; i + + ) {
struct ctdb_req_control req ;
2011-11-10 20:17:20 +04:00
pid_t pid ;
2014-05-06 14:21:42 +04:00
struct iovec iov [ 2 ] ;
ssize_t nwritten ;
2011-10-23 23:38:54 +04:00
results [ i ] = false ;
reqids [ i ] = ctdbd_next_reqid ( conn ) ;
ZERO_STRUCT ( req ) ;
2011-11-10 20:17:20 +04:00
/*
* pids [ i ] . pid is uint64_t , scale down to pid_t which
* is the wire protocol towards ctdb .
*/
pid = pids [ i ] . pid ;
2011-10-26 19:51:09 +04:00
DEBUG ( 10 , ( " Requesting PID %d/%d, reqid=%d \n " ,
2011-11-10 20:17:20 +04:00
( int ) pids [ i ] . vnn , ( int ) pid ,
2011-10-26 19:51:09 +04:00
( int ) reqids [ i ] ) ) ;
2011-10-23 23:38:54 +04:00
req . hdr . length = offsetof ( struct ctdb_req_control , data ) ;
2011-11-10 20:17:20 +04:00
req . hdr . length + = sizeof ( pid ) ;
2011-10-23 23:38:54 +04:00
req . hdr . ctdb_magic = CTDB_MAGIC ;
2014-10-21 04:53:29 +04:00
req . hdr . ctdb_version = CTDB_PROTOCOL ;
2011-10-23 23:38:54 +04:00
req . hdr . operation = CTDB_REQ_CONTROL ;
req . hdr . reqid = reqids [ i ] ;
req . hdr . destnode = pids [ i ] . vnn ;
req . opcode = CTDB_CONTROL_PROCESS_EXISTS ;
req . srvid = 0 ;
2011-11-10 20:17:20 +04:00
req . datalen = sizeof ( pid ) ;
2011-10-23 23:38:54 +04:00
req . flags = 0 ;
DEBUG ( 10 , ( " ctdbd_control: Sending ctdb packet \n " ) ) ;
ctdb_packet_dump ( & req . hdr ) ;
2014-05-06 14:21:42 +04:00
iov [ 0 ] . iov_base = & req ;
iov [ 0 ] . iov_len = offsetof ( struct ctdb_req_control , data ) ;
iov [ 1 ] . iov_base = & pid ;
iov [ 1 ] . iov_len = sizeof ( pid ) ;
nwritten = write_data_iov ( conn - > fd , iov , ARRAY_SIZE ( iov ) ) ;
if ( nwritten = = - 1 ) {
DEBUG ( 10 , ( " write_data_iov failed: %s \n " ,
strerror ( errno ) ) ) ;
2011-10-23 23:38:54 +04:00
goto fail ;
}
}
num_received = 0 ;
while ( num_received < num_pids ) {
2014-05-06 14:21:42 +04:00
struct ctdb_req_header * hdr ;
struct ctdb_reply_control * reply ;
2011-10-23 23:38:54 +04:00
uint32_t reqid ;
2015-06-19 12:47:01 +03:00
int ret ;
2011-10-23 23:38:54 +04:00
2015-06-19 12:47:01 +03:00
ret = ctdb_read_req ( conn , 0 , talloc_tos ( ) , & hdr ) ;
if ( ret ! = 0 ) {
2011-10-23 23:38:54 +04:00
DEBUG ( 10 , ( " ctdb_read_req failed: %s \n " ,
2015-06-19 12:47:01 +03:00
strerror ( ret ) ) ) ;
2011-10-23 23:38:54 +04:00
goto fail ;
}
2014-05-06 14:21:42 +04:00
if ( hdr - > operation ! = CTDB_REPLY_CONTROL ) {
2011-10-23 23:38:54 +04:00
DEBUG ( 10 , ( " Received invalid reply \n " ) ) ;
goto fail ;
}
2014-05-06 14:21:42 +04:00
reply = ( struct ctdb_reply_control * ) hdr ;
2011-10-23 23:38:54 +04:00
reqid = reply - > hdr . reqid ;
2011-10-26 19:51:09 +04:00
DEBUG ( 10 , ( " Received reqid %d \n " , ( int ) reqid ) ) ;
2011-10-23 23:38:54 +04:00
for ( i = 0 ; i < num_pids ; i + + ) {
if ( reqid = = reqids [ i ] ) {
break ;
}
}
if ( i = = num_pids ) {
DEBUG ( 10 , ( " Received unknown record number %u \n " ,
( unsigned ) reqid ) ) ;
goto fail ;
}
results [ i ] = ( ( reply - > status ) = = 0 ) ;
TALLOC_FREE ( reply ) ;
num_received + = 1 ;
}
result = true ;
fail :
TALLOC_FREE ( frame ) ;
return result ;
}
2007-06-10 21:02:09 +04:00
/*
* Get a db path
*/
char * ctdbd_dbpath ( struct ctdbd_connection * conn ,
TALLOC_CTX * mem_ctx , uint32_t db_id )
{
NTSTATUS status ;
TDB_DATA data ;
2015-03-04 11:43:19 +03:00
TDB_DATA rdata = { 0 } ;
2015-03-03 10:48:00 +03:00
int32_t cstatus = 0 ;
2007-06-10 21:02:09 +04:00
data . dptr = ( uint8_t * ) & db_id ;
data . dsize = sizeof ( db_id ) ;
status = ctdbd_control ( conn , CTDB_CURRENT_NODE ,
2015-03-04 11:43:09 +03:00
CTDB_CONTROL_GETDBPATH , 0 , 0 , data ,
2015-03-04 11:43:19 +03:00
mem_ctx , & rdata , & cstatus ) ;
2007-06-10 21:02:09 +04:00
if ( ! NT_STATUS_IS_OK ( status ) | | cstatus ! = 0 ) {
DEBUG ( 0 , ( __location__ " ctdb_control for getdbpath failed \n " ) ) ;
return NULL ;
}
2015-03-04 11:43:19 +03:00
return ( char * ) rdata . dptr ;
2007-06-10 21:02:09 +04:00
}
/*
* 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
2012-06-20 13:47:53 +04:00
data = string_term_tdb_data ( name ) ;
2007-06-10 21:02:09 +04:00
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 ,
2015-03-04 11:43:09 +03: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
*/
2012-07-30 17:31:59 +04:00
NTSTATUS ctdbd_migrate ( struct ctdbd_connection * conn , uint32_t db_id ,
2007-06-10 21:02:09 +04:00
TDB_DATA key )
{
struct ctdb_req_call req ;
2014-05-06 14:21:42 +04:00
struct ctdb_req_header * hdr ;
struct iovec iov [ 2 ] ;
ssize_t nwritten ;
2007-06-10 21:02:09 +04:00
NTSTATUS status ;
2015-06-19 12:47:01 +03:00
int ret ;
2007-06-10 21:02:09 +04:00
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 ;
2014-10-21 04:53:29 +04:00
req . hdr . ctdb_version = CTDB_PROTOCOL ;
2007-06-10 21:02:09 +04:00
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 ) ;
2014-05-06 14:21:42 +04:00
iov [ 0 ] . iov_base = & req ;
iov [ 0 ] . iov_len = offsetof ( struct ctdb_req_call , data ) ;
iov [ 1 ] . iov_base = key . dptr ;
iov [ 1 ] . iov_len = key . dsize ;
2007-06-10 21:02:09 +04:00
2014-05-06 14:21:42 +04:00
nwritten = write_data_iov ( conn - > fd , iov , ARRAY_SIZE ( iov ) ) ;
if ( nwritten = = - 1 ) {
DEBUG ( 3 , ( " write_data_iov failed: %s \n " , strerror ( errno ) ) ) ;
cluster_fatal ( " cluster dispatch daemon msg write error \n " ) ;
2007-06-10 21:02:09 +04:00
}
2015-06-19 12:47:01 +03:00
ret = ctdb_read_req ( conn , req . hdr . reqid , NULL , & hdr ) ;
if ( ret ! = 0 ) {
DEBUG ( 10 , ( " ctdb_read_req failed: %s \n " , strerror ( ret ) ) ) ;
status = map_nt_error_from_unix ( ret ) ;
2007-06-10 21:02:09 +04:00
goto fail ;
}
2014-05-06 14:21:42 +04:00
if ( hdr - > operation ! = CTDB_REPLY_CALL ) {
2007-06-10 21:02:09 +04:00
DEBUG ( 0 , ( " received invalid reply \n " ) ) ;
status = NT_STATUS_INTERNAL_ERROR ;
goto fail ;
}
status = NT_STATUS_OK ;
fail :
2014-05-06 14:21:42 +04:00
TALLOC_FREE ( hdr ) ;
2007-06-10 21:02:09 +04:00
return status ;
}
2012-11-23 20:54:57 +04:00
/*
* Fetch a record and parse it
*/
NTSTATUS ctdbd_parse ( struct ctdbd_connection * conn , uint32_t db_id ,
TDB_DATA key , bool local_copy ,
void ( * parser ) ( TDB_DATA key , TDB_DATA data ,
void * private_data ) ,
void * private_data )
{
struct ctdb_req_call req ;
2014-05-06 14:21:42 +04:00
struct ctdb_req_header * hdr = NULL ;
2012-11-23 20:54:57 +04:00
struct ctdb_reply_call * reply ;
2014-05-06 14:21:42 +04:00
struct iovec iov [ 2 ] ;
ssize_t nwritten ;
2012-11-23 20:54:57 +04:00
NTSTATUS status ;
uint32_t flags ;
2015-06-19 12:47:01 +03:00
int ret ;
2012-11-23 20:54:57 +04:00
flags = local_copy ? CTDB_WANT_READONLY : 0 ;
ZERO_STRUCT ( req ) ;
req . hdr . length = offsetof ( struct ctdb_req_call , data ) + key . dsize ;
req . hdr . ctdb_magic = CTDB_MAGIC ;
2014-10-21 04:53:29 +04:00
req . hdr . ctdb_version = CTDB_PROTOCOL ;
2012-11-23 20:54:57 +04:00
req . hdr . operation = CTDB_REQ_CALL ;
req . hdr . reqid = ctdbd_next_reqid ( conn ) ;
req . flags = flags ;
req . callid = CTDB_FETCH_FUNC ;
req . db_id = db_id ;
req . keylen = key . dsize ;
2014-05-06 14:21:42 +04:00
iov [ 0 ] . iov_base = & req ;
iov [ 0 ] . iov_len = offsetof ( struct ctdb_req_call , data ) ;
iov [ 1 ] . iov_base = key . dptr ;
iov [ 1 ] . iov_len = key . dsize ;
2012-11-23 20:54:57 +04:00
2014-05-06 14:21:42 +04:00
nwritten = write_data_iov ( conn - > fd , iov , ARRAY_SIZE ( iov ) ) ;
if ( nwritten = = - 1 ) {
DEBUG ( 3 , ( " write_data_iov failed: %s \n " , strerror ( errno ) ) ) ;
cluster_fatal ( " cluster dispatch daemon msg write error \n " ) ;
2012-11-23 20:54:57 +04:00
}
2015-06-19 12:47:01 +03:00
ret = ctdb_read_req ( conn , req . hdr . reqid , NULL , & hdr ) ;
if ( ret ! = 0 ) {
DEBUG ( 10 , ( " ctdb_read_req failed: %s \n " , strerror ( ret ) ) ) ;
status = map_nt_error_from_unix ( ret ) ;
2012-11-23 20:54:57 +04:00
goto fail ;
}
2015-04-23 19:06:17 +03:00
if ( ( hdr = = NULL ) | | ( hdr - > operation ! = CTDB_REPLY_CALL ) ) {
2012-11-23 20:54:57 +04:00
DEBUG ( 0 , ( " received invalid reply \n " ) ) ;
status = NT_STATUS_INTERNAL_ERROR ;
goto fail ;
}
2014-05-06 14:21:42 +04:00
reply = ( struct ctdb_reply_call * ) hdr ;
2012-11-23 20:54:57 +04:00
2013-08-28 15:34:08 +04:00
if ( reply - > datalen = = 0 ) {
/*
* Treat an empty record as non - existing
*/
status = NT_STATUS_NOT_FOUND ;
goto fail ;
}
2012-11-23 20:54:57 +04:00
parser ( key , make_tdb_data ( & reply - > data [ 0 ] , reply - > datalen ) ,
private_data ) ;
status = NT_STATUS_OK ;
fail :
2014-05-06 14:21:42 +04:00
TALLOC_FREE ( hdr ) ;
2007-06-10 21:02:09 +04:00
return status ;
}
/*
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 .
*/
2015-09-26 02:09:23 +03:00
NTSTATUS ctdbd_traverse ( struct ctdbd_connection * master , uint32_t db_id ,
2007-06-10 21:02:09 +04:00
void ( * fn ) ( TDB_DATA key , TDB_DATA data ,
void * private_data ) ,
void * private_data )
{
struct ctdbd_connection * conn ;
NTSTATUS status ;
2014-05-06 14:21:42 +04:00
TDB_DATA key , data ;
2007-06-10 21:02:09 +04:00
struct ctdb_traverse_start t ;
int cstatus ;
2011-12-23 17:45:45 +04:00
become_root ( ) ;
2015-09-26 02:09:23 +03:00
status = ctdbd_init_connection ( NULL , master - > sockname , master - > timeout ,
& conn ) ;
2011-12-23 17:45:45 +04:00
unbecome_root ( ) ;
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 ;
}
2014-05-06 14:21:42 +04:00
TALLOC_FREE ( conn ) ;
return status ;
2007-06-10 21:02:09 +04:00
}
while ( True ) {
2015-03-03 10:48:00 +03:00
struct ctdb_req_header * hdr = NULL ;
2014-05-06 14:21:42 +04:00
struct ctdb_req_message * m ;
struct ctdb_rec_data * d ;
2015-07-11 13:23:22 +03:00
int ret ;
2007-06-10 21:02:09 +04:00
2015-09-26 00:36:35 +03:00
ret = ctdb_read_packet ( conn - > fd , conn - > timeout , conn , & hdr ) ;
2015-07-11 13:23:22 +03:00
if ( ret ! = 0 ) {
2014-05-06 14:21:42 +04:00
DEBUG ( 0 , ( " ctdb_read_packet failed: %s \n " ,
2015-07-11 13:23:22 +03:00
strerror ( ret ) ) ) ;
2014-05-06 14:21:42 +04:00
cluster_fatal ( " ctdbd died \n " ) ;
}
2007-06-10 21:02:09 +04:00
2014-05-06 14:21:42 +04:00
if ( hdr - > operation ! = CTDB_REQ_MESSAGE ) {
DEBUG ( 0 , ( " Got operation %u, expected a message \n " ,
( unsigned ) hdr - > operation ) ) ;
TALLOC_FREE ( conn ) ;
return NT_STATUS_UNEXPECTED_IO_ERROR ;
2007-06-10 21:02:09 +04:00
}
2014-05-06 14:21:42 +04:00
m = ( struct ctdb_req_message * ) hdr ;
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 ) ) ;
TALLOC_FREE ( conn ) ;
return NT_STATUS_UNEXPECTED_IO_ERROR ;
2007-06-10 21:02:09 +04:00
}
2014-05-06 14:21:42 +04:00
key . dsize = d - > keylen ;
key . dptr = & d - > data [ 0 ] ;
data . dsize = d - > datalen ;
data . dptr = & d - > data [ d - > keylen ] ;
2007-06-10 21:02:09 +04:00
2014-05-06 14:21:42 +04:00
if ( key . dsize = = 0 & & data . dsize = = 0 ) {
/* end of traverse */
TALLOC_FREE ( conn ) ;
return NT_STATUS_OK ;
2007-07-13 14:40:53 +04:00
}
2014-05-06 14:21:42 +04:00
if ( data . dsize < sizeof ( struct ctdb_ltdb_header ) ) {
DEBUG ( 0 , ( " Got invalid ltdb header length %d \n " ,
( int ) data . dsize ) ) ;
TALLOC_FREE ( conn ) ;
return NT_STATUS_UNEXPECTED_IO_ERROR ;
2007-06-10 21:02:09 +04:00
}
2014-05-06 14:21:42 +04:00
data . dsize - = sizeof ( struct ctdb_ltdb_header ) ;
data . dptr + = sizeof ( struct ctdb_ltdb_header ) ;
2007-06-10 21:02:09 +04:00
2014-05-06 14:21:42 +04:00
if ( fn ! = NULL ) {
fn ( key , data , private_data ) ;
2007-06-10 21:02:09 +04:00
}
}
2014-05-06 14:21:42 +04:00
return NT_STATUS_OK ;
2007-06-10 21:02:09 +04:00
}
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 } ;
2012-06-20 13:47:32 +04:00
const struct sockaddr_in6 * in6 =
( const struct sockaddr_in6 * ) in ;
2009-01-28 20:55:13 +03:00
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 ;
2012-02-06 19:53:22 +04:00
memcpy ( & out4 - > sin_addr , & in6 - > sin6_addr . s6_addr [ 12 ] , 4 ) ;
2009-01-28 20:55:13 +03:00
}
}
# 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 ,
2015-06-23 20:07:44 +03:00
int ( * cb ) ( uint32_t src_vnn , uint32_t dst_vnn ,
uint64_t dst_srvid ,
const uint8_t * msg , size_t msglen ,
void * private_data ) ,
2007-06-10 21:02:09 +04:00
void * private_data )
{
2009-01-14 14:09:46 +03:00
struct ctdb_control_tcp_addr p ;
2015-05-20 09:12:46 +03:00
TDB_DATA data = { . dptr = ( uint8_t * ) & p , . dsize = sizeof ( p ) } ;
2007-06-10 21:02:09 +04:00
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
*/
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 :
2015-03-23 09:32:34 +03:00
memcpy ( & p . dest . ip , & server , sizeof ( p . dest . ip ) ) ;
memcpy ( & p . src . ip , & client , sizeof ( p . src . ip ) ) ;
2008-12-18 17:02:42 +03:00
break ;
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 ) ) ;
2008-12-18 17:02:42 +03:00
break ;
default :
return NT_STATUS_INTERNAL_ERROR ;
}
2007-06-10 21:02:09 +04:00
/*
* We want to be told about IP releases
*/
2015-06-23 20:07:44 +03:00
status = register_with_ctdbd ( conn , CTDB_SRVID_RELEASE_IP ,
cb , private_data ) ;
2007-06-10 21:02:09 +04:00
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
*/
2015-03-04 11:43:09 +03:00
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 ) ;
}
2008-08-07 10:20:05 +04:00
/*
call a control on the local node
*/
2012-07-30 17:31:59 +04:00
NTSTATUS ctdbd_control_local ( struct ctdbd_connection * conn , uint32_t opcode ,
uint64_t srvid , uint32_t flags , TDB_DATA data ,
2008-08-07 10:20:05 +04:00
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 ;
}
2015-09-26 02:52:58 +03:00
NTSTATUS ctdbd_probe ( const char * sockname , int timeout )
2013-01-31 14:15:09 +04:00
{
/*
* Do a very early check if ctdbd is around to avoid an abort and core
* later
*/
struct ctdbd_connection * conn = NULL ;
NTSTATUS status ;
2015-09-26 02:52:58 +03:00
status = ctdbd_messaging_connection ( talloc_tos ( ) , sockname , timeout ,
& conn ) ;
2013-01-31 14:15:09 +04:00
/*
* We only care if we can connect .
*/
TALLOC_FREE ( conn ) ;
return status ;
}