|
|
|
@ -2,27 +2,31 @@ |
|
|
|
#include <hiredis.h> |
|
|
|
#include <sys/types.h> |
|
|
|
#include <sys/time.h> |
|
|
|
#include <unistd.h> |
|
|
|
|
|
|
|
#include "redis.h" |
|
|
|
#include "aux.h" |
|
|
|
#include "call.h" |
|
|
|
#include "log.h" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct redis *redis_new(u_int32_t ip, u_int16_t port, char *key) { |
|
|
|
struct redis *r; |
|
|
|
#define redisCommandNR(a...) (int)({ void *__tmp; __tmp = redisCommand(a); if (__tmp) freeReplyObject(__tmp); __tmp ? 0 : -1;}) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int redis_connect(struct redis *r, int wait) { |
|
|
|
struct timeval tv; |
|
|
|
redisReply *rp; |
|
|
|
char *s; |
|
|
|
|
|
|
|
r = malloc(sizeof(*r)); |
|
|
|
ZERO(*r); |
|
|
|
|
|
|
|
sprintf(r->host, IPF, IPP(ip)); |
|
|
|
r->port = port; |
|
|
|
r->key = key; |
|
|
|
if (r->ctx) |
|
|
|
redisFree(r->ctx); |
|
|
|
r->ctx = NULL; |
|
|
|
|
|
|
|
tv.tv_sec = 1; |
|
|
|
tv.tv_usec = 0; |
|
|
|
@ -31,39 +35,123 @@ struct redis *redis_new(u_int32_t ip, u_int16_t port, char *key) { |
|
|
|
if (!r->ctx) |
|
|
|
goto err; |
|
|
|
if (r->ctx->err) |
|
|
|
goto err; |
|
|
|
goto err2; |
|
|
|
|
|
|
|
rp = redisCommand(r->ctx, "PING"); |
|
|
|
if (!rp) |
|
|
|
goto err; |
|
|
|
freeReplyObject(rp); |
|
|
|
if (redisCommandNR(r->ctx, "PING")) |
|
|
|
goto err2; |
|
|
|
|
|
|
|
rp = redisCommand(r->ctx, "INFO"); |
|
|
|
if (!rp) |
|
|
|
goto err; |
|
|
|
s = strstr(rp->str, "role:"); |
|
|
|
if (!s) { |
|
|
|
freeReplyObject(rp); |
|
|
|
goto err; |
|
|
|
} |
|
|
|
if (!memcmp(s, "role:master", 9)) |
|
|
|
r->active = 1; |
|
|
|
else if (!memcmp(s, "role:slave", 8)) |
|
|
|
; /* it's already 0 */ |
|
|
|
else { |
|
|
|
mylog(LOG_ERR, "Unable to determine Redis master/slave state\n"); |
|
|
|
if (redisCommandNR(r->ctx, "SELECT %i", r->db)) |
|
|
|
goto err2; |
|
|
|
|
|
|
|
while (wait-- >= 0) { |
|
|
|
mylog(LOG_INFO, "Asking Redis whether it's master or slave...\n"); |
|
|
|
rp = redisCommand(r->ctx, "INFO"); |
|
|
|
if (!rp) |
|
|
|
goto err2; |
|
|
|
|
|
|
|
s = strstr(rp->str, "role:"); |
|
|
|
if (!s) |
|
|
|
goto err3; |
|
|
|
if (!memcmp(s, "role:master", 9)) |
|
|
|
goto done; |
|
|
|
else if (!memcmp(s, "role:slave", 8)) |
|
|
|
goto next; |
|
|
|
else |
|
|
|
goto err3; |
|
|
|
|
|
|
|
next: |
|
|
|
freeReplyObject(rp); |
|
|
|
goto err; |
|
|
|
mylog(LOG_INFO, "Connected to Redis, but it's in slave mode\n"); |
|
|
|
sleep(1); |
|
|
|
} |
|
|
|
|
|
|
|
goto err2; |
|
|
|
|
|
|
|
done: |
|
|
|
freeReplyObject(rp); |
|
|
|
mylog(LOG_INFO, "Connected to Redis\n"); |
|
|
|
return 0; |
|
|
|
|
|
|
|
err3: |
|
|
|
freeReplyObject(rp); |
|
|
|
err2: |
|
|
|
if (r->ctx->err) |
|
|
|
mylog(LOG_ERR, "Redis error: %s\n", r->ctx->errstr); |
|
|
|
redisFree(r->ctx); |
|
|
|
r->ctx = NULL; |
|
|
|
err: |
|
|
|
mylog(LOG_ERR, "Failed to connect to master Redis database\n"); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct redis *redis_new(u_int32_t ip, u_int16_t port, int db) { |
|
|
|
struct redis *r; |
|
|
|
|
|
|
|
r = malloc(sizeof(*r)); |
|
|
|
ZERO(*r); |
|
|
|
|
|
|
|
sprintf(r->host, IPF, IPP(ip)); |
|
|
|
r->port = port; |
|
|
|
r->db = db; |
|
|
|
|
|
|
|
if (redis_connect(r, 10)) |
|
|
|
goto err; |
|
|
|
|
|
|
|
return r; |
|
|
|
|
|
|
|
err: |
|
|
|
if (r->ctx && r->ctx->err && r->ctx->errstr) |
|
|
|
mylog(LOG_CRIT, "Redis error: %s\n", r->ctx->errstr); |
|
|
|
if (r->ctx) |
|
|
|
redisFree(r->ctx); |
|
|
|
free(r); |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int redis_restore(struct callmaster *m) { |
|
|
|
struct redis *r = m->redis; |
|
|
|
redisReply *rp, *rp2, *rp3; |
|
|
|
int i; |
|
|
|
|
|
|
|
rp = redisCommand(r->ctx, "SMEMBERS calls"); |
|
|
|
if (!rp || rp->type != REDIS_REPLY_ARRAY) { |
|
|
|
mylog(LOG_ERR, "Could not retrieve call list from Redis: %s\n", r->ctx->errstr); |
|
|
|
goto err; |
|
|
|
} |
|
|
|
|
|
|
|
for (i = 0; i < rp->elements; i++) { |
|
|
|
rp2 = rp->element[i]; |
|
|
|
if (rp2->type != REDIS_REPLY_STRING) |
|
|
|
continue; |
|
|
|
|
|
|
|
rp3 = redisCommand(r->ctx, "HMGET %s callid created", rp2->str); |
|
|
|
|
|
|
|
if (!rp3) |
|
|
|
goto del; |
|
|
|
if (rp3->type != REDIS_REPLY_ARRAY) |
|
|
|
goto del2; |
|
|
|
if (rp3->elements != 2) |
|
|
|
goto del2; |
|
|
|
if (rp3->element[0]->type != REDIS_REPLY_STRING) |
|
|
|
goto del2; |
|
|
|
if (rp3->element[1]->type != REDIS_REPLY_INTEGER) |
|
|
|
goto del2; |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
del2: |
|
|
|
freeReplyObject(rp3); |
|
|
|
del: |
|
|
|
redisCommandNR(r->ctx, "DEL %s", rp2->str); |
|
|
|
redisCommandNR(r->ctx, "SREM calls %s", rp2->str); |
|
|
|
} |
|
|
|
|
|
|
|
freeReplyObject(rp); |
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
err: |
|
|
|
return -1; |
|
|
|
} |