[PECL-CVS] [pecl-networking-ssh2] feature/keepalive-support: Add keepalive support

[email protected] (Rasmus Lerdorf) Sat, 4 Apr 2026 11:04:33 +0000
Newsgroups php.pecl.cvs
Message-ID <[email protected]>
Author: Rasmus Lerdorf (rlerdorf)
Date: 2026-04-04T07:04:18-04:00

Commit: https://github.com/php/pecl-networking-ssh2/commit/98c65339c861bcceda3e8c08df7a595d3bbbf2cf
Raw diff: https://github.com/php/pecl-networking-ssh2/commit/98c65339c861bcceda3e8c08df7a595d3bbbf2cf.diff

Add keepalive support

Changed paths:
  A  tests/ssh2_keepalive.phpt
  M  config.m4
  M  ssh2.c


Diff:

diff --git a/config.m4 b/config.m4
index b2746e2..500c8d6 100644
--- a/config.m4
+++ b/config.m4
@@ -53,6 +53,15 @@ if test "$PHP_SSH2" != "no"; then
     -L$SSH2_DIR/lib -lm 
   ])
 
+  PHP_CHECK_LIBRARY(ssh2,libssh2_keepalive_config,
+  [
+    AC_DEFINE(PHP_SSH2_KEEPALIVE, 1, [Have libssh2 with keepalive support])
+  ],[
+    AC_MSG_WARN([libssh2 keepalive support not available])
+  ],[
+    -L$SSH2_DIR/lib -lm
+  ])
+
   PHP_SUBST(SSH2_SHARED_LIBADD)
 
   PHP_NEW_EXTENSION(ssh2, ssh2.c ssh2_fopen_wrappers.c ssh2_sftp.c, $ext_shared)
diff --git a/ssh2.c b/ssh2.c
index e2c28db..7ff1335 100644
--- a/ssh2.c
+++ b/ssh2.c
@@ -475,6 +475,57 @@ PHP_FUNCTION(ssh2_set_timeout)
 }
 /* }}} */
 
+/* {{{ proto void ssh2_keepalive_config(resource session, bool want_reply, int interval)
+ * Set how often keepalive messages should be sent. interval is the number
+ * of seconds that can pass without any I/O; use 0 (the default) to disable
+ * keepalives. want_reply indicates whether the keepalive messages should
+ * request a response from the server.
+ */
+PHP_FUNCTION(ssh2_keepalive_config)
+{
+	LIBSSH2_SESSION *session;
+	zval *zsession;
+	zend_bool want_reply;
+	zend_long interval;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rbl", &zsession, &want_reply, &interval) == FAILURE) {
+		return;
+	}
+
+	if ((session = (LIBSSH2_SESSION *)zend_fetch_resource(Z_RES_P(zsession), PHP_SSH2_SESSION_RES_NAME, le_ssh2_session)) == NULL) {
+		return;
+	}
+
+	libssh2_keepalive_config(session, want_reply, interval);
+}
+/* }}} */
+
+/* {{{ proto int|false ssh2_keepalive_send(resource session)
+ * Send a keepalive message if needed. Returns the number of seconds you
+ * can sleep before you need to call this function again, or false on error.
+ */
+PHP_FUNCTION(ssh2_keepalive_send)
+{
+	LIBSSH2_SESSION *session;
+	zval *zsession;
+	int seconds_to_next;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &zsession) == FAILURE) {
+		return;
+	}
+
+	if ((session = (LIBSSH2_SESSION *)zend_fetch_resource(Z_RES_P(zsession), PHP_SSH2_SESSION_RES_NAME, le_ssh2_session)) == NULL) {
+		return;
+	}
+
+	if (libssh2_keepalive_send(session, &seconds_to_next)) {
+		RETURN_FALSE;
+	}
+
+	RETURN_LONG(seconds_to_next);
+}
+/* }}} */
+
 /* {{{ proto array ssh2_methods_negotiated(resource session)
  * Return list of negotiaed methods
  */
@@ -1430,6 +1481,16 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_ssh2_set_timeout, 0, 0, 2)
  	ZEND_ARG_INFO(0, microseconds)
 ZEND_END_ARG_INFO()
 
+ZEND_BEGIN_ARG_INFO_EX(arginfo_ssh2_keepalive_config, 0, 0, 3)
+	ZEND_ARG_INFO(0, session)
+	ZEND_ARG_INFO(0, want_reply)
+	ZEND_ARG_INFO(0, interval)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_ssh2_keepalive_send, 0, 0, 1)
+	ZEND_ARG_INFO(0, session)
+ZEND_END_ARG_INFO()
+
 ZEND_BEGIN_ARG_INFO(arginfo_ssh2_methods_negotiated, 1)
  	ZEND_ARG_INFO(0, session)
 ZEND_END_ARG_INFO()
@@ -1640,6 +1701,8 @@ zend_function_entry ssh2_functions[] = {
 	PHP_FE(ssh2_connect,						arginfo_ssh2_connect)
 	PHP_FE(ssh2_disconnect,						arginfo_ssh2_disconnect)
 	PHP_FE(ssh2_set_timeout,					arginfo_ssh2_set_timeout)
+	PHP_FE(ssh2_keepalive_config,				arginfo_ssh2_keepalive_config)
+	PHP_FE(ssh2_keepalive_send,					arginfo_ssh2_keepalive_send)
 	PHP_FE(ssh2_methods_negotiated,				arginfo_ssh2_methods_negotiated)
 	PHP_FE(ssh2_fingerprint,					arginfo_ssh2_fingerprint)
 
diff --git a/tests/ssh2_keepalive.phpt b/tests/ssh2_keepalive.phpt
new file mode 100644
index 0000000..878fd71
--- /dev/null
+++ b/tests/ssh2_keepalive.phpt
@@ -0,0 +1,28 @@
+--TEST--
+ssh2_keepalive_config() and ssh2_keepalive_send() basic functionality
+--SKIPIF--
+<?php require('ssh2_skip.inc'); ?>
+--FILE--
+<?php require('ssh2_test.inc');
+
+$ssh = ssh2_connect(TEST_SSH2_HOSTNAME, TEST_SSH2_PORT);
+
+echo "**Configure keepalive\n";
+ssh2_keepalive_config($ssh, true, 10);
+
+echo "**Send keepalive\n";
+$seconds = ssh2_keepalive_send($ssh);
+var_dump(is_int($seconds));
+var_dump($seconds > 0);
+
+echo "**Disable keepalive\n";
+ssh2_keepalive_config($ssh, false, 0);
+$seconds = ssh2_keepalive_send($ssh);
+var_dump($seconds === 0);
+--EXPECT--
+**Configure keepalive
+**Send keepalive
+bool(true)
+bool(true)
+**Disable keepalive
+bool(true)