1
0
mirror of https://github.com/danog/phpseclib.git synced 2024-12-15 10:26:59 +01:00

Merge branch 'keepalive-master'

This commit is contained in:
terrafrost 2020-12-16 23:15:16 -06:00
commit d1c8c6dba1

View File

@ -715,6 +715,14 @@ class SSH2
*/ */
protected $curTimeout; protected $curTimeout;
/**
* Keep Alive Interval
*
* @see self::setKeepAlive()
* @access private
*/
var $keepAlive;
/** /**
* Real-time log file pointer * Real-time log file pointer
* *
@ -2537,6 +2545,19 @@ class SSH2
$this->timeout = $this->curTimeout = $timeout; $this->timeout = $this->curTimeout = $timeout;
} }
/**
* Set Keep Alive
*
* Sends an SSH2_MSG_IGNORE message every x seconds, if x is a positive non-zero number.
*
* @param mixed $timeout
* @access public
*/
function setKeepAlive($interval)
{
$this->keepAlive = $interval;
}
/** /**
* Get the output from stdError * Get the output from stdError
* *
@ -3167,6 +3188,54 @@ class SSH2
*/ */
private function get_binary_packet($skip_channel_filter = false) private function get_binary_packet($skip_channel_filter = false)
{ {
if ($skip_channel_filter) {
$read = [$this->fsock];
$write = $except = null;
if ($this->curTimeout <= 0) {
if ($this->keepAlive <= 0) {
stream_select($read, $write, $except, null);
} else {
if (!stream_select($read, $write, $except, $this->keepAlive)) {
$this->send_binary_packet(pack('CN', NET_SSH2_MSG_IGNORE, 0));
return $this->get_binary_packet(true);
}
}
} else {
if ($this->curTimeout < 0) {
$this->is_timeout = true;
return true;
}
$read = [$this->fsock];
$write = $except = null;
$start = microtime(true);
if ($this->keepAlive > 0 && $this->keepAlive < $this->curTimeout) {
if (!stream_select($read, $write, $except, $this->keepAlive)) {
$this->send_binary_packet(pack('CN', NET_SSH2_MSG_IGNORE, 0));
$elapsed = microtime(true) - $start;
$this->curTimeout-= $elapsed;
return $this->get_binary_packet(true);
}
$elapsed = microtime(true) - $start;
$this->curTimeout-= $elapsed;
}
$sec = floor($this->curTimeout);
$usec = 1000000 * ($this->curTimeout - $sec);
// on windows this returns a "Warning: Invalid CRT parameters detected" error
if (!stream_select($read, $write, $except, $sec, $usec)) {
$this->is_timeout = true;
return true;
}
$elapsed = microtime(true) - $start;
$this->curTimeout-= $elapsed;
}
}
if (!is_resource($this->fsock) || feof($this->fsock)) { if (!is_resource($this->fsock) || feof($this->fsock)) {
$this->bitmap = 0; $this->bitmap = 0;
throw new ConnectionClosedException('Connection closed prematurely'); throw new ConnectionClosedException('Connection closed prematurely');
@ -3423,9 +3492,19 @@ class SSH2
// only called when we've already logged in // only called when we've already logged in
if (($this->bitmap & self::MASK_CONNECTED) && $this->isAuthenticated()) { if (($this->bitmap & self::MASK_CONNECTED) && $this->isAuthenticated()) {
switch (ord($payload[0])) { switch (ord($payload[0])) {
case NET_SSH2_MSG_CHANNEL_REQUEST:
if (strlen($payload) == 31) {
extract(unpack('cpacket_type/Nchannel/Nlength', $payload));
if (substr($payload, 9, $length) == 'keepalive@openssh.com' && isset($this->server_channels[$channel])) {
if (ord(substr($payload, 9 + $length))) { // want reply
$this->send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_SUCCESS, $this->server_channels[$channel]));
}
$payload = $this->get_binary_packet($skip_channel_filter);
}
}
break;
case NET_SSH2_MSG_CHANNEL_DATA: case NET_SSH2_MSG_CHANNEL_DATA:
case NET_SSH2_MSG_CHANNEL_EXTENDED_DATA: case NET_SSH2_MSG_CHANNEL_EXTENDED_DATA:
case NET_SSH2_MSG_CHANNEL_REQUEST:
case NET_SSH2_MSG_CHANNEL_CLOSE: case NET_SSH2_MSG_CHANNEL_CLOSE:
case NET_SSH2_MSG_CHANNEL_EOF: case NET_SSH2_MSG_CHANNEL_EOF:
if (!$skip_channel_filter && !empty($this->server_channels)) { if (!$skip_channel_filter && !empty($this->server_channels)) {
@ -3609,35 +3688,13 @@ class SSH2
$response = $this->binary_packet_buffer; $response = $this->binary_packet_buffer;
$this->binary_packet_buffer = false; $this->binary_packet_buffer = false;
} else { } else {
$read = [$this->fsock]; $response = $this->get_binary_packet(true);
$write = $except = null; if ($response === true && $this->is_timeout) {
if (!$this->curTimeout) {
stream_select($read, $write, $except, null);
} else {
if ($this->curTimeout < 0) {
$this->is_timeout = true;
return true;
}
$read = [$this->fsock];
$write = $except = null;
$start = microtime(true);
$sec = floor($this->curTimeout);
$usec = 1000000 * ($this->curTimeout - $sec);
if (!stream_select($read, $write, $except, $sec, $usec)) {
$this->is_timeout = true;
if ($client_channel == self::CHANNEL_EXEC && !$this->request_pty) { if ($client_channel == self::CHANNEL_EXEC && !$this->request_pty) {
$this->close_channel($client_channel); $this->close_channel($client_channel);
} }
return true; return true;
} }
$elapsed = microtime(true) - $start;
$this->curTimeout-= $elapsed;
}
$response = $this->get_binary_packet(true);
if ($response === false) { if ($response === false) {
$this->disconnect_helper(NET_SSH2_DISCONNECT_CONNECTION_LOST); $this->disconnect_helper(NET_SSH2_DISCONNECT_CONNECTION_LOST);
throw new ConnectionClosedException('Connection closed by server'); throw new ConnectionClosedException('Connection closed by server');