void Discover::announceRecords () { // Reset timer timer->start(announcePeriodMsec); if (not running) return; // Servers don't announce periodically or send departure messages if (mServerMode) return; // Start building a list of records to send in each scope QList<Record> recordsToSend; /////////////////////////////////////////////////////////////////////// // Global scope first /////////////////////////////////////////////////////////////////////// for (Record record : ownedRecords) if (record["Scope"] == "Global") { recordsToSend.push_back(record); } if (not recordsToSend.empty() or defaultScope=="Global") { // This is a discovery request which should be responded to QByteArray datagram("DSDR"); if (departure) datagram = "DSDD"; datagram += makeDatagram(recordsToSend, false); // Send to each Global server for (QPair<QHostAddress,quint16> globalServer : globalServers) { globalSocket->writeDatagram(datagram, globalServer.first, globalServer.second); } } /////////////////////////////////////////////////////////////////////// // Local scope next /////////////////////////////////////////////////////////////////////// for (Record record : ownedRecords) if (record["Scope"] == "Local") { recordsToSend.push_back(record); } if (not recordsToSend.empty() or defaultScope=="Global" or defaultScope=="Local") { QByteArray datagram("DSDA"); if (announceNeedsResponse) datagram = "DSDR"; if (departure) datagram = "DSDD"; datagram += makeDatagram(recordsToSend, true); // For each interface for (auto iface : QNetworkInterface::allInterfaces()) { // For each IPv4 address on this interface for (auto entry : iface.addressEntries()) { if (entry.ip().protocol() != QAbstractSocket::IPv4Protocol) continue; // Add it to addressEntryCache if necessary for local scope testing if (not addressEntryCache.contains(entry)) addressEntryCache.push_back(entry); // Multicast if (iface.flags().testFlag(QNetworkInterface::CanMulticast) and !entry.ip().isNull() and !entry.ip().isLoopback()) { // Create the socket if it doesn't exit yet if (not multiSocket.contains(entry.ip().toString())) { logDebug(QString("New multicast socket: %1 %2").arg(entry.ip().toString(), entry.netmask().toString())); // Add it, create and bind the socket QUdpSocket* socket = new QUdpSocket(this); connect(socket, SIGNAL(readyRead()), this, SLOT(readDatagrams())); socket->setSocketOption(QAbstractSocket::MulticastTtlOption, 1); if (not socket->bind(QHostAddress::AnyIPv4, port, QAbstractSocket::ShareAddress | QAbstractSocket::ReuseAddressHint)) { logWarning(QString("Error binding to iface %1: %2").arg(entry.ip().toString(), socket->errorString())); } socket->setMulticastInterface(iface); socket->joinMulticastGroup(groupAddress, iface); multiSocket.insert(entry.ip().toString(), socket); } // Send datagram multiSocket[entry.ip().toString()]->writeDatagram(datagram, groupAddress, port); } } } } /////////////////////////////////////////////////////////////////////// // Loopback scope last /////////////////////////////////////////////////////////////////////// for (Record record : ownedRecords) if (record["Scope"] == "Loopback") { recordsToSend.push_back(record); } if (not recordsToSend.empty() or true) // Any scope is above or equivalent to loopback { QByteArray datagram("DSDA"); if (announceNeedsResponse) datagram = "DSDR"; if (departure) datagram = "DSDD"; datagram += makeDatagram(recordsToSend, true); // Loopback //loopbackSocket->writeDatagram(datagram, QHostAddress::LocalHost, port); } // Reset announceNeedsResponse = false; departure = false; }