From eb98ec73e8612a253b5ad247d02e3c0fc8d88edb Mon Sep 17 00:00:00 2001 From: git-hulk Date: Sun, 8 May 2022 14:59:03 +0800 Subject: [PATCH 1/4] Support to listen on ipv6 --- kvrocks.conf | 2 +- src/worker.cc | 60 ++++++++++++++++++++++++++++++++++----------------- src/worker.h | 2 +- 3 files changed, 42 insertions(+), 22 deletions(-) diff --git a/kvrocks.conf b/kvrocks.conf index 805b84bfdce..d98eed1df3a 100644 --- a/kvrocks.conf +++ b/kvrocks.conf @@ -8,7 +8,7 @@ # Examples: # # bind 192.168.1.100 10.0.0.1 -# bind 127.0.0.1 +# bind 127.0.0.1 ::1 bind 0.0.0.0 # Unix socket. diff --git a/src/worker.cc b/src/worker.cc index 6caf2fada5d..af8ce1652d6 100644 --- a/src/worker.cc +++ b/src/worker.cc @@ -44,10 +44,15 @@ Worker::Worker(Server *svr, Config *config, bool repl) : svr_(svr) { timeval tm = {10, 0}; evtimer_add(timer_, &tm); + Status s; int port = config->port; auto binds = config->binds; for (const auto &bind : binds) { - Status s = listenTCP(bind, port, config->backlog); + if (strchr(bind.data(), ':')) { + s = listenTCP(bind, port, AF_INET6, config->backlog); + } else { + s = listenTCP(bind, port, AF_INET, config->backlog); + } if (!s.IsOK()) { LOG(ERROR) << "[worker] Failed to listen on: "<< bind << ":" << port << ", encounter error: " << s.Msg(); @@ -153,27 +158,42 @@ void Worker::newUnixSocketConnection(evconnlistener *listener, evutil_socket_t f } } -Status Worker::listenTCP(const std::string &host, int port, int backlog) { - sockaddr_in sin{}; - sin.sin_family = AF_INET; - evutil_inet_pton(AF_INET, host.data(), &(sin.sin_addr)); - sin.sin_port = htons(port); - int fd = socket(AF_INET, SOCK_STREAM, 0); - int sock_opt = 1; - if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &sock_opt, sizeof(sock_opt)) < 0) { - return Status(Status::NotOK, evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR())); - } - // to support multi-thread binding on macOS - if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &sock_opt, sizeof(sock_opt)) < 0) { - return Status(Status::NotOK, evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR())); +Status Worker::listenTCP(const std::string &host, int port, int af, int backlog) { + char _port[6]; + int rv, fd, sock_opt = 1; + + snprintf(_port, sizeof(_port), "%d", port); + struct addrinfo hints, *srv_info, *p; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = af; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + + if ((rv = getaddrinfo(host.data(), _port, &hints, &srv_info)) != 0) { + return Status(Status::NotOK, gai_strerror(rv)); } - if (bind(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { - return Status(Status::NotOK, evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR())); + + for (p = srv_info; p != nullptr; p = p->ai_next) { + if ((fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) + continue; + if (af == AF_INET6 && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &sock_opt, sizeof(sock_opt)) == -1) { + return Status(Status::NotOK, evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR())); + } + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &sock_opt, sizeof(sock_opt)) < 0) { + return Status(Status::NotOK, evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR())); + } + // to support multi-thread binding on macOS + if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &sock_opt, sizeof(sock_opt)) < 0) { + return Status(Status::NotOK, evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR())); + } + if (bind(fd, p->ai_addr, p->ai_addrlen)) { + return Status(Status::NotOK, evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR())); + } + evutil_make_socket_nonblocking(fd); + auto lev = evconnlistener_new(base_, newTCPConnection, this, + LEV_OPT_CLOSE_ON_FREE, backlog, fd); + listen_events_.emplace_back(lev); } - evutil_make_socket_nonblocking(fd); - auto lev = evconnlistener_new(base_, newTCPConnection, this, - LEV_OPT_CLOSE_ON_FREE, backlog, fd); - listen_events_.emplace_back(lev); return Status::OK(); } diff --git a/src/worker.h b/src/worker.h index 14a278dc600..46baad1924f 100644 --- a/src/worker.h +++ b/src/worker.h @@ -65,7 +65,7 @@ class Worker { Server *svr_; private: - Status listenTCP(const std::string &host, int port, int backlog); + Status listenTCP(const std::string &host, int port, int af, int backlog); static void newTCPConnection(evconnlistener *listener, evutil_socket_t fd, sockaddr *address, int socklen, void *ctx); static void newUnixSocketConnection(evconnlistener *listener, evutil_socket_t fd, From adabcb19397d421fc34f5ce552c3f2f12acf4b5a Mon Sep 17 00:00:00 2001 From: git-hulk Date: Sun, 8 May 2022 14:59:33 +0800 Subject: [PATCH 2/4] Support to get peer ipv6 address --- src/util.cc | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/util.cc b/src/util.cc index 9bb138c8629..b393597fb23 100644 --- a/src/util.cc +++ b/src/util.cc @@ -306,21 +306,27 @@ Status SockReadLine(int fd, std::string *data) { } int GetPeerAddr(int fd, std::string *addr, uint32_t *port) { + addr->clear(); + sockaddr_storage sa{}; socklen_t sa_len = sizeof(sa); if (getpeername(fd, reinterpret_cast(&sa), &sa_len) < 0) { return -1; } - if (sa.ss_family == AF_INET) { + if (sa.ss_family == AF_INET6) { + char buf[INET6_ADDRSTRLEN]; + auto sa6 = reinterpret_cast(&sa); + inet_ntop(AF_INET6, reinterpret_cast(&sa6->sin6_addr), buf, INET_ADDRSTRLEN); + addr->append(buf); + *port = ntohs(sa6->sin6_port); + } else { auto sa4 = reinterpret_cast(&sa); char buf[INET_ADDRSTRLEN]; inet_ntop(AF_INET, reinterpret_cast(&sa4->sin_addr), buf, INET_ADDRSTRLEN); - addr->clear(); addr->append(buf); *port = ntohs(sa4->sin_port); - return 0; } - return -2; // only support AF_INET currently + return 0; } Status DecimalStringToNum(const std::string &str, int64_t *n, int64_t min, int64_t max) { From 0adfbc423203c9036d28a4e68adb5c4483b8c4df Mon Sep 17 00:00:00 2001 From: git-hulk Date: Wed, 11 May 2022 21:26:50 +0800 Subject: [PATCH 3/4] Move the check ai_family type into listenTCP --- src/worker.cc | 14 ++++++++------ src/worker.h | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/worker.cc b/src/worker.cc index af8ce1652d6..46403e8c09c 100644 --- a/src/worker.cc +++ b/src/worker.cc @@ -48,11 +48,7 @@ Worker::Worker(Server *svr, Config *config, bool repl) : svr_(svr) { int port = config->port; auto binds = config->binds; for (const auto &bind : binds) { - if (strchr(bind.data(), ':')) { - s = listenTCP(bind, port, AF_INET6, config->backlog); - } else { - s = listenTCP(bind, port, AF_INET, config->backlog); - } + s = listenTCP(bind, port, config->backlog); if (!s.IsOK()) { LOG(ERROR) << "[worker] Failed to listen on: "<< bind << ":" << port << ", encounter error: " << s.Msg(); @@ -158,10 +154,16 @@ void Worker::newUnixSocketConnection(evconnlistener *listener, evutil_socket_t f } } -Status Worker::listenTCP(const std::string &host, int port, int af, int backlog) { +Status Worker::listenTCP(const std::string &host, int port, int backlog) { char _port[6]; + int af; int rv, fd, sock_opt = 1; + if (strchr(host.data(), ':')) { + af = AF_INET6; + } else { + af = AF_INET; + } snprintf(_port, sizeof(_port), "%d", port); struct addrinfo hints, *srv_info, *p; memset(&hints, 0, sizeof(hints)); diff --git a/src/worker.h b/src/worker.h index 46baad1924f..14a278dc600 100644 --- a/src/worker.h +++ b/src/worker.h @@ -65,7 +65,7 @@ class Worker { Server *svr_; private: - Status listenTCP(const std::string &host, int port, int af, int backlog); + Status listenTCP(const std::string &host, int port, int backlog); static void newTCPConnection(evconnlistener *listener, evutil_socket_t fd, sockaddr *address, int socklen, void *ctx); static void newUnixSocketConnection(evconnlistener *listener, evutil_socket_t fd, From 67363d157c5effc95f47f012af36b6fe7400fb64 Mon Sep 17 00:00:00 2001 From: git-hulk Date: Thu, 12 May 2022 19:08:28 +0800 Subject: [PATCH 4/4] Fix didn't free the addrinfo --- src/worker.cc | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/worker.cc b/src/worker.cc index 46403e8c09c..06faeb44eb9 100644 --- a/src/worker.cc +++ b/src/worker.cc @@ -156,8 +156,7 @@ void Worker::newUnixSocketConnection(evconnlistener *listener, evutil_socket_t f Status Worker::listenTCP(const std::string &host, int port, int backlog) { char _port[6]; - int af; - int rv, fd, sock_opt = 1; + int af, rv, fd, sock_opt = 1; if (strchr(host.data(), ':')) { af = AF_INET6; @@ -179,24 +178,30 @@ Status Worker::listenTCP(const std::string &host, int port, int backlog) { if ((fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) continue; if (af == AF_INET6 && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &sock_opt, sizeof(sock_opt)) == -1) { - return Status(Status::NotOK, evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR())); + goto error; } if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &sock_opt, sizeof(sock_opt)) < 0) { - return Status(Status::NotOK, evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR())); + goto error; } // to support multi-thread binding on macOS if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &sock_opt, sizeof(sock_opt)) < 0) { - return Status(Status::NotOK, evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR())); + goto error; } if (bind(fd, p->ai_addr, p->ai_addrlen)) { - return Status(Status::NotOK, evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR())); + goto error; } evutil_make_socket_nonblocking(fd); auto lev = evconnlistener_new(base_, newTCPConnection, this, LEV_OPT_CLOSE_ON_FREE, backlog, fd); listen_events_.emplace_back(lev); } + + freeaddrinfo(srv_info); return Status::OK(); + +error: + freeaddrinfo(srv_info); + return Status(Status::NotOK, evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR())); } Status Worker::ListenUnixSocket(const std::string &path, int perm, int backlog) {