title: Checking if an SSH tunnel is up and running
body: <p>I have a perl script which, when destilled a bit, looks like this:</p>
  
  <pre><code>my $randport = int(10000 + rand(1000));          # Random port as other scripts like this run at the same time
  my $localip = '192.168.100.' . ($port - 4000);   # Don't ask... backwards compatibility
  system("ssh -NL $randport:$localip:23 root\@$ip -o ConnectTimeout=60 -i somekey &amp;");    # create the tunnel in the background
  
  sleep 10;       # Give the tunnel some time to come up
  
  # Create the telnet object
  my $telnet = new Net::Telnet(
          Timeout =&gt;      10,
          Host    =&gt;      'localhost',
          Port    =&gt;      $randport,
          Telnetmode =&gt;   0,
          Errmode =&gt;      \&amp;fail,
  );
  
  # SNIPPED... a bunch of parsing data from $telnet
  </code></pre>
  
  <p>The thing is that the target $ip is on a link with very unpredictable bandwidth, so the tunnel might come up right away, it might take a while, it might not come up at all. So a sleep is necessary to give the tunnel some time to get up and running.</p>
  
  <p>So the question is: How can i test if the tunnel is up and running? 10 seconds is a really undesirable delay if the tunnel comes up straight away. Ideally, i would like to check if it's up and continue with creating the telnet object once it is, to a maximum of, say, 30 seconds.</p>
  
  <p><strong>Edit:</strong> Ping doesn't help me mouch, as the remote end of the tunnel is generally up, but with a very high amount of packetloss</p>
  
  <p><strong>Solved:</strong> Extrapolating from the tip suggested by mikebabcock, <code>sleep 10</code> has been replaced with this block which works like a charm:</p>
  
  <pre><code>my $starttime = time();
  while (1)
  {
      # Check for success
      if (system("nc -dzw10 localhost $randport &gt; /dev/null") == 0) { last }
  
      # Check for timeout
      if (time() &gt; $starttime + 30) { &amp;fail() }
  
      # 250ms delay before recheck
      select (undef, undef, undef, 0.25);
  }
  </code></pre>