bool InspIRCd::BindPort(ConfigTag* tag, const irc::sockets::sockaddrs& sa, std::vector<ListenSocket*>& old_ports) { for (std::vector<ListenSocket*>::iterator n = old_ports.begin(); n != old_ports.end(); ++n) { if ((**n).bind_sa == sa) { // Replace tag, we know addr and port match, but other info (type, ssl) may not. ServerInstance->Logs.Log("SOCKET", LOG_DEFAULT, "Replacing listener on %s from old tag at %s with new tag from %s", sa.str().c_str(), (*n)->bind_tag->getTagLocation().c_str(), tag->getTagLocation().c_str()); (*n)->bind_tag = tag; (*n)->ResetIOHookProvider(); old_ports.erase(n); return true; } } ListenSocket* ll = new ListenSocket(tag, sa); if (ll->GetFd() < 0) { ServerInstance->Logs.Log("SOCKET", LOG_DEFAULT, "Failed to listen on %s from tag at %s: %s", sa.str().c_str(), tag->getTagLocation().c_str(), strerror(errno)); delete ll; return false; } ServerInstance->Logs.Log("SOCKET", LOG_DEFAULT, "Added a listener on %s from tag at %s", sa.str().c_str(), tag->getTagLocation().c_str()); ports.push_back(ll); return true; }
ListenSocket::ListenSocket(ConfigTag* tag, const irc::sockets::sockaddrs& bind_to) : bind_tag(tag) { irc::sockets::satoap(bind_to, bind_addr, bind_port); bind_desc = bind_to.str(); fd = socket(bind_to.sa.sa_family, SOCK_STREAM, 0); if (this->fd == -1) return; #ifdef IPV6_V6ONLY /* This OS supports IPv6 sockets that can also listen for IPv4 * connections. If our address is "*" or empty, enable both v4 and v6 to * allow for simpler configuration on dual-stack hosts. Otherwise, if it * is "::" or an IPv6 address, disable support so that an IPv4 bind will * work on the port (by us or another application). */ if (bind_to.sa.sa_family == AF_INET6) { std::string addr = tag->getString("address"); /* This must be >= sizeof(DWORD) on Windows */ const int enable = (addr.empty() || addr == "*") ? 0 : 1; /* This must be before bind() */ setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast<const char *>(&enable), sizeof(enable)); // errors ignored intentionally } #endif ServerInstance->SE->SetReuse(fd); int rv = ServerInstance->SE->Bind(this->fd, bind_to); if (rv >= 0) rv = ServerInstance->SE->Listen(this->fd, ServerInstance->Config->MaxConn); int timeout = tag->getInt("defer", 0); if (timeout && !rv) { #if defined TCP_DEFER_ACCEPT setsockopt(fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &timeout, sizeof(timeout)); #elif defined SO_ACCEPTFILTER struct accept_filter_arg afa; memset(&afa, 0, sizeof(afa)); strcpy(afa.af_name, "dataready"); setsockopt(fd, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa)); #endif } if (rv < 0) { int errstore = errno; ServerInstance->SE->Shutdown(this, 2); ServerInstance->SE->Close(this); this->fd = -1; errno = errstore; } else { ServerInstance->SE->NonBlocking(this->fd); ServerInstance->SE->AddFd(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE); } }