From 593ba012ac49065343f6bbf10adca5047414ce85 Mon Sep 17 00:00:00 2001 From: michael-grunder Date: Sun, 4 May 2025 10:20:01 -0700 Subject: [PATCH] Check for `dragonfly_version` in `HELLO` response DragonflyDB will report to be Redis but also include `dragonfly_version` in the hello response, which we can use to identify the fork. Also fix parsing of the `HELLO` response for `serverName()` and `serverVersion()`. Starting in Redis 8.0 there seem to always be modules running, which the previous function was not expecting or parsing. --- library.c | 39 ++++++++++++++++++++++++++------------- redis.c | 2 +- tests/RedisTest.php | 2 ++ 3 files changed, 29 insertions(+), 14 deletions(-) diff --git a/library.c b/library.c index a9fb523e48..ce3e2672d0 100644 --- a/library.c +++ b/library.c @@ -2018,26 +2018,31 @@ static int redis_hello_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx) { - int numElems; zval z_ret, *zv; + int numElems; - if (read_mbulk_header(redis_sock, &numElems) < 0) { - if (IS_ATOMIC(redis_sock)) { - RETVAL_FALSE; - } else { - add_next_index_bool(z_tab, 0); - } - return FAILURE; - } + if (read_mbulk_header(redis_sock, &numElems) < 0) + goto fail; array_init(&z_ret); - redis_mbulk_reply_zipped_raw_variant(redis_sock, &z_ret, numElems); + + if (redis_read_multibulk_recursive(redis_sock, numElems, 0, &z_ret) != SUCCESS || + array_zip_values_recursive(&z_ret) != SUCCESS) + { + zval_dtor(&z_ret); + goto fail; + } if (redis_sock->hello.server) { zend_string_release(redis_sock->hello.server); } - zv = zend_hash_str_find(Z_ARRVAL(z_ret), ZEND_STRL("server")); - redis_sock->hello.server = zv ? zval_get_string(zv) : ZSTR_EMPTY_ALLOC(); + + if ((zv = zend_hash_str_find(Z_ARRVAL(z_ret), ZEND_STRL("dragonfly_version")))) { + redis_sock->hello.server = zend_string_init(ZEND_STRL("dragonfly"), 0); + } else { + zv = zend_hash_str_find(Z_ARRVAL(z_ret), ZEND_STRL("server")); + redis_sock->hello.server = zv ? zval_get_string(zv) : ZSTR_EMPTY_ALLOC(); + } if (redis_sock->hello.version) { zend_string_release(redis_sock->hello.version); @@ -2063,6 +2068,14 @@ redis_hello_response(INTERNAL_FUNCTION_PARAMETERS, } return SUCCESS; + +fail: + if (IS_ATOMIC(redis_sock)) { + RETVAL_FALSE; + } else { + add_next_index_bool(z_tab, 0); + } + return FAILURE; } @@ -4302,7 +4315,7 @@ redis_read_multibulk_recursive(RedisSock *redis_sock, long long elements, int st elements--; } - return 0; + return SUCCESS; } static int diff --git a/redis.c b/redis.c index 3f13a59888..629dd5c20b 100644 --- a/redis.c +++ b/redis.c @@ -2131,7 +2131,7 @@ redis_sock_read_multibulk_multi_reply_loop(INTERNAL_FUNCTION_PARAMETERS, int num = atol(inbuf + 1); - if (num > 0 && redis_read_multibulk_recursive(redis_sock, num, 0, &z_ret) < 0) { + if (num > 0 && redis_read_multibulk_recursive(redis_sock, num, 0, &z_ret) != SUCCESS) { return FAILURE; } } diff --git a/tests/RedisTest.php b/tests/RedisTest.php index e7854da442..1ebcc61e51 100644 --- a/tests/RedisTest.php +++ b/tests/RedisTest.php @@ -2476,6 +2476,7 @@ public function testServerInfo() { $this->markTestSkipped(); $hello = $this->execHello(); + if ( ! $this->assertArrayKey($hello, 'server') || ! $this->assertArrayKey($hello, 'version')) { @@ -2486,6 +2487,7 @@ public function testServerInfo() { $this->assertEquals($hello['version'], $this->redis->serverVersion()); $info = $this->redis->info(); + $cmd1 = $info['total_commands_processed']; /* Shouldn't hit the server */