diff --git a/phpseclib/Net/SSH2.php b/phpseclib/Net/SSH2.php index 8ebfa804..ef02ebd1 100644 --- a/phpseclib/Net/SSH2.php +++ b/phpseclib/Net/SSH2.php @@ -938,6 +938,14 @@ class SSH2 */ var $preferred_signature_format = false; + /** + * Authentication Credentials + * + * @var array + * @access private + */ + var $auth = array(); + /** * Default Constructor. * @@ -2136,6 +2144,7 @@ class SSH2 */ public function login($username, ...$args) { + $this->auth[] = array_merge([$username], $args); return $this->sublogin($username, ...$args); } @@ -3266,6 +3275,64 @@ class SSH2 return (bool) ($this->bitmap & self::MASK_LOGIN); } + /** + * Pings a server connection, or tries to reconnect if the connection has gone down + * + * Inspired by http://php.net/manual/en/mysqli.ping.php + * + * @return bool + */ + public function ping() + { + if (!$this->isAuthenticated()) { + return false; + } + + $this->window_size_server_to_client[NET_SSH2_CHANNEL_KEEP_ALIVE] = $this->window_size; + $packet_size = 0x4000; + $packet = pack( + 'CNa*N3', + NET_SSH2_MSG_CHANNEL_OPEN, + strlen('session'), + 'session', + NET_SSH2_CHANNEL_KEEP_ALIVE, + $this->window_size_server_to_client[NET_SSH2_CHANNEL_KEEP_ALIVE], + $packet_size + ); + + if (!@$this->send_binary_packet($packet)) { + return $this->reconnect(); + } + + $this->channel_status[NET_SSH2_CHANNEL_KEEP_ALIVE] = NET_SSH2_MSG_CHANNEL_OPEN; + + $response = @$this->get_channel_packet(NET_SSH2_CHANNEL_KEEP_ALIVE); + if ($response !== false) { + $this->close_channel(NET_SSH2_CHANNEL_KEEP_ALIVE); + return true; + } + + return $this->reconnect(); + } + + /** + * In situ reconnect method + * + * @return boolean + */ + private function reconnect() + { + $this->reset_connection(NET_SSH2_DISCONNECT_CONNECTION_LOST); + $this->retry_connect = true; + if (!$this->connect()) { + return false; + } + foreach ($this->auth as $auth) { + $result = call_user_func_array(array(&$this, 'parent::login'), $auth); + } + return $result; + } + /** * Resets a connection for re-use *