HOST: foreach $host (@hostlist) { my $timeout = 30; #connect to the remote site Log(LOGFILE, "INFO: $0::Connecting to $host"); eval { local $SIG{ALRM} = sub { die "alarm\n" }; alarm $timeout; $ibisSite=openRemoteSql($host,$mySocket,"$user","$pass"); alarm 0; }; if ($@) { Log(LOGFILE, "ERROR: $0:$host:Cant Connect to site:$@"); next HOST; } #### # # Use openRemote to create a tunnel to the remote mysql server. # Then try to connect to it every 3 seconds for 15 seconds (I made these numbers # up ... they may need to increase for China ! ) # sub openRemoteSql { $hostname = $_[0] ; $port = $_[1] ; $user = $_[2] ; $pass = $_[3] ; # # Look for a free "port" to use $cnt = 0 ; $tmp = -1 ; while( $tmp == -1 ) { if( $cnt > 10 ) { print "can't find a free port in $_[1] .. $port\n" ; return 0; } $port = $_[1] + $cnt ; #print $port , "\n" ; $tmp = openRemote( $hostname,$port,3306,$user,$pass ) ; $cnt ++; } # # if openRemote returns '0' then the ssh failed, probably can't contact # host or some other shyte # if( $tmp < 1 ) { return $tmp ; } $cnt = 0 ; while( $cnt < 5 ) { $db = DBI->connect("dbi:mysql:database="$remotedb";host=127.0.0.1;port=$port", "$user", "$pass"); if( $db ) { # # Wow .. it all worked ..... # return $db ; } $cnt ++ ; sleep( 3 ) ; } closeRemote($port) ; return 0 ; } #### # # Open the SSH Connection to the site.... this provides us with a tunnel for # any other services ! # # Return # -1 Lock File Exists # 0 == Failure # 1 = allOk # sub openRemote { use FileHandle; use IPC::Open2; $hostname = $_[0] ; $lport = $_[1] ; $rport = $_[2] ; $user = $_[3] ; $pass = $_[4] ; $timeout = $_[5] ; # mod 001 add timeout to open ssh if( ! $timeout ) { $timeout = 120 ; } if( ! testSite( $hostname ) ) { return 0 ; } ################################################## # # If the Lock file exists return -1 # ################################################## $lockFile = LockFileName( $lport ) ; if ( -e $lockFile ) { return -1 ; } $g_RemotePort = $lport ; ################################################## # # create the ssh gateway # ################################################## # # Save current alarm handler # $saved = $SIG{ ALRM } ; $SIG{ALRM} = sub { die 'Open Remote : timeout' } ; eval{ alarm( $timeout ) ; $s = " /usr/bin/ssh -T root@" . $hostname . " -L ". $lport .":127.0.0.1:" . $rport . " -g " ; $pid = open2( \*SSHRead , \*SSHWrite , $s ) || die "Can't open a ssh connection to " . $hostname ; $debug = 0; if( $debug == 1 ) { print $hostname . "Opened Connection returned pid = $pid \n" ; } # # For some reason the constants are not defined ... # open mode is create/write/exclusive # if file exists .. then this will explode ! # sysopen(WTMP, $lockFile, 0301) || die "Exclusive Access to $lockFile failed" ; print WTMP " kill -9 $pid\n" ; close WTMP ; SSHWrite->autoflush(); # # we execute the following commands so we can tell when the # ssh has "REALLY" connected, and then we can check that we # are on the host we are suppesed to be on .. this is an un-necessary # step but I don't mind 'cos there'd be real problems if # something went wrong, such as an old process hanging around # print SSHWrite "echo XXXXX Started OK \n" ; print SSHWrite "echo \$HOSTNAME\n" ; SSHWrite->autoflush(); # # read what is being returned from the "remote end" # timeout processing means that this will die if the # above echos are not returned "pretty quick" # while( 1 ) { $s = ; if( ! defined($s)) { print "SSH Failure\n"; return 0 ; } if( $s =~ /bind:/ ) { print "Failure $s\n" ; $s = ; print "$s\n" ; return 0 ; } if( $s =~ /XXXXX Started OK/ ) { $s = ; return 1 ; } } } ; # # if we timedout then set the pid to 0, code later on then handles this # if ($@) { if ( $@ =~ /timeout/ ){ print "FATAL ERROR : Timeout when ssh-ing to $hostname\n" ; $pid = 0 ; } $globalErrorMessage = $@ ; } # # restore alarm handler # alarm(0) ; if( $saved ) { $SIG{ ALRM } = $saved ; } # # if the connection failed ... then return 0 --> Failure # if( ! $pid ) { closeRemote( $g_RemotePort ) ; return 0 ; } return 1 ; }