From 91867a5ea28e30f9f9bea212aaa47df2fb868649 Mon Sep 17 00:00:00 2001 From: antirez Date: Thu, 21 Apr 2011 15:38:02 +0200 Subject: [PATCH] CLIENT LIST implemented --- src/anet.c | 10 ++++++++++ src/anet.h | 1 + src/networking.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ src/redis-cli.c | 10 +++++++++- src/redis.c | 3 ++- src/redis.h | 1 + 6 files changed, 69 insertions(+), 2 deletions(-) diff --git a/src/anet.c b/src/anet.c index 4e16f2e4..692cef19 100644 --- a/src/anet.c +++ b/src/anet.c @@ -345,3 +345,13 @@ int anetUnixAccept(char *err, int s) { return fd; } + +int anetPeerToString(int fd, char *ip, int *port) { + struct sockaddr_in sa; + socklen_t salen = sizeof(sa); + + if (getpeername(fd,(struct sockaddr*)&sa,&salen) == -1) return -1; + if (ip) strcpy(ip,inet_ntoa(sa.sin_addr)); + if (port) *port = ntohs(sa.sin_port); + return 0; +} diff --git a/src/anet.h b/src/anet.h index 118b4dda..2b2dea45 100644 --- a/src/anet.h +++ b/src/anet.h @@ -53,5 +53,6 @@ int anetWrite(int fd, char *buf, int count); int anetNonBlock(char *err, int fd); int anetTcpNoDelay(char *err, int fd); int anetTcpKeepAlive(char *err, int fd); +int anetPeerToString(int fd, char *ip, int *port); #endif diff --git a/src/networking.c b/src/networking.c index ce66307b..b059787a 100644 --- a/src/networking.c +++ b/src/networking.c @@ -865,3 +865,49 @@ void getClientsMaxBuffers(unsigned long *longest_output_list, *biggest_input_buffer = bib; } +void clientCommand(redisClient *c) { + if (!strcasecmp(c->argv[1]->ptr,"list") && c->argc == 2) { + listNode *ln; + listIter li; + sds o = sdsempty(); + time_t now = time(NULL); + + listRewind(server.clients,&li); + while ((ln = listNext(&li)) != NULL) { + redisClient *client; + char ip[32], flags[16], *p; + int port; + + client = listNodeValue(ln); + if (anetPeerToString(client->fd,ip,&port) == -1) continue; + p = flags; + if (client->flags & REDIS_SLAVE) { + if (client->flags & REDIS_MONITOR) + *p++ = 'O'; + else + *p++ = 'S'; + } + if (client->flags & REDIS_MASTER) *p++ = 'M'; + if (p == flags) *p++ = 'N'; + if (client->flags & REDIS_MULTI) *p++ = 'x'; + if (client->flags & REDIS_BLOCKED) *p++ = 'b'; + if (client->flags & REDIS_IO_WAIT) *p++ = 'i'; + if (client->flags & REDIS_DIRTY_CAS) *p++ = 'd'; + if (client->flags & REDIS_CLOSE_AFTER_REPLY) *p++ = 'c'; + if (client->flags & REDIS_UNBLOCKED) *p++ = 'u'; + *p++ = '\0'; + o = sdscatprintf(o, + "addr=%s:%d fd=%d idle=%ld flags=%s db=%d sub=%d psub=%d\n", + ip,port,client->fd, + (long)(now - client->lastinteraction), + flags, + client->db->id, + (int) dictSize(client->pubsub_channels), + (int) listLength(client->pubsub_patterns)); + } + addReplyBulkCBuffer(c,o,sdslen(o)); + sdsfree(o); + } else { + addReplyError(c, "Syntax error, try CLIENT (LIST | KILL ip:port)"); + } +} diff --git a/src/redis-cli.c b/src/redis-cli.c index f0c712e7..9e497b4b 100644 --- a/src/redis-cli.c +++ b/src/redis-cli.c @@ -465,7 +465,15 @@ static int cliSendCommand(int argc, char **argv, int repeat) { return REDIS_OK; } - output_raw = !strcasecmp(command,"info"); + output_raw = 0; + if (!strcasecmp(command,"info") || + (argc == 2 && !strcasecmp(command,"client") && + !strcasecmp(argv[1],"list"))) + + { + output_raw = 1; + } + if (!strcasecmp(command,"help") || !strcasecmp(command,"?")) { cliOutputHelp(--argc, ++argv); return REDIS_OK; diff --git a/src/redis.c b/src/redis.c index fd7e56b2..c4d5e70f 100644 --- a/src/redis.c +++ b/src/redis.c @@ -188,7 +188,8 @@ struct redisCommand readonlyCommandTable[] = { {"publish",publishCommand,3,REDIS_CMD_FORCE_REPLICATION,NULL,0,0,0}, {"watch",watchCommand,-2,0,NULL,0,0,0}, {"unwatch",unwatchCommand,1,0,NULL,0,0,0}, - {"object",objectCommand,-2,0,NULL,0,0,0} + {"object",objectCommand,-2,0,NULL,0,0,0}, + {"client",clientCommand,-2,0,NULL,0,0,0} }; /*============================ Utility functions ============================ */ diff --git a/src/redis.h b/src/redis.h index 31f77f96..a9f46f9c 100644 --- a/src/redis.h +++ b/src/redis.h @@ -1031,6 +1031,7 @@ void publishCommand(redisClient *c); void watchCommand(redisClient *c); void unwatchCommand(redisClient *c); void objectCommand(redisClient *c); +void clientCommand(redisClient *c); #if defined(__GNUC__) void *calloc(size_t count, size_t size) __attribute__ ((deprecated));