2006-11-18 02:41:20 +03:00
/*
ctdb over TCP
Copyright ( C ) Andrew Tridgell 2006
This library is free software ; you can redistribute it and / or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation ; either
version 2 of the License , or ( at your option ) any later version .
This library is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
Lesser General Public License for more details .
You should have received a copy of the GNU Lesser General Public
License along with this library ; if not , write to the Free Software
Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# include "includes.h"
# include "lib/events/events.h"
# include "system/network.h"
# include "system/filesys.h"
# include "ctdb_private.h"
2006-11-27 13:38:13 +03:00
# include "ctdb_tcp.h"
2006-11-18 02:41:20 +03:00
/*
called when socket becomes writeable on connect
*/
static void ctdb_node_connect_write ( struct event_context * ev , struct fd_event * fde ,
uint16_t flags , void * private )
{
struct ctdb_node * node = talloc_get_type ( private , struct ctdb_node ) ;
2006-11-27 13:38:13 +03:00
struct ctdb_tcp_node * tnode = talloc_get_type ( node - > private ,
struct ctdb_tcp_node ) ;
2006-11-18 02:41:20 +03:00
struct ctdb_context * ctdb = node - > ctdb ;
int error ;
socklen_t len ;
2006-11-27 13:38:13 +03:00
if ( getsockopt ( tnode - > fd , SOL_SOCKET , SO_ERROR , & error , & len ) ! = 0 | |
2006-11-18 07:27:36 +03:00
error ! = 0 ) {
if ( error = = EINPROGRESS ) {
printf ( " connect in progress \n " ) ;
return ;
}
printf ( " getsockopt errno=%s \n " , strerror ( errno ) ) ;
talloc_free ( fde ) ;
2006-11-27 13:38:13 +03:00
close ( tnode - > fd ) ;
tnode - > fd = - 1 ;
2006-11-18 02:41:20 +03:00
event_add_timed ( ctdb - > ev , node , timeval_current_ofs ( 1 , 0 ) ,
2006-11-28 03:51:33 +03:00
ctdb_tcp_node_connect , node ) ;
2006-11-18 02:41:20 +03:00
return ;
}
2006-11-18 03:21:40 +03:00
printf ( " Established connection to %s:%u \n " ,
node - > address . address , node - > address . port ) ;
2006-11-18 02:41:20 +03:00
talloc_free ( fde ) ;
2006-11-27 13:38:13 +03:00
event_add_fd ( node - > ctdb - > ev , node , tnode - > fd , EVENT_FD_READ ,
2006-11-28 03:51:33 +03:00
ctdb_tcp_node_read , node ) ;
2006-11-18 02:41:20 +03:00
}
/*
called when we should try and establish a tcp connection to a node
*/
2006-11-28 03:51:33 +03:00
void ctdb_tcp_node_connect ( struct event_context * ev , struct timed_event * te ,
struct timeval t , void * private )
2006-11-18 02:41:20 +03:00
{
2006-11-18 07:27:36 +03:00
struct ctdb_node * node = talloc_get_type ( private , struct ctdb_node ) ;
2006-11-27 13:38:13 +03:00
struct ctdb_tcp_node * tnode = talloc_get_type ( node - > private ,
struct ctdb_tcp_node ) ;
2006-11-18 02:41:20 +03:00
struct ctdb_context * ctdb = node - > ctdb ;
unsigned v ;
struct sockaddr_in sock_out ;
2006-11-27 13:38:13 +03:00
tnode - > fd = socket ( PF_INET , SOCK_STREAM , IPPROTO_TCP ) ;
2006-11-18 02:41:20 +03:00
2006-11-27 13:38:13 +03:00
v = fcntl ( tnode - > fd , F_GETFL , 0 ) ;
fcntl ( tnode - > fd , F_SETFL , v | O_NONBLOCK ) ;
2006-11-18 02:41:20 +03:00
2006-11-18 03:21:40 +03:00
inet_pton ( AF_INET , node - > address . address , & sock_out . sin_addr ) ;
sock_out . sin_port = htons ( node - > address . port ) ;
2006-11-18 02:41:20 +03:00
sock_out . sin_family = PF_INET ;
2006-11-27 13:38:13 +03:00
if ( connect ( tnode - > fd , & sock_out , sizeof ( sock_out ) ) ! = 0 & &
2006-11-18 02:41:20 +03:00
errno ! = EINPROGRESS ) {
/* try again once a second */
2006-11-27 13:38:13 +03:00
close ( tnode - > fd ) ;
2006-11-18 02:41:20 +03:00
event_add_timed ( ctdb - > ev , node , timeval_current_ofs ( 1 , 0 ) ,
2006-11-28 03:51:33 +03:00
ctdb_tcp_node_connect , node ) ;
2006-11-18 02:41:20 +03:00
return ;
}
/* non-blocking connect - wait for write event */
2006-11-27 13:38:13 +03:00
event_add_fd ( node - > ctdb - > ev , node , tnode - > fd , EVENT_FD_WRITE ,
2006-11-18 02:41:20 +03:00
ctdb_node_connect_write , node ) ;
}
2006-11-18 05:45:04 +03:00
/*
called when we get contacted by another node
currently makes no attempt to check if the connection is really from a ctdb
node in our cluster
*/
static void ctdb_listen_event ( struct event_context * ev , struct fd_event * fde ,
uint16_t flags , void * private )
{
struct ctdb_context * ctdb ;
2006-11-27 13:38:13 +03:00
struct ctdb_tcp * ctcp ;
2006-11-18 07:27:36 +03:00
struct sockaddr_in addr ;
2006-11-18 05:45:04 +03:00
socklen_t len ;
int fd ;
struct ctdb_incoming * in ;
ctdb = talloc_get_type ( private , struct ctdb_context ) ;
2006-11-27 13:38:13 +03:00
ctcp = talloc_get_type ( ctdb - > private , struct ctdb_tcp ) ;
2006-11-18 07:27:36 +03:00
memset ( & addr , 0 , sizeof ( addr ) ) ;
len = sizeof ( addr ) ;
2006-11-27 13:38:13 +03:00
fd = accept ( ctcp - > listen_fd , ( struct sockaddr * ) & addr , & len ) ;
2006-11-18 05:45:04 +03:00
if ( fd = = - 1 ) return ;
in = talloc ( ctdb , struct ctdb_incoming ) ;
in - > fd = fd ;
in - > ctdb = ctdb ;
event_add_fd ( ctdb - > ev , in , in - > fd , EVENT_FD_READ ,
2006-11-28 03:51:33 +03:00
ctdb_tcp_incoming_read , in ) ;
2006-11-18 07:27:36 +03:00
printf ( " New incoming socket %d \n " , in - > fd ) ;
2006-11-18 05:45:04 +03:00
}
/*
listen on our own address
*/
2006-11-28 03:51:33 +03:00
int ctdb_tcp_listen ( struct ctdb_context * ctdb )
2006-11-18 05:45:04 +03:00
{
2006-11-27 13:38:13 +03:00
struct ctdb_tcp * ctcp = talloc_get_type ( ctdb - > private , struct ctdb_tcp ) ;
2006-11-18 05:45:04 +03:00
struct sockaddr_in sock ;
int one = 1 ;
sock . sin_port = htons ( ctdb - > address . port ) ;
sock . sin_family = PF_INET ;
inet_pton ( AF_INET , ctdb - > address . address , & sock . sin_addr ) ;
2006-11-27 13:38:13 +03:00
ctcp - > listen_fd = socket ( PF_INET , SOCK_STREAM , IPPROTO_TCP ) ;
if ( ctcp - > listen_fd = = - 1 ) {
2006-11-18 05:45:04 +03:00
ctdb_set_error ( ctdb , " socket failed \n " ) ;
return - 1 ;
}
2006-11-27 13:38:13 +03:00
setsockopt ( ctcp - > listen_fd , SOL_SOCKET , SO_REUSEADDR , ( char * ) & one , sizeof ( one ) ) ;
2006-11-18 05:45:04 +03:00
2006-11-27 13:38:13 +03:00
if ( bind ( ctcp - > listen_fd , ( struct sockaddr * ) & sock , sizeof ( sock ) ) ! = 0 ) {
2006-11-18 05:45:04 +03:00
ctdb_set_error ( ctdb , " bind failed \n " ) ;
2006-11-27 13:38:13 +03:00
close ( ctcp - > listen_fd ) ;
ctcp - > listen_fd = - 1 ;
2006-11-18 05:45:04 +03:00
return - 1 ;
}
2006-11-27 13:38:13 +03:00
if ( listen ( ctcp - > listen_fd , 10 ) = = - 1 ) {
2006-11-18 05:45:04 +03:00
ctdb_set_error ( ctdb , " listen failed \n " ) ;
2006-11-27 13:38:13 +03:00
close ( ctcp - > listen_fd ) ;
ctcp - > listen_fd = - 1 ;
2006-11-18 05:45:04 +03:00
return - 1 ;
}
2006-11-27 13:38:13 +03:00
event_add_fd ( ctdb - > ev , ctdb , ctcp - > listen_fd , EVENT_FD_READ ,
2006-11-18 05:45:04 +03:00
ctdb_listen_event , ctdb ) ;
return 0 ;
}