phpseclib: setTimeout doesn't work with the sleep command
Hello, thank you for the wonderful library and all the work you do with phpseclib.
I am curious about the following case.
When I’m setting timeout for some command like ‘ping’ it works as expected.
When I’m setting timeout and call ‘sleep’, command waits the exact number of seconds passed to sleep, instead of respecting the timeout set to SSH2.
The code:
<?php
use phpseclib\Crypt\RSA;
use phpseclib\Net\SSH2;
$key = new RSA();
$key->loadKey(file_get_contents('private-key.txt'));
$ssh = new SSH2('127.0.0.1');
if (!$ssh->login('username', $key)) {
exit('Login Failed');
}
$ssh->setTimeout(3);
$start = microtime(true);
$ssh->exec('ping google.com');
$elapsed = microtime(true) - $start;
if ($ssh->isTimeout()) {
echo sprintf('Command timed out in %01.2f seconds', $elapsed);
} else {
echo sprintf('Command completed in %01.2f seconds', $elapsed);
}
The code above returns as expected:
Command timed out in 3.12 seconds
However:
<?php
use phpseclib\Crypt\RSA;
use phpseclib\Net\SSH2;
$key = new RSA();
$key->loadKey(file_get_contents('private-key.txt'));
$ssh = new SSH2('127.0.0.1');
if (!$ssh->login('username', $key)) {
exit('Login Failed');
}
$ssh->setTimeout(3);
$start = microtime(true);
$ssh->exec('sleep 10');
$elapsed = microtime(true) - $start;
if ($ssh->isTimeout()) {
echo sprintf('Command timed out in %01.2f seconds', $elapsed);
} else {
echo sprintf('Command completed in %01.2f seconds', $elapsed);
}
I am expecting the command to time out after 3 seconds. But the second code runs for 10 seconds instead of 3 and outputs
Command timed out in 10.11 seconds
What am I missing here?
About this issue
- Original URL
- State: open
- Created 5 years ago
- Comments: 15 (11 by maintainers)
Commits related to this issue
- SSH2: timeout after 5s for channel closures — committed to phpseclib/phpseclib by terrafrost 4 years ago
I’m able to reproduce the issue.
From the logs:
Per that phpseclib does try to close the channel after ~3s. The problem is that the server isn’t acknowledging the close request until ~7s after it was sent (ie. after which ~10s has cumulatively passed).
Unfortunately, I’m not really sure what can be done about this. phpseclib could be updated so that it doesn’t wait for the close request to be acknowledged by the server but then what? If you just want to issue that one command then it’s not a problem but if you do want to issue other commands then it becomes more complicated.
In phpseclib 4.0 I want to rewrite SSH2 so that it supports multiple channels. At that point phpseclib wouldn’t need to wait for the close confirmation - every
execwould be on it’s own unique channel. But that’s not an option for phpseclib 1.0 - 3.0. For these we’d just need to wait for that close confirmation before the the next command could be ran.Meh. I’m sure that’s not the answer you were hoping to hear 😦
Just in case, the following way of setting a timeout will also work perfectly with
sleep:$ssh->exec('timeout 5 sleep 10');As you can see, it relies on having the
timeoututility from GNU coreutils available on the remote system, so YMMV. AFAIK it is available on most modern linux distributions.No worries, thank you for at least looking into the issue. I guess I’ll wait for the future versions then - good luck with the releases!