int InspIRCd::BindPorts(FailedPortList& failed_ports) { int bound = 0; std::vector<ListenSocket*> old_ports(ports.begin(), ports.end()); ConfigTagList tags = ServerInstance->Config->ConfTags("bind"); for (ConfigIter i = tags.first; i != tags.second; ++i) { ConfigTag* tag = i->second; // Are we creating a TCP/IP listener? const std::string address = tag->getString("address"); const std::string portlist = tag->getString("port"); if (!address.empty() || !portlist.empty()) { // InspIRCd supports IPv4 and IPv6 natively; no 4in6 required. if (strncasecmp(address.c_str(), "::ffff:", 7) == 0) this->Logs.Log("SOCKET", LOG_DEFAULT, "Using 4in6 (::ffff:) isn't recommended. You should bind IPv4 addresses directly instead."); // A TCP listener with no ports is not very useful. if (portlist.empty()) this->Logs.Log("SOCKET", LOG_DEFAULT, "TCP listener on %s at %s has no ports specified!", address.empty() ? "*" : address.c_str(), tag->getTagLocation().c_str()); irc::portparser portrange(portlist, false); for (int port; (port = portrange.GetToken()); ) { irc::sockets::sockaddrs bindspec; if (!irc::sockets::aptosa(address, port, bindspec)) continue; if (!BindPort(tag, bindspec, old_ports)) failed_ports.push_back(std::make_pair(bindspec, errno)); else bound++; } continue; } #ifndef _WIN32 // Are we creating a UNIX listener? const std::string path = tag->getString("path"); if (!path.empty()) { // UNIX socket paths are length limited to less than PATH_MAX. irc::sockets::sockaddrs bindspec; if (path.length() > std::min(ServerInstance->Config->Limits.MaxHost, sizeof(bindspec.un.sun_path))) { this->Logs.Log("SOCKET", LOG_DEFAULT, "UNIX listener on %s at %s specified a path that is too long!", path.c_str(), tag->getTagLocation().c_str()); continue; } // Create the bindspec manually (aptosa doesn't work with AF_UNIX yet). memset(&bindspec, 0, sizeof(bindspec)); bindspec.un.sun_family = AF_UNIX; memcpy(&bindspec.un.sun_path, path.c_str(), sizeof(bindspec.un.sun_path)); if (!BindPort(tag, bindspec, old_ports)) failed_ports.push_back(std::make_pair(bindspec, errno)); else bound++; } #endif } std::vector<ListenSocket*>::iterator n = ports.begin(); for (std::vector<ListenSocket*>::iterator o = old_ports.begin(); o != old_ports.end(); ++o) { while (n != ports.end() && *n != *o) n++; if (n == ports.end()) { this->Logs.Log("SOCKET", LOG_DEFAULT, "Port bindings slipped out of vector, aborting close!"); break; } this->Logs.Log("SOCKET", LOG_DEFAULT, "Port binding %s was removed from the config file, closing.", (**n).bind_sa.str().c_str()); delete *n; // this keeps the iterator valid, pointing to the next element n = ports.erase(n); } return bound; }
int InspIRCd::BindPorts(FailedPortList &failed_ports) { int bound = 0; std::vector<ListenSocket*> old_ports(ports.begin(), ports.end()); ConfigTagList tags = ServerInstance->Config->ConfTags("bind"); for(ConfigIter i = tags.first; i != tags.second; ++i) { ConfigTag* tag = i->second; std::string porttag = tag->getString("port"); std::string Addr = tag->getString("address"); if (strncasecmp(Addr.c_str(), "::ffff:", 7) == 0) this->Logs->Log("SOCKET", LOG_DEFAULT, "Using 4in6 (::ffff:) isn't recommended. You should bind IPv4 addresses directly instead."); irc::portparser portrange(porttag, false); int portno = -1; while (0 != (portno = portrange.GetToken())) { irc::sockets::sockaddrs bindspec; if (!irc::sockets::aptosa(Addr, portno, bindspec)) continue; std::string bind_readable = bindspec.str(); bool skip = false; for (std::vector<ListenSocket*>::iterator n = old_ports.begin(); n != old_ports.end(); ++n) { if ((**n).bind_desc == bind_readable) { (*n)->bind_tag = tag; // Replace tag, we know addr and port match, but other info (type, ssl) may not (*n)->ResetIOHookProvider(); skip = true; old_ports.erase(n); break; } } if (!skip) { ListenSocket* ll = new ListenSocket(tag, bindspec); if (ll->GetFd() > -1) { bound++; ports.push_back(ll); } else { failed_ports.push_back(std::make_pair(bind_readable, strerror(errno))); delete ll; } } } } std::vector<ListenSocket*>::iterator n = ports.begin(); for (std::vector<ListenSocket*>::iterator o = old_ports.begin(); o != old_ports.end(); ++o) { while (n != ports.end() && *n != *o) n++; if (n == ports.end()) { this->Logs->Log("SOCKET", LOG_DEFAULT, "Port bindings slipped out of vector, aborting close!"); break; } this->Logs->Log("SOCKET", LOG_DEFAULT, "Port binding %s was removed from the config file, closing.", (**n).bind_desc.c_str()); delete *n; // this keeps the iterator valid, pointing to the next element n = ports.erase(n); } return bound; }