/// François-Régis Colin /// http://www.tls.cena.fr/products/ivy/ /// * /// (C) CENA /// * namespace IvyBus { using System; using System.Threading; using System.IO; using System.Net; using System.Net.Sockets; using System.Text.RegularExpressions; using System.Configuration; using System.Text; /// IvyWatcher, A private Class for the Ivy rendezvous /// /// right now, the rendez vous is either an UDP socket or a TCP multicast. /// The watcher will answer to /// each peer advertising its arrival on the bus. The intrinsics of Unix are so /// that the broadcast is done using the same socket, which is not a good /// thing. /// internal class IvyWatcher { private bool isMulticastAddress = false; private Ivy bus; /* master bus controler */ private Socket broadcast; /* supervision socket */// To do reuseaddr we must use a Socket not a udp client private String domainaddr; private int port; private volatile Thread listenThread; private IPAddress group; /// creates an Ivy watcher /// /// the bus /// /// the domain /// /// the port number /// internal IvyWatcher(Ivy bus, String domainaddr, int port) { this.bus = bus; this.domainaddr = domainaddr; this.port = port; listenThread = new Thread(new ThreadStart(this.Run)); // create the MulticastSocket try { group = Dns.GetHostByName(domainaddr).AddressList[0]; broadcast = new Socket(AddressFamily.InterNetwork, SocketType.Dgram,ProtocolType.Udp); IPEndPoint EPhost = new IPEndPoint(IPAddress.Any, port); broadcast.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast,1); broadcast.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress,1); broadcast.Bind(EPhost); //test isMulticastAddress // TODO better check if ((group.Address & 0xf0000000) == 0xe0000000) { isMulticastAddress = true; broadcast.SetSocketOption(SocketOptionLevel.Udp, SocketOptionName.AddMembership, new MulticastOption( group )); } } catch (IOException e) { throw new IvyException("IvyWatcher I/O error" + e); } } /// the behaviour of each thread watching the UDP socket. /// public void Run() { traceDebug("beginning of a watcher Thread"); byte[] buf = new byte[4096]; int len; IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, 0); EndPoint tempRemoteEP = (EndPoint)remoteEP; remoteEP = null; try { bool running = true; while (running) { int port; try { len = broadcast.ReceiveFrom(buf, ref tempRemoteEP); // I was summoned to leave during the receive String msg = Encoding.ASCII.GetString(buf); remoteEP = (IPEndPoint)tempRemoteEP; IPAddress remotehost = remoteEP.Address; traceDebug("BUSWATCHER Receive Broadcast from " + Dns.GetHostName() + ":" + remoteEP.Port); // TODO if ( !isInDomain( remotehost ) ) continue; String[] st = msg.Split(new char[]{' ','\n'},3); if (st.Length != 3) { Console.Error.WriteLine("Bad format " + msg); continue; } int version = Int32.Parse(st[0]); port = Int32.Parse(st[1]); if (version != Ivy.PROCOCOLVERSION) { Console.Error.WriteLine("Ignoring bad protocol version broadcast"); continue; } if ((bus.applicationPort == port)) continue; traceDebug("BUSWATCHER Broadcast de " + Dns.GetHostName() + ":" + remoteEP.Port + " port " + port + " version " + version); try { MyTcpClient socket = new MyTcpClient(remoteEP.Address.ToString(),port); bus.addClient(socket); } catch (Exception e) { Console.Error.WriteLine("can't connect to " + remotehost + " port " + port + " \n"+ e.Message); } } catch (IOException jii) { running = false; } } // while } catch (SocketException se) { traceDebug( "watcher socket closed" ); } catch (IOException ioe) { Console.Error.WriteLine( ioe.StackTrace ); } traceDebug("end of a watcher thread"); } /// stops the thread waiting on the broadcast socket /// internal virtual void stop() { lock(this) { traceDebug("begining stopping an IvyWatcher"); Thread t = listenThread; listenThread = null; broadcast.Close(); if (t != null) { t.Interrupt(); } // it might not even have been created traceDebug("ending stopping an IvyWatcher"); } } internal virtual void start() { lock(this) { String hello = Ivy.PROCOCOLVERSION + " " + bus.applicationPort + "\n"; listenThread.Start(); byte[] hellob = Encoding.ASCII.GetBytes( hello ); IPEndPoint EPhost = new IPEndPoint(group, port); broadcast.SendTo(hellob,0,EPhost); // notifies our arrival on each domain: protocol version + port } } internal static String getDomain(String net) { int sep_index = net.LastIndexOf(":"); if (sep_index != - 1) { net = net.Substring(0, (sep_index) - (0)); } try { net += ".255.255.255"; Regex exp = new Regex("^(\\d+\\.\\d+\\.\\d+\\.\\d+).*"); net = exp.Replace(net, "$1"); } catch (ArgumentException e) { Console.Out.WriteLine("Bad broascat addr " + net); return null; } // out.println("net: "+net); return net; } internal static int getPort(String net) { int sep_index = net.LastIndexOf(":"); int port = (sep_index == - 1)?Ivy.DEFAULT_PORT:Int32.Parse(net.Substring(sep_index + 1)); // out.println("net: ["+net+"]\nsep_index: "+sep_index+"\nport: "+port); return port; } private void traceDebug(String s) { if (bus.Debug) Console.Out.WriteLine("-->ivywatcher<-- " + s); } } // class IvyWatcher /* EOF */ }