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;
|
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
|
* Modules API internals
|
||||||
* -------------------------------------------------------------------------- */
|
* -------------------------------------------------------------------------- */
|
||||||
@ -4575,4 +4594,6 @@ void moduleRegisterCoreAPI(void) {
|
|||||||
REGISTER_API(GetTimerInfo);
|
REGISTER_API(GetTimerInfo);
|
||||||
REGISTER_API(GetMyClusterID);
|
REGISTER_API(GetMyClusterID);
|
||||||
REGISTER_API(GetClusterSize);
|
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);
|
int REDISMODULE_API_FUNC(RedisModule_GetTimerInfo)(RedisModuleCtx *ctx, RedisModuleTimerID id, uint64_t *remaining, void **data);
|
||||||
const char *REDISMODULE_API_FUNC(RedisModule_GetMyClusterID)(void);
|
const char *REDISMODULE_API_FUNC(RedisModule_GetMyClusterID)(void);
|
||||||
size_t REDISMODULE_API_FUNC(RedisModule_GetClusterSize)(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 */
|
/* Experimental APIs */
|
||||||
#ifdef REDISMODULE_EXPERIMENTAL_API
|
#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(GetTimerInfo);
|
||||||
REDISMODULE_GET_API(GetMyClusterID);
|
REDISMODULE_GET_API(GetMyClusterID);
|
||||||
REDISMODULE_GET_API(GetClusterSize);
|
REDISMODULE_GET_API(GetClusterSize);
|
||||||
|
REDISMODULE_GET_API(GetRandomBytes);
|
||||||
|
REDISMODULE_GET_API(GetRandomHexChars);
|
||||||
|
|
||||||
#ifdef REDISMODULE_EXPERIMENTAL_API
|
#ifdef REDISMODULE_EXPERIMENTAL_API
|
||||||
REDISMODULE_GET_API(GetThreadSafeContext);
|
REDISMODULE_GET_API(GetThreadSafeContext);
|
||||||
|
@ -1366,7 +1366,8 @@ void moduleNotifyKeyspaceEvent(int type, const char *event, robj *key, int dbid)
|
|||||||
/* Utils */
|
/* Utils */
|
||||||
long long ustime(void);
|
long long ustime(void);
|
||||||
long long mstime(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);
|
uint64_t crc64(uint64_t crc, const unsigned char *s, uint64_t l);
|
||||||
void exitFromChild(int retcode);
|
void exitFromChild(int retcode);
|
||||||
size_t redisPopcount(void *s, long count);
|
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;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Generate the Redis "Run ID", a SHA1-sized random number that identifies a
|
/* Get random bytes, attempts to get an initial seed from /dev/urandom and
|
||||||
* given execution of Redis, so that if you are talking with an instance
|
* the uses a one way hash function in counter mode to generate a random
|
||||||
* having run_id == A, and you reconnect and it has run_id == B, you can be
|
* stream. However if /dev/urandom is not available, a weaker seed is used.
|
||||||
* sure that it is either a different instance or it was restarted. */
|
*
|
||||||
void getRandomHexChars(char *p, unsigned int len) {
|
* This function is not thread safe, since the state is global. */
|
||||||
char *charset = "0123456789abcdef";
|
void getRandomBytes(unsigned char *p, size_t len) {
|
||||||
unsigned int j;
|
|
||||||
|
|
||||||
/* Global state. */
|
/* Global state. */
|
||||||
static int seed_initialized = 0;
|
static int seed_initialized = 0;
|
||||||
static unsigned char seed[20]; /* The SHA1 seed, from /dev/urandom. */
|
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
|
* function we just need non-colliding strings, there are no
|
||||||
* cryptographic security needs. */
|
* cryptographic security needs. */
|
||||||
FILE *fp = fopen("/dev/urandom","r");
|
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;
|
seed_initialized = 1;
|
||||||
|
}
|
||||||
if (fp) fclose(fp);
|
if (fp) fclose(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (seed_initialized) {
|
|
||||||
while(len) {
|
while(len) {
|
||||||
unsigned char digest[20];
|
unsigned char digest[20];
|
||||||
SHA1_CTX ctx;
|
SHA1_CTX ctx;
|
||||||
@ -573,44 +580,21 @@ void getRandomHexChars(char *p, unsigned int len) {
|
|||||||
counter++;
|
counter++;
|
||||||
|
|
||||||
memcpy(p,digest,copylen);
|
memcpy(p,digest,copylen);
|
||||||
/* Convert to hex digits. */
|
|
||||||
for (j = 0; j < copylen; j++) p[j] = charset[p[j] & 0x0F];
|
|
||||||
len -= copylen;
|
len -= copylen;
|
||||||
p += 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. */
|
/* Generate the Redis "Run ID", a SHA1-sized random number that identifies a
|
||||||
gettimeofday(&tv,NULL);
|
* given execution of Redis, so that if you are talking with an instance
|
||||||
if (l >= sizeof(tv.tv_usec)) {
|
* having run_id == A, and you reconnect and it has run_id == B, you can be
|
||||||
memcpy(x,&tv.tv_usec,sizeof(tv.tv_usec));
|
* sure that it is either a different instance or it was restarted. */
|
||||||
l -= sizeof(tv.tv_usec);
|
void getRandomHexChars(char *p, size_t len) {
|
||||||
x += sizeof(tv.tv_usec);
|
char *charset = "0123456789abcdef";
|
||||||
}
|
size_t j;
|
||||||
if (l >= sizeof(tv.tv_sec)) {
|
|
||||||
memcpy(x,&tv.tv_sec,sizeof(tv.tv_sec));
|
getRandomBytes((unsigned char*)p,len);
|
||||||
l -= sizeof(tv.tv_sec);
|
for (j = 0; j < len; j++) p[j] = charset[p[j] & 0x0F];
|
||||||
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];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Given the filename, return the absolute path as an SDS string, or NULL
|
/* Given the filename, return the absolute path as an SDS string, or NULL
|
||||||
|
Loading…
x
Reference in New Issue
Block a user