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
*/
2016-04-08 17:14:33 +03:00
# include "replace.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"
2015-10-12 16:57:34 +03:00
# include "lib/util/sys_rw_data.h"
2015-05-25 09:50:35 +03:00
# include "lib/util/iov_buf.h"
2016-04-19 17:14:30 +03:00
# include "lib/util/select.h"
2016-04-08 17:14:33 +03:00
# include "lib/util/debug.h"
# include "lib/util/talloc_stack.h"
# include "lib/util/genrand.h"
# include "lib/util/fault.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_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 {
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 ;
}
2015-10-03 06:31:52 +03:00
static int ctdbd_control ( struct ctdbd_connection * conn ,
uint32_t vnn , uint32_t opcode ,
uint64_t srvid , uint32_t flags ,
TDB_DATA data ,
TALLOC_CTX * mem_ctx , TDB_DATA * outdata ,
2016-04-21 14:31:39 +03:00
int32_t * cstatus ) ;
2007-06-10 21:02:09 +04:00
/*
* 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-10-03 06:42:05 +03:00
int register_with_ctdbd ( struct ctdbd_connection * conn , uint64_t srvid ,
int ( * cb ) ( uint32_t src_vnn , uint32_t dst_vnn ,
uint64_t dst_srvid ,
const uint8_t * msg , size_t msglen ,
void * private_data ) ,
void * private_data )
2007-06-10 21:02:09 +04:00
{
2016-04-21 14:31:39 +03:00
int ret ;
int32_t 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
2016-04-13 19:47:46 +03:00
ret = ctdbd_control_local ( conn , CTDB_CONTROL_REGISTER_SRVID , srvid , 0 ,
tdb_null , NULL , NULL , & cstatus ) ;
2015-10-03 06:00:32 +03:00
if ( ret ! = 0 ) {
2015-10-03 06:42:05 +03:00
return ret ;
2014-11-21 18:20:10 +03:00
}
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 ) {
2015-10-03 06:42:05 +03:00
return ENOMEM ;
2014-11-21 18:20:10 +03:00
}
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
2015-10-03 06:42:05 +03:00
return 0 ;
2014-11-21 18:20:10 +03:00
}
2015-06-23 17:59:00 +03:00
static int ctdbd_msg_call_back ( struct ctdbd_connection * conn ,
2015-10-29 08:36:30 +03:00
struct ctdb_req_message_old * msg )
2015-05-19 16:07:33 +03:00
{
2016-04-19 17:02:49 +03:00
uint32_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 ;
2015-10-29 08:36:30 +03:00
if ( msg_len < offsetof ( struct ctdb_req_message_old , data ) ) {
2016-04-19 17:02:49 +03:00
DBG_DEBUG ( " len % " PRIu32 " too small \n " , msg_len ) ;
2015-06-23 17:59:00 +03:00
return 0 ;
2015-06-02 23:30:06 +03:00
}
2015-10-29 08:36:30 +03:00
msg_len - = offsetof ( struct ctdb_req_message_old , data ) ;
2015-06-02 23:30:06 +03:00
if ( msg_len < msg - > datalen ) {
2016-04-19 17:02:49 +03:00
DBG_DEBUG ( " msg_len=% " PRIu32 " < msg->datalen=% " PRIu32 " \n " ,
msg_len , 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
*/
2015-10-03 06:42:05 +03:00
static int get_cluster_vnn ( struct ctdbd_connection * conn , uint32_t * vnn )
2007-06-10 21:02:09 +04:00
{
int32_t cstatus = - 1 ;
2015-10-03 06:00:32 +03:00
int ret ;
2016-04-13 19:47:46 +03:00
ret = ctdbd_control_local ( conn , CTDB_CONTROL_GET_PNN , 0 , 0 ,
tdb_null , NULL , NULL , & cstatus ) ;
2015-10-03 06:00:32 +03:00
if ( ret ! = 0 ) {
DEBUG ( 1 , ( " ctdbd_control failed: %s \n " , strerror ( ret ) ) ) ;
2015-10-03 06:42:05 +03:00
return ret ;
2007-06-10 21:02:09 +04:00
}
* vnn = ( uint32_t ) cstatus ;
2015-10-03 06:42:05 +03:00
return ret ;
2007-06-10 21:02:09 +04:00
}
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 ;
TDB_DATA outdata ;
2015-10-29 09:22:48 +03:00
struct ctdb_node_map_old * m ;
2009-11-16 14:03:24 +03:00
uint32_t failure_flags ;
2015-10-03 06:05:15 +03:00
bool ok = false ;
2016-04-08 16:59:08 +03:00
uint32_t i ;
int ret ;
2009-11-16 14:03:24 +03:00
2016-04-13 19:47:46 +03:00
ret = ctdbd_control_local ( conn , CTDB_CONTROL_GET_NODEMAP , 0 , 0 ,
tdb_null , talloc_tos ( ) , & outdata , & cstatus ) ;
2015-10-03 06:06:59 +03:00
if ( ret ! = 0 ) {
DEBUG ( 1 , ( " ctdbd_control failed: %s \n " , strerror ( ret ) ) ) ;
2013-01-31 14:02:52 +04:00
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 ;
}
2015-10-29 09:22:48 +03:00
m = ( struct ctdb_node_map_old * ) outdata . dptr ;
2009-11-16 14:03:24 +03:00
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 ;
}
2015-10-03 06:05:15 +03:00
ok = true ;
2009-11-16 14:03:24 +03:00
fail :
TALLOC_FREE ( outdata . dptr ) ;
2015-10-03 06:05:15 +03:00
return ok ;
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 ;
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 ) {
2016-04-19 17:14:30 +03:00
struct pollfd pfd = { . fd = fd , . events = POLLIN } ;
int ret ;
ret = sys_poll_intr ( & pfd , 1 , timeout ) ;
2014-07-21 16:35:39 +04:00
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-10-03 05:51:01 +03:00
TALLOC_FREE ( req ) ;
2015-07-11 13:23:22 +03:00
return errno ;
2015-05-17 21:23:35 +03:00
}
if ( nread = = 0 ) {
2015-10-03 05:51:01 +03:00
TALLOC_FREE ( req ) ;
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 ) {
2015-10-29 08:36:30 +03:00
struct ctdb_req_message_old * msg = ( struct ctdb_req_message_old * ) hdr ;
2007-06-10 21:02:09 +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 )
{
2015-10-05 16:57:42 +03:00
TALLOC_FREE ( c - > fde ) ;
if ( c - > fd ! = - 1 ) {
close ( c - > fd ) ;
c - > fd = - 1 ;
}
2014-05-06 14:21:42 +04:00
return 0 ;
}
2007-06-10 21:02:09 +04:00
/*
* Get us a ctdbd connection
*/
2016-04-05 11:09:35 +03:00
int ctdbd_init_connection ( TALLOC_CTX * mem_ctx ,
const char * sockname , int timeout ,
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
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 " ) ) ;
2015-10-03 06:42:05 +03:00
return ENOMEM ;
2007-06-10 21:02:09 +04:00
}
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 ;
}
2016-04-19 22:40:40 +03:00
ret = ctdbd_connect ( sockname , & conn - > fd ) ;
2014-05-06 14:21:42 +04:00
if ( ret ! = 0 ) {
2015-06-26 14:17:01 +03:00
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
2015-10-03 06:42:05 +03:00
ret = get_cluster_vnn ( conn , & conn - > our_vnn ) ;
2007-06-10 21:02:09 +04:00
2015-10-03 06:42:05 +03:00
if ( ret ! = 0 ) {
DEBUG ( 10 , ( " get_cluster_vnn failed: %s \n " , strerror ( ret ) ) ) ;
2007-06-10 21:02:09 +04:00
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 " ) ) ;
2015-10-03 06:42:05 +03:00
ret = EIO ;
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-10-03 06:42:05 +03:00
ret = register_with_ctdbd ( conn , conn - > rand_srvid , NULL , NULL ) ;
2007-06-10 21:02:09 +04:00
2015-10-03 06:42:05 +03:00
if ( ret ! = 0 ) {
2007-06-10 21:02:09 +04:00
DEBUG ( 5 , ( " Could not register random srvid: %s \n " ,
2015-10-03 06:42:05 +03:00
strerror ( ret ) ) ) ;
2007-06-10 21:02:09 +04:00
goto fail ;
}
* pconn = conn ;
2015-10-03 06:42:05 +03:00
return 0 ;
2007-06-10 21:02:09 +04:00
fail :
TALLOC_FREE ( conn ) ;
2015-10-03 06:42:05 +03:00
return ret ;
2007-06-10 21:02:09 +04:00
}
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
{
2015-10-29 08:36:30 +03:00
struct ctdb_req_message_old * msg ;
2007-06-10 21:02:09 +04:00
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
}
2015-10-29 08:36:30 +03:00
msg = ( struct ctdb_req_message_old * ) hdr ;
2014-05-06 14:21:42 +04:00
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
}
2016-04-24 18:36:00 +03:00
void ctdbd_socket_readable ( struct ctdbd_connection * conn )
2007-06-10 21:02:09 +04:00
{
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
}
}
2015-10-03 06:42:05 +03:00
int 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
{
2015-10-29 08:36:30 +03:00
struct ctdb_req_message_old 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
2015-10-29 08:36:30 +03:00
r . hdr . length = offsetof ( struct ctdb_req_message_old , 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 ;
2015-10-29 08:36:30 +03:00
iov2 [ 0 ] . iov_len = offsetof ( struct ctdb_req_message_old , data ) ;
2015-05-25 09:50:35 +03:00
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
2015-10-03 06:42:05 +03:00
return 0 ;
2007-06-10 21:02:09 +04:00
}
/*
* send / recv a generic ctdb control message
*/
2015-10-03 06:31:52 +03:00
static int ctdbd_control ( struct ctdbd_connection * conn ,
uint32_t vnn , uint32_t opcode ,
uint64_t srvid , uint32_t flags ,
TDB_DATA data ,
TALLOC_CTX * mem_ctx , TDB_DATA * outdata ,
2016-04-21 14:31:39 +03:00
int32_t * cstatus )
2007-06-10 21:02:09 +04:00
{
2015-10-29 08:42:05 +03:00
struct ctdb_req_control_old req ;
2014-05-06 14:21:42 +04:00
struct ctdb_req_header * hdr ;
2015-10-29 08:44:08 +03:00
struct ctdb_reply_control_old * reply = NULL ;
2014-05-06 14:21:42 +04:00
struct iovec iov [ 2 ] ;
ssize_t nwritten ;
2015-06-19 12:47:01 +03:00
int ret ;
2007-06-10 21:02:09 +04:00
ZERO_STRUCT ( req ) ;
2015-10-29 08:42:05 +03:00
req . hdr . length = offsetof ( struct ctdb_req_control_old , data ) + data . dsize ;
2007-06-10 21:02:09 +04:00
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
2016-04-21 12:21:26 +03:00
DBG_DEBUG ( " Sending ctdb packet reqid=% " PRIu32 " , vnn=% " PRIu32 " , "
" opcode=% " PRIu32 " , srvid=% " PRIu64 " \n " , req . hdr . reqid ,
req . hdr . destnode , req . opcode , req . srvid ) ;
2007-08-29 15:46:44 +04:00
ctdb_packet_dump ( & req . hdr ) ;
2014-05-06 14:21:42 +04:00
iov [ 0 ] . iov_base = & req ;
2015-10-29 08:42:05 +03:00
iov [ 0 ] . iov_len = offsetof ( struct ctdb_req_control_old , data ) ;
2014-05-06 14:21:42 +04:00
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 ;
}
2015-10-03 05:54:31 +03:00
return 0 ;
2008-08-07 10:20:05 +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 ) ) ) ;
2015-10-03 05:54:31 +03:00
return ret ;
2007-06-10 21:02:09 +04:00
}
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 " ) ) ;
2015-10-03 05:54:31 +03:00
TALLOC_FREE ( hdr ) ;
return EIO ;
2007-06-10 21:02:09 +04:00
}
2015-10-29 08:44:08 +03:00
reply = ( struct ctdb_reply_control_old * ) 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 ) ;
2015-10-03 05:54:31 +03:00
return ENOMEM ;
2007-06-10 21:02:09 +04:00
}
outdata - > dsize = reply - > datalen ;
}
if ( cstatus ) {
( * cstatus ) = reply - > status ;
}
TALLOC_FREE ( reply ) ;
2015-10-03 05:54:31 +03:00
return ret ;
}
2007-06-10 21:02:09 +04:00
/*
* 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
{
2016-04-11 18:15:29 +03:00
int32_t cstatus = 0 ;
int ret ;
2007-06-10 21:02:09 +04:00
2016-04-11 18:15:29 +03:00
ret = ctdbd_control ( conn , vnn , CTDB_CONTROL_PROCESS_EXISTS , 0 , 0 ,
( TDB_DATA ) { . dptr = ( uint8_t * ) & pid ,
. dsize = sizeof ( pid ) } ,
NULL , NULL , & cstatus ) ;
if ( ret ! = 0 ) {
2011-10-26 13:36:21 +04:00
return false ;
2007-06-10 21:02:09 +04:00
}
2016-04-11 18:15:29 +03:00
return ( cstatus = = 0 ) ;
2011-10-23 23:38:54 +04:00
}
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 )
{
2015-10-03 06:08:53 +03:00
int ret ;
2007-06-10 21:02:09 +04:00
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 ) ;
2016-04-13 19:47:46 +03:00
ret = ctdbd_control_local ( conn , CTDB_CONTROL_GETDBPATH , 0 , 0 , data ,
mem_ctx , & rdata , & cstatus ) ;
2015-10-03 06:08:53 +03:00
if ( ( ret ! = 0 ) | | cstatus ! = 0 ) {
DEBUG ( 0 , ( __location__ " ctdb_control for getdbpath failed: %s \n " ,
strerror ( ret ) ) ) ;
2007-06-10 21:02:09 +04:00
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
*/
2015-10-03 06:42:05 +03:00
int ctdbd_db_attach ( struct ctdbd_connection * conn ,
const char * name , uint32_t * db_id , int tdb_flags )
2007-06-10 21:02:09 +04:00
{
2015-10-03 06:08:53 +03:00
int ret ;
2007-06-10 21:02:09 +04:00
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
2016-04-13 19:47:46 +03:00
ret = ctdbd_control_local ( conn ,
persistent
? CTDB_CONTROL_DB_ATTACH_PERSISTENT
: CTDB_CONTROL_DB_ATTACH ,
tdb_flags , 0 , data , NULL , & data , & cstatus ) ;
2015-10-03 06:08:53 +03:00
if ( ret ! = 0 ) {
2007-06-10 21:02:09 +04:00
DEBUG ( 0 , ( __location__ " ctdb_control for db_attach "
2015-10-03 06:08:53 +03:00
" failed: %s \n " , strerror ( ret ) ) ) ;
2015-10-03 06:42:05 +03:00
return ret ;
2007-06-10 21:02:09 +04:00
}
if ( cstatus ! = 0 | | data . dsize ! = sizeof ( uint32_t ) ) {
DEBUG ( 0 , ( __location__ " ctdb_control for db_attach failed \n " ) ) ;
2015-10-03 06:42:05 +03:00
return EIO ;
2007-06-10 21:02:09 +04:00
}
* db_id = * ( uint32_t * ) data . dptr ;
talloc_free ( data . dptr ) ;
if ( ! ( tdb_flags & TDB_SEQNUM ) ) {
2015-10-03 06:42:05 +03:00
return 0 ;
2007-06-10 21:02:09 +04:00
}
data . dptr = ( uint8_t * ) db_id ;
data . dsize = sizeof ( * db_id ) ;
2016-04-13 19:47:46 +03:00
ret = ctdbd_control_local ( conn , CTDB_CONTROL_ENABLE_SEQNUM , 0 , 0 , data ,
NULL , NULL , & cstatus ) ;
2015-10-03 06:08:53 +03:00
if ( ( ret ! = 0 ) | | cstatus ! = 0 ) {
DEBUG ( 0 , ( __location__ " ctdb_control for enable seqnum "
" failed: %s \n " , strerror ( ret ) ) ) ;
2015-10-03 06:42:05 +03:00
return ( ret = = 0 ) ? EIO : ret ;
2007-06-10 21:02:09 +04:00
}
2015-10-03 06:42:05 +03:00
return 0 ;
2007-06-10 21:02:09 +04:00
}
/*
* force the migration of a record to this node
*/
2015-10-03 06:42:05 +03:00
int ctdbd_migrate ( struct ctdbd_connection * conn , uint32_t db_id , TDB_DATA key )
2007-06-10 21:02:09 +04:00
{
2015-10-29 08:26:29 +03:00
struct ctdb_req_call_old req ;
2014-05-06 14:21:42 +04:00
struct ctdb_req_header * hdr ;
struct iovec iov [ 2 ] ;
ssize_t nwritten ;
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
2015-10-29 08:26:29 +03:00
req . hdr . length = offsetof ( struct ctdb_req_call_old , data ) + key . dsize ;
2007-06-10 21:02:09 +04:00
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 ;
2015-10-29 08:26:29 +03:00
iov [ 0 ] . iov_len = offsetof ( struct ctdb_req_call_old , data ) ;
2014-05-06 14:21:42 +04:00
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 ) ) ) ;
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 " ) ) ;
goto fail ;
}
fail :
2014-05-06 14:21:42 +04:00
TALLOC_FREE ( hdr ) ;
2015-10-03 06:42:05 +03:00
return ret ;
2007-06-10 21:02:09 +04:00
}
2012-11-23 20:54:57 +04:00
/*
* Fetch a record and parse it
*/
2015-10-03 06:42:05 +03:00
int 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 )
2012-11-23 20:54:57 +04:00
{
2015-10-29 08:26:29 +03:00
struct ctdb_req_call_old req ;
2014-05-06 14:21:42 +04:00
struct ctdb_req_header * hdr = NULL ;
2015-10-29 08:29:01 +03:00
struct ctdb_reply_call_old * reply ;
2014-05-06 14:21:42 +04:00
struct iovec iov [ 2 ] ;
ssize_t nwritten ;
2012-11-23 20:54:57 +04:00
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 ) ;
2015-10-29 08:26:29 +03:00
req . hdr . length = offsetof ( struct ctdb_req_call_old , data ) + key . dsize ;
2012-11-23 20:54:57 +04:00
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 ;
2015-10-29 08:26:29 +03:00
iov [ 0 ] . iov_len = offsetof ( struct ctdb_req_call_old , data ) ;
2014-05-06 14:21:42 +04:00
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 ) ) ) ;
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 " ) ) ;
2015-10-03 06:42:05 +03:00
ret = EIO ;
2012-11-23 20:54:57 +04:00
goto fail ;
}
2015-10-29 08:29:01 +03:00
reply = ( struct ctdb_reply_call_old * ) 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
*/
2015-10-03 06:42:05 +03:00
ret = ENOENT ;
2013-08-28 15:34:08 +04:00
goto fail ;
}
2012-11-23 20:54:57 +04:00
parser ( key , make_tdb_data ( & reply - > data [ 0 ] , reply - > datalen ) ,
private_data ) ;
2015-10-03 06:42:05 +03:00
ret = 0 ;
2012-11-23 20:54:57 +04:00
fail :
2014-05-06 14:21:42 +04:00
TALLOC_FREE ( hdr ) ;
2015-10-03 06:42:05 +03:00
return ret ;
2007-06-10 21:02:09 +04:00
}
/*
2016-04-05 18:30:11 +03:00
Traverse a ctdb database . " conn " must be an otherwise unused
ctdb_connection where no other messages but the traverse ones are
expected .
2007-06-10 21:02:09 +04:00
*/
2016-04-05 18:30:11 +03:00
int ctdbd_traverse ( struct ctdbd_connection * conn , 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 )
{
2015-10-03 06:08:53 +03:00
int ret ;
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 ;
2016-04-21 14:31:39 +03:00
int32_t cstatus ;
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 ) ;
2016-04-13 19:47:46 +03:00
ret = ctdbd_control_local ( conn , CTDB_CONTROL_TRAVERSE_START ,
conn - > rand_srvid ,
0 , data , NULL , NULL , & cstatus ) ;
2007-06-10 21:02:09 +04:00
2015-10-03 06:08:53 +03:00
if ( ( ret ! = 0 ) | | ( cstatus ! = 0 ) ) {
DEBUG ( 0 , ( " ctdbd_control failed: %s, %d \n " , strerror ( ret ) ,
2007-06-10 21:02:09 +04:00
cstatus ) ) ;
2015-10-03 06:42:05 +03:00
if ( ret = = 0 ) {
2007-06-10 21:02:09 +04:00
/*
* We need a mapping here
*/
2015-10-03 06:42:05 +03:00
ret = EIO ;
2007-06-10 21:02:09 +04:00
}
2015-10-03 06:42:05 +03:00
return ret ;
2007-06-10 21:02:09 +04:00
}
2016-04-08 17:14:33 +03:00
while ( true ) {
2015-03-03 10:48:00 +03:00
struct ctdb_req_header * hdr = NULL ;
2015-10-29 08:36:30 +03:00
struct ctdb_req_message_old * m ;
2015-10-29 09:30:30 +03:00
struct ctdb_rec_data_old * d ;
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 ) ) ;
2015-10-03 06:42:05 +03:00
return EIO ;
2007-06-10 21:02:09 +04:00
}
2015-10-29 08:36:30 +03:00
m = ( struct ctdb_req_message_old * ) hdr ;
2015-10-29 09:30:30 +03:00
d = ( struct ctdb_rec_data_old * ) & m - > data [ 0 ] ;
2014-05-06 14:21:42 +04:00
if ( m - > datalen < sizeof ( uint32_t ) | | m - > datalen ! = d - > length ) {
DEBUG ( 0 , ( " Got invalid traverse data of length %d \n " ,
( int ) m - > datalen ) ) ;
2015-10-03 06:42:05 +03:00
return EIO ;
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 */
2015-10-03 06:42:05 +03:00
return 0 ;
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 ) ) ;
2015-10-03 06:42:05 +03:00
return EIO ;
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
}
}
2015-10-03 06:42:05 +03:00
return 0 ;
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
*/
2015-10-03 06:42:05 +03:00
int ctdbd_register_ips ( struct ctdbd_connection * conn ,
const struct sockaddr_storage * _server ,
const struct sockaddr_storage * _client ,
int ( * cb ) ( uint32_t src_vnn , uint32_t dst_vnn ,
uint64_t dst_srvid ,
const uint8_t * msg , size_t msglen ,
void * private_data ) ,
void * private_data )
2007-06-10 21:02:09 +04:00
{
2015-10-29 06:25:34 +03:00
struct ctdb_connection p ;
2015-05-20 09:12:46 +03:00
TDB_DATA data = { . dptr = ( uint8_t * ) & p , . dsize = sizeof ( p ) } ;
2015-10-03 06:08:53 +03:00
int ret ;
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-10-29 06:25:34 +03:00
memcpy ( & p . dst . ip , & server , sizeof ( p . dst . ip ) ) ;
2015-03-23 09:32:34 +03:00
memcpy ( & p . src . ip , & client , sizeof ( p . src . ip ) ) ;
2008-12-18 17:02:42 +03:00
break ;
case AF_INET6 :
2015-10-29 06:25:34 +03:00
memcpy ( & p . dst . ip6 , & server , sizeof ( p . dst . ip6 ) ) ;
2011-10-21 14:04:59 +04:00
memcpy ( & p . src . ip6 , & client , sizeof ( p . src . ip6 ) ) ;
2008-12-18 17:02:42 +03:00
break ;
default :
2015-10-03 06:42:05 +03:00
return EIO ;
2008-12-18 17:02:42 +03:00
}
2007-06-10 21:02:09 +04:00
/*
* We want to be told about IP releases
*/
2015-10-03 06:42:05 +03:00
ret = register_with_ctdbd ( conn , CTDB_SRVID_RELEASE_IP ,
cb , private_data ) ;
if ( ret ! = 0 ) {
2015-10-03 06:42:05 +03:00
return ret ;
2007-06-10 21:02:09 +04:00
}
/*
* 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-10-03 06:31:52 +03:00
ret = ctdbd_control ( conn , CTDB_CURRENT_NODE ,
CTDB_CONTROL_TCP_CLIENT , 0 ,
CTDB_CTRL_FLAG_NOREPLY , data , NULL , NULL ,
NULL ) ;
2015-10-03 06:08:53 +03:00
if ( ret ! = 0 ) {
2015-10-03 06:42:05 +03:00
return ret ;
2015-10-03 06:08:53 +03:00
}
2015-10-03 06:42:05 +03:00
return 0 ;
2007-06-10 21:02:09 +04:00
}
2008-08-07 10:20:05 +04:00
/*
call a control on the local node
*/
2015-10-03 06:42:05 +03:00
int ctdbd_control_local ( struct ctdbd_connection * conn , uint32_t opcode ,
uint64_t srvid , uint32_t flags , TDB_DATA data ,
TALLOC_CTX * mem_ctx , TDB_DATA * outdata ,
2016-04-21 14:31:39 +03:00
int32_t * cstatus )
2008-08-07 10:20:05 +04:00
{
2015-10-03 06:42:05 +03:00
return ctdbd_control ( conn , CTDB_CURRENT_NODE , opcode , srvid , flags , data ,
mem_ctx , outdata , cstatus ) ;
2008-08-07 10:20:05 +04:00
}
2015-10-03 06:42:05 +03:00
int ctdb_watch_us ( struct ctdbd_connection * conn )
2009-10-25 18:12:12 +03:00
{
2015-10-28 09:43:20 +03:00
struct ctdb_notify_data_old reg_data ;
2009-10-25 18:12:12 +03:00
size_t struct_len ;
2015-10-03 06:42:05 +03:00
int ret ;
2016-04-21 14:31:39 +03:00
int32_t cstatus ;
2009-10-25 18:12:12 +03:00
reg_data . srvid = CTDB_SRVID_SAMBA_NOTIFY ;
reg_data . len = 1 ;
reg_data . notify_data [ 0 ] = 0 ;
2015-10-28 09:43:20 +03:00
struct_len = offsetof ( struct ctdb_notify_data_old ,
2009-10-25 18:12:12 +03:00
notify_data ) + reg_data . len ;
2015-10-03 06:42:05 +03:00
ret = ctdbd_control_local (
2009-10-25 18:12:12 +03:00
conn , CTDB_CONTROL_REGISTER_NOTIFY , conn - > rand_srvid , 0 ,
make_tdb_data ( ( uint8_t * ) & reg_data , struct_len ) ,
NULL , NULL , & cstatus ) ;
2015-10-03 06:42:05 +03:00
if ( ret ! = 0 ) {
2009-10-25 18:12:12 +03:00
DEBUG ( 1 , ( " ctdbd_control_local failed: %s \n " ,
2015-10-03 06:42:05 +03:00
strerror ( ret ) ) ) ;
2009-10-25 18:12:12 +03:00
}
2015-10-03 06:42:05 +03:00
return ret ;
2009-10-25 18:12:12 +03:00
}
2015-10-03 06:42:05 +03:00
int ctdb_unwatch ( struct ctdbd_connection * conn )
2009-10-25 18:12:12 +03:00
{
2015-10-28 09:47:03 +03:00
uint64_t srvid = CTDB_SRVID_SAMBA_NOTIFY ;
2015-10-03 06:42:05 +03:00
int ret ;
2016-04-21 14:31:39 +03:00
int32_t cstatus ;
2009-10-25 18:12:12 +03:00
2015-10-03 06:42:05 +03:00
ret = ctdbd_control_local (
2009-10-25 18:12:12 +03:00
conn , CTDB_CONTROL_DEREGISTER_NOTIFY , conn - > rand_srvid , 0 ,
2015-10-28 09:47:03 +03:00
make_tdb_data ( ( uint8_t * ) & srvid , sizeof ( srvid ) ) ,
2009-10-25 18:12:12 +03:00
NULL , NULL , & cstatus ) ;
2015-10-03 06:42:05 +03:00
if ( ret ! = 0 ) {
2009-10-25 18:12:12 +03:00
DEBUG ( 1 , ( " ctdbd_control_local failed: %s \n " ,
2015-10-03 06:42:05 +03:00
strerror ( ret ) ) ) ;
2009-10-25 18:12:12 +03:00
}
2015-10-03 06:42:05 +03:00
return ret ;
2009-10-25 18:12:12 +03:00
}
2015-10-03 06:42:05 +03:00
int 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 ;
2015-10-03 06:42:05 +03:00
int ret ;
2013-01-31 14:15:09 +04:00
2016-04-05 10:52:01 +03:00
ret = ctdbd_init_connection ( talloc_tos ( ) , sockname , timeout ,
& conn ) ;
2013-01-31 14:15:09 +04:00
/*
* We only care if we can connect .
*/
TALLOC_FREE ( conn ) ;
2015-10-03 06:42:05 +03:00
return ret ;
2013-01-31 14:15:09 +04:00
}