#include "common.hh" #include "inet.hh" #include "io.hh" #include "logger.hh" #include #include #include #include #include #include #include namespace inet { unique_fd accept(Logger* logger, int fd, bool make_nonblock) { #if HAVE_ACCEPT4 unique_fd ret(accept4(fd, nullptr, nullptr, make_nonblock ? SOCK_NONBLOCK : 0)); if (!ret) logger->warn("accept: %s", strerror(errno)); return ret; #else unique_fd ret(::accept(fd, nullptr, nullptr)); if (ret) { if (make_nonblock && !io::make_nonblocking(ret.get())) { logger->warn("make nonblock failed: %s", strerror(errno)); ret.reset(); } } else { logger->warn("accept: %s", strerror(errno)); } return ret; #endif } bool bind_and_listen(Logger* logger, std::string const& addr, std::string const& port, std::vector* out) { out->clear(); struct addrinfo hints = {}; struct addrinfo* ret; hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG | AI_PASSIVE; auto err = getaddrinfo(addr.empty() ? nullptr : addr.c_str(), port.c_str(), &hints, &ret); if (err) { logger->warn("%s:%s: getaddrinfo: %s", addr.c_str(), port.c_str(), gai_strerror(err)); return false; } for (auto* rp = ret; rp != nullptr; rp = rp->ai_next) { unique_fd fd(socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)); if (!fd) continue; if (bind(fd.get(), rp->ai_addr, rp->ai_addrlen)) { logger->warn("%s:%s: bind: %s", addr.c_str(), port.c_str(), strerror(errno)); continue; } if (listen(fd.get(), 4096)) { logger->warn("%s:%s: listen: %s", addr.c_str(), port.c_str(), strerror(errno)); continue; } out->emplace_back(std::move(fd)); } freeaddrinfo(ret); return !out->empty(); } } // namespace inet namespace unix { unique_fd bind_and_listen(Logger* logger, std::string_view path) { unique_fd fd(socket(AF_UNIX, SOCK_STREAM, 0)); if (fd) { sockaddr_un addr; if (path.size() >= sizeof(addr.sun_path)) { logger->warn("%.*s: Too long path", static_cast(path.size()), path.data()); return unique_fd(); } memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; std::copy_n(path.data(), path.size(), addr.sun_path); addr.sun_path[path.size()] = '\0'; if (bind(fd.get(), reinterpret_cast(&addr), sizeof(addr))) { logger->warn("%.*s: bind: %s", static_cast(path.size()), path.data(), strerror(errno)); return unique_fd(); } if (listen(fd.get(), 4096)) { logger->warn("%.*s: listen: %s", static_cast(path.size()), path.data(), strerror(errno)); return unique_fd(); } } return fd; } } // namespace unix