package org.rzo.netty.mcast.discovery; import static org.jboss.netty.channel.Channels.pipeline; import java.net.InetAddress; import java.net.InetSocketAddress; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.handler.ipfilter.IpFilterRule; import org.jboss.netty.handler.ipfilter.IpFilterRuleList; import org.rzo.netty.ahessian.Constants; import org.rzo.netty.mcast.MulticastEndpoint; public class DiscoveryClient extends MulticastEndpoint { private String name; private Set<String> hosts = Collections.synchronizedSet(new HashSet<String>()); private volatile boolean stop = false; private Set<DiscoveryListener> listeners = Collections.synchronizedSet(new HashSet<DiscoveryListener>()); private static Executor executor = Executors.newCachedThreadPool(); private IpFilterRuleList firewall; public void init() throws Exception { ChannelPipelineFactory factory = new ChannelPipelineFactory() { public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = pipeline(); pipeline.addLast("discoveryClient", new SimpleChannelUpstreamHandler() { @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { try { String response = getStringMessage(e); if (response == null) return; String[] resp = response.split("&"); if (resp.length == 3) { String remoteName = resp[0]; if (!name.equals(remoteName)) return; if (!validate(e)) return; String host = resp[1]; // check the name. if not valid will cause an exception InetAddress.getByName(host); // get the port. if not a number will cause an exception int port = Integer.parseInt(resp[2]); if (!hosts.contains(response)) { hosts.add(response); for (DiscoveryListener listener : listeners) { listener.newHost(name, response); } } } } catch (Exception ex) { Constants.ahessianLogger.warn("", ex); } } }); return pipeline; } }; super.init(factory); } public void start() throws Exception { stop = false; discoverServices(); } private void discoverServices() throws Exception { executor.execute(new Runnable() { public void run() { while (!stop) { try { send(ChannelBuffers.wrappedBuffer((name).getBytes())); } catch (Exception e) { Constants.ahessianLogger.warn("", e); } try { Thread.sleep(1000); } catch (InterruptedException e) { Constants.ahessianLogger.warn("", e); } } } }); } public String getName() { return name; } public void setName(String name) { this.name = name; } public void stop() { stop = true; } public void addListener(DiscoveryListener listener) { listeners.add(listener); } public void removeHost(String host) { hosts.remove(host); } private boolean validate(MessageEvent e) { if (firewall == null) return true; else { InetAddress inetAddress = ((InetSocketAddress)e.getRemoteAddress()).getAddress(); Iterator<IpFilterRule> iterator = firewall.iterator(); IpFilterRule ipFilterRule = null; while (iterator.hasNext()) { ipFilterRule = iterator.next(); if (ipFilterRule.contains(inetAddress)) { // Match founds, is it a ALLOW or DENY rule return ipFilterRule.isAllowRule(); } } // No limitation founds and no allow either, but as it is like Firewall rules, it is therefore accepted return true; } } public void setIpSet(IpFilterRuleList ipSet) { this.firewall = ipSet; } }