diff options
author | Viktor Söderqvist <viktor.soderqvist@est.tech> | 2022-06-26 13:34:59 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-06-26 14:34:59 +0300 |
commit | 6272ca609e67d1f35dda50a82027d7401892e383 (patch) | |
tree | f584684b145807e3c5f0da6f0f3293e2b65ee461 /src | |
parent | d96cf3639a371574c212d87c70e5a80214fc721f (diff) | |
download | redis-6272ca609e67d1f35dda50a82027d7401892e383.tar.gz |
Add RM_SetClientNameById and RM_GetClientNameById (#10839)
Adding Module APIs to let the module read and set the client name of an arbitrary connection.
Diffstat (limited to 'src')
-rw-r--r-- | src/module.c | 36 | ||||
-rw-r--r-- | src/networking.c | 38 | ||||
-rw-r--r-- | src/redismodule.h | 4 | ||||
-rw-r--r-- | src/server.h | 1 |
4 files changed, 64 insertions, 15 deletions
diff --git a/src/module.c b/src/module.c index 084ee5fd5..f81b2c042 100644 --- a/src/module.c +++ b/src/module.c @@ -3373,6 +3373,40 @@ int RM_GetClientInfoById(void *ci, uint64_t id) { return modulePopulateClientInfoStructure(ci,client,structver); } +/* Returns the name of the client connection with the given ID. + * + * If the client ID does not exist or if the client has no name associated with + * it, NULL is returned. */ +RedisModuleString *RM_GetClientNameById(RedisModuleCtx *ctx, uint64_t id) { + client *client = lookupClientByID(id); + if (client == NULL || client->name == NULL) return NULL; + robj *name = client->name; + incrRefCount(name); + autoMemoryAdd(ctx, REDISMODULE_AM_STRING, name); + return name; +} + +/* Sets the name of the client with the given ID. This is equivalent to the client calling + * `CLIENT SETNAME name`. + * + * Returns REDISMODULE_OK on success. On failure, REDISMODULE_ERR is returned + * and errno is set as follows: + * + * - ENOENT if the client does not exist + * - EINVAL if the name contains invalid characters */ +int RM_SetClientNameById(uint64_t id, RedisModuleString *name) { + client *client = lookupClientByID(id); + if (client == NULL) { + errno = ENOENT; + return REDISMODULE_ERR; + } + if (clientSetName(client, name) == C_ERR) { + errno = EINVAL; + return REDISMODULE_ERR; + } + return REDISMODULE_OK; +} + /* Publish a message to subscribers (see PUBLISH command). */ int RM_PublishMessage(RedisModuleCtx *ctx, RedisModuleString *channel, RedisModuleString *message) { UNUSED(ctx); @@ -12601,6 +12635,8 @@ void moduleRegisterCoreAPI(void) { REGISTER_API(ServerInfoGetFieldUnsigned); REGISTER_API(ServerInfoGetFieldDouble); REGISTER_API(GetClientInfoById); + REGISTER_API(GetClientNameById); + REGISTER_API(SetClientNameById); REGISTER_API(PublishMessage); REGISTER_API(PublishMessageShard); REGISTER_API(SubscribeToServerEvent); diff --git a/src/networking.c b/src/networking.c index 44aa50642..8cace10d4 100644 --- a/src/networking.c +++ b/src/networking.c @@ -2832,18 +2832,9 @@ sds getAllClientsInfoString(int type) { return o; } -/* This function implements CLIENT SETNAME, including replying to the - * user with an error if the charset is wrong (in that case C_ERR is - * returned). If the function succeeded C_OK is returned, and it's up - * to the caller to send a reply if needed. - * - * Setting an empty string as name has the effect of unsetting the - * currently set name: the client will remain unnamed. - * - * This function is also used to implement the HELLO SETNAME option. */ -int clientSetNameOrReply(client *c, robj *name) { - int len = sdslen(name->ptr); - char *p = name->ptr; +/* Returns C_OK if the name has been set or C_ERR if the name is invalid. */ +int clientSetName(client *c, robj *name) { + int len = (name != NULL) ? sdslen(name->ptr) : 0; /* Setting the client name to an empty string actually removes * the current name. */ @@ -2856,11 +2847,9 @@ int clientSetNameOrReply(client *c, robj *name) { /* Otherwise check if the charset is ok. We need to do this otherwise * CLIENT LIST format will break. You should always be able to * split by space to get the different fields. */ + char *p = name->ptr; for (int j = 0; j < len; j++) { if (p[j] < '!' || p[j] > '~') { /* ASCII is assumed. */ - addReplyError(c, - "Client names cannot contain spaces, " - "newlines or special characters."); return C_ERR; } } @@ -2870,6 +2859,25 @@ int clientSetNameOrReply(client *c, robj *name) { return C_OK; } +/* This function implements CLIENT SETNAME, including replying to the + * user with an error if the charset is wrong (in that case C_ERR is + * returned). If the function succeeded C_OK is returned, and it's up + * to the caller to send a reply if needed. + * + * Setting an empty string as name has the effect of unsetting the + * currently set name: the client will remain unnamed. + * + * This function is also used to implement the HELLO SETNAME option. */ +int clientSetNameOrReply(client *c, robj *name) { + int result = clientSetName(c, name); + if (result == C_ERR) { + addReplyError(c, + "Client names cannot contain spaces, " + "newlines or special characters."); + } + return result; +} + /* Reset the client state to resemble a newly connected client. */ void resetCommand(client *c) { diff --git a/src/redismodule.h b/src/redismodule.h index 899bb519d..e36d5f3c0 100644 --- a/src/redismodule.h +++ b/src/redismodule.h @@ -1000,6 +1000,8 @@ REDISMODULE_API void (*RedisModule_ChannelAtPosWithFlags)(RedisModuleCtx *ctx, i REDISMODULE_API unsigned long long (*RedisModule_GetClientId)(RedisModuleCtx *ctx) REDISMODULE_ATTR; REDISMODULE_API RedisModuleString * (*RedisModule_GetClientUserNameById)(RedisModuleCtx *ctx, uint64_t id) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_GetClientInfoById)(void *ci, uint64_t id) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleString * (*RedisModule_GetClientNameById)(RedisModuleCtx *ctx, uint64_t id) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_SetClientNameById)(uint64_t id, RedisModuleString *name) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_PublishMessage)(RedisModuleCtx *ctx, RedisModuleString *channel, RedisModuleString *message) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_PublishMessageShard)(RedisModuleCtx *ctx, RedisModuleString *channel, RedisModuleString *message) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_GetContextFlags)(RedisModuleCtx *ctx) REDISMODULE_ATTR; @@ -1426,6 +1428,8 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int REDISMODULE_GET_API(ServerInfoGetFieldUnsigned); REDISMODULE_GET_API(ServerInfoGetFieldDouble); REDISMODULE_GET_API(GetClientInfoById); + REDISMODULE_GET_API(GetClientNameById); + REDISMODULE_GET_API(SetClientNameById); REDISMODULE_GET_API(PublishMessage); REDISMODULE_GET_API(PublishMessageShard); REDISMODULE_GET_API(SubscribeToServerEvent); diff --git a/src/server.h b/src/server.h index abaa5f046..6beae765b 100644 --- a/src/server.h +++ b/src/server.h @@ -2498,6 +2498,7 @@ char *getClientPeerId(client *client); char *getClientSockName(client *client); sds catClientInfoString(sds s, client *client); sds getAllClientsInfoString(int type); +int clientSetName(client *c, robj *name); void rewriteClientCommandVector(client *c, int argc, ...); void rewriteClientCommandArgument(client *c, int i, robj *newval); void replaceClientCommandVector(client *c, int argc, robj **argv); |