QList<int> getListenFds() { QList<int> fds; int n = sd_listen_fds(0); for(int i=0;i<n;++i) { int fd = SD_LISTEN_FDS_START + i; if(sd_is_socket_inet(fd, AF_UNSPEC, SOCK_STREAM, 1, 0) < 0) { logger::error() << "Socket" << i << " is not listening inet socket!"; } else { fds.append(fd); } } return fds; }
static int setup_socket_from_systemd(void) { int fd = SD_LISTEN_FDS_START; if (!sd_is_socket_inet(fd, AF_UNSPEC, SOCK_STREAM, 1, 0)) lwan_status_critical("Passed file descriptor is not a " "listening TCP socket"); int flags = fcntl(fd, F_GETFD); if (flags < 0) lwan_status_critical_perror("Could not obtain socket flags"); if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) lwan_status_critical_perror("Could not set socket flags"); return fd; }
static PyObject* is_socket_inet(PyObject *self, PyObject *args) { int r; int fd, family = AF_UNSPEC, type = 0, listening = -1, port = 0; if (!PyArg_ParseTuple(args, "i|iiii:_is_socket_inet", &fd, &family, &type, &listening, &port)) return NULL; if (port < 0 || port > UINT16_MAX) { set_error(-EINVAL, NULL, "port must fit into uint16_t"); return NULL; } r = sd_is_socket_inet(fd, family, type, listening, (uint16_t) port); if (set_error(r, NULL, NULL) < 0) return NULL; return PyBool_FromLong(r); }
/*! starts listening on a TCP/IP (v4 or v6) address. * * \param address the IP address to bind to * \param port the TCP/IP port number to listen to * \param flags some flags, such as O_CLOEXEC and O_NONBLOCK (the most prominent) to set on server socket and each created client socket * * \retval true successfully initialized * \retval false some failure occured during setting up the server socket. */ bool ServerSocket::open(const std::string& address, int port, int flags) { #ifndef NDEBUG setLoggingPrefix("ServerSocket(%s:%d)", address.c_str(), port); #endif TRACE("opening"); int sd_fd_count = sd_listen_fds(false); addrinfo* res = nullptr; addrinfo hints; addrinfo* ri = nullptr; int rc; int fd = -1; in6_addr saddr; memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_NUMERICSERV; hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; if ((rc = inet_pton(AF_INET, address.c_str(), &saddr)) == 1) { hints.ai_family = AF_INET; hints.ai_flags |= AI_NUMERICHOST; } else if ((rc = inet_pton(AF_INET6, address.c_str(), &saddr)) == 1) { hints.ai_family = AF_INET6; hints.ai_flags |= AI_NUMERICHOST; } else { switch (rc) { case -1: // errno is set properly errorText_ = strerror(errno); break; case 0: // invalid network addr format errorText_ = strerror(EINVAL); break; default: // unknown error errorText_ = strerror(EINVAL); break; } return false; } char sport[16]; snprintf(sport, sizeof(sport), "%d", port); if ((rc = getaddrinfo(address.c_str(), sport, &hints, &res)) != 0) { errorText_ = gai_strerror(rc); goto err; } typeMask_ = 0; flags_ = flags; if (flags & O_CLOEXEC) { flags_ &= ~O_CLOEXEC; typeMask_ |= SOCK_CLOEXEC; } if (flags & O_NONBLOCK) { flags_ &= ~O_NONBLOCK; typeMask_ |= SOCK_NONBLOCK; } // check if passed by parent x0d first for (ri = res; ri != nullptr; ri = ri->ai_next) { if ((fd = x0::getSocketInet(address.c_str(), port)) >= 0) { // socket found, but ensure our expected `flags` are set. if ((flags & O_NONBLOCK) && fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK) < 0) goto syserr; if ((flags & O_CLOEXEC) && fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC) < 0) goto syserr; goto done; } } // check if systemd created the socket for us if (sd_fd_count > 0) { fd = SD_LISTEN_FDS_START; int last = fd + sd_fd_count; for (addrinfo* ri = res; ri != nullptr; ri = ri->ai_next) { for (; fd < last; ++fd) { if (sd_is_socket_inet(fd, ri->ai_family, ri->ai_socktype, true, port) > 0) { // socket found, but ensure our expected `flags` are set. if ((flags & O_NONBLOCK) && fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK) < 0) goto syserr; if ((flags & O_CLOEXEC) && fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC) < 0) goto syserr; #if defined(TCP_QUICKACK) if (::setsockopt(fd, SOL_TCP, TCP_QUICKACK, &rc, sizeof(rc)) < 0) goto syserr; #endif #if defined(TCP_DEFER_ACCEPT) && defined(WITH_TCP_DEFER_ACCEPT) if (::setsockopt(fd, SOL_TCP, TCP_DEFER_ACCEPT, &rc, sizeof(rc)) < 0) goto syserr; #endif goto done; } } } char buf[256]; snprintf(buf, sizeof(buf), "Running under systemd socket unit, but we received no socket for %s:%d.", address.c_str(), port); errorText_ = buf; goto err; } // create socket manually for (ri = res; ri != nullptr; ri = ri->ai_next) { fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (fd < 0) goto syserr; if ((flags & O_NONBLOCK) && fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK) < 0) goto syserr; if ((flags & O_CLOEXEC) && fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC) < 0) goto syserr; rc = 1; #if defined(SO_REUSEADDR) if (::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &rc, sizeof(rc)) < 0) goto syserr; #endif #if defined(TCP_QUICKACK) if (::setsockopt(fd, SOL_TCP, TCP_QUICKACK, &rc, sizeof(rc)) < 0) goto syserr; #endif #if defined(TCP_DEFER_ACCEPT) && defined(WITH_TCP_DEFER_ACCEPT) if (::setsockopt(fd, SOL_TCP, TCP_DEFER_ACCEPT, &rc, sizeof(rc)) < 0) goto syserr; #endif // TODO so_linger(false, 0) // TODO so_keepalive(true) if (::bind(fd, res->ai_addr, res->ai_addrlen) < 0) goto syserr; if (::listen(fd, backlog_) < 0) goto syserr; goto done; } done: fd_ = fd; addressFamily_ = res->ai_family; freeaddrinfo(res); address_ = address; port_ = port; io_.set<ServerSocket, &ServerSocket::accept>(this); start(); return true; syserr: errorText_ = strerror(errno); err: if (res) freeaddrinfo(res); if (fd >= 0) ::close(fd); return false; }
int make_server_socket(char *host, char *port) { int fd = -1, flags, r; struct linger linger = {0, 0}; struct addrinfo *airoot, *ai, hints; /* See if we got a listen fd from systemd. If so, all socket options etc * are already set, so we check that the fd is a TCP listen socket and * return. */ r = sd_listen_fds(1); if (r < 0) { return twarn("sd_listen_fds"), -1; } if (r > 0) { if (r > 1) { twarnx("inherited more than one listen socket;" " ignoring all but the first"); r = 1; } fd = SD_LISTEN_FDS_START; r = sd_is_socket_inet(fd, 0, SOCK_STREAM, 1, 0); if (r < 0) { errno = -r; twarn("sd_is_socket_inet"); return -1; } if (!r) { twarnx("inherited fd is not a TCP listen socket"); return -1; } return fd; } memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; r = getaddrinfo(host, port, &hints, &airoot); if (r == -1) return twarn("getaddrinfo()"), -1; for(ai = airoot; ai; ai = ai->ai_next) { fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (fd == -1) { twarn("socket()"); continue; } flags = fcntl(fd, F_GETFL, 0); if (flags < 0) { twarn("getting flags"); close(fd); continue; } r = fcntl(fd, F_SETFL, flags | O_NONBLOCK); if (r == -1) { twarn("setting O_NONBLOCK"); close(fd); continue; } flags = 1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof flags); setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &flags, sizeof flags); setsockopt(fd, SOL_SOCKET, SO_LINGER, &linger, sizeof linger); setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &flags, sizeof flags); if (verbose) { char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV], *h = host, *p = port; r = getnameinfo(ai->ai_addr, ai->ai_addrlen, hbuf, sizeof hbuf, pbuf, sizeof pbuf, NI_NUMERICHOST|NI_NUMERICSERV); if (!r) { h = hbuf; p = pbuf; } if (ai->ai_family == AF_INET6) { printf("bind %d [%s]:%s\n", fd, h, p); } else { printf("bind %d %s:%s\n", fd, h, p); } } r = bind(fd, ai->ai_addr, ai->ai_addrlen); if (r == -1) { twarn("bind()"); close(fd); continue; } r = listen(fd, 1024); if (r == -1) { twarn("listen()"); close(fd); continue; } break; } freeaddrinfo(airoot); if(ai == NULL) fd = -1; return fd; }