summaryrefslogtreecommitdiff
path: root/src/inet.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/inet.cc')
-rw-r--r--src/inet.cc112
1 files changed, 112 insertions, 0 deletions
diff --git a/src/inet.cc b/src/inet.cc
new file mode 100644
index 0000000..1700a14
--- /dev/null
+++ b/src/inet.cc
@@ -0,0 +1,112 @@
+#include "common.hh"
+
+#include "inet.hh"
+#include "io.hh"
+#include "logger.hh"
+
+#include <algorithm>
+#include <errno.h>
+#include <netdb.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+
+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<unique_fd>* 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<int>(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<struct sockaddr*>(&addr),
+ sizeof(addr))) {
+ logger->warn("%.*s: bind: %s",
+ static_cast<int>(path.size()), path.data(), strerror(errno));
+ return unique_fd();
+ }
+ if (listen(fd.get(), 4096)) {
+ logger->warn("%.*s: listen: %s",
+ static_cast<int>(path.size()), path.data(), strerror(errno));
+ return unique_fd();
+ }
+ }
+ return fd;
+}
+
+} // namespace unix