From 7ae03a25003bf78914b8c14fedea5c76317055c5 Mon Sep 17 00:00:00 2001 From: Attila Kovacs Date: Wed, 4 Sep 2024 20:11:30 +0200 Subject: [PATCH] Add redisSetUser() pre-connect configuration function --- README.md | 13 +++++++++++ include/redisx-priv.h | 1 + include/redisx.h | 5 +++-- src/redisx-net.c | 5 ++++- src/redisx.c | 50 +++++++++++++++++++++++++++++++++++-------- 5 files changed, 62 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 5478d42..776ad92 100644 --- a/README.md +++ b/README.md @@ -153,6 +153,19 @@ you application: redisxSetTcpBuf(65536); ``` +Optionally you can select the database index to use now (and also later, after connecting), if not the default (index +0): + +```c + Redis *redis = ... + + // Select the database index 2 + redisxSelectDB(redis); +``` + +(Note that you can switch the database index any time, with the caveat that it's not possible to change it for the +subscription client when there are active subscriptions.) + ### Connecting diff --git a/include/redisx-priv.h b/include/redisx-priv.h index ec1bfe2..f32c6fd 100644 --- a/include/redisx-priv.h +++ b/include/redisx-priv.h @@ -58,6 +58,7 @@ typedef struct { uint32_t addr; ///< The 32-bit inet address int port; ///< port number (usually 6379) int dbIndex; ///< the zero-based database index + char *username; ///< REdis user name (if any) char *password; ///< Redis password (if any) RedisClient *clients; diff --git a/include/redisx.h b/include/redisx.h index 727be26..6fa48d9 100644 --- a/include/redisx.h +++ b/include/redisx.h @@ -220,7 +220,9 @@ void redisxSetTcpBuf(int size); int redisxGetTcpBuf(); void redisxSetPort(Redis *redis, int port); -void redisxSetPassword(Redis *redis, const char *passwd); +int redisxSetUser(Redis *redis, const char *username); +int redisxSetPassword(Redis *redis, const char *passwd); +int redisxSelectDB(Redis *redis, int idx); int redisxSetTransmitErrorHandler(Redis *redis, RedisErrorHandler f); @@ -235,7 +237,6 @@ boolean redisxIsConnected(Redis *redis); boolean redisxHasPipeline(Redis *redis); RedisClient *redisxGetClient(Redis *redis, enum redisx_channel channel); -int redisxSelectDB(Redis *redis, int idx, boolean confirm); void redisxAddConnectHook(Redis *redis, void (*setupCall)(Redis *)); void redisxRemoveConnectHook(Redis *redis, void (*setupCall)(Redis *)); diff --git a/src/redisx-net.c b/src/redisx-net.c index 5e8fdf7..6f2cfa3 100644 --- a/src/redisx-net.c +++ b/src/redisx-net.c @@ -130,7 +130,7 @@ static int rAuthAsync(RedisClient *cl) { const RedisPrivate *p = (RedisPrivate *) cp->redis->priv; RESP *reply; - int status = redisxSendRequestAsync(cl, "AUTH", p->password, NULL, NULL); + int status = p->username ? redisxSendRequestAsync(cl, "AUTH", p->username, p->password, NULL) : redisxSendRequestAsync(cl, "AUTH", p->password, NULL, NULL); if(status) return redisxError("rAuthAsync()", status); reply = redisxReadReplyAsync(cl); @@ -582,7 +582,10 @@ void redisxSetPort(Redis *redis, int port) { * * \sa redisxInit() * \sa redisxSetPort() + * \sa redisxSetUser() + * \sa redisxSetPassword() * \sa redisxSetTcpBuf() + * \sa redisxSelectDB() * \sa redisxDisconnect() */ int redisxConnect(Redis *redis, boolean usePipeline) { diff --git a/src/redisx.c b/src/redisx.c index 83eda4b..97c0adf 100644 --- a/src/redisx.c +++ b/src/redisx.c @@ -95,23 +95,56 @@ boolean redisxIsVerbose() { return xIsVerbose(); } +/** + * Sets the user name to use for authenticating on the Redis server after connection. See the + * `AUTH` Redis command for more explanation. Naturally, you need to call this prior to connecting + * your Redis instance to have the desired effect. + * + * @param redis Pointer to the Redis instance for which to set credentials + * @param username the password to use for authenticating on the server, or NULL to clear a + * previously configured password. + * @return X_SUCCESS (0) if successful, X_NULL if the redis argument is NULL, or + * X_ALREADY_OPEN if called after Redis was already connected. + * + * @sa redisxSetPassword() + */ +int redisxSetUser(Redis *redis, const char *username) { + RedisPrivate *p; + + if(!redis) return X_NULL; + if(redisxIsConnected(redis)) return redisxError("redisxSetUser()", X_ALREADY_OPEN); + + p = (RedisPrivate *) redis->priv; + if(p->username) free(p->username); + p->username = xStringCopyOf(username); + + return X_SUCCESS; +} + /** * Sets the password to use for authenticating on the Redis server after connection. See the AUTH * Redis command for more explanation. Naturally, you need to call this prior to connecting * your Redis instance to have the desired effect. * - * @param redis Pointer to the Redis instance for which to set credentials - * @param passwd the password to use for authenticating on the server, or NULL to clear a - * previously configured password. + * @param redis Pointer to the Redis instance for which to set credentials + * @param passwd the password to use for authenticating on the server, or NULL to clear a + * previously configured password. + * @return X_SUCCESS (0) if successful, X_NULL if the redis argument is NULL, or + * X_ALREADY_OPEN if called after Redis was already connected. + * + * @sa redisxSetUser() */ -void redisxSetPassword(Redis *redis, const char *passwd) { +int redisxSetPassword(Redis *redis, const char *passwd) { RedisPrivate *p; - if(!redis) return; + if(!redis) return X_NULL; + if(redisxIsConnected(redis)) return redisxError("redisxSetPassword()", X_ALREADY_OPEN); p = (RedisPrivate *) redis->priv; if(p->password) free(p->password); p->password = xStringCopyOf(passwd); + + return X_SUCCESS; } /** @@ -463,7 +496,7 @@ int redisxSelectClientDBAsync(RedisClient *cl, int idx, boolean confirm) { static void rAffirmDB(Redis *redis) { const RedisPrivate *p = (RedisPrivate *) redis->priv; - redisxSelectDB(redis, p->dbIndex, TRUE); + redisxSelectDB(redis, p->dbIndex); } /** @@ -473,7 +506,6 @@ static void rAffirmDB(Redis *redis) { * * @param redis Pointer to a Redis instance. * @param idx zero-based database index - * @param confirm Whether to wait for confirmation from Redis, and check the response. * @return X_SUCCESS (0) if successful, or * X_NULL if the redis argument is NULL, * X_INCOMPLETE if there is an active subscription channel that cannot be switched or @@ -483,7 +515,7 @@ static void rAffirmDB(Redis *redis) { * @sa redisxSelectDB() * @sa redisxLockEnabled() */ -int redisxSelectDB(Redis *redis, int idx, boolean confirm) { +int redisxSelectDB(Redis *redis, int idx) { RedisPrivate *p; enum redisx_channel c; int status = X_SUCCESS; @@ -511,7 +543,7 @@ int redisxSelectDB(Redis *redis, int idx, boolean confirm) { continue; } - s = redisxSelectClientDBAsync(cl, idx, confirm && c != PIPELINE_CHANNEL); + s = redisxSelectClientDBAsync(cl, idx, c != PIPELINE_CHANNEL); redisxUnlockClient(cl); if(s) status = X_INCOMPLETE;