summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorViktor Söderqvist <viktor.soderqvist@est.tech>2022-06-26 13:34:59 +0200
committerGitHub <noreply@github.com>2022-06-26 14:34:59 +0300
commit6272ca609e67d1f35dda50a82027d7401892e383 (patch)
treef584684b145807e3c5f0da6f0f3293e2b65ee461 /src
parentd96cf3639a371574c212d87c70e5a80214fc721f (diff)
downloadredis-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.c36
-rw-r--r--src/networking.c38
-rw-r--r--src/redismodule.h4
-rw-r--r--src/server.h1
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);