mirror of https://github.com/valkey-io/valkey
Fix CLUSTER SLOTS crash when called from module timer callback (#2915)
The CLUSTER SLOTS reply depends on whether the client is connected over IPv6, but for a fake client there is no connection and when this command is called from a module timer callback or other scenario where no real client is involved, there is no connection to check IPv6 support on. This fix handles the missing case by returning the reply for IPv4 connected clients. Fixes #2912. --------- Signed-off-by: Su Ko <rhtn1128@gmail.com> Signed-off-by: Binbin <binloveplay1314@qq.com> Signed-off-by: Viktor Söderqvist <viktor.soderqvist@est.tech> Co-authored-by: Su Ko <rhtn1128@gmail.com> Co-authored-by: KarthikSubbarao <karthikrs2021@gmail.com> Co-authored-by: Binbin <binloveplay1314@qq.com> Co-authored-by: Viktor Söderqvist <viktor.soderqvist@est.tech>
This commit is contained in:
parent
48e0cbbb41
commit
2a9a1731ee
|
|
@ -4194,11 +4194,17 @@ int isClientConnIpV6(client *c) {
|
|||
/* The cached client peer id is on the form "[IPv6]:port" for IPv6
|
||||
* addresses, so we just check for '[' here. */
|
||||
if (c->flag.fake && server.current_client) {
|
||||
/* Fake client? Use current client instead.
|
||||
* Noted that in here we are assuming server.current_client is set
|
||||
* and real (aof has already violated this in loadSingleAppendOnlyFil). */
|
||||
/* Fake client? Use current client instead, if we have one. */
|
||||
c = server.current_client;
|
||||
}
|
||||
|
||||
if (c->flag.fake || !c->conn) {
|
||||
/* If we still don't have a client with a real connection (e.g., called
|
||||
* from module timer with no real current client), default to IPv4 to
|
||||
* avoid crashing. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
return getClientPeerId(c)[0] == '[';
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,35 @@
|
|||
|
||||
#define UNUSED(x) (void)(x)
|
||||
|
||||
void cluster_timer_handler(ValkeyModuleCtx *ctx, void *data) {
|
||||
VALKEYMODULE_NOT_USED(data);
|
||||
|
||||
ValkeyModuleCallReply *rep = ValkeyModule_Call(ctx, "CLUSTER", "c", "SLOTS");
|
||||
|
||||
if (rep) {
|
||||
if (ValkeyModule_CallReplyType(rep) == VALKEYMODULE_REPLY_ARRAY) {
|
||||
ValkeyModule_Log(ctx, "notice", "Timer: CLUSTER SLOTS success");
|
||||
} else {
|
||||
ValkeyModule_Log(ctx, "notice",
|
||||
"Timer: CLUSTER SLOTS unexpected reply type %d",
|
||||
ValkeyModule_CallReplyType(rep));
|
||||
}
|
||||
ValkeyModule_FreeCallReply(rep);
|
||||
} else {
|
||||
ValkeyModule_Log(ctx, "warning", "Timer: CLUSTER SLOTS failed");
|
||||
}
|
||||
}
|
||||
|
||||
int test_start_cluster_timer(ValkeyModuleCtx *ctx, ValkeyModuleString **argv, int argc) {
|
||||
VALKEYMODULE_NOT_USED(argv);
|
||||
VALKEYMODULE_NOT_USED(argc);
|
||||
|
||||
ValkeyModule_CreateTimer(ctx, 1, cluster_timer_handler, NULL);
|
||||
|
||||
return ValkeyModule_ReplyWithSimpleString(ctx, "OK");
|
||||
}
|
||||
|
||||
|
||||
int test_cluster_slots(ValkeyModuleCtx *ctx, ValkeyModuleString **argv, int argc) {
|
||||
UNUSED(argv);
|
||||
|
||||
|
|
@ -77,8 +106,12 @@ int ValkeyModule_OnLoad(ValkeyModuleCtx *ctx, ValkeyModuleString **argv, int arg
|
|||
if (ValkeyModule_CreateCommand(ctx, "test.cluster_shards", test_cluster_shards, "", 0, 0, 0) == VALKEYMODULE_ERR)
|
||||
return VALKEYMODULE_ERR;
|
||||
|
||||
if (ValkeyModule_CreateCommand(ctx, "test.start_cluster_timer", test_start_cluster_timer, "", 0, 0, 0) == VALKEYMODULE_ERR)
|
||||
return VALKEYMODULE_ERR;
|
||||
|
||||
/* Register our handlers for different message types. */
|
||||
ValkeyModule_RegisterClusterMessageReceiver(ctx, MSGTYPE_DING, DingReceiver);
|
||||
ValkeyModule_RegisterClusterMessageReceiver(ctx, MSGTYPE_DONG, DongReceiver);
|
||||
|
||||
return VALKEYMODULE_OK;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -285,6 +285,18 @@ start_cluster 3 0 [list config_lines $modules] {
|
|||
assert_equal [lsort [$node2 cluster shards]] [lsort [$node2 test.cluster_shards]]
|
||||
assert_equal [lsort [$node3 cluster shards]] [lsort [$node3 test.cluster_shards]]
|
||||
}
|
||||
|
||||
test "VM_CALL CLUSTER SLOTS from Module Timer" {
|
||||
assert_equal {OK} [$node1 test.start_cluster_timer]
|
||||
assert_equal {OK} [$node2 test.start_cluster_timer]
|
||||
assert_equal {OK} [$node3 test.start_cluster_timer]
|
||||
|
||||
wait_for_condition 50 100 {
|
||||
[count_log_message 0 "* <cluster> Timer: CLUSTER SLOTS success*"] >= 1
|
||||
} else {
|
||||
fail "Timer did not execute CLUSTER SLOTS or server crashed"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} ;# end tag
|
||||
|
|
|
|||
Loading…
Reference in New Issue