2015-04-14 10:20:05 +03:00
/*
CTDB protocol marshalling
Copyright ( C ) Amitay Isaacs 2015
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , see < http : //www.gnu.org/licenses/>.
*/
# include "replace.h"
# include "system/network.h"
# include <talloc.h>
2018-07-11 11:35:46 +03:00
# include "common/line.h"
2015-04-14 10:20:05 +03:00
# include "protocol.h"
2017-09-04 09:00:48 +03:00
# include "protocol_util.h"
2019-01-29 15:03:20 +03:00
# include "lib/util/util.h"
2020-07-03 09:11:20 +03:00
# include "lib/util/smb_strtox.h"
2015-04-14 10:20:05 +03:00
static struct {
enum ctdb_runstate runstate ;
const char * label ;
} runstate_map [ ] = {
{ CTDB_RUNSTATE_UNKNOWN , " UNKNOWN " } ,
{ CTDB_RUNSTATE_INIT , " INIT " } ,
{ CTDB_RUNSTATE_SETUP , " SETUP " } ,
{ CTDB_RUNSTATE_FIRST_RECOVERY , " FIRST_RECOVERY " } ,
{ CTDB_RUNSTATE_STARTUP , " STARTUP " } ,
{ CTDB_RUNSTATE_RUNNING , " RUNNING " } ,
{ CTDB_RUNSTATE_SHUTDOWN , " SHUTDOWN " } ,
{ - 1 , NULL } ,
} ;
const char * ctdb_runstate_to_string ( enum ctdb_runstate runstate )
{
int i ;
for ( i = 0 ; runstate_map [ i ] . label ! = NULL ; i + + ) {
if ( runstate_map [ i ] . runstate = = runstate ) {
return runstate_map [ i ] . label ;
}
}
return runstate_map [ 0 ] . label ;
}
enum ctdb_runstate ctdb_runstate_from_string ( const char * runstate_str )
{
int i ;
for ( i = 0 ; runstate_map [ i ] . label ! = NULL ; i + + ) {
if ( strcasecmp ( runstate_map [ i ] . label ,
runstate_str ) = = 0 ) {
return runstate_map [ i ] . runstate ;
}
}
return CTDB_RUNSTATE_UNKNOWN ;
}
static struct {
enum ctdb_event event ;
const char * label ;
} event_map [ ] = {
{ CTDB_EVENT_INIT , " init " } ,
{ CTDB_EVENT_SETUP , " setup " } ,
{ CTDB_EVENT_STARTUP , " startup " } ,
{ CTDB_EVENT_START_RECOVERY , " startrecovery " } ,
{ CTDB_EVENT_RECOVERED , " recovered " } ,
{ CTDB_EVENT_TAKE_IP , " takeip " } ,
{ CTDB_EVENT_RELEASE_IP , " releaseip " } ,
{ CTDB_EVENT_MONITOR , " monitor " } ,
{ CTDB_EVENT_SHUTDOWN , " shutdown " } ,
{ CTDB_EVENT_UPDATE_IP , " updateip " } ,
{ CTDB_EVENT_IPREALLOCATED , " ipreallocated " } ,
{ CTDB_EVENT_MAX , " all " } ,
{ - 1 , NULL } ,
} ;
const char * ctdb_event_to_string ( enum ctdb_event event )
{
int i ;
for ( i = 0 ; event_map [ i ] . label ! = NULL ; i + + ) {
if ( event_map [ i ] . event = = event ) {
return event_map [ i ] . label ;
}
}
return " unknown " ;
}
enum ctdb_event ctdb_event_from_string ( const char * event_str )
{
int i ;
for ( i = 0 ; event_map [ i ] . label ! = NULL ; i + + ) {
if ( strcmp ( event_map [ i ] . label , event_str ) = = 0 ) {
return event_map [ i ] . event ;
}
}
return CTDB_EVENT_MAX ;
}
2015-11-02 08:24:15 +03:00
2017-09-11 08:00:10 +03:00
int ctdb_sock_addr_to_buf ( char * buf , socklen_t buflen ,
ctdb_sock_addr * addr , bool with_port )
2015-11-02 08:24:15 +03:00
{
2017-06-30 08:11:04 +03:00
const char * t ;
2021-12-30 04:29:58 +03:00
size_t len = 0 ;
2015-11-02 08:24:15 +03:00
switch ( addr - > sa . sa_family ) {
case AF_INET :
2017-06-30 08:11:04 +03:00
t = inet_ntop ( addr - > ip . sin_family , & addr - > ip . sin_addr ,
buf , buflen ) ;
if ( t = = NULL ) {
return errno ;
}
2021-12-30 04:29:58 +03:00
if ( with_port ) {
len = strlen ( buf ) ;
}
2015-11-02 08:24:15 +03:00
break ;
2021-12-30 04:29:58 +03:00
case AF_INET6 : {
char tmp [ INET6_ADDRSTRLEN ] ;
t = inet_ntop ( addr - > ip6 . sin6_family ,
& addr - > ip6 . sin6_addr ,
tmp ,
sizeof ( tmp ) ) ;
2017-06-30 08:11:04 +03:00
if ( t = = NULL ) {
return errno ;
}
2021-12-30 04:29:58 +03:00
if ( with_port ) {
int ret = snprintf ( buf , buflen , " [%s] " , tmp ) ;
if ( ret < 0 ) {
return ENOSPC ;
}
len = ( size_t ) ret ;
} else {
len = strlcpy ( buf , tmp , buflen ) ;
}
if ( len > = buflen ) {
return ENOSPC ;
}
2015-11-02 08:24:15 +03:00
break ;
2021-12-30 04:29:58 +03:00
}
2015-11-02 08:24:15 +03:00
default :
2017-06-30 08:11:04 +03:00
return EAFNOSUPPORT ;
2015-11-02 08:24:15 +03:00
break ;
}
2017-09-11 08:00:10 +03:00
if ( with_port ) {
int ret ;
ret = snprintf ( buf + len , buflen - len ,
" :%u " , ctdb_sock_addr_port ( addr ) ) ;
2019-06-23 14:00:38 +03:00
if ( ret < 0 | | ( size_t ) ret > = buflen - len ) {
2017-09-11 08:00:10 +03:00
return ENOSPC ;
}
}
2017-06-30 08:11:04 +03:00
return 0 ;
}
2019-05-27 13:31:51 +03:00
char * ctdb_sock_addr_to_string ( TALLOC_CTX * mem_ctx ,
ctdb_sock_addr * addr ,
bool with_port )
2017-06-30 08:11:04 +03:00
{
size_t len = 64 ;
char * cip ;
int ret ;
cip = talloc_size ( mem_ctx , len ) ;
if ( cip = = NULL ) {
return NULL ;
}
2017-09-11 08:00:10 +03:00
ret = ctdb_sock_addr_to_buf ( cip , len , addr , with_port ) ;
2017-06-30 08:11:04 +03:00
if ( ret ! = 0 ) {
talloc_free ( cip ) ;
return NULL ;
}
2015-11-02 08:24:15 +03:00
return cip ;
}
2016-04-27 11:30:12 +03:00
2017-09-11 09:39:38 +03:00
static int ipv4_from_string ( const char * str , struct sockaddr_in * ip )
{
int ret ;
* ip = ( struct sockaddr_in ) {
. sin_family = AF_INET ,
} ;
ret = inet_pton ( AF_INET , str , & ip - > sin_addr ) ;
if ( ret ! = 1 ) {
return EINVAL ;
}
# ifdef HAVE_SOCK_SIN_LEN
ip - > sin_len = sizeof ( * ip ) ;
# endif
return 0 ;
}
static int ipv6_from_string ( const char * str , struct sockaddr_in6 * ip6 )
{
int ret ;
* ip6 = ( struct sockaddr_in6 ) {
. sin6_family = AF_INET6 ,
} ;
ret = inet_pton ( AF_INET6 , str , & ip6 - > sin6_addr ) ;
if ( ret ! = 1 ) {
return EINVAL ;
}
2018-06-27 06:41:38 +03:00
# ifdef HAVE_SOCK_SIN6_LEN
2017-09-11 09:39:38 +03:00
ip6 - > sin6_len = sizeof ( * ip6 ) ;
# endif
return 0 ;
}
static int ip_from_string ( const char * str , ctdb_sock_addr * addr )
{
char * p ;
int ret ;
if ( addr = = NULL ) {
return EINVAL ;
}
ZERO_STRUCTP ( addr ) ; /* valgrind :-) */
/* IPv4 or IPv6 address?
*
2021-12-29 17:10:28 +03:00
* Use strrchr ( ) because we need the right - most ' : ' below for
2017-09-11 09:39:38 +03:00
* IPv4 - mapped IPv6 addresses anyway . . .
*/
2021-12-29 17:10:28 +03:00
p = strrchr ( str , ' : ' ) ;
2017-09-11 09:39:38 +03:00
if ( p = = NULL ) {
ret = ipv4_from_string ( str , & addr - > ip ) ;
} else {
2021-12-29 16:46:14 +03:00
static const uint8_t ipv4_mapped_prefix [ 12 ] = {
2017-09-11 09:39:38 +03:00
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xff , 0xff
} ;
2021-12-23 13:52:38 +03:00
size_t len = strlen ( str ) ;
char s [ 64 ] ;
len = strlcpy ( s , str , sizeof ( s ) ) ;
if ( len > = sizeof ( s ) ) {
return EINVAL ;
}
if ( ( len > = 2 ) & & ( s [ 0 ] = = ' [ ' ) & & ( s [ len - 1 ] = = ' ] ' ) ) {
s [ len - 1 ] = ' \0 ' ;
str = s + 1 ;
p = strrchr ( str , ' : ' ) ;
}
2017-09-11 09:39:38 +03:00
ret = ipv6_from_string ( str , & addr - > ip6 ) ;
if ( ret ! = 0 ) {
return ret ;
}
/*
* Check for IPv4 - mapped IPv6 address
* ( e . g . : : ffff : 192.0 .2 .128 ) - reparse as IPv4 if
* necessary
*/
if ( memcmp ( & addr - > ip6 . sin6_addr . s6_addr [ 0 ] ,
ipv4_mapped_prefix ,
sizeof ( ipv4_mapped_prefix ) ) = = 0 ) {
ctdb: Initialize addr struct to zero before reparsing as IPV4
Failed to kill the tcp connection that using IPv4-mapped IPv6 address
(e.g. ctdb_killtcp eth0 ::ffff:192.168.200.44:2049
::ffff:192.168.200.45:863).
When the ctdb_killtcp is used to kill the tcp connection, the IPs and
ports in the connection will be parsed to conn.client and conn.server
(call stack: main->ctdb_sock_addr_from_string->ip_from_string). In
the ip_from_string, as we are using IPv4-mapped IPv6 addresses, the
ipv6_from_string will be used to parse ip to addr.ip6 first. The next
step the ipv4_from_string will be used to reparse ip to addr.ip.
As a result, the data that dump from conn.server is "2 0 8 1 192 168
200 44 0 0 0 0 0 0 0 0 0 0 255 255 192 168 200 44 0 0 0 0", the data
from conn.client is "2 0 3 95 192 168 200 45 0 0 0 0 0 0 0 0 0 0 255 255
192 168 200 45 0 0 0 0". The connection will be add to conn_list by
ctdb_connection_list_add. Then the reset_connections_send uses conn_list
as parameter to start to reset connections in the conn_list.
In the reset_connections_send, the database "connections" will be
created. The connections from conn_list will be written to the
database(call db_hash_add), and use the data that dump from conn_client
and conn_server as key.
In the reset_connections_capture_tcp_handler, the
ctdb_sys_read_tcp_packet will receive data on the raw socket. And
extract the IPs and ports from the tcp packet. when extracting IP and
port, the tcp4_extract OR tcp6_extract will be used. Then we got the
new conn.client and conn.server. the data that dump from the
conn.server is "2 0 8 1 192 168 200 44 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0", the data from conn.client is "2 0 3 95 192 168 200 45 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0". Finally, we use the data as key to check
if this connection is one being reset(call db_hash_delete). The
db_hash_delete will return ENOENT. Because the two key that being used
by db_hash_delete and db_hash_add are different.
So, the TCP RST will be NOT sent for the connection forever. We should
initialize addr struct to zero before reparsing as IPV4 in the
ip_from_string.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=13839
Signed-off-by: Zhu Shangzhong <zhu.shangzhong@zte.com.cn>
Reviewed-by: Martin Schwenke <martin@meltin.net>
Reviewed-by: Amitay Isaacs <amitay@samba.org>
2019-03-12 15:49:48 +03:00
/* Initialize addr struct to zero before reparsing as IPV4 */
ZERO_STRUCTP ( addr ) ;
2017-09-11 09:39:38 +03:00
/* Reparse as IPv4 */
ret = ipv4_from_string ( p + 1 , & addr - > ip ) ;
}
}
return ret ;
}
int ctdb_sock_addr_from_string ( const char * str ,
ctdb_sock_addr * addr , bool with_port )
{
char * p ;
char s [ 64 ] ; /* Much longer than INET6_ADDRSTRLEN */
unsigned port ;
size_t len ;
2017-10-09 06:52:30 +03:00
int ret ;
2017-09-11 09:39:38 +03:00
if ( ! with_port ) {
ret = ip_from_string ( str , addr ) ;
return ret ;
}
/* Parse out port number and then IP address */
2018-07-26 04:01:30 +03:00
len = strlcpy ( s , str , sizeof ( s ) ) ;
2017-09-11 09:39:38 +03:00
if ( len > = sizeof ( s ) ) {
return EINVAL ;
}
2021-12-29 17:10:28 +03:00
p = strrchr ( s , ' : ' ) ;
2017-09-11 09:39:38 +03:00
if ( p = = NULL ) {
return EINVAL ;
}
2019-04-12 17:58:13 +03:00
port = smb_strtoul ( p + 1 , NULL , 10 , & ret , SMB_STR_FULL_STR_CONV ) ;
if ( ret ! = 0 ) {
2017-09-11 09:39:38 +03:00
/* Empty string or trailing garbage */
return EINVAL ;
}
* p = ' \0 ' ;
ret = ip_from_string ( s , addr ) ;
ctdb_sock_addr_set_port ( addr , port ) ;
return ret ;
}
2018-06-08 00:13:25 +03:00
int ctdb_sock_addr_mask_from_string ( const char * str ,
ctdb_sock_addr * addr ,
unsigned int * mask )
{
char * p ;
char s [ 64 ] ; /* Much longer than INET6_ADDRSTRLEN */
unsigned int m ;
2019-06-23 13:59:34 +03:00
size_t len ;
2019-01-29 15:03:20 +03:00
int ret = 0 ;
2018-06-08 00:13:25 +03:00
if ( addr = = NULL | | mask = = NULL ) {
return EINVAL ;
}
len = strlcpy ( s , str , sizeof ( s ) ) ;
if ( len > = sizeof ( s ) ) {
return EINVAL ;
}
2021-12-29 17:10:28 +03:00
p = strrchr ( s , ' / ' ) ;
2018-06-08 00:13:25 +03:00
if ( p = = NULL ) {
return EINVAL ;
}
2019-04-12 17:58:13 +03:00
m = smb_strtoul ( p + 1 , NULL , 10 , & ret , SMB_STR_FULL_STR_CONV ) ;
if ( ret ! = 0 ) {
2018-06-08 00:13:25 +03:00
/* Empty string or trailing garbage */
return EINVAL ;
}
* p = ' \0 ' ;
ret = ip_from_string ( s , addr ) ;
if ( ret = = 0 ) {
* mask = m ;
}
return ret ;
}
2017-06-02 09:17:22 +03:00
unsigned int ctdb_sock_addr_port ( ctdb_sock_addr * addr )
{
switch ( addr - > sa . sa_family ) {
case AF_INET :
return ntohs ( addr - > ip . sin_port ) ;
break ;
case AF_INET6 :
return ntohs ( addr - > ip6 . sin6_port ) ;
break ;
default :
return 0 ;
}
}
void ctdb_sock_addr_set_port ( ctdb_sock_addr * addr , unsigned int port )
{
switch ( addr - > sa . sa_family ) {
case AF_INET :
addr - > ip . sin_port = htons ( port ) ;
break ;
case AF_INET6 :
addr - > ip6 . sin6_port = htons ( port ) ;
break ;
default :
break ;
}
}
2017-09-13 09:18:29 +03:00
static int ctdb_sock_addr_cmp_family ( const ctdb_sock_addr * addr1 ,
const ctdb_sock_addr * addr2 )
2016-04-27 11:30:12 +03:00
{
2016-05-23 03:35:10 +03:00
/* This is somewhat arbitrary. However, when used for sorting
* it just needs to be consistent .
*/
if ( addr1 - > sa . sa_family < addr2 - > sa . sa_family ) {
return - 1 ;
}
if ( addr1 - > sa . sa_family > addr2 - > sa . sa_family ) {
return 1 ;
2016-04-27 11:30:12 +03:00
}
2017-09-13 09:18:29 +03:00
return 0 ;
}
int ctdb_sock_addr_cmp_ip ( const ctdb_sock_addr * addr1 ,
const ctdb_sock_addr * addr2 )
{
int ret ;
ret = ctdb_sock_addr_cmp_family ( addr1 , addr2 ) ;
if ( ret ! = 0 ) {
return ret ;
}
2016-04-27 11:30:12 +03:00
switch ( addr1 - > sa . sa_family ) {
case AF_INET :
2016-05-23 03:35:10 +03:00
ret = memcmp ( & addr1 - > ip . sin_addr . s_addr ,
& addr2 - > ip . sin_addr . s_addr , 4 ) ;
2016-04-27 11:30:12 +03:00
break ;
case AF_INET6 :
2016-05-23 03:35:10 +03:00
ret = memcmp ( addr1 - > ip6 . sin6_addr . s6_addr ,
addr2 - > ip6 . sin6_addr . s6_addr , 16 ) ;
2016-07-22 06:35:00 +03:00
break ;
default :
2016-05-23 03:35:10 +03:00
ret = - 1 ;
2016-07-22 06:35:00 +03:00
}
2016-05-23 03:35:10 +03:00
return ret ;
2016-07-22 06:35:00 +03:00
}
2016-05-23 03:35:10 +03:00
int ctdb_sock_addr_cmp ( const ctdb_sock_addr * addr1 ,
const ctdb_sock_addr * addr2 )
2016-07-22 06:35:00 +03:00
{
2016-05-23 03:35:10 +03:00
int ret = 0 ;
ret = ctdb_sock_addr_cmp_ip ( addr1 , addr2 ) ;
if ( ret ! = 0 ) {
return ret ;
2016-07-22 06:35:00 +03:00
}
switch ( addr1 - > sa . sa_family ) {
case AF_INET :
2016-05-23 03:35:10 +03:00
if ( addr1 - > ip . sin_port < addr2 - > ip . sin_port ) {
ret = - 1 ;
} else if ( addr1 - > ip . sin_port > addr2 - > ip . sin_port ) {
ret = 1 ;
2016-07-22 06:35:00 +03:00
}
break ;
case AF_INET6 :
2016-05-23 03:35:10 +03:00
if ( addr1 - > ip6 . sin6_port < addr2 - > ip6 . sin6_port ) {
ret = - 1 ;
} else if ( addr1 - > ip6 . sin6_port > addr2 - > ip6 . sin6_port ) {
ret = 1 ;
2016-04-27 11:30:12 +03:00
}
break ;
default :
2016-05-23 03:35:10 +03:00
ret = - 1 ;
2016-04-27 11:30:12 +03:00
}
2016-05-23 03:35:10 +03:00
return ret ;
}
bool ctdb_sock_addr_same_ip ( const ctdb_sock_addr * addr1 ,
const ctdb_sock_addr * addr2 )
{
return ( ctdb_sock_addr_cmp_ip ( addr1 , addr2 ) = = 0 ) ;
}
bool ctdb_sock_addr_same ( const ctdb_sock_addr * addr1 ,
const ctdb_sock_addr * addr2 )
{
return ( ctdb_sock_addr_cmp ( addr1 , addr2 ) = = 0 ) ;
2016-04-27 11:30:12 +03:00
}
2017-09-04 09:41:30 +03:00
2023-12-12 15:39:21 +03:00
bool ctdb_connection_same ( const struct ctdb_connection * conn1 ,
const struct ctdb_connection * conn2 )
{
bool same ;
same = ctdb_sock_addr_same ( & conn1 - > src , & conn2 - > src ) ;
if ( ! same ) {
return false ;
}
same = ctdb_sock_addr_same ( & conn1 - > dst , & conn2 - > dst ) ;
if ( ! same ) {
return false ;
}
return true ;
}
2022-07-19 04:53:15 +03:00
int ctdb_connection_to_buf ( char * buf ,
size_t buflen ,
struct ctdb_connection * conn ,
bool client_first ,
const char * sep )
2017-09-04 09:41:30 +03:00
{
char server [ 64 ] , client [ 64 ] ;
int ret ;
ret = ctdb_sock_addr_to_buf ( server , sizeof ( server ) ,
& conn - > server , true ) ;
if ( ret ! = 0 ) {
return ret ;
}
ret = ctdb_sock_addr_to_buf ( client , sizeof ( client ) ,
& conn - > client , true ) ;
if ( ret ! = 0 ) {
return ret ;
}
if ( ! client_first ) {
2022-07-19 04:53:15 +03:00
ret = snprintf ( buf , buflen , " %s%s%s " , server , sep , client ) ;
2017-09-04 09:41:30 +03:00
} else {
2022-07-19 04:53:15 +03:00
ret = snprintf ( buf , buflen , " %s%s%s " , client , sep , server ) ;
2017-09-04 09:41:30 +03:00
}
2019-06-23 14:00:38 +03:00
if ( ret < 0 | | ( size_t ) ret > = buflen ) {
2017-09-04 09:41:30 +03:00
return ENOSPC ;
}
return 0 ;
}
2019-05-27 13:31:51 +03:00
char * ctdb_connection_to_string ( TALLOC_CTX * mem_ctx ,
struct ctdb_connection * conn ,
bool client_first )
2017-09-04 09:41:30 +03:00
{
const size_t len = 128 ;
char * out ;
int ret ;
out = talloc_size ( mem_ctx , len ) ;
if ( out = = NULL ) {
return NULL ;
}
2022-07-19 04:53:15 +03:00
ret = ctdb_connection_to_buf ( out , len , conn , client_first , " " ) ;
2017-09-04 09:41:30 +03:00
if ( ret ! = 0 ) {
talloc_free ( out ) ;
return NULL ;
}
return out ;
}
int ctdb_connection_from_string ( const char * str , bool client_first ,
struct ctdb_connection * conn )
{
char s [ 128 ] ;
char * t1 = NULL , * t2 = NULL ;
size_t len ;
ctdb_sock_addr * first = ( client_first ? & conn - > client : & conn - > server ) ;
ctdb_sock_addr * second = ( client_first ? & conn - > server : & conn - > client ) ;
int ret ;
len = strlcpy ( s , str , sizeof ( s ) ) ;
if ( len > = sizeof ( s ) ) {
return EINVAL ;
}
t1 = strtok ( s , " \t \n " ) ;
if ( t1 = = NULL ) {
return EINVAL ;
}
t2 = strtok ( NULL , " \t \n \0 " ) ;
if ( t2 = = NULL ) {
return EINVAL ;
}
ret = ctdb_sock_addr_from_string ( t1 , first , true ) ;
if ( ret ! = 0 ) {
return ret ;
}
ret = ctdb_sock_addr_from_string ( t2 , second , true ) ;
if ( ret ! = 0 ) {
return ret ;
}
ret = ctdb_sock_addr_cmp_family ( first , second ) ;
if ( ret ! = 0 ) {
return EINVAL ;
}
return 0 ;
}
2017-09-04 10:01:05 +03:00
int ctdb_connection_list_add ( struct ctdb_connection_list * conn_list ,
struct ctdb_connection * conn )
{
uint32_t len ;
if ( conn_list = = NULL ) {
return EINVAL ;
}
/* Ensure array is big enough */
len = talloc_array_length ( conn_list - > conn ) ;
if ( conn_list - > num = = len ) {
conn_list - > conn = talloc_realloc ( conn_list , conn_list - > conn ,
struct ctdb_connection ,
len + 128 ) ;
if ( conn_list - > conn = = NULL ) {
return ENOMEM ;
}
}
conn_list - > conn [ conn_list - > num ] = * conn ;
conn_list - > num + + ;
return 0 ;
}
static int connection_cmp ( const void * a , const void * b )
{
const struct ctdb_connection * conn_a = a ;
const struct ctdb_connection * conn_b = b ;
int ret ;
ret = ctdb_sock_addr_cmp ( & conn_a - > server , & conn_b - > server ) ;
if ( ret = = 0 ) {
ret = ctdb_sock_addr_cmp ( & conn_a - > client , & conn_b - > client ) ;
}
return ret ;
}
int ctdb_connection_list_sort ( struct ctdb_connection_list * conn_list )
{
if ( conn_list = = NULL ) {
return EINVAL ;
}
if ( conn_list - > num > 0 ) {
qsort ( conn_list - > conn , conn_list - > num ,
sizeof ( struct ctdb_connection ) , connection_cmp ) ;
}
return 0 ;
}
2019-05-27 13:31:51 +03:00
char * ctdb_connection_list_to_string (
2017-09-04 10:01:05 +03:00
TALLOC_CTX * mem_ctx ,
struct ctdb_connection_list * conn_list , bool client_first )
{
uint32_t i ;
char * out ;
out = talloc_strdup ( mem_ctx , " " ) ;
if ( out = = NULL ) {
return NULL ;
}
if ( conn_list = = NULL | | conn_list - > num = = 0 ) {
return out ;
}
for ( i = 0 ; i < conn_list - > num ; i + + ) {
char buf [ 128 ] ;
int ret ;
2022-07-19 04:53:15 +03:00
ret = ctdb_connection_to_buf ( buf ,
sizeof ( buf ) ,
& conn_list - > conn [ i ] ,
client_first ,
" " ) ;
2017-09-04 10:01:05 +03:00
if ( ret ! = 0 ) {
talloc_free ( out ) ;
return NULL ;
}
out = talloc_asprintf_append ( out , " %s \n " , buf ) ;
if ( out = = NULL ) {
return NULL ;
}
}
return out ;
}
2018-07-11 11:35:46 +03:00
struct ctdb_connection_list_read_state {
2017-09-04 10:01:05 +03:00
struct ctdb_connection_list * list ;
2018-07-11 11:35:46 +03:00
bool client_first ;
} ;
static int ctdb_connection_list_read_line ( char * line , void * private_data )
{
struct ctdb_connection_list_read_state * state =
( struct ctdb_connection_list_read_state * ) private_data ;
struct ctdb_connection conn ;
2017-09-04 10:01:05 +03:00
int ret ;
2018-07-11 11:35:46 +03:00
/* Skip empty lines */
if ( line [ 0 ] = = ' \0 ' ) {
return 0 ;
2017-09-04 10:01:05 +03:00
}
2018-07-11 11:35:46 +03:00
/* Comment */
if ( line [ 0 ] = = ' # ' ) {
return 0 ;
2017-09-04 10:01:05 +03:00
}
2018-07-11 11:35:46 +03:00
ret = ctdb_connection_from_string ( line , state - > client_first , & conn ) ;
if ( ret ! = 0 ) {
return ret ;
}
2017-09-04 10:01:05 +03:00
2018-07-11 11:35:46 +03:00
ret = ctdb_connection_list_add ( state - > list , & conn ) ;
if ( ret ! = 0 ) {
return ret ;
}
2017-09-04 10:01:05 +03:00
2018-07-11 11:35:46 +03:00
return 0 ;
}
2017-09-04 10:01:05 +03:00
2018-07-18 12:00:42 +03:00
int ctdb_connection_list_read ( TALLOC_CTX * mem_ctx ,
int fd ,
bool client_first ,
2018-07-11 11:35:46 +03:00
struct ctdb_connection_list * * conn_list )
{
struct ctdb_connection_list_read_state state ;
int ret ;
2017-09-04 10:01:05 +03:00
2018-07-11 11:35:46 +03:00
if ( conn_list = = NULL ) {
return EINVAL ;
}
2017-09-04 10:01:05 +03:00
2018-07-11 11:35:46 +03:00
state . list = talloc_zero ( mem_ctx , struct ctdb_connection_list ) ;
if ( state . list = = NULL ) {
return ENOMEM ;
2017-09-04 10:01:05 +03:00
}
2018-07-11 11:35:46 +03:00
state . client_first = client_first ;
2018-07-18 12:00:42 +03:00
ret = line_read ( fd ,
2018-07-11 11:35:46 +03:00
128 ,
mem_ctx ,
ctdb_connection_list_read_line ,
& state ,
NULL ) ;
2017-09-04 10:01:05 +03:00
2018-07-11 11:35:46 +03:00
* conn_list = state . list ;
return ret ;
2017-09-04 10:01:05 +03:00
}