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 diff --git a/src/aof.c b/src/aof.c index b9072da93..0f67f0575 100644 --- a/src/aof.c +++ b/src/aof.c @@ -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); -} - -int connFormatPeer(connection *conn, char *buf, size_t buf_len) { - return anetFormatPeer(conn ? conn->fd : -1, buf, buf_len); + return anetFdToString(conn ? conn->fd : -1, ip, ip_len, port, FD_TO_PEER_NAME); } int connSockName(connection *conn, char *ip, size_t ip_len, int *port) { - return anetSockName(conn->fd, ip, ip_len, port); + return anetFdToString(conn->fd, ip, ip_len, port, FD_TO_SOCK_NAME); +} + +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 -- Kill connection made from .", "KILL