diff --git a/src/module.c b/src/module.c index c79f1133..ac935d5c 100644 --- a/src/module.c +++ b/src/module.c @@ -4818,6 +4818,25 @@ int moduleUnload(sds name) { return REDISMODULE_OK; } +/* Helper function for the MODULE and HELLO command: send the list of the + * loaded modules to the client. */ +void addReplyLoadedModules(client *c) { + dictIterator *di = dictGetIterator(modules); + dictEntry *de; + + addReplyArrayLen(c,dictSize(modules)); + while ((de = dictNext(di)) != NULL) { + sds name = dictGetKey(de); + struct RedisModule *module = dictGetVal(de); + addReplyMapLen(c,2); + addReplyBulkCString(c,"name"); + addReplyBulkCBuffer(c,name,sdslen(name)); + addReplyBulkCString(c,"ver"); + addReplyLongLong(c,module->ver); + } + dictReleaseIterator(di); +} + /* Redis MODULE command. * * MODULE LOAD [args...] */ @@ -4865,20 +4884,7 @@ NULL addReplyErrorFormat(c,"Error unloading module: %s",errmsg); } } else if (!strcasecmp(subcmd,"list") && c->argc == 2) { - dictIterator *di = dictGetIterator(modules); - dictEntry *de; - - addReplyArrayLen(c,dictSize(modules)); - while ((de = dictNext(di)) != NULL) { - sds name = dictGetKey(de); - struct RedisModule *module = dictGetVal(de); - addReplyMapLen(c,2); - addReplyBulkCString(c,"name"); - addReplyBulkCBuffer(c,name,sdslen(name)); - addReplyBulkCString(c,"ver"); - addReplyLongLong(c,module->ver); - } - dictReleaseIterator(di); + addReplyLoadedModules(c); } else { addReplySubcommandSyntaxError(c); return; diff --git a/src/networking.c b/src/networking.c index 8be22629..5e442e28 100644 --- a/src/networking.c +++ b/src/networking.c @@ -1998,6 +1998,54 @@ NULL } } +/* HELLO [AUTH ] */ +void helloCommand(client *c) { + long long ver; + + if (getLongLongFromObject(c->argv[1],&ver) != C_OK || + ver < 2 || ver > 3) + { + addReplyError(c,"-NOPROTO unsupported protocol version"); + return; + } + + /* Switching to protocol v2 is not allowed. But we send a specific + * error message in this case. */ + if (ver == 2) { + addReplyError(c,"Switching to RESP version 2 is not allowed."); + return; + } + + /* Let's switch to RESP3 mode. */ + c->resp = 3; + addReplyMapLen(c,7); + + addReplyBulkCString(c,"server"); + addReplyBulkCString(c,"redis"); + + addReplyBulkCString(c,"version"); + addReplyBulkCString(c,REDIS_VERSION); + + addReplyBulkCString(c,"proto"); + addReplyLongLong(c,3); + + addReplyBulkCString(c,"id"); + addReplyLongLong(c,c->id); + + addReplyBulkCString(c,"mode"); + if (server.sentinel_mode) addReplyBulkCString(c,"sentinel"); + if (server.cluster_enabled) addReplyBulkCString(c,"cluster"); + else addReplyBulkCString(c,"standalone"); + + if (!server.sentinel_mode) { + addReplyBulkCString(c,"role"); + addReplyBulkCString(c,server.masterhost ? "replica" : "master"); + } + + addReplyBulkCString(c,"modules"); + addReplyLoadedModules(c); +} + /* This callback is bound to POST and "Host:" command names. Those are not * really commands, but are used in security attacks in order to talk to * Redis instances via HTTP, with a technique called "cross protocol scripting" diff --git a/src/sentinel.c b/src/sentinel.c index 536edcdd..1696b121 100644 --- a/src/sentinel.c +++ b/src/sentinel.c @@ -453,7 +453,8 @@ struct redisCommand sentinelcmds[] = { {"role",sentinelRoleCommand,1,"l",0,NULL,0,0,0,0,0}, {"client",clientCommand,-2,"rs",0,NULL,0,0,0,0,0}, {"shutdown",shutdownCommand,-1,"",0,NULL,0,0,0,0,0}, - {"auth",authCommand,2,"sltF",0,NULL,0,0,0,0,0} + {"auth",authCommand,2,"sltF",0,NULL,0,0,0,0,0}, + {"hello",helloCommand,-2,"sF",0,NULL,0,0,0,0,0} }; /* This function overwrites a few normal Redis config default with Sentinel diff --git a/src/server.c b/src/server.c index 79df0282..8cdbdad7 100644 --- a/src/server.c +++ b/src/server.c @@ -284,6 +284,7 @@ struct redisCommand redisCommandTable[] = { {"object",objectCommand,-2,"rR",0,NULL,2,2,1,0,0}, {"memory",memoryCommand,-2,"rR",0,NULL,0,0,0,0,0}, {"client",clientCommand,-2,"as",0,NULL,0,0,0,0,0}, + {"hello",helloCommand,-2,"sF",0,NULL,0,0,0,0,0}, {"eval",evalCommand,-3,"s",0,evalGetKeys,0,0,0,0,0}, {"evalsha",evalShaCommand,-3,"s",0,evalGetKeys,0,0,0,0,0}, {"slowlog",slowlogCommand,-2,"aR",0,NULL,0,0,0,0,0}, diff --git a/src/server.h b/src/server.h index 0cc14f08..6a398dc3 100644 --- a/src/server.h +++ b/src/server.h @@ -1459,6 +1459,7 @@ void addReplyAttributeLen(client *c, long length); void addReplyPushLen(client *c, long length); void addReplyHelp(client *c, const char **help); void addReplySubcommandSyntaxError(client *c); +void addReplyLoadedModules(client *c); void copyClientOutputBuffer(client *dst, client *src); size_t sdsZmallocSize(sds s); size_t getStringObjectSdsUsedMemory(robj *o); @@ -2093,6 +2094,7 @@ void dumpCommand(client *c); void objectCommand(client *c); void memoryCommand(client *c); void clientCommand(client *c); +void helloCommand(client *c); void evalCommand(client *c); void evalShaCommand(client *c); void scriptCommand(client *c);