package org.jgroups.protocols.dns; import org.jgroups.Address; import org.jgroups.Event; import org.jgroups.Message; import org.jgroups.PhysicalAddress; import org.jgroups.annotations.Property; import org.jgroups.protocols.Discovery; import org.jgroups.protocols.PingData; import org.jgroups.protocols.PingHeader; import org.jgroups.stack.IpAddress; import org.jgroups.util.BoundedList; import org.jgroups.util.NameCache; import org.jgroups.util.Responses; import org.jgroups.util.Tuple; import java.util.List; public class DNS_PING extends Discovery { private static final String DEFAULT_DNS_FACTORY = "com.sun.jndi.dns.DnsContextFactory"; private static final String DEFAULT_DNS_RECORD_TYPE = "A"; @Property(description = "DNS Context Factory") protected String dns_context_factory = DEFAULT_DNS_FACTORY; @Property(description = "DNS Address. This property will be assembed with the 'dns://' prefix") protected String dns_address; @Property(description = "DNS Record type") protected String dns_record_type = DEFAULT_DNS_RECORD_TYPE; @Property(description = "DNS query for fetching members") protected String dns_query; protected volatile DNSResolver dns_Resolver; protected BoundedList<Address> discovered_hosts = new BoundedList<>(); private int transportPort; @Override public void init() throws Exception { super.init(); validateProperties(); transportPort = getTransport().getBindPort(); if(transportPort <= 0) { log.warn("Unable to discover transport port. This may prevent members from being discovered."); } if(dns_Resolver == null) { dns_Resolver = new DefaultDNSResolver(dns_context_factory, dns_address); } } protected void validateProperties() { if(dns_query == null) { throw new IllegalArgumentException("dns_query can not be null or empty"); } if(dns_address == null) { throw new IllegalArgumentException("dns_query can not be null or empty"); } } @Override public boolean isDynamic() { return true; } @Override public Object down(Event evt) { Object retval = super.down(evt); switch (evt.getType()) { case Event.VIEW_CHANGE: for (Address logical_addr : view.getMembersRaw()) { PhysicalAddress physical_addr = (PhysicalAddress) down_prot.down(new Event(Event.GET_PHYSICAL_ADDRESS, logical_addr)); if (physical_addr != null) { discovered_hosts.addIfAbsent(physical_addr); } } break; case Event.SUSPECT: Address address = evt.getArg(); discovered_hosts.remove(address); break; case Event.ADD_PHYSICAL_ADDRESS: Tuple<Address, PhysicalAddress> tuple = evt.getArg(); PhysicalAddress physical_addr = tuple.getVal2(); if (physical_addr != null) discovered_hosts.addIfAbsent(physical_addr); break; } return retval; } public void discoveryRequestReceived(Address sender, String logical_name, PhysicalAddress physical_addr) { super.discoveryRequestReceived(sender, logical_name, physical_addr); log.debug("Received discovery from: %s, IP: %s", sender.toString(), physical_addr.printIpAddress()); if (physical_addr != null) discovered_hosts.addIfAbsent(sender); } @Override public void findMembers(List<Address> members, boolean initial_discovery, Responses responses) { PingData data = null; PhysicalAddress physical_addr = null; if (!use_ip_addrs || !initial_discovery) { log.debug("Performing initial discovery"); physical_addr = (PhysicalAddress) down(new Event(Event.GET_PHYSICAL_ADDRESS, local_addr)); // https://issues.jboss.org/browse/JGRP-1670 data = new PingData(local_addr, false, NameCache.get(local_addr), physical_addr); if (members != null && members.size() <= max_members_in_discovery_request) data.mbrs(members); } List<Address> dns_discovery_members = dns_Resolver.resolveIps(dns_query, DNSResolver.DNSRecordType.valueOf(dns_record_type)); log.debug("Entries collected from DNS: %s", dns_discovery_members); if(dns_discovery_members != null) { for(Address address : dns_discovery_members) { if (physical_addr != null && address.equals(physical_addr)) { // no need to send the request to myself continue; } Address addressToBeAdded = address; if(address instanceof IpAddress) { IpAddress ip = ((IpAddress) address); if(ip.getPort() == 0) { log.debug("Discovered IP Address with port 0 (%s). Replacing with default Transport port: %d", ip.printIpAddress(), transportPort); addressToBeAdded = new IpAddress(ip.getIpAddress(), transportPort); } } discovered_hosts.addIfAbsent(addressToBeAdded); } } log.debug("Performing discovery of the following hosts %s", discovered_hosts.toString()); PingHeader hdr = new PingHeader(PingHeader.GET_MBRS_REQ).clusterName(cluster_name).initialDiscovery(initial_discovery); for (final Address addr : discovered_hosts) { // the message needs to be DONT_BUNDLE, see explanation above final Message msg = new Message(addr).setFlag(Message.Flag.INTERNAL, Message.Flag.DONT_BUNDLE, Message.Flag.OOB) .putHeader(this.id, hdr); if (data != null) msg.setBuffer(marshal(data)); if (async_discovery_use_separate_thread_per_request) timer.execute(() -> sendDiscoveryRequest(msg), sends_can_block); else sendDiscoveryRequest(msg); } } protected void sendDiscoveryRequest(Message req) { try { log.debug("%s: sending discovery request to %s", local_addr, req.getDest()); down_prot.down(req); } catch (Throwable t) { log.debug("sending discovery request to %s failed: %s", req.dest(), t); } } }