diff options
-rw-r--r-- | src/anet.c | 46 | ||||
-rw-r--r-- | src/anet.h | 10 | ||||
-rw-r--r-- | src/aof.c | 1 | ||||
-rw-r--r-- | src/connection.c | 10 | ||||
-rw-r--r-- | src/connection.h | 2 | ||||
-rw-r--r-- | src/networking.c | 48 | ||||
-rw-r--r-- | src/replication.c | 7 | ||||
-rw-r--r-- | src/sentinel.c | 6 | ||||
-rw-r--r-- | src/server.h | 4 |
9 files changed, 70 insertions, 64 deletions
diff --git a/src/anet.c b/src/anet.c index e9615a128..d46ce5398 100644 --- a/src/anet.c +++ b/src/anet.c @@ -592,11 +592,15 @@ int anetUnixAccept(char *err, int s) { return fd; } -int anetPeerToString(int fd, char *ip, size_t ip_len, int *port) { +int anetFdToString(int fd, char *ip, size_t ip_len, int *port, int fd_to_str_type) { struct sockaddr_storage sa; socklen_t salen = sizeof(sa); - if (getpeername(fd,(struct sockaddr*)&sa,&salen) == -1) goto error; + if (fd_to_str_type == FD_TO_PEER_NAME) { + if (getpeername(fd, (struct sockaddr *)&sa, &salen) == -1) goto error; + } else { + if (getsockname(fd, (struct sockaddr *)&sa, &salen) == -1) goto error; + } if (ip_len == 0) goto error; if (sa.ss_family == AF_INET) { @@ -608,7 +612,7 @@ int anetPeerToString(int fd, char *ip, size_t ip_len, int *port) { if (ip) inet_ntop(AF_INET6,(void*)&(s->sin6_addr),ip,ip_len); if (port) *port = ntohs(s->sin6_port); } else if (sa.ss_family == AF_UNIX) { - if (ip) strncpy(ip,"/unixsocket",ip_len); + if (ip) snprintf(ip, ip_len, "/unixsocket"); if (port) *port = 0; } else { goto error; @@ -636,41 +640,11 @@ int anetFormatAddr(char *buf, size_t buf_len, char *ip, int port) { "[%s]:%d" : "%s:%d", ip, port); } -/* Like anetFormatAddr() but extract ip and port from the socket's peer. */ -int anetFormatPeer(int fd, char *buf, size_t buf_len) { +/* Like anetFormatAddr() but extract ip and port from the socket's peer/sockname. */ +int anetFormatFdAddr(int fd, char *buf, size_t buf_len, int fd_to_str_type) { char ip[INET6_ADDRSTRLEN]; int port; - anetPeerToString(fd,ip,sizeof(ip),&port); + anetFdToString(fd,ip,sizeof(ip),&port,fd_to_str_type); return anetFormatAddr(buf, buf_len, ip, port); } - -int anetSockName(int fd, char *ip, size_t ip_len, int *port) { - struct sockaddr_storage sa; - socklen_t salen = sizeof(sa); - - if (getsockname(fd,(struct sockaddr*)&sa,&salen) == -1) { - if (port) *port = 0; - ip[0] = '?'; - ip[1] = '\0'; - return -1; - } - if (sa.ss_family == AF_INET) { - struct sockaddr_in *s = (struct sockaddr_in *)&sa; - if (ip) inet_ntop(AF_INET,(void*)&(s->sin_addr),ip,ip_len); - if (port) *port = ntohs(s->sin_port); - } else { - struct sockaddr_in6 *s = (struct sockaddr_in6 *)&sa; - if (ip) inet_ntop(AF_INET6,(void*)&(s->sin6_addr),ip,ip_len); - if (port) *port = ntohs(s->sin6_port); - } - return 0; -} - -int anetFormatSock(int fd, char *fmt, size_t fmt_len) { - char ip[INET6_ADDRSTRLEN]; - int port; - - anetSockName(fd,ip,sizeof(ip),&port); - return anetFormatAddr(fmt, fmt_len, ip, port); -} diff --git a/src/anet.h b/src/anet.h index 23f19643c..fbf41cd17 100644 --- a/src/anet.h +++ b/src/anet.h @@ -49,6 +49,10 @@ #undef ip_len #endif +/* FD to address string conversion types */ +#define FD_TO_PEER_NAME 0 +#define FD_TO_SOCK_NAME 1 + int anetTcpConnect(char *err, const char *addr, int port); int anetTcpNonBlockConnect(char *err, const char *addr, int port); int anetTcpNonBlockBindConnect(char *err, const char *addr, int port, const char *source_addr); @@ -71,11 +75,9 @@ int anetDisableTcpNoDelay(char *err, int fd); int anetTcpKeepAlive(char *err, int fd); int anetSendTimeout(char *err, int fd, long long ms); int anetRecvTimeout(char *err, int fd, long long ms); -int anetPeerToString(int fd, char *ip, size_t ip_len, int *port); +int anetFdToString(int fd, char *ip, size_t ip_len, int *port, int fd_to_str_type); int anetKeepAlive(char *err, int fd, int interval); -int anetSockName(int fd, char *ip, size_t ip_len, int *port); int anetFormatAddr(char *fmt, size_t fmt_len, char *ip, int port); -int anetFormatPeer(int fd, char *fmt, size_t fmt_len); -int anetFormatSock(int fd, char *fmt, size_t fmt_len); +int anetFormatFdAddr(int fd, char *buf, size_t buf_len, int fd_to_str_type); #endif @@ -681,6 +681,7 @@ struct client *createAOFClient(void) { c->obuf_soft_limit_reached_time = 0; c->watched_keys = listCreate(); c->peerid = NULL; + c->sockname = NULL; c->resp = 2; c->user = NULL; listSetFreeMethod(c->reply,freeClientReplyValue); diff --git a/src/connection.c b/src/connection.c index 83fb84d6d..a4610a42e 100644 --- a/src/connection.c +++ b/src/connection.c @@ -374,15 +374,15 @@ int connGetSocketError(connection *conn) { } int connPeerToString(connection *conn, char *ip, size_t ip_len, int *port) { - return anetPeerToString(conn ? conn->fd : -1, ip, ip_len, port); + return anetFdToString(conn ? conn->fd : -1, ip, ip_len, port, FD_TO_PEER_NAME); } -int connFormatPeer(connection *conn, char *buf, size_t buf_len) { - return anetFormatPeer(conn ? conn->fd : -1, buf, buf_len); +int connSockName(connection *conn, char *ip, size_t ip_len, int *port) { + return anetFdToString(conn->fd, ip, ip_len, port, FD_TO_SOCK_NAME); } -int connSockName(connection *conn, char *ip, size_t ip_len, int *port) { - return anetSockName(conn->fd, ip, ip_len, port); +int connFormatFdAddr(connection *conn, char *buf, size_t buf_len, int fd_to_str_type) { + return anetFormatFdAddr(conn ? conn->fd : -1, buf, buf_len, fd_to_str_type); } int connBlock(connection *conn) { diff --git a/src/connection.h b/src/connection.h index 03281a3d9..60f1f70cb 100644 --- a/src/connection.h +++ b/src/connection.h @@ -225,7 +225,7 @@ int connKeepAlive(connection *conn, int interval); int connSendTimeout(connection *conn, long long ms); int connRecvTimeout(connection *conn, long long ms); int connPeerToString(connection *conn, char *ip, size_t ip_len, int *port); -int connFormatPeer(connection *conn, char *buf, size_t buf_len); +int connFormatFdAddr(connection *conn, char *buf, size_t buf_len, int fd_to_str_type); int connSockName(connection *conn, char *ip, size_t ip_len, int *port); const char *connGetInfo(connection *conn, char *buf, size_t buf_len); diff --git a/src/networking.c b/src/networking.c index fcb612e0b..4f0e378da 100644 --- a/src/networking.c +++ b/src/networking.c @@ -168,6 +168,7 @@ client *createClient(connection *conn) { c->pubsub_channels = dictCreate(&objectKeyPointerValueDictType,NULL); c->pubsub_patterns = listCreate(); c->peerid = NULL; + c->sockname = NULL; c->client_list_node = NULL; c->client_tracking_redirection = 0; c->client_tracking_prefixes = NULL; @@ -1300,6 +1301,7 @@ void freeClient(client *c) { c->argv_len_sum = 0; freeClientMultiState(c); sdsfree(c->peerid); + sdsfree(c->sockname); zfree(c); } @@ -2079,25 +2081,25 @@ void getClientsMaxBuffers(unsigned long *longest_output_list, *biggest_input_buffer = bib; } -/* A Redis "Peer ID" is a colon separated ip:port pair. +/* A Redis "Address String" is a colon separated ip:port pair. * For IPv4 it's in the form x.y.z.k:port, example: "127.0.0.1:1234". * For IPv6 addresses we use [] around the IP part, like in "[::1]:1234". * For Unix sockets we use path:0, like in "/tmp/redis:0". * - * A Peer ID always fits inside a buffer of NET_PEER_ID_LEN bytes, including - * the null term. + * An Address String always fits inside a buffer of NET_ADDR_STR_LEN bytes, + * including the null term. * - * On failure the function still populates 'peerid' with the "?:0" string - * in case you want to relax error checking or need to display something - * anyway (see anetPeerToString implementation for more info). */ -void genClientPeerId(client *client, char *peerid, - size_t peerid_len) { + * On failure the function still populates 'addr' with the "?:0" string in case + * you want to relax error checking or need to display something anyway (see + * anetFdToString implementation for more info). */ +void genClientAddrString(client *client, char *addr, + size_t addr_len, int fd_to_str_type) { if (client->flags & CLIENT_UNIX_SOCKET) { /* Unix socket client. */ - snprintf(peerid,peerid_len,"%s:0",server.unixsocket); + snprintf(addr,addr_len,"%s:0",server.unixsocket); } else { /* TCP client. */ - connFormatPeer(client->conn,peerid,peerid_len); + connFormatFdAddr(client->conn,addr,addr_len,fd_to_str_type); } } @@ -2106,15 +2108,29 @@ void genClientPeerId(client *client, char *peerid, * The Peer ID never changes during the life of the client, however it * is expensive to compute. */ char *getClientPeerId(client *c) { - char peerid[NET_PEER_ID_LEN]; + char peerid[NET_ADDR_STR_LEN]; if (c->peerid == NULL) { - genClientPeerId(c,peerid,sizeof(peerid)); + genClientAddrString(c,peerid,sizeof(peerid),FD_TO_PEER_NAME); c->peerid = sdsnew(peerid); } return c->peerid; } +/* This function returns the client bound socket name, by creating and caching + * it if client->sockname is NULL, otherwise returning the cached value. + * The Socket Name never changes during the life of the client, however it + * is expensive to compute. */ +char *getClientSockname(client *c) { + char sockname[NET_ADDR_STR_LEN]; + + if (c->sockname == NULL) { + genClientAddrString(c,sockname,sizeof(sockname),FD_TO_SOCK_NAME); + c->sockname = sdsnew(sockname); + } + return c->sockname; +} + /* Concatenate a string representing the state of a client in a human * readable format, into the sds string 's'. */ sds catClientInfoString(sds s, client *client) { @@ -2162,9 +2178,10 @@ sds catClientInfoString(sds s, client *client) { total_mem += zmalloc_size(client->argv); return sdscatfmt(s, - "id=%U addr=%s %s name=%s age=%I idle=%I flags=%s db=%i sub=%i psub=%i multi=%i qbuf=%U qbuf-free=%U argv-mem=%U obl=%U oll=%U omem=%U tot-mem=%U events=%s cmd=%s user=%s", + "id=%U addr=%s laddr=%s %s name=%s age=%I idle=%I flags=%s db=%i sub=%i psub=%i multi=%i qbuf=%U qbuf-free=%U argv-mem=%U obl=%U oll=%U omem=%U tot-mem=%U events=%s cmd=%s user=%s", (unsigned long long) client->id, getClientPeerId(client), + getClientSockname(client), connGetInfo(client->conn, conninfo, sizeof(conninfo)), client->name ? (char*)client->name->ptr : "", (long long)(server.unixtime - client->ctime), @@ -2251,6 +2268,7 @@ void clientCommand(client *c) { "KILL <ip:port> -- Kill connection made from <ip:port>.", "KILL <option> <value> [option value ...] -- Kill connections. Options are:", " ADDR <ip:port> -- Kill connection made from <ip:port>", +" LADDR <ip:port> -- Kill connection made to <ip:port>", " TYPE (normal|master|replica|pubsub) -- Kill connections by type.", " USER <username> -- Kill connections authenticated with such user.", " SKIPME (yes|no) -- Skip killing current connection (default: yes).", @@ -2304,6 +2322,7 @@ NULL /* CLIENT KILL <ip:port> * CLIENT KILL <option> [value] ... <option> [value] */ char *addr = NULL; + char *laddr = NULL; user *user = NULL; int type = -1; uint64_t id = 0; @@ -2336,6 +2355,8 @@ NULL } } else if (!strcasecmp(c->argv[i]->ptr,"addr") && moreargs) { addr = c->argv[i+1]->ptr; + } else if (!strcasecmp(c->argv[i]->ptr,"laddr") && moreargs) { + laddr = c->argv[i+1]->ptr; } else if (!strcasecmp(c->argv[i]->ptr,"user") && moreargs) { user = ACLGetUserByName(c->argv[i+1]->ptr, sdslen(c->argv[i+1]->ptr)); @@ -2369,6 +2390,7 @@ NULL while ((ln = listNext(&li)) != NULL) { client *client = listNodeValue(ln); if (addr && strcmp(getClientPeerId(client),addr) != 0) continue; + if (laddr && strcmp(getClientSockname(client),laddr) != 0) continue; if (type != -1 && getClientType(client) != type) continue; if (id != 0 && client->id != id) continue; if (user && client->user != user) continue; diff --git a/src/replication.c b/src/replication.c index da70c4082..d1d26a970 100644 --- a/src/replication.c +++ b/src/replication.c @@ -57,7 +57,7 @@ int RDBGeneratedByReplication = 0; * IP address and its listening port which is more clear for the user, for * example: "Closing connection with replica 10.1.2.3:6380". */ char *replicationGetSlaveName(client *c) { - static char buf[NET_PEER_ID_LEN]; + static char buf[NET_ADDR_STR_LEN]; char ip[NET_IP_STR_LEN]; ip[0] = '\0'; @@ -2792,6 +2792,11 @@ void replicationCacheMaster(client *c) { sdsfree(c->peerid); c->peerid = NULL; } + /* Invalidate the Sock Name cache. */ + if (c->sockname) { + sdsfree(c->sockname); + c->sockname = NULL; + } /* Caching the master happens instead of the actual freeClient() call, * so make sure to adjust the replication state. This function will diff --git a/src/sentinel.c b/src/sentinel.c index 71e28e1d2..87fc20e9f 100644 --- a/src/sentinel.c +++ b/src/sentinel.c @@ -1194,7 +1194,7 @@ sentinelRedisInstance *createSentinelRedisInstance(char *name, int flags, char * sentinelRedisInstance *ri; sentinelAddr *addr; dict *table = NULL; - char slavename[NET_PEER_ID_LEN], *sdsname; + char slavename[NET_ADDR_STR_LEN], *sdsname; serverAssert(flags & (SRI_MASTER|SRI_SLAVE|SRI_SENTINEL)); serverAssert((flags & SRI_MASTER) || master != NULL); @@ -1320,7 +1320,7 @@ sentinelRedisInstance *sentinelRedisInstanceLookupSlave( { sds key; sentinelRedisInstance *slave; - char buf[NET_PEER_ID_LEN]; + char buf[NET_ADDR_STR_LEN]; serverAssert(ri->flags & SRI_MASTER); anetFormatAddr(buf,sizeof(buf),ip,port); @@ -2674,7 +2674,7 @@ int sentinelSendHello(sentinelRedisInstance *ri) { if (sentinel.announce_ip) { announce_ip = sentinel.announce_ip; } else { - if (anetSockName(ri->link->cc->c.fd,ip,sizeof(ip),NULL) == -1) + if (anetFdToString(ri->link->cc->c.fd,ip,sizeof(ip),NULL,FD_TO_SOCK_NAME) == -1) return C_ERR; announce_ip = ip; } diff --git a/src/server.h b/src/server.h index b68d06497..b1e645b0c 100644 --- a/src/server.h +++ b/src/server.h @@ -112,7 +112,7 @@ typedef long long ustime_t; /* microsecond time type. */ #define CONFIG_DEFAULT_UNIX_SOCKET_PERM 0 #define CONFIG_DEFAULT_LOGFILE "" #define NET_IP_STR_LEN 46 /* INET6_ADDRSTRLEN is 46, but we need to be sure */ -#define NET_PEER_ID_LEN (NET_IP_STR_LEN+32) /* Must be enough for ip:port */ +#define NET_ADDR_STR_LEN (NET_IP_STR_LEN+32) /* Must be enough for ip:port */ #define CONFIG_BINDADDR_MAX 16 #define CONFIG_MIN_RESERVED_FDS 32 @@ -850,6 +850,7 @@ typedef struct client { dict *pubsub_channels; /* channels a client is interested in (SUBSCRIBE) */ list *pubsub_patterns; /* patterns a client is interested in (SUBSCRIBE) */ sds peerid; /* Cached peer ID. */ + sds sockname; /* Cached connection target address. */ listNode *client_list_node; /* list node in client list */ RedisModuleUserChangedFunc auth_callback; /* Module callback to execute * when the authenticated user @@ -1716,6 +1717,7 @@ void *dupClientReplyValue(void *o); void getClientsMaxBuffers(unsigned long *longest_output_list, unsigned long *biggest_input_buffer); char *getClientPeerId(client *client); +char *getClientSockName(client *client); sds catClientInfoString(sds s, client *client); sds getAllClientsInfoString(int type); void rewriteClientCommandVector(client *c, int argc, ...); |