mirror of
https://github.com/fluencelabs/redis
synced 2025-03-19 09:00:51 +00:00
Modules API: RM_GetRandomBytes() / GetRandomHexChars().
This commit is contained in:
parent
c75582889a
commit
b2868c7b9c
21
src/module.c
21
src/module.c
@ -4183,6 +4183,25 @@ int RM_GetTimerInfo(RedisModuleCtx *ctx, RedisModuleTimerID id, uint64_t *remain
|
||||
return REDISMODULE_OK;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* Modules utility APIs
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
/* Return random bytes using SHA1 in counter mode with a /dev/urandom
|
||||
* initialized seed. This function is fast so can be used to generate
|
||||
* many bytes without any effect on the operating system entropy pool.
|
||||
* Currently this function is not thread safe. */
|
||||
void RM_GetRandomBytes(unsigned char *dst, size_t len) {
|
||||
getRandomBytes(dst,len);
|
||||
}
|
||||
|
||||
/* Like RedisModule_GetRandomBytes() but instead of setting the string to
|
||||
* random bytes the string is set to random characters in the in the
|
||||
* hex charset [0-9a-f]. */
|
||||
void RM_GetRandomHexChars(char *dst, size_t len) {
|
||||
getRandomHexChars(dst,len);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* Modules API internals
|
||||
* -------------------------------------------------------------------------- */
|
||||
@ -4575,4 +4594,6 @@ void moduleRegisterCoreAPI(void) {
|
||||
REGISTER_API(GetTimerInfo);
|
||||
REGISTER_API(GetMyClusterID);
|
||||
REGISTER_API(GetClusterSize);
|
||||
REGISTER_API(GetRandomBytes);
|
||||
REGISTER_API(GetRandomHexChars);
|
||||
}
|
||||
|
@ -278,6 +278,9 @@ int REDISMODULE_API_FUNC(RedisModule_StopTimer)(RedisModuleCtx *ctx, RedisModule
|
||||
int REDISMODULE_API_FUNC(RedisModule_GetTimerInfo)(RedisModuleCtx *ctx, RedisModuleTimerID id, uint64_t *remaining, void **data);
|
||||
const char *REDISMODULE_API_FUNC(RedisModule_GetMyClusterID)(void);
|
||||
size_t REDISMODULE_API_FUNC(RedisModule_GetClusterSize)(void);
|
||||
void REDISMODULE_API_FUNC(RedisModule_GetRandomBytes)(unsigned char *dst, size_t len);
|
||||
void REDISMODULE_API_FUNC(RedisModule_GetRandomHexChars)(char *dst, size_t len);
|
||||
|
||||
|
||||
/* Experimental APIs */
|
||||
#ifdef REDISMODULE_EXPERIMENTAL_API
|
||||
@ -411,6 +414,8 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int
|
||||
REDISMODULE_GET_API(GetTimerInfo);
|
||||
REDISMODULE_GET_API(GetMyClusterID);
|
||||
REDISMODULE_GET_API(GetClusterSize);
|
||||
REDISMODULE_GET_API(GetRandomBytes);
|
||||
REDISMODULE_GET_API(GetRandomHexChars);
|
||||
|
||||
#ifdef REDISMODULE_EXPERIMENTAL_API
|
||||
REDISMODULE_GET_API(GetThreadSafeContext);
|
||||
|
@ -1366,7 +1366,8 @@ void moduleNotifyKeyspaceEvent(int type, const char *event, robj *key, int dbid)
|
||||
/* Utils */
|
||||
long long ustime(void);
|
||||
long long mstime(void);
|
||||
void getRandomHexChars(char *p, unsigned int len);
|
||||
void getRandomHexChars(char *p, size_t len);
|
||||
void getRandomBytes(unsigned char *p, size_t len);
|
||||
uint64_t crc64(uint64_t crc, const unsigned char *s, uint64_t l);
|
||||
void exitFromChild(int retcode);
|
||||
size_t redisPopcount(void *s, long count);
|
||||
|
72
src/util.c
72
src/util.c
@ -536,14 +536,12 @@ int ld2string(char *buf, size_t len, long double value, int humanfriendly) {
|
||||
return l;
|
||||
}
|
||||
|
||||
/* Generate the Redis "Run ID", a SHA1-sized random number that identifies a
|
||||
* given execution of Redis, so that if you are talking with an instance
|
||||
* having run_id == A, and you reconnect and it has run_id == B, you can be
|
||||
* sure that it is either a different instance or it was restarted. */
|
||||
void getRandomHexChars(char *p, unsigned int len) {
|
||||
char *charset = "0123456789abcdef";
|
||||
unsigned int j;
|
||||
|
||||
/* Get random bytes, attempts to get an initial seed from /dev/urandom and
|
||||
* the uses a one way hash function in counter mode to generate a random
|
||||
* stream. However if /dev/urandom is not available, a weaker seed is used.
|
||||
*
|
||||
* This function is not thread safe, since the state is global. */
|
||||
void getRandomBytes(unsigned char *p, size_t len) {
|
||||
/* Global state. */
|
||||
static int seed_initialized = 0;
|
||||
static unsigned char seed[20]; /* The SHA1 seed, from /dev/urandom. */
|
||||
@ -555,12 +553,21 @@ void getRandomHexChars(char *p, unsigned int len) {
|
||||
* function we just need non-colliding strings, there are no
|
||||
* cryptographic security needs. */
|
||||
FILE *fp = fopen("/dev/urandom","r");
|
||||
if (fp && fread(seed,sizeof(seed),1,fp) == 1)
|
||||
if (fp == NULL || fread(seed,sizeof(seed),1,fp) != 1) {
|
||||
/* Revert to a weaker seed, and in this case reseed again
|
||||
* at every call.*/
|
||||
for (unsigned int j = 0; j < sizeof(seed); j++) {
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv,NULL);
|
||||
pid_t pid = getpid();
|
||||
seed[j] = tv.tv_sec ^ tv.tv_usec ^ pid ^ (long)fp;
|
||||
}
|
||||
} else {
|
||||
seed_initialized = 1;
|
||||
}
|
||||
if (fp) fclose(fp);
|
||||
}
|
||||
|
||||
if (seed_initialized) {
|
||||
while(len) {
|
||||
unsigned char digest[20];
|
||||
SHA1_CTX ctx;
|
||||
@ -573,44 +580,21 @@ void getRandomHexChars(char *p, unsigned int len) {
|
||||
counter++;
|
||||
|
||||
memcpy(p,digest,copylen);
|
||||
/* Convert to hex digits. */
|
||||
for (j = 0; j < copylen; j++) p[j] = charset[p[j] & 0x0F];
|
||||
len -= copylen;
|
||||
p += copylen;
|
||||
}
|
||||
} else {
|
||||
/* If we can't read from /dev/urandom, do some reasonable effort
|
||||
* in order to create some entropy, since this function is used to
|
||||
* generate run_id and cluster instance IDs */
|
||||
char *x = p;
|
||||
unsigned int l = len;
|
||||
struct timeval tv;
|
||||
pid_t pid = getpid();
|
||||
}
|
||||
|
||||
/* Use time and PID to fill the initial array. */
|
||||
gettimeofday(&tv,NULL);
|
||||
if (l >= sizeof(tv.tv_usec)) {
|
||||
memcpy(x,&tv.tv_usec,sizeof(tv.tv_usec));
|
||||
l -= sizeof(tv.tv_usec);
|
||||
x += sizeof(tv.tv_usec);
|
||||
}
|
||||
if (l >= sizeof(tv.tv_sec)) {
|
||||
memcpy(x,&tv.tv_sec,sizeof(tv.tv_sec));
|
||||
l -= sizeof(tv.tv_sec);
|
||||
x += sizeof(tv.tv_sec);
|
||||
}
|
||||
if (l >= sizeof(pid)) {
|
||||
memcpy(x,&pid,sizeof(pid));
|
||||
l -= sizeof(pid);
|
||||
x += sizeof(pid);
|
||||
}
|
||||
/* Finally xor it with rand() output, that was already seeded with
|
||||
* time() at startup, and convert to hex digits. */
|
||||
for (j = 0; j < len; j++) {
|
||||
p[j] ^= rand();
|
||||
p[j] = charset[p[j] & 0x0F];
|
||||
}
|
||||
}
|
||||
/* Generate the Redis "Run ID", a SHA1-sized random number that identifies a
|
||||
* given execution of Redis, so that if you are talking with an instance
|
||||
* having run_id == A, and you reconnect and it has run_id == B, you can be
|
||||
* sure that it is either a different instance or it was restarted. */
|
||||
void getRandomHexChars(char *p, size_t len) {
|
||||
char *charset = "0123456789abcdef";
|
||||
size_t j;
|
||||
|
||||
getRandomBytes((unsigned char*)p,len);
|
||||
for (j = 0; j < len; j++) p[j] = charset[p[j] & 0x0F];
|
||||
}
|
||||
|
||||
/* Given the filename, return the absolute path as an SDS string, or NULL
|
||||
|
Loading…
x
Reference in New Issue
Block a user