public void route(Packet packet) {
        Set<String> remoteServers = new HashSet<>();
        List<String> targets = new ArrayList<>();
        Packet localBroadcast = packet.createCopy();
        Element addresses = getAddresses(localBroadcast);
        String localDomain = "@" + server.getServerInfo().getXMPPDomain();
        // Build the <addresses> element to be included for local users and identify
        // remote domains that should receive the packet too
        for (Iterator<Element> it=addresses.elementIterator("address");it.hasNext();) {
            Element address = it.next();
            // Skip addresses of type noreply since they don't have any address
            if (Type.noreply.toString().equals(address.attributeValue("type"))) {
                continue;
            }
            String jid = address.attributeValue("jid");
            // Only send to local users and if packet has not already been delivered
            if (jid.contains(localDomain) && address.attributeValue("delivered") == null) {
                targets.add(jid);
            }
            else if (!jid.contains(localDomain)) {
                remoteServers.add(new JID(jid).getDomain());
            }
            // Set as delivered
            address.addAttribute("delivered", "true");
            // Remove bcc addresses
            if (Type.bcc.toString().equals(address.attributeValue("type"))) {
                it.remove();
            }
        }
        // Send the packet to local target users
        for (String jid : targets) {
            localBroadcast.setTo(jid);
            packetRouter.route(localBroadcast);
        }

        // Keep a registry of packets that should be sent to remote domains.
        for (String domain : remoteServers) {
            boolean shouldDiscover = false;
            synchronized (domainMutex.intern(new JID(null, domain, null))) {
                Collection<Packet> packets = remotePackets.get(domain);
                if (packets == null) {
                    packets = new ArrayList<>();
                    remotePackets.put(domain, packets);
                    shouldDiscover = true;
                }
                // Add that this packet should be sent to the requested remote server
                packets.add(packet);
            }
            if (shouldDiscover) {
                // First time a packet is sent to this remote server so start the extra work
                // of discovering if remote server supports multicast service and actually send
                // the packet to the remote server
                sendToRemoteEntity(domain);
            }
        }
        // TODO Add thread that checks every 5 minutes if packets to remote servers were not
        // TODO sent because no disco response was received. So assume that remote server does
        // TODO not support JEP-33 and send pending packets
    }
Keeps an association of node and server where the node was discovered. This information
is used when discovering whether remote servers support multicast service or not.
Note: key=node, value=domain of remote server
xmppserver/src/main/java/org/jivesoftware/openfire/MulticastRouter.java