From 5e310bef48ed719d15d88aafb9b92e674cb42b96 Mon Sep 17 00:00:00 2001 From: fcolin Date: Mon, 18 Oct 2010 15:42:04 +0000 Subject: utilisation de socket IPV6 si le domain contient un multicast IPV6 genre FF02::1 --- Ivy/Ivy.cs | 2568 +++++++++++++++--------------- Ivy/IvyApplicationBinding.cs | 4 +- Ivy/IvyClient.cs | 767 ++++----- Ivy/IvyUDPStream.cs | 2 +- Ivy/IvyWatcher.cs | 261 +-- Ivy/app.config | 38 +- IvyControl/IvyControl.cs | 13 +- IvyControl/IvyDomain.Designer.cs | 17 +- IvyControl/IvyDomain.cs | 2 + IvyControl/IvyDomain.resx | 3 + IvyDaemon/IvyDaemon.cs | 6 +- IvyProbe/IvyProbe.Designer.cs | 16 +- IvyProbe/IvyProbe.cs | 11 +- IvyProbe/Properties/Settings.Designer.cs | 2 +- IvyProbe/Properties/Settings.settings | 2 +- IvyProbe/app.config | 2 +- 16 files changed, 1905 insertions(+), 1809 deletions(-) diff --git a/Ivy/Ivy.cs b/Ivy/Ivy.cs index 922bb27..9b0674f 100644 --- a/Ivy/Ivy.cs +++ b/Ivy/Ivy.cs @@ -7,1333 +7,1393 @@ [assembly: System.CLSCompliant(true)] namespace IvyBus { - using System; - using System.IO; - using System.Collections; - using System.Collections.Specialized; - using System.Collections.Generic; - using System.Net; - using System.Net.Sockets; - using System.Threading; - using System.Configuration; - using System.Globalization; - using System.Text.RegularExpressions; - using System.Text; - using System.Reflection; - using System.Diagnostics; - using System.Collections.ObjectModel; - using IvyBus.Properties; - - /// The Main bus Class - /// - /// - public class Ivy - { - /* Event */ - /// - /// raise when an new IvyClient is connected - /// - public event EventHandler ClientConnected; - /// - /// raise when an new IvyClient is disconnected - /// - public event EventHandler ClientDisconnected; - /// - /// raise when a direct message is received - /// - public event EventHandler DirectMessageReceived; - /// - /// raise when some IvyClient ask me to die - /// - public event EventHandler DieReceived; - /// - /// raise when an IvyClient register a binding - /// - public event EventHandler BindingAdd; - /// - /// raise when an IvyClient unregister a binding - /// - public event EventHandler BindingRemove; - /// - /// raise when an IvyClient binding is filteredout - /// - public event EventHandler BindingFilter; - /// - /// raise when an IvyClient changer a binding - /// - public event EventHandler BindingChange; - /// - /// raise when an error message is received - /// - public event EventHandler ErrorMessage; - - /// - /// Flag for displaying internal debug message of the protocol intrinsics - /// - public static bool DebugProtocol - { - get - { - return debugProtocol; - } - set - { - debugProtocol = value; - } - - } - /// - /// Language for the Ivy SendMsg formating default en-US - /// ie: send point on float value sent - /// - public CultureInfo Culture - { - get - { - return culture; - } - set - { - culture = value; - } + using System; + using System.IO; + using System.Collections; + using System.Collections.Specialized; + using System.Collections.Generic; + using System.Net; + using System.Net.Sockets; + using System.Threading; + using System.Configuration; + using System.Globalization; + using System.Text.RegularExpressions; + using System.Text; + using System.Reflection; + using System.Diagnostics; + using System.Collections.ObjectModel; + using IvyBus.Properties; + + /// The Main bus Class + /// + /// + public class Ivy + { + /* Event */ + /// + /// raise when an new IvyClient is connected + /// + public event EventHandler ClientConnected; + /// + /// raise when an new IvyClient is disconnected + /// + public event EventHandler ClientDisconnected; + /// + /// raise when a direct message is received + /// + public event EventHandler DirectMessageReceived; + /// + /// raise when some IvyClient ask me to die + /// + public event EventHandler DieReceived; + /// + /// raise when an IvyClient register a binding + /// + public event EventHandler BindingAdd; + /// + /// raise when an IvyClient unregister a binding + /// + public event EventHandler BindingRemove; + /// + /// raise when an IvyClient binding is filteredout + /// + public event EventHandler BindingFilter; + /// + /// raise when an IvyClient changer a binding + /// + public event EventHandler BindingChange; + /// + /// raise when an error message is received + /// + public event EventHandler ErrorMessage; + + /// + /// Flag for displaying internal debug message of the protocol intrinsics + /// + public static bool DebugProtocol + { + get + { + return debugProtocol; + } + set + { + debugProtocol = value; + } - } + } + /// + /// Language for the Ivy SendMsg formating default en-US + /// ie: send point on float value sent + /// + public CultureInfo Culture + { + get + { + return culture; + } + set + { + culture = value; + } - /// IvyClients accesses the list of the connected clients + } - public ReadOnlyCollection IvyClients - { - get - { - return new ReadOnlyCollection(clients); - } + /// IvyClients accesses the list of the connected clients - } - - /// AppName the application name + public ReadOnlyCollection IvyClients + { + get + { + return new ReadOnlyCollection(clients); + } - public string AppName - { - set - { - appName = value; - } - get - { - return appName; - } + } + + /// AppName the application name - } - /// - /// AppId the Application Unique ID - /// + public string AppName + { + set + { + appName = value; + } + get + { + return appName; + } - public string AppId - { - get - { - return applicationUniqueId; - } + } + /// + /// AppId the Application Unique ID + /// - } - - /// - /// the Ivy Protocol version - /// - public int ProtocolVersion - { - get - { - return protocolVersion; - } + public string AppId + { + get + { + return applicationUniqueId; + } - } + } + + /// + /// the Ivy Protocol version + /// + public int ProtocolVersion + { + get + { + return protocolVersion; + } - /// - /// IsRunning is the bus Started and connected ? - /// - public bool IsRunning - { - get - { - return !stopped; - } + } + /// + /// IsSynchronous is the bus Synchronous of the main thread ( ie callback running in the main thread) ? + /// + private bool synchronous = true; + public bool Synchronous + { + set + { + synchronous = value && syncContext != null; + } + get + { + return synchronous; + } - } - ///SentMessageClasses the first word token of sent messages - /// optimise the parsing process when sending messages - /// + } - public Collection SentMessageFilter - { - get - { - return sent_messageFilter; - } - } - /// ReadyMessage message send when Application receive all the regexp at the connection of the client + /// + /// IsRunning is the bus Started and connected ? + /// + public bool IsRunning + { + get + { + return !stopped; + } - public string ReadyMessage - { - get { return ready_message; } - set { ready_message = value; } - } + } + ///SentMessageClasses the first word token of sent messages + /// optimise the parsing process when sending messages + /// - internal class MyTcpListener : TcpListener - { - public MyTcpListener(IPAddress address, int port) - : base(address, port) - { - } - public bool IsActive() - { - return this.Active; - } - } - /// the name of the application on the bus - internal string appName; - /// the port for the UDP rendez vous, if none is supplied - internal const ushort DefaultPort = 2010; - /// the domain for the UDP rendez vous - private static readonly string DefaultDomain = "127.0.0.1:" + DefaultPort; - internal int protocolVersion = 3; - private static bool debugProtocol; // false by default runtime - private static int serial = -1; /* an unique ID for each regexp */ // -1 to start numbering at 0 - private MyTcpListener app; - private List watchers; - private Thread serverThread; // to ensure quick communication of the end - private AutoResetEvent tcplistener_running; - - /// - /// the Ivy Assembly version - /// - static public Version Version - { - get { return Assembly.GetExecutingAssembly().GetName().Version; } - } - // Class representing Ivy Binding receive from client - internal class IvyClientBinding - { - internal IvyBindingBase binding; - internal Dictionary> client_bindind_ids; - } - // The Application bindings - internal Dictionary bindings; - // the clients bindings - private Dictionary client_bindings; - private List clients; - private Collection sent_messageFilter; - private bool stopped = true; - internal int applicationPort; /* Application port number */ - internal IPAddress applicationHost; /* Application host number */ - internal string applicationUniqueId; /* identifier Application unique timestamp-ipaddress-port */ - private string ready_message; - private CultureInfo culture = new CultureInfo("en-us"); - internal static Encoding ivyEncoding = Encoding.GetEncoding("iso-8859-15"); // ASCII 8 bits iso-8859-2 + public Collection SentMessageFilter + { + get + { + return sent_messageFilter; + } + } + /// ReadyMessage message send when Application receive all the regexp at the connection of the client + + public string ReadyMessage + { + get { return ready_message; } + set { ready_message = value; } + } + + internal class MyTcpListener : TcpListener + { + public MyTcpListener(IPAddress address, int port) + : base(address, port) + { + } + public bool IsActive() + { + return this.Active; + } + } + /// the name of the application on the bus + internal string appName; + /// the port for the UDP rendez vous, if none is supplied + internal const ushort DefaultPort = 2010; + /// the domain for the UDP rendez vous + private static readonly string DefaultDomain = "127.0.0.1:" + DefaultPort; + internal int protocolVersion = 3; + private static bool debugProtocol; // false by default runtime + private static int serial = -1; /* an unique ID for each regexp */ // -1 to start numbering at 0 + private MyTcpListener app; + private List watchers; + private Thread serverThread; // to ensure quick communication of the end + private AutoResetEvent tcplistener_running; + private bool ipv6; + + /// + /// the Ivy IP version to use + /// + public bool IpV6 + { + get { return ipv6; } + } + + /// + /// the Ivy Assembly version + /// + static public Version Version + { + get { return Assembly.GetExecutingAssembly().GetName().Version; } + } + // Class representing Ivy Binding receive from client + internal class IvyClientBinding + { + internal IvyBindingBase binding; + internal Dictionary> client_bindind_ids; + } + // The Application bindings + internal Dictionary bindings; + // the clients bindings + private Dictionary client_bindings; + private List clients; + private Collection sent_messageFilter; + private bool stopped = true; + internal int applicationPort; /* Application port number */ + internal IPAddress applicationHost; /* Application host number */ + internal string applicationUniqueId; /* identifier Application unique timestamp-ipaddress-port */ + private string ready_message; + private CultureInfo culture = new CultureInfo("en-us"); + internal static Encoding ivyEncoding = Encoding.GetEncoding("iso-8859-15"); // ASCII 8 bits iso-8859-2 - // for synchronous event + // for synchronous event #if (PocketPC) - private System.Windows.Forms.ContainerControl parentControl; + private System.Windows.Forms.ContainerControl parentControl; #else - private readonly SynchronizationContext syncContext; + private readonly SynchronizationContext syncContext; #endif - /// - /// Initializes a new instance of the Ivy Bus. - /// Readies the structures for the software bus connexion. - /// - public Ivy() - { - clients = new List(); - bindings = new Dictionary(); - client_bindings = new Dictionary(); - sent_messageFilter = new Collection(); + /// + /// Initializes a new instance of the Ivy Bus. + /// Readies the structures for the software bus connexion. + /// + public Ivy() + { + this.ipv6 = false; + clients = new List(); + bindings = new Dictionary(); + client_bindings = new Dictionary(); + sent_messageFilter = new Collection(); #if (!PocketPC) - syncContext = SynchronizationContext.Current; - debugProtocol = Properties.Settings.Default.IvyDebug; - protocolVersion = Properties.Settings.Default.IvyProtocolVersion; + syncContext = SynchronizationContext.Current; + debugProtocol = Properties.Settings.Default.IvyDebug; + protocolVersion = Properties.Settings.Default.IvyProtocolVersion; #endif - // get binding from Attribute IvyBinding - //TODO Autobinding attribute + // get binding from Attribute IvyBinding + //TODO Autobinding attribute #if (PocketPC) - if (parentControl != null) - BindAttibute(parentControl); + if (parentControl != null) + BindAttibute(parentControl); #endif - Assembly assembly = Assembly.GetCallingAssembly(); - if ( assembly != this.GetType().Assembly ) - BindAttribute(assembly); - } - - /// - /// Readies the structures for the software bus connexion. - /// - /// This sample shows how to start working with Ivy. - /// - /// Ivy bus = new Ivy("Dummy agent","ready"); - /// bus.bindMsg("(.*)",myMessageListener); - /// bus.start(null); - /// - /// How to send & receive: - /// the Ivy agent A performs b.bindMsg("^Hello (*)",cb); - /// the Ivy agent B performs b2.sendMsg("Hello world"); - /// a thread in A will run the callback cb with its second argument set - /// to a array of string, with one single element, "world" - /// - /// - /// the real work begin in the start() method - /// - /// - /// The name of your Ivy agent on the software bus - /// - /// The hellow message you will send once ready - /// - public Ivy(string name, string readyMessage) - : this() - { - appName = name; - this.ready_message = readyMessage; - // get binding from Attribute IvyBinding - //TODO Autobinding attribute - Assembly assembly = Assembly.GetCallingAssembly(); - if (assembly != this.GetType().Assembly) - BindAttribute(assembly); - } - - internal void AddBinding(int id, IvyClient clnt, IvyBindingBase bindexp) - { - bool change = false; - IvyClientBinding clientbind; - lock (client_bindings) - { - if (client_bindings.ContainsKey(bindexp.Expression)) - { - // check if id exits to remove it - - clientbind = client_bindings[bindexp.Expression]; - - foreach (IvyClientBinding clbind in client_bindings.Values) - { - lock (clbind.client_bindind_ids) - { - if (clbind.client_bindind_ids.ContainsKey(clnt)) - { - if (clbind.client_bindind_ids[clnt].Contains(id)) - { - // remove from old - clbind.client_bindind_ids[clnt].Remove(id); - // add to new later - change = true; //mark to call right handler - break; - } - } - } - - } - - } - else - { - clientbind = new IvyClientBinding(); - clientbind.binding = bindexp; - clientbind.client_bindind_ids = new Dictionary>(); - clientbind.client_bindind_ids[clnt] = new List(); - client_bindings[bindexp.Expression] = clientbind; - - } - } - - lock (clientbind.client_bindind_ids) - { - if (!clientbind.client_bindind_ids.ContainsKey(clnt)) - { - clientbind.client_bindind_ids[clnt] = new List(); - } - clientbind.client_bindind_ids[clnt].Add(id); - } - if (change) - { - OnClientChangeBinding(new IvyEventArgs(clnt, id, bindexp.Expression)); - } - else - { - OnClientAddBinding(new IvyEventArgs(clnt, id, bindexp.Expression)); - } - } - internal void DelBinding(int id, IvyClient clnt) - { - IvyClientBinding clientbind = null; - lock (client_bindings) - { - foreach (IvyClientBinding clbind in client_bindings.Values) - { - lock (clbind.client_bindind_ids) - { - if (clbind.client_bindind_ids.ContainsKey(clnt)) - { - clbind.client_bindind_ids[clnt].Remove(id); - clientbind = clbind; - break; - } - } - } - if (clientbind != null) - { - lock (clientbind.client_bindind_ids) - { - if (clientbind.client_bindind_ids.Count == 0) - { - client_bindings.Remove(clientbind.binding.Expression); - } - } - } - } - if (clientbind != null ) - OnClientRemoveBinding(new IvyEventArgs(clnt, id, clientbind.binding.Expression)); - - } - /// - /// Automatic binding on static method of a Type - /// - /// - public void BindAttribute(Type type) - { - if (type == null) return; - //Get instance of the IvyBindingAttribute. - foreach (MethodInfo m in type.GetMethods(BindingFlags.Static | BindingFlags.NonPublic)) - { - foreach (IvyBindingAttribute attr in Attribute.GetCustomAttributes(m, typeof(IvyBindingAttribute))) - { - //TODO check paramater type MessageHandler - Debug.WriteLine("IvyBinding '" + attr.GetFormattedExpression(null) + "' to Method " + m.Name); - EventHandler handler; + Assembly assembly = Assembly.GetCallingAssembly(); + if ( assembly != this.GetType().Assembly ) + BindAttribute(assembly); + } + + /// + /// Readies the structures for the software bus connexion. + /// + /// This sample shows how to start working with Ivy. + /// + /// Ivy bus = new Ivy("Dummy agent","ready"); + /// bus.bindMsg("(.*)",myMessageListener); + /// bus.start(null); + /// + /// How to send & receive: + /// the Ivy agent A performs b.bindMsg("^Hello (*)",cb); + /// the Ivy agent B performs b2.sendMsg("Hello world"); + /// a thread in A will run the callback cb with its second argument set + /// to a array of string, with one single element, "world" + /// + /// + /// the real work begin in the start() method + /// + /// + /// The name of your Ivy agent on the software bus + /// + /// The hellow message you will send once ready + /// + public Ivy(string name, string readyMessage) + : this() + { + appName = name; + this.ready_message = readyMessage; + + // get binding from Attribute IvyBinding + //TODO Autobinding attribute + Assembly assembly = Assembly.GetCallingAssembly(); + if (assembly != this.GetType().Assembly) + BindAttribute(assembly); + } + + + internal void AddBinding(int id, IvyClient clnt, IvyBindingBase bindexp) + { + bool change = false; + IvyClientBinding clientbind; + lock (client_bindings) + { + if (client_bindings.ContainsKey(bindexp.Expression)) + { + // check if id exits to remove it + + clientbind = client_bindings[bindexp.Expression]; + + foreach (IvyClientBinding clbind in client_bindings.Values) + { + lock (clbind.client_bindind_ids) + { + if (clbind.client_bindind_ids.ContainsKey(clnt)) + { + if (clbind.client_bindind_ids[clnt].Contains(id)) + { + // remove from old + clbind.client_bindind_ids[clnt].Remove(id); + // add to new later + change = true; //mark to call right handler + break; + } + } + } + + } + + } + else + { + clientbind = new IvyClientBinding(); + clientbind.binding = bindexp; + clientbind.client_bindind_ids = new Dictionary>(); + clientbind.client_bindind_ids[clnt] = new List(); + client_bindings[bindexp.Expression] = clientbind; + + } + } + + lock (clientbind.client_bindind_ids) + { + if (!clientbind.client_bindind_ids.ContainsKey(clnt)) + { + clientbind.client_bindind_ids[clnt] = new List(); + } + clientbind.client_bindind_ids[clnt].Add(id); + } + if (change) + { + OnClientChangeBinding(new IvyEventArgs(clnt, id, bindexp.Expression)); + } + else + { + OnClientAddBinding(new IvyEventArgs(clnt, id, bindexp.Expression)); + } + } + internal void DelBinding(int id, IvyClient clnt) + { + IvyClientBinding clientbind = null; + lock (client_bindings) + { + foreach (IvyClientBinding clbind in client_bindings.Values) + { + lock (clbind.client_bindind_ids) + { + if (clbind.client_bindind_ids.ContainsKey(clnt)) + { + clbind.client_bindind_ids[clnt].Remove(id); + clientbind = clbind; + break; + } + } + } + if (clientbind != null) + { + lock (clientbind.client_bindind_ids) + { + if (clientbind.client_bindind_ids.Count == 0) + { + client_bindings.Remove(clientbind.binding.Expression); + } + } + } + } + if (clientbind != null ) + OnClientRemoveBinding(new IvyEventArgs(clnt, id, clientbind.binding.Expression)); + + } + /// + /// Automatic binding on static method of a Type + /// + /// + public void BindAttribute(Type type) + { + if (type == null) return; + //Get instance of the IvyBindingAttribute. + foreach (MethodInfo m in type.GetMethods(BindingFlags.Static | BindingFlags.NonPublic)) + { + foreach (IvyBindingAttribute attr in Attribute.GetCustomAttributes(m, typeof(IvyBindingAttribute))) + { + //TODO check paramater type MessageHandler + Debug.WriteLine("IvyBinding '" + attr.GetFormattedExpression(null) + "' to Method " + m.Name); + EventHandler handler; #if (PocketPC) - //Createdelegate mydlg = new Createdelegate(m, null, EventArgs.Empty); - //bindMsg(attr.GetExpression(null), mydlg); - handler = null; + //Createdelegate mydlg = new Createdelegate(m, null, EventArgs.Empty); + //bindMsg(attr.GetExpression(null), mydlg); + handler = null; #else - handler = (EventHandler)Delegate.CreateDelegate(typeof(EventHandler), m); + handler = (EventHandler)Delegate.CreateDelegate(typeof(EventHandler), m); #endif - BindMsg(attr.GetFormattedExpression(null), handler); - } - } - } - - - /// - /// Autobinding on instance method - /// - /// - public void BindAttribute(object target) - { - if (target == null) return; - Type type = target.GetType(); - //Get instance of the IvyBindingAttribute. - foreach (MethodInfo m in type.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic)) - { - foreach (IvyBindingAttribute attr in Attribute.GetCustomAttributes(m, typeof(IvyBindingAttribute))) - { - //TODO check paramater type MessageHandler - Ivy.traceProtocol(Resources.Ivy, "BindAttibute " + attr.GetFormattedExpression(target) + "' to Method " + m.Name); - EventHandler handler; + BindMsg(attr.GetFormattedExpression(null), handler); + } + } + } + + + /// + /// Autobinding on instance method + /// + /// + public void BindAttribute(object target) + { + if (target == null) return; + Type type = target.GetType(); + //Get instance of the IvyBindingAttribute. + foreach (MethodInfo m in type.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic)) + { + foreach (IvyBindingAttribute attr in Attribute.GetCustomAttributes(m, typeof(IvyBindingAttribute))) + { + //TODO check paramater type MessageHandler + Ivy.traceProtocol(Resources.Ivy, "BindAttibute " + attr.GetFormattedExpression(target) + "' to Method " + m.Name); + EventHandler handler; #if (PocketPC) - handler = null; // TODO + handler = null; // TODO #else - handler = (EventHandler)Delegate.CreateDelegate(typeof(EventHandler), target, m); + handler = (EventHandler)Delegate.CreateDelegate(typeof(EventHandler), target, m); #endif - BindMsg(attr.GetFormattedExpression(target), handler); - } - } + BindMsg(attr.GetFormattedExpression(target), handler); + } + } - } - // Autobinding on IvyBindingAttribute method - /// - /// Automatic binding of IvyBindAttribute in an assembly - /// - /// - public void BindAttribute(Assembly target) - { - if (target != null) - { - foreach (Type typ in target.GetTypes()) - { - BindAttribute(typ); - } - } - } - /// - /// connects the Ivy bus to a domain or list of domains. - /// - /// a domain of the form 10.0.0:1234, it is similar to the - /// netmask without the trailing .255. This will determine the meeting point - /// of the different applications. Right now, this is done with an UDP - /// broadcast. Beware of routing problems ! You can also use a comma - /// separated list of domains. - /// - /// One thread (IvyWatcher) for each traffic rendezvous (either UDP broadcast or TCP Multicast). - /// One thread (serverThread/Ivy) to accept incoming connexions on server socket. - /// a thread for each IvyClient when the connexion has been done. - /// - public void Start(string domainBus) - { - domainBus = GetDomain(domainBus); - try - { - long seed = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; - Random rand = new Random( (int)seed ); - - app = new MyTcpListener(IPAddress.Any, 0); - app.Start(); // should be started before getting port - applicationHost = LocalIP; - applicationPort = ((IPEndPoint)app.LocalEndpoint).Port; - applicationUniqueId = string.Format(culture,"{0}:{1}:{2}", - rand.Next(), - seed, - //applicationHost.ToString().Replace(".", ""), - applicationPort); + } + // Autobinding on IvyBindingAttribute method + /// + /// Automatic binding of IvyBindAttribute in an assembly + /// + /// + public void BindAttribute(Assembly target) + { + if (target != null) + { + foreach (Type typ in target.GetTypes()) + { + BindAttribute(typ); + } + } + } + /// + /// connects the Ivy bus to a domain or list of domains. + /// + /// a domain of the form 10.0.0:1234, it is similar to the + /// netmask without the trailing .255. This will determine the meeting point + /// of the different applications. Right now, this is done with an UDP + /// broadcast. Beware of routing problems ! You can also use a comma + /// separated list of domains. + /// + /// One thread (IvyWatcher) for each traffic rendezvous (either UDP broadcast or TCP Multicast). + /// One thread (serverThread/Ivy) to accept incoming connexions on server socket. + /// a thread for each IvyClient when the connexion has been done. + /// + public void Start(string domainBus) + { + domainBus = GetDomain(domainBus); + // check for IPV6 mode + Domain[] d = parseDomains(domainBus); + IPAddress group = IPAddress.Parse(d[0].Domainaddr); + ipv6 = group.IsIPv6Multicast; + + try + { + long seed = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; + Random rand = new Random( (int)seed ); + + app = new MyTcpListener(ipv6 ? IPAddress.IPv6Any :IPAddress.Any, 0); + app.Start(); // should be started before getting port + applicationHost = LocalIP; + applicationPort = ((IPEndPoint)app.LocalEndpoint).Port; + applicationUniqueId = string.Format(culture,"{0}:{1}:{2}", + rand.Next(), + seed, + //applicationHost.ToString().Replace(".", ""), + applicationPort); - } - catch (IOException e) - { - throw new IvyException("can't open TCP service socket " + e); - } - Ivy.traceProtocol("BindAttibute", "Ivy protocol: " + ProtocolVersion + " TCP service open on port " + applicationPort); - watchers = new List(); + } + catch (IOException e) + { + throw new IvyException("can't open TCP service socket " + e); + } + Ivy.traceProtocol("BindAttibute", "Ivy protocol: " + ProtocolVersion + " TCP service open on port " + applicationPort); + watchers = new List(); - Domain[] d = parseDomains(domainBus); - // readies the rendezvous : an IvyWatcher (thread) per domain bus - for (int index = 0; index < d.Length; index++) - { - IvyWatcher watcher = new IvyWatcher(this, d[index].Domainaddr, d[index].Port); - watchers.Add(watcher); - } - serverThread = new Thread(new ThreadStart(this.TcpListener)); - serverThread.Name = "Ivy Tcp Server Thread"; - stopped = false; - tcplistener_running = new AutoResetEvent(false); - serverThread.Start(); + // readies the rendezvous : an IvyWatcher (thread) per domain bus + for (int index = 0; index < d.Length; index++) + { + IvyWatcher watcher = new IvyWatcher(this, d[index].Domainaddr, d[index].Port, ipv6 ); + watchers.Add(watcher); + } + serverThread = new Thread(new ThreadStart(this.TcpListener)); + serverThread.Name = "Ivy Tcp Server Thread"; + stopped = false; + tcplistener_running = new AutoResetEvent(false); + serverThread.Start(); // Wait for readyness - tcplistener_running.WaitOne(); + tcplistener_running.WaitOne(); - // sends the broadcasts and listen to incoming connexions - for (int i = 0; i < watchers.Count; i++) - { - watchers[i].start(); - } - } - internal void SortClients() - { - lock (clients) - { - //clients.Sort(new IvyClient.IvyClientPriority()); - clients.Sort(); - } - } - - - internal static Domain[] parseDomains(string domainbus) - { - string[] st = domainbus.Split(','); - Domain[] d = new Domain[st.Length]; - for (int i = 0; i < st.Length; i++) - { - d[i] = new Domain(st[i]); - } - return d; - } - - /// - /// disconnects from the Ivy bus - /// - public void Stop() - { - if (stopped) - return; - lock (app) - { - stopped = true; - Ivy.traceProtocol(Resources.Ivy, "beginning stopping the bus"); - try - { - // stopping the serverThread - if (serverThread != null) - { - app.Stop(); - // Wait for Thread to end. - bool term = serverThread.Join(10000); - if (!term && (serverThread != null)) serverThread.Abort(); - serverThread = null; - } - // The serverThread might be stopped even before having been created - if (app != null) - app.Stop(); - // stopping the IvyWatchers - if (watchers != null) - for (int i = 0; i < watchers.Count; i++) - { - ((IvyWatcher)watchers[i]).stop(); - } - // stopping the remaining IvyClients - // copy the values in temporary variable to eliminate Thread modifying collection - if (clients.Count != 0) - { - IvyClient[] copyClient; - lock (clients) - { - copyClient = new IvyClient[clients.Count]; - clients.CopyTo(copyClient); - } - foreach (IvyClient client in copyClient) - { - client.close(true); // will notify the reading thread - //removeClient(client); already donne in the thread - } - } - } - catch (IOException e) - { - Ivy.traceError(Resources.Ivy, "IOexception Stop " + e.Message); - } - Ivy.traceProtocol(Resources.Ivy, "the bus should have stopped so far"); - } - } - /// - /// join the main thread of Ivy ( ie wait until stopped ) - /// - /// - /// Performs a join on the Principal Thread. - /// - /// Number of millisecondes to wait before the Thread Stop. - /// - /// true if the thread stopped; false if it did not stop after the expiry of the period specified by the parameter millisecondsTimeout - /// - public bool Join(int millisecondsTimeout) - { - return serverThread.Join(millisecondsTimeout); - } - /// - /// Block the calling Thread until Ivy Stop - /// - /// - /// Performs a join on the Principal Thread. - /// - public void MainLoop() - { - this.Join(Timeout.Infinite); - } - - /// - /// Send a formated message to someone on the bus - /// - /// - /// Performs a pattern matching according to everyone's regexps, and sends - /// the results to the relevant ivy agents. - /// There is one thread for each client connected, we could also - /// create another thread each time we send a message. - /// - /// A string message format to build the message - /// args used in message format - /// - /// the number of messages actually sent - /// - public int SendMsg(string format, params object[] args) - { - // send to everybody - string msg = string.Format(culture, format, args); - int count = 0; - // hash message in V4 protocol only - if (ProtocolVersion == 4) - IvyBindingSimple.Prepare(msg); - // an alternate implementation would one sender thread per client - // instead of one for all the clients. It might be a performance issue - // Tentative of using BeginInvoke EndInvoke is slower - lock (client_bindings) - { - foreach (IvyClientBinding clbind in client_bindings.Values) - { - string[] matches = clbind.binding.Match(msg); - if (matches != null) - { - lock (clbind.client_bindind_ids) - { - - foreach (KeyValuePair> assoc in clbind.client_bindind_ids) - { - foreach (ushort id in assoc.Value) - { - count += assoc.Key.sendMsg(id, matches); - } - - } - - } - } - - } - - } - - return count; - } - - internal int SendMsgToClient(IvyClient clnt, string format, params object[] args) - { - string msg = string.Format(culture, format, args); - int count = 0; - // hash message in V4 protocol only - if (ProtocolVersion == 4) - IvyBindingSimple.Prepare(msg); - // an alternate implementation would one sender thread per client - // instead of one for all the clients. It might be a performance issue - lock (client_bindings) - { - - foreach (IvyClientBinding clbind in client_bindings.Values) - { - string[] matches = clbind.binding.Match(msg); - if (matches != null) - { - lock (clbind.client_bindind_ids) - { - if (clbind.client_bindind_ids.ContainsKey(clnt)) - { - List ids = clbind.client_bindind_ids[clnt]; - foreach (ushort id in ids) - { - count += clnt.sendMsg(id, matches); - } - } - } - } - } - } - - - return count; - } - /// - /// Make a binding to a message using regular expresssion - /// - /// - /// - public int BindMsg(IvyApplicationBinding newBinding) - { - newBinding.Key = Interlocked.Increment(ref serial); - - lock (bindings) bindings.Add(newBinding.Key, newBinding); - // notifies the other clients this new regexp - lock (clients) - { - foreach (IvyClient c in clients) - { - c.stream.TokenAddBinding(newBinding.Binding, newBinding.Key, newBinding.FormattedExpression); - } - } - return newBinding.Key; - } - /// - /// Subscribes to a regular expression. - /// - /// a regular expression, groups are done with parenthesis - /// any objects implementing the EventHandler - /// The args. - /// the id of the regular expression - /// - /// The callback will be executed with - /// the saved parameters of the regexp as arguments when a message will sent - /// by another agent. A program doesn't receive its own messages. - /// the expression cant containt some dynamics argument replacement of the form %number[:objectFormat]% - /// the string will be replaced by arg[number].ToString(objectFormat) - /// - // - public int BindMsg(string expression, EventHandler callback, params object[] args) - { - // creates a new binding (regexp,callback) - IvyApplicationBinding newbind; - newbind = new IvyApplicationBinding(BindingType.RegularExpression, expression, args); - newbind.Callback += callback; - return BindMsg(newbind); - } - - /// - /// unsubscribes a regular expression - /// - /// the id of the regular expression, returned when it was bound - public void UnbindMsg(int id) - { - if (!bindings.ContainsKey(id)) - { - throw new IvyException("client wants to remove an unexistant regexp " + id); - } - lock (clients) - { - foreach (IvyClient c in clients) - { - try - { - if ( c.stream != null ) - c.stream.TokenDelBinding(id); - } - catch (IOException) - { - // client closed ignore it - } - } - } - lock (bindings) bindings.Remove(id); - } - /// - /// Change a binding already registred - /// - /// - /// - /// - public int ChangeMsg(int id, string expression) - { - IvyApplicationBinding newbind; - if (!bindings.ContainsKey(id)) - { - throw new IvyException("client wants to change an unexistant regexp " + id); - } - - // change binding (regexp,callback) - lock (bindings) - { - newbind = bindings[id]; - newbind.Expression = expression; - } - // notifies the other clients this new regexp - lock (clients) - { - foreach (IvyClient c in clients) - { - c.stream.TokenAddBinding(newbind.Binding, newbind.Key, newbind.FormattedExpression); - } - } - return id; - } - - - /// - /// unsubscribes a regular expression - /// - /// the string for the regular expression - /// - /// a boolean, true if the regexp existed, false otherwise or - /// whenever an exception occured during unbinding - /// - public bool UnbindMsg(string re) - { - foreach (IvyApplicationBinding bind in bindings.Values) - { - if (bind.Expression == re) - { - try - { - UnbindMsg(bind.Key); - } - catch (IvyException) - { - return false; - } - return true; - } - } - return false; - } + // sends the broadcasts and listen to incoming connexions + for (int i = 0; i < watchers.Count; i++) + { + watchers[i].start(); + } + } + internal void SortClients() + { + lock (clients) + { + //clients.Sort(new IvyClient.IvyClientPriority()); + clients.Sort(); + } + } + + + internal static Domain[] parseDomains(string domainbus) + { + string[] st = domainbus.Split(','); + Domain[] d = new Domain[st.Length]; + for (int i = 0; i < st.Length; i++) + { + d[i] = new Domain(st[i]); + } + return d; + } + + /// + /// disconnects from the Ivy bus + /// + public void Stop() + { + if (stopped) + return; + lock (app) + { + stopped = true; + Ivy.traceProtocol(Resources.Ivy, "beginning stopping the bus"); + try + { + // stopping the serverThread + if (serverThread != null) + { + app.Stop(); + // Wait for Thread to end. + bool term = serverThread.Join(10000); + if (!term && (serverThread != null)) serverThread.Abort(); + serverThread = null; + } + // The serverThread might be stopped even before having been created + if (app != null) + app.Stop(); + // stopping the IvyWatchers + if (watchers != null) + for (int i = 0; i < watchers.Count; i++) + { + ((IvyWatcher)watchers[i]).stop(); + } + // stopping the remaining IvyClients + // copy the values in temporary variable to eliminate Thread modifying collection + if (clients.Count != 0) + { + IvyClient[] copyClient; + lock (clients) + { + copyClient = new IvyClient[clients.Count]; + clients.CopyTo(copyClient); + } + foreach (IvyClient client in copyClient) + { + client.close(true); // will notify the reading thread + //removeClient(client); already donne in the thread + } + } + } + catch (IOException e) + { + Ivy.traceError(Resources.Ivy, "IOexception Stop " + e.Message); + } + Ivy.traceProtocol(Resources.Ivy, "the bus should have stopped so far"); + } + } + /// + /// join the main thread of Ivy ( ie wait until stopped ) + /// + /// + /// Performs a join on the Principal Thread. + /// + /// Number of millisecondes to wait before the Thread Stop. + /// + /// true if the thread stopped; false if it did not stop after the expiry of the period specified by the parameter millisecondsTimeout + /// + public bool Join(int millisecondsTimeout) + { + return serverThread.Join(millisecondsTimeout); + } + /// + /// Block the calling Thread until Ivy Stop + /// + /// + /// Performs a join on the Principal Thread. + /// + public void MainLoop() + { + this.Join(Timeout.Infinite); + } + + /// + /// Send a formated message to someone on the bus + /// + /// + /// Performs a pattern matching according to everyone's regexps, and sends + /// the results to the relevant ivy agents. + /// There is one thread for each client connected, we could also + /// create another thread each time we send a message. + /// + /// A string message format to build the message + /// args used in message format + /// + /// the number of messages actually sent + /// + public int SendMsg(string format, params object[] args) + { + // send to everybody + string msg = string.Format(culture, format, args); + int count = 0; + // hash message in V4 protocol only + if (ProtocolVersion == 4) + IvyBindingSimple.Prepare(msg); + // an alternate implementation would one sender thread per client + // instead of one for all the clients. It might be a performance issue + // Tentative of using BeginInvoke EndInvoke is slower + lock (client_bindings) + { + foreach (IvyClientBinding clbind in client_bindings.Values) + { + string[] matches = clbind.binding.Match(msg); + if (matches != null) + { + lock (clbind.client_bindind_ids) + { + + foreach (KeyValuePair> assoc in clbind.client_bindind_ids) + { + foreach (ushort id in assoc.Value) + { + count += assoc.Key.sendMsg(id, matches); + } + + } + + } + } + + } + + } + return count; + } + + internal int SendMsgToClient(IvyClient clnt, string format, params object[] args) + { + string msg = string.Format(culture, format, args); + int count = 0; + // hash message in V4 protocol only + if (ProtocolVersion == 4) + IvyBindingSimple.Prepare(msg); + // an alternate implementation would one sender thread per client + // instead of one for all the clients. It might be a performance issue + lock (client_bindings) + { - /// - /// Subscribes to a simple expression ( msg ar1 arg2 arg3 etc). - /// - /// - /// The callback will be executed with - /// the saved parameters of the regexp as arguments when a message will sent - /// by another agent. A program doesn't receive its own messages. - /// - /// - /// a regular expression, groups are done with parenthesis - /// any objects implementing the EventHandler - /// - /// the id of the regular expression - /// - public int BindSimpleMsg(string expression, EventHandler callback, params object[] args) - { - // creates a new binding (regexp,callback) - IvyApplicationBinding newbind; - newbind = new IvyApplicationBinding(BindingType.Simple, expression, args); - newbind.Callback += callback; - return BindMsg(newbind); - } - /// - /// Dies the specified target. - /// - /// The target. - /// The reason message. - /// - public int Die(string target, string message) - { - ReadOnlyCollection v = GetClientsByName(target); - foreach (IvyClient clnt in v) - clnt.stream.TokenDie(0, message); - return v.Count; - } - /// - /// Pings the specified target. - /// - /// The target. - /// The message. - /// - public int Ping(string target, string message) - { - int id = (int)DateTime.Now.Ticks; - ReadOnlyCollection v = GetClientsByName(target); - foreach (IvyClient clnt in v) - { - clnt.stream.TokenPing(id, message); - } - return v.Count; - } + foreach (IvyClientBinding clbind in client_bindings.Values) + { + string[] matches = clbind.binding.Match(msg); + if (matches != null) + { + lock (clbind.client_bindind_ids) + { + if (clbind.client_bindind_ids.ContainsKey(clnt)) + { + List ids = clbind.client_bindind_ids[clnt]; + foreach (ushort id in ids) + { + count += clnt.sendMsg(id, matches); + } + } + } + } + } + } + + + return count; + } + /// + /// Make a binding to a message using regular expresssion + /// + /// + /// + public int BindMsg(IvyApplicationBinding newBinding) + { + newBinding.Key = Interlocked.Increment(ref serial); + + lock (bindings) bindings.Add(newBinding.Key, newBinding); + // notifies the other clients this new regexp + lock (clients) + { + foreach (IvyClient c in clients) + { + c.stream.TokenAddBinding(newBinding.Binding, newBinding.Key, newBinding.FormattedExpression); + } + } + return newBinding.Key; + } + /// + /// Subscribes to a regular expression. + /// + /// a regular expression, groups are done with parenthesis + /// any objects implementing the EventHandler + /// The args. + /// the id of the regular expression + /// + /// The callback will be executed with + /// the saved parameters of the regexp as arguments when a message will sent + /// by another agent. A program doesn't receive its own messages. + /// the expression cant containt some dynamics argument replacement of the form %number[:objectFormat]% + /// the string will be replaced by arg[number].ToString(objectFormat) + /// + // + public int BindMsg(string expression, EventHandler callback, params object[] args) + { + // creates a new binding (regexp,callback) + IvyApplicationBinding newbind; + newbind = new IvyApplicationBinding(BindingType.RegularExpression, expression, args); + newbind.Callback += callback; + return BindMsg(newbind); + } + + /// + /// unsubscribes a regular expression + /// + /// the id of the regular expression, returned when it was bound + public void UnbindMsg(int id) + { + if (!bindings.ContainsKey(id)) + { + throw new IvyException("client wants to remove an unexistant regexp " + id); + } + lock (clients) + { + foreach (IvyClient c in clients) + { + try + { + if ( c.stream != null ) + c.stream.TokenDelBinding(id); + } + catch (IOException) + { + // client closed ignore it + } + } + } + lock (bindings) bindings.Remove(id); + } + /// + /// Change a binding already registred + /// + /// + /// + /// + public int ChangeMsg(int id, string expression) + { + IvyApplicationBinding newbind; + if (!bindings.ContainsKey(id)) + { + throw new IvyException("client wants to change an unexistant regexp " + id); + } + + // change binding (regexp,callback) + lock (bindings) + { + newbind = bindings[id]; + newbind.Expression = expression; + } + // notifies the other clients this new regexp + lock (clients) + { + foreach (IvyClient c in clients) + { + c.stream.TokenAddBinding(newbind.Binding, newbind.Key, newbind.FormattedExpression); + } + } + return id; + } + + + /// + /// unsubscribes a regular expression + /// + /// the string for the regular expression + /// + /// a boolean, true if the regexp existed, false otherwise or + /// whenever an exception occured during unbinding + /// + public bool UnbindMsg(string re) + { + foreach (IvyApplicationBinding bind in bindings.Values) + { + if (bind.Expression == re) + { + try + { + UnbindMsg(bind.Key); + } + catch (IvyException) + { + return false; + } + return true; + } + } + return false; + } + + + /// + /// Subscribes to a simple expression ( msg ar1 arg2 arg3 etc). + /// + /// + /// The callback will be executed with + /// the saved parameters of the regexp as arguments when a message will sent + /// by another agent. A program doesn't receive its own messages. + /// + /// + /// a regular expression, groups are done with parenthesis + /// any objects implementing the EventHandler + /// + /// the id of the regular expression + /// + public int BindSimpleMsg(string expression, EventHandler callback, params object[] args) + { + // creates a new binding (regexp,callback) + IvyApplicationBinding newbind; + newbind = new IvyApplicationBinding(BindingType.Simple, expression, args); + newbind.Callback += callback; + return BindMsg(newbind); + } + /// + /// Dies the specified target. + /// + /// The target. + /// The reason message. + /// + public int Die(string target, string message) + { + ReadOnlyCollection v = GetClientsByName(target); + foreach (IvyClient clnt in v) + clnt.stream.TokenDie(0, message); + return v.Count; + } + /// + /// Pings the specified target. + /// + /// The target. + /// The message. + /// + public int Ping(string target, string message) + { + int id = (int)DateTime.Now.Ticks; + ReadOnlyCollection v = GetClientsByName(target); + foreach (IvyClient clnt in v) + { + clnt.stream.TokenPing(id, message); + } + return v.Count; + } - internal virtual void FireEvent(EventHandler ev, IvyEventArgs e) - { - if (ev != null) - { + internal virtual void FireEvent(EventHandler ev, IvyEventArgs e) + { + if (ev != null) + { #if (PocketPC) - if (parentControl != null) - { - parentControl.Invoke(ev, this, e); - } + if (parentControl != null) + { + parentControl.Invoke(ev, this, e); + } #else - if (syncContext != null) - { - SendOrPostCallback update = delegate(object state) - { - IvyEventArgs args = (IvyEventArgs)state; - ev(this, args); - }; - syncContext.Post(update, e); - } + if (synchronous) + { + SendOrPostCallback update = delegate(object state) + { + IvyEventArgs args = (IvyEventArgs)state; + ev(this, args); + }; + syncContext.Post(update, e); + } #endif - else - ev(this, e); - } - } - - - internal virtual void OnDirectMessage(IvyEventArgs e) - { - // Copy to a temporary variable to be thread-safe. - EventHandler temp = DirectMessageReceived; - FireEvent(temp,e); - } - internal virtual void OnClientConnected(IvyEventArgs e) - { - // Copy to a temporary variable to be thread-safe. - EventHandler temp = ClientConnected; - FireEvent(temp,e); - } - internal virtual void OnClientDisconnected(IvyEventArgs e) - { - // Copy to a temporary variable to be thread-safe. - EventHandler temp = ClientDisconnected; - try - { - FireEvent(temp,e); - } + else + ev(this, e); + } + } + + + internal virtual void OnDirectMessage(IvyEventArgs e) + { + // Copy to a temporary variable to be thread-safe. + EventHandler temp = DirectMessageReceived; + FireEvent(temp,e); + } + internal virtual void OnClientConnected(IvyEventArgs e) + { + // Copy to a temporary variable to be thread-safe. + EventHandler temp = ClientConnected; + FireEvent(temp,e); + } + internal virtual void OnClientDisconnected(IvyEventArgs e) + { + // Copy to a temporary variable to be thread-safe. + EventHandler temp = ClientDisconnected; + try + { + FireEvent(temp,e); + } #if (!PocketPC) - catch (SynchronizationLockException) - { - // protect terminaison - } + catch (SynchronizationLockException) + { + // protect terminaison + } #endif - catch (ObjectDisposedException) - { - // protect terminaison - } - - } - internal virtual void OnClientAddBinding(IvyEventArgs e) - { - // Copy to a temporary variable to be thread-safe. - EventHandler temp = BindingAdd; - FireEvent(temp,e); - } - internal virtual void OnClientRemoveBinding(IvyEventArgs e) - { - // Copy to a temporary variable to be thread-safe. - EventHandler temp = BindingRemove; - FireEvent(temp,e); - } - internal virtual void OnClientChangeBinding(IvyEventArgs e) - { - // Copy to a temporary variable to be thread-safe. - EventHandler temp = BindingChange; - FireEvent(temp, e); - } - internal virtual void OnClientFilterBinding(IvyEventArgs e) - { - // Copy to a temporary variable to be thread-safe. - EventHandler temp = BindingFilter; - FireEvent(temp,e); - } - internal virtual void OnError(IvyEventArgs e) - { - // Copy to a temporary variable to be thread-safe. - EventHandler temp = ErrorMessage; - FireEvent(temp, e); - } + catch (ObjectDisposedException) + { + // protect terminaison + } + + } + internal virtual void OnClientAddBinding(IvyEventArgs e) + { + // Copy to a temporary variable to be thread-safe. + EventHandler temp = BindingAdd; + FireEvent(temp,e); + } + internal virtual void OnClientRemoveBinding(IvyEventArgs e) + { + // Copy to a temporary variable to be thread-safe. + EventHandler temp = BindingRemove; + FireEvent(temp,e); + } + internal virtual void OnClientChangeBinding(IvyEventArgs e) + { + // Copy to a temporary variable to be thread-safe. + EventHandler temp = BindingChange; + FireEvent(temp, e); + } + internal virtual void OnClientFilterBinding(IvyEventArgs e) + { + // Copy to a temporary variable to be thread-safe. + EventHandler temp = BindingFilter; + FireEvent(temp,e); + } + internal virtual void OnError(IvyEventArgs e) + { + // Copy to a temporary variable to be thread-safe. + EventHandler temp = ErrorMessage; + FireEvent(temp, e); + } #if (PocketPC) - internal virtual void OnDie(IvyDieEventArgs e) - { - // Copy to a temporary variable to be thread-safe. - EventHandler temp = DieReceived; - if (temp != null) - { - if (parentControl != null) - { - parentControl.Invoke(temp, this, e); - } - else - temp(this, e); - } - } + internal virtual void OnDie(IvyDieEventArgs e) + { + // Copy to a temporary variable to be thread-safe. + EventHandler temp = DieReceived; + if (temp != null) + { + if (parentControl != null) + { + parentControl.Invoke(temp, this, e); + } + else + temp(this, e); + } + } #else - internal virtual void OnDie(IvyDieEventArgs e) - { - // Copy to a temporary variable to be thread-safe. - EventHandler temp = DieReceived; - if (temp != null) - { - if (syncContext != null) - { - SendOrPostCallback update = delegate(object state) - { - IvyDieEventArgs args = (IvyDieEventArgs)state; - temp(this, args); - }; - syncContext.Post(update, e); - } - else - temp(this, e); - } - } + internal virtual void OnDie(IvyDieEventArgs e) + { + // Copy to a temporary variable to be thread-safe. + EventHandler temp = DieReceived; + if (temp != null) + { + if (syncContext != null) + { + SendOrPostCallback update = delegate(object state) + { + IvyDieEventArgs args = (IvyDieEventArgs)state; + temp(this, args); + }; + syncContext.Post(update, e); + } + else + temp(this, e); + } + } #endif - internal void OnMessage(IvyMessageEventArgs e) - { - if (!bindings.ContainsKey( e.Id)) - { - throw new IvyException("(callCallback) Not regexp matching id " + e.Id); - } - IvyApplicationBinding bind = bindings[e.Id]; + internal void OnMessage(IvyMessageEventArgs e) + { + if (!bindings.ContainsKey( e.Id)) + { + throw new IvyException("(callCallback) Not regexp matching id " + e.Id); + } + IvyApplicationBinding bind = bindings[e.Id]; #if(PocketPC) - bind.Firevent(parentControl, e); + bind.Firevent(parentControl, e); #else - bind.Firevent(syncContext, e); + bind.Firevent(syncContext,synchronous, e); #endif - } - - /* - * removes a client from the list - */ - internal void removeClient(IvyClient c) - { - lock (clients) - { - clients.Remove(c); - } - List purge_bind = new List(); - lock (client_bindings) - { - foreach (IvyClientBinding clbind in client_bindings.Values) - { - lock (clbind.client_bindind_ids) - { - clbind.client_bindind_ids.Remove(c); - if ( clbind.client_bindind_ids.Count == 0 ) - purge_bind.Add( clbind.binding.Expression); - } - } - // remove Binding if no client - foreach ( string expr in purge_bind ) - { - client_bindings.Remove(expr); - } - } - } - - - /// - /// gives a list of IvyClient(s) with the name given in parameter - /// - /// The name of the Ivy agent you're looking for - /// - public ReadOnlyCollection GetClientsByName(string name) - { - List v = new List(); - foreach (IvyClient ic in clients) - { - if (ic.ApplicationName.CompareTo(name) == 0) - v.Add(ic); - } - return new ReadOnlyCollection(v); - } - - /////////////////////////////////////////////////////////////////: - // - // Protected methods - // - /////////////////////////////////////////////////////////////////: - - internal void addClient(IvyClient client) - { - if (stopped) - return; - - lock (clients) - { - clients.Add(client); - } - - } - - /// - /// return the first non loopback adress - /// on a one network interface machine it will be my IP adresse - /// - public static IPAddress LocalIP - { - get - { - IPAddress returnaddr = null; - //TODO remove ALL reverse DNS search !!!! - IPHostEntry ip = Dns.GetHostEntry(Dns.GetHostName()); - foreach (IPAddress addr in ip.AddressList) - { - returnaddr = addr; - if (IPAddress.IsLoopback(addr)) continue; - break; - } - return returnaddr; - } - } - /// - /// Get the FDQN Domain from a string - /// - /// - /// - public static string GetDomain(string domainBus) - { + } + + /* + * removes a client from the list + */ + internal void removeClient(IvyClient c) + { + lock (clients) + { + clients.Remove(c); + } + List purge_bind = new List(); + lock (client_bindings) + { + foreach (IvyClientBinding clbind in client_bindings.Values) + { + lock (clbind.client_bindind_ids) + { + clbind.client_bindind_ids.Remove(c); + if ( clbind.client_bindind_ids.Count == 0 ) + purge_bind.Add( clbind.binding.Expression); + } + } + // remove Binding if no client + foreach ( string expr in purge_bind ) + { + client_bindings.Remove(expr); + } + } + } + + + /// + /// gives a list of IvyClient(s) with the name given in parameter + /// + /// The name of the Ivy agent you're looking for + /// + public ReadOnlyCollection GetClientsByName(string name) + { + List v = new List(); + foreach (IvyClient ic in clients) + { + if (ic.ApplicationName.CompareTo(name) == 0) + v.Add(ic); + } + return new ReadOnlyCollection(v); + } + + /////////////////////////////////////////////////////////////////: + // + // Protected methods + // + /////////////////////////////////////////////////////////////////: + + internal void addClient(IvyClient client) + { + if (stopped) + return; + + lock (clients) + { + clients.Add(client); + } + + } + + /// + /// return the first non loopback adress + /// on a one network interface machine it will be my IP adresse + /// + public static IPAddress LocalIP + { + get + { + IPAddress returnaddr = null; + //TODO remove ALL reverse DNS search !!!! + IPHostEntry ip = Dns.GetHostEntry(Dns.GetHostName()); + foreach (IPAddress addr in ip.AddressList) + { + returnaddr = addr; + if (IPAddress.IsLoopback(addr)) continue; + break; + } + return returnaddr; + } + } + /// + /// Get the FDQN Domain from a string + /// + /// + /// + public static string GetDomain(string domainBus) + { #if (PocketPC) // TODO integrate in normal version - if (domainbus == null || domainbus.Length == 0) - { - IPAddress addr = GetLocalIP(); - //TODO Find Braodcast addr from IP; - byte[] bytes = addr.GetAddressBytes(); - if (IPAddress.IsLoopback(addr)) - { - // 127.255.255.255 - bytes[1] = 255; - bytes[2] = 255; - bytes[3] = 255; - } - else - { - // else assume class C network - // TODO find exact netmask - bytes[3] = 255; - } - IPAddress bcast = new IPAddress(bytes); - domainbus = bcast + ":" + Domain.getPort(domainbus); - } + if (domainbus == null || domainbus.Length == 0) + { + IPAddress addr = GetLocalIP(); + //TODO Find Braodcast addr from IP; + byte[] bytes = addr.GetAddressBytes(); + if (IPAddress.IsLoopback(addr)) + { + // 127.255.255.255 + bytes[1] = 255; + bytes[2] = 255; + bytes[3] = 255; + } + else + { + // else assume class C network + // TODO find exact netmask + bytes[3] = 255; + } + IPAddress bcast = new IPAddress(bytes); + domainbus = bcast + ":" + Domain.getPort(domainbus); + } #else - if (domainBus == null || domainBus.Length == 0 ) + if (domainBus == null || domainBus.Length == 0 ) { domainBus = Environment.GetEnvironmentVariable("IVYBUS"); } - if (domainBus == null || domainBus.Length == 0) - { - domainBus = Properties.Settings.Default.IvyBus; - } + if (domainBus == null || domainBus.Length == 0) + { + domainBus = Properties.Settings.Default.IvyBus; + } #endif - if (domainBus == null || domainBus.Length == 0) - domainBus = DefaultDomain; - return domainBus; - } - - - /// checks the "validity" of a regular expression. //TODO put in IvyBinding - internal bool CheckRegexp(string exp) - { - bool regexp_ok = true; - // Attention Bug - // ClockStop ClockStart & ^Clock(Start|Pause) - // should Stop to the first parent - if ((sent_messageFilter.Count != 0) && exp.StartsWith("^")) - { - regexp_ok = false; - // extract first word from regexp... - string token = Regex.Replace(exp, @"^\^(?[a-zA-Z_0-9-]+).*", @"${token}"); - - foreach (string exp_class in sent_messageFilter) - { - if (exp_class.StartsWith(token)) - return true; - } - } - return regexp_ok; - } + if (domainBus == null || domainBus.Length == 0) + domainBus = DefaultDomain; + return domainBus; + } + + + /// checks the "validity" of a regular expression. //TODO put in IvyBinding + internal bool CheckRegexp(string exp) + { + bool regexp_ok = true; + // Attention Bug + // ClockStop ClockStart & ^Clock(Start|Pause) + // should Stop to the first parent + if ((sent_messageFilter.Count != 0) && exp.StartsWith("^")) + { + regexp_ok = false; + // extract first word from regexp... + string token = Regex.Replace(exp, @"^\^(?[a-zA-Z_0-9-]+).*", @"${token}"); + + foreach (string exp_class in sent_messageFilter) + { + if (exp_class.StartsWith(token)) + return true; + } + } + return regexp_ok; + } + + /* + * prevents two clients from connecting to each other at the same time + * there might still be a lingering bug here, that we could avoid with the + * SchizoToken. + */ + internal IvyClient checkConnected(IvyClient clnt) + { + IvyClient sameClnt = null; + if (clnt.AppPort == 0) + { + Console.WriteLine(" client {0} port == 0 ", clnt.appName); + return sameClnt; + } + lock (clients) + { + foreach (IvyClient client in clients) + { + if (clnt == client) continue; // SKIP himself + if (client.sameIvyClient(clnt)) + { + sameClnt = client; + break; + } + } + } + return sameClnt; + } + + /* + * the service socket thread reader main loop + */ + private void TcpListener() + { + Ivy.traceProtocol(Resources.Ivy, "Ivy service Thread started"); + bool running = true; + tcplistener_running.Set(); + while (running) + { + try + { + Socket socket = app.AcceptSocket(); + // early disconnexion + if (stopped) + break; + // the peer called me + IvyClient client = new IvyClient(this, socket, "Unkown(waiting for name reception)",0); + client.SendBindings(); //TODO in a Thread or wait for the peer to sent his before sending mine + + } + catch (IOException e) + { + Ivy.traceError(Resources.Ivy,Resources.IvyIOException + e.Message); + } + catch (SocketException e) + { + Ivy.traceError(Resources.Ivy,Resources.IvySocketException + e.Message); + running = false; + } + } + Ivy.traceProtocol(Resources.Ivy, "Ivy service Thread stopped"); + } + + [Conditional("DEBUG")] + internal static void traceProtocol(string name, string message) + { + if ( debugProtocol ) + Console.WriteLine( "-->{0}<-- {1}", name, message); + } + internal static void traceError(string name, string message) + { + Console.WriteLine("-->{0}<-- {1}", name, message); + } + + internal class Domain + { + public virtual string Domainaddr + { + get + { + return domainaddr; + } - /* - * prevents two clients from connecting to each other at the same time - * there might still be a lingering bug here, that we could avoid with the - * SchizoToken. - */ - internal IvyClient checkConnected(IvyClient clnt) - { - IvyClient sameClnt = null; - if (clnt.AppPort == 0) - { - Console.WriteLine(" client {0} port == 0 ", clnt.appName); - return sameClnt; - } - lock (clients) - { - foreach (IvyClient client in clients) - { - if (clnt == client) continue; // SKIP himself - if (client.sameIvyClient(clnt)) - { - sameClnt = client; - break; - } - } - } - return sameClnt; - } + } + public virtual int Port + { + get + { + return port; + } - /* - * the service socket thread reader main loop - */ - private void TcpListener() - { - Ivy.traceProtocol(Resources.Ivy, "Ivy service Thread started"); - bool running = true; - tcplistener_running.Set(); - while (running) - { - try - { - Socket socket = app.AcceptSocket(); - // early disconnexion - if (stopped) - break; - // the peer called me - IvyClient client = new IvyClient(this, socket, "Unkown(waiting for name reception)",0); - client.SendBindings(); //TODO in a Thread or wait for the peer to sent his before sending mine - - } - catch (IOException e) - { - Ivy.traceError(Resources.Ivy,Resources.IvyIOException + e.Message); - } - catch (SocketException e) - { - Ivy.traceError(Resources.Ivy,Resources.IvySocketException + e.Message); - running = false; - } - } - Ivy.traceProtocol(Resources.Ivy, "Ivy service Thread stopped"); - } + } + private string domainaddr; + private int port; + public Domain(string net):this( getDomain(net),getPort(net)) + { + } + public Domain(string domainaddr, int port) + { + this.domainaddr = domainaddr; + this.port = port; + } + public override string ToString() + { + return domainaddr + ":" + port; + } + public static string getDomain(string net) + { + int sep_index = net.LastIndexOf(":"); + if (sep_index != -1) + { + net = net.Substring(0, (sep_index) - (0)); + } + try + { + if (!net.Contains("::")) // if not IPV6 multicast paste with 255 + { + net += ".255.255.255"; + Regex exp = new Regex("^(\\d+\\.\\d+\\.\\d+\\.\\d+).*"); + net = exp.Replace(net, "$1"); + } + } + catch (ArgumentException e) + { + Ivy.traceError(Resources.Ivy,Resources.BadBroadcast + net + "error " + e.Message); + return null; + } + return net; + } - [Conditional("DEBUG")] - internal static void traceProtocol(string name, string message) - { - if ( debugProtocol ) - Console.WriteLine( "-->{0}<-- {1}", name, message); - } - internal static void traceError(string name, string message) - { - Console.WriteLine("-->{0}<-- {1}", name, message); - } + public static int getPort(string net) + { + if (net == null) { return Ivy.DefaultPort; } + int sep_index = net.LastIndexOf(":"); + int port = (sep_index == -1) ? Ivy.DefaultPort : Int32.Parse(net.Substring(sep_index + 1)); + return port; + } + } - internal class Domain + /// + /// check Validity of Ivy Bus Domain + /// + /// + /// + public static bool ValidatingDomain(string domain) { - public virtual string Domainaddr - { - get - { - return domainaddr; - } - - } - public virtual int Port - { - get - { - return port; - } - - } - private string domainaddr; - private int port; - public Domain(string net):this( getDomain(net),getPort(net)) - { - } - public Domain(string domainaddr, int port) + IPAddress result; + bool valid = false; + string addr = Domain.getDomain(domain); + try { - this.domainaddr = domainaddr; - this.port = port; + int port = Domain.getPort(domain); + if (port < IPEndPoint.MinPort || port > IPEndPoint.MaxPort) return false; } - public override string ToString() + catch (OverflowException e) { - return domainaddr + ":" + port; + return false; } - public static string getDomain(string net) + if (String.IsNullOrEmpty(addr)) { - 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) - { - Ivy.traceError(Resources.Ivy,Resources.BadBroadcast + net + "error " + e.Message); - return null; - } - return net; + // address wasnt provided so return false + valid = false; } - - public static int getPort(string net) + else { - if (net == null) { return Ivy.DefaultPort; } - int sep_index = net.LastIndexOf(":"); - int port = (sep_index == -1) ? Ivy.DefaultPort : Int32.Parse(net.Substring(sep_index + 1)); - return port; + //use TryParse to see if this is a + //valid ip address. TryParse returns a + //boolean based on the validity of the + //provided address, so assign that value + //to our boolean variable + valid = IPAddress.TryParse(addr, out result); } + return valid; } - /// - /// check Validity of Ivy Bus Domain - /// - /// - /// - public static bool ValidatingDomain(string domain) - { - // domain if of the form ip1[:port][,ip2[:port]] with ip of the form n1.n2.n3.n4 - return Regex.IsMatch(domain, @"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+"); - } - - } + } } \ No newline at end of file diff --git a/Ivy/IvyApplicationBinding.cs b/Ivy/IvyApplicationBinding.cs index b8932c8..d282583 100644 --- a/Ivy/IvyApplicationBinding.cs +++ b/Ivy/IvyApplicationBinding.cs @@ -147,7 +147,7 @@ namespace IvyBus temp(this, e); } #else - internal void Firevent(System.Threading.SynchronizationContext syncContext, IvyMessageEventArgs e) + internal void Firevent(System.Threading.SynchronizationContext syncContext, bool synchronous , IvyMessageEventArgs e) { //// Safely invoke an event: EventHandler temp = Callback; @@ -156,7 +156,7 @@ namespace IvyBus { throw new IvyException("(callCallback) Not callback for id " + e.Id); } - if (syncContext != null) + if (synchronous ) { SendOrPostCallback update = delegate(object state) { diff --git a/Ivy/IvyClient.cs b/Ivy/IvyClient.cs index 98d7901..7a34070 100644 --- a/Ivy/IvyClient.cs +++ b/Ivy/IvyClient.cs @@ -7,17 +7,17 @@ namespace IvyBus { using System; using System.Collections; - using System.Collections.Specialized; - using System.Collections.Generic; + using System.Collections.Specialized; + using System.Collections.Generic; using System.Threading; using System.Text; using System.IO; using System.Net; using System.Net.Sockets; using System.Configuration; - using System.Diagnostics; - using System.Collections.ObjectModel; - using IvyBus.Properties; + using System.Diagnostics; + using System.Collections.ObjectModel; + using IvyBus.Properties; /// A Class for the the peers on the bus. /// @@ -27,19 +27,19 @@ namespace IvyBus /// die messages, direct messages, add or remove regexps, or quit. A thread is /// created for each remote client. /// - public class IvyClient : IvyProtocol, IComparable, IDisposable + public class IvyClient : IvyProtocol, IComparable, IDisposable { - public int CompareTo(IvyClient other) - { - if (other == null) - return clientPriority; - else - return (other.clientPriority - clientPriority); - } - - /// - /// the client application Name - /// + public int CompareTo(IvyClient other) + { + if (other == null) + return clientPriority; + else + return (other.clientPriority - clientPriority); + } + + /// + /// the client application Name + /// public String ApplicationName { get @@ -49,20 +49,20 @@ namespace IvyBus } - //public ReadOnlyCollection Regexps - //{ - // get - // { - // List tab = new List(); - // lock (bindings) - // { - // foreach (IvyBindingBase bind in bindings.Values) - // tab.Add(bind.Expression); - // } - // return new ReadOnlyCollection(tab); - // } + //public ReadOnlyCollection Regexps + //{ + // get + // { + // List tab = new List(); + // lock (bindings) + // { + // foreach (IvyBindingBase bind in bindings.Values) + // tab.Add(bind.Expression); + // } + // return new ReadOnlyCollection(tab); + // } - //} + //} internal int AppPort { get @@ -71,145 +71,146 @@ namespace IvyBus } } - /// - /// adress of the client - /// - public IPAddress RemoteAddress + /// + /// adress of the client + /// + public IPAddress RemoteAddress { get { - return remoteHost; + return remoteHost; } } - /// - /// port of the client - /// + /// + /// port of the client + /// public int RemotePort { get { - return remotePort; + return remotePort; } } private Ivy bus; - //private Dictionary bindings; + //private Dictionary bindings; private int appPort; - private string clientId; /* an unique ID for each IvyClient */ + private string clientId; /* an unique ID for each IvyClient */ private int clientPriority; /* client priority */ - + private volatile Thread clientThread; // volatile to ensure the quick communication - private bool doping; // false by runtime default + private bool doping; // false by runtime default private const int PINGTIMEOUT = 5000; private volatile Thread pingerThread; - private int localPort; + private int localPort; - private int remotePort; - private IPAddress remoteHost; + private int remotePort; + private IPAddress remoteHost; private int readyToSend; - private Object readyToSendLock; + private Object readyToSendLock; // protected variables internal String appName; - internal IvyProtocol stream; + internal IvyProtocol stream; internal IvyClient(Ivy bus, Socket socket, string appname, int appPort) { //bindings = new Dictionary(); this.appName = appname; - this.appPort = appPort; + this.appPort = appPort; this.bus = bus; - readyToSendLock = new Object(); - this.readyToSend = 0; - - // set TCP_NODELAY to lower latency - socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.NoDelay, true); - localPort = ((IPEndPoint)socket.LocalEndPoint).Port; - - IPEndPoint endpoint = (IPEndPoint)socket.RemoteEndPoint; - remoteHost = endpoint.Address; - remotePort = endpoint.Port; - - if ( bus.ProtocolVersion == 4 ) - stream = new IvyTCPStreamV4( socket, this ); - else - stream = new IvyTCPStreamV3(socket, this); + readyToSendLock = new Object(); + this.readyToSend = 0; + + // set TCP_NODELAY to lower latency + //socket.SetSocketOption( SocketOptionLevel.IP, SocketOptionName.NoDelay, true); + socket.NoDelay = true; + localPort = ((IPEndPoint)socket.LocalEndPoint).Port; + + IPEndPoint endpoint = (IPEndPoint)socket.RemoteEndPoint; + remoteHost = endpoint.Address; + remotePort = endpoint.Port; + + if ( bus.ProtocolVersion == 4 ) + stream = new IvyTCPStreamV4( socket, this ); + else + stream = new IvyTCPStreamV3(socket, this); // spawns a thread to manage the incoming traffic on this - // socket. We should be ready to receive messages now. - clientThread = new Thread(new ThreadStart(this.Run)); - clientThread.Name = "Ivy Tcp Client Reader Thread ("+appname+")"; - - bus.addClient(this); - - clientThread.Start(); - - } - - internal void SendBindings() - { - try - { - - // sends our ID, whether we initiated the connexion or not - // the ID is the couple "host name,application Port", the host name - // information is in the socket itself, the port is not known if we - // initiate the connexion - stream.TokenStartRegexp(bus.applicationPort, bus.appName); - // sends our regexps to the peer - lock (bus.bindings) - { - foreach (IvyApplicationBinding bind in bus.bindings.Values) - { - stream.TokenAddBinding(bind.Binding, bind.Key, bind.FormattedExpression); - } - } - // send end of bindings peers can now send ReadyMessage - stream.TokenEndRegexp(); - // try to send Ready Msg - SendReadyToPeer(); + // socket. We should be ready to receive messages now. + clientThread = new Thread(new ThreadStart(this.Run)); + clientThread.Name = "Ivy Tcp Client Reader Thread ("+appname+")"; + + bus.addClient(this); + + clientThread.Start(); + + } + + internal void SendBindings() + { + try + { + + // sends our ID, whether we initiated the connexion or not + // the ID is the couple "host name,application Port", the host name + // information is in the socket itself, the port is not known if we + // initiate the connexion + stream.TokenStartRegexp(bus.applicationPort, bus.appName); + // sends our regexps to the peer + lock (bus.bindings) + { + foreach (IvyApplicationBinding bind in bus.bindings.Values) + { + stream.TokenAddBinding(bind.Binding, bind.Key, bind.FormattedExpression); + } + } + // send end of bindings peers can now send ReadyMessage + stream.TokenEndRegexp(); + // try to send Ready Msg + SendReadyToPeer(); #if (!PocketPC) - doping = Properties.Settings.Default.IvyPing; + doping = Properties.Settings.Default.IvyPing; #endif - if (doping) - { - pingerThread = new Thread(new ThreadStart(PingerRun)); - pingerThread.Name = "Ivy Pinger Thread"; - pingerThread.Start(); - } - - - } - catch (NullReferenceException ex) - { - // the client nous a coupé l'herbe sous le pied - Ivy.traceError(Resources.IvyClient, Resources.IvyClientLeft + " " + appName + " " + ex.Message); - // connexion close in rare concurrent connexion - close(false); - } - catch (ObjectDisposedException ex) - { - // the client nous a coupé l'herbe sous le pied - Ivy.traceError(Resources.IvyClient, Resources.IvyClientLeft + " " + appName + " " + ex.Message); - // invokes the Disconnected applicationListeners - //bus.OnClientDisconnected(new IvyEventArgs(this,id, message )); - // called by the receiver Thread - close(false); - } - catch (IOException ex) - { - // the client nous a coupé l'herbe sous le pied - Ivy.traceError(Resources.IvyClient, Resources.IvyClientLeft + " " + appName + " " + ex.Message); - // invokes the Disconnected applicationListeners - //bus.OnClientDisconnected(new IvyEventArgs(this,id, message )); - // called by the receiver Thread - close(false); - } - - } + if (doping) + { + pingerThread = new Thread(new ThreadStart(PingerRun)); + pingerThread.Name = "Ivy Pinger Thread"; + pingerThread.Start(); + } + + + } + catch (NullReferenceException ex) + { + // the client nous a coupé l'herbe sous le pied + Ivy.traceError(Resources.IvyClient, Resources.IvyClientLeft + " " + appName + " " + ex.Message); + // connexion close in rare concurrent connexion + close(false); + } + catch (ObjectDisposedException ex) + { + // the client nous a coupé l'herbe sous le pied + Ivy.traceError(Resources.IvyClient, Resources.IvyClientLeft + " " + appName + " " + ex.Message); + // invokes the Disconnected applicationListeners + //bus.OnClientDisconnected(new IvyEventArgs(this,id, message )); + // called by the receiver Thread + close(false); + } + catch (IOException ex) + { + // the client nous a coupé l'herbe sous le pied + Ivy.traceError(Resources.IvyClient, Resources.IvyClientLeft + " " + appName + " " + ex.Message); + // invokes the Disconnected applicationListeners + //bus.OnClientDisconnected(new IvyEventArgs(this,id, message )); + // called by the receiver Thread + close(false); + } + + } /// returns the name of the remote agent. /// allow an Ivy package class to access the list of regexps at a @@ -225,11 +226,11 @@ namespace IvyBus /// the string that will be match-tested /// /// - public void SendDirectMsg(int id, string message) + public void SendDirectMsg(int id, string message) { try { - stream.TokenDirectMsg( id, message); + stream.TokenDirectMsg( id, message); } catch (IOException ex) { @@ -237,8 +238,8 @@ namespace IvyBus // first, I'm not a first class IvyClient any more bus.removeClient(this); // invokes the Disconnected applicationListeners - //bus.OnClientDisconnected(new IvyEventArgs(this,id, message )); - // should be called by receiver thread + //bus.OnClientDisconnected(new IvyEventArgs(this,id, message )); + // should be called by receiver thread close(false); } } @@ -252,66 +253,66 @@ namespace IvyBus internal void close(bool notify) { Ivy.traceProtocol(Resources.IvyClient,Resources.Closing + appName); - if (doping ) + if (doping ) { StopPinging(); } if (notify) - try - { - if (stream != null) - stream.TokenBye(0, Resources.ByeMessage); - } - catch (ObjectDisposedException) - { - } - catch (IOException ioe) - { - SocketException se = ioe.InnerException as SocketException; - if (se != null) - { - if (!(se.SocketErrorCode == SocketError.ConnectionReset || - se.SocketErrorCode == SocketError.ConnectionAborted)) - - throw new IvyException(ioe.Message); - } - else - { - throw new IvyException(ioe.Message); - } - - } - // stop the thread and close the stream - if (clientThread == null) - return; - // Tell Thread to stop. - if (stream != null) - { - try - { - stream.Close(); // should stop the Reading Client Thread - } - catch (EndOfStreamException ioe) - { - throw new IvyException(ioe.Message); - } - catch (IOException ioe) - { - throw new IvyException(ioe.Message); - } - //socket.Close(); // pris en charge par stream ( NetWorkStream ) - stream = null; - } - // Potential dead lok when thread issue ClientDisconnected event - //if (Thread.CurrentThread != clientThread && (clientThread != null)) - //{ - // // Wait for Thread to end. - // bool term = clientThread.Join(10000); - // if (!term && (clientThread != null)) clientThread.Abort(); - //} - - clientThread = null; - + try + { + if (stream != null) + stream.TokenBye(0, Resources.ByeMessage); + } + catch (ObjectDisposedException) + { + } + catch (IOException ioe) + { + SocketException se = ioe.InnerException as SocketException; + if (se != null) + { + if (!(se.SocketErrorCode == SocketError.ConnectionReset || + se.SocketErrorCode == SocketError.ConnectionAborted)) + + throw new IvyException(ioe.Message); + } + else + { + throw new IvyException(ioe.Message); + } + + } + // stop the thread and close the stream + if (clientThread == null) + return; + // Tell Thread to stop. + if (stream != null) + { + try + { + stream.Close(); // should stop the Reading Client Thread + } + catch (EndOfStreamException ioe) + { + throw new IvyException(ioe.Message); + } + catch (IOException ioe) + { + throw new IvyException(ioe.Message); + } + //socket.Close(); // pris en charge par stream ( NetWorkStream ) + stream = null; + } + // Potential dead lok when thread issue ClientDisconnected event + //if (Thread.CurrentThread != clientThread && (clientThread != null)) + //{ + // // Wait for Thread to end. + // bool term = clientThread.Join(10000); + // if (!term && (clientThread != null)) clientThread.Abort(); + //} + + clientThread = null; + } @@ -327,34 +328,34 @@ namespace IvyBus int count = 0; - try - { - if (stream != null) - { - stream.TokenMsg(id, args); - count++; - } - } - catch (ObjectDisposedException ex) - { - Ivy.traceError(Resources.IvyClient, Resources.IvyClientLeft + ex.Message); - // first, I'm not a first class IvyClient any more - bus.removeClient(this); //TODO trouble in upper loop iter - // invokes the Disconnected applicationListeners - // in the receiver thread - close(false); - } - catch (IOException ex) - { - Ivy.traceError(Resources.IvyClient, Resources.IvyClientLeft + ex.Message); - // first, I'm not a first class IvyClient any more - bus.removeClient(this); //TODO trouble in upper loop iter - // invokes the Disconnected applicationListeners - // in the receiver thread - close(false); - } + try + { + if (stream != null) + { + stream.TokenMsg(id, args); + count++; + } + } + catch (ObjectDisposedException ex) + { + Ivy.traceError(Resources.IvyClient, Resources.IvyClientLeft + ex.Message); + // first, I'm not a first class IvyClient any more + bus.removeClient(this); //TODO trouble in upper loop iter + // invokes the Disconnected applicationListeners + // in the receiver thread + close(false); + } + catch (IOException ex) + { + Ivy.traceError(Resources.IvyClient, Resources.IvyClientLeft + ex.Message); + // first, I'm not a first class IvyClient any more + bus.removeClient(this); //TODO trouble in upper loop iter + // invokes the Disconnected applicationListeners + // in the receiver thread + close(false); + } - + return count; } @@ -369,9 +370,9 @@ namespace IvyBus /// internal bool sameIvyClient(IvyClient clnt) { - // clientId est null si le protocol n'envoie pas le client ID - if (clnt.clientId != null && this.clientId != null && clnt.clientId == this.clientId) - return true; + // clientId est null si le protocol n'envoie pas le client ID + if (clnt.clientId != null && this.clientId != null && clnt.clientId == this.clientId) + return true; return (this.appPort != 0) && (this.appPort == clnt.appPort) && (this.RemoteAddress.Equals(clnt.RemoteAddress)); } @@ -381,9 +382,9 @@ namespace IvyBus { Ivy.traceProtocol(Resources.IvyClient, Resources.Connected + RemoteAddress + ":" + RemotePort); - Ivy.traceProtocol(Resources.IvyClient,"Thread started"); + Ivy.traceProtocol(Resources.IvyClient,Resources.ThreadStart); - bool running = true; + bool running = true; while ( running && (stream != null) ) { try @@ -397,20 +398,20 @@ namespace IvyBus else { Ivy.traceProtocol(Resources.IvyClient, Resources.BadReceive); - running = false; + running = false; break; } } catch ( ObjectDisposedException ex ) { - Ivy.traceError(Resources.IvyClient, Resources.SocketClosed + ex.Message); + Ivy.traceError(Resources.IvyClient, Resources.SocketClosed + ex.Message); running = false; break; } catch (IvyException ie) { - Ivy.traceError(Resources.IvyClient, Resources.SocketClosed + ie.Message); - running = false; + Ivy.traceError(Resources.IvyClient, Resources.SocketClosed + ie.Message); + running = false; break; } catch (SocketException se) @@ -423,7 +424,7 @@ namespace IvyBus { if ( ex.InnerException is SocketException ) { - Ivy.traceProtocol(Resources.IvyClient, Resources.SocketClosed ); + Ivy.traceProtocol(Resources.IvyClient, Resources.SocketClosed ); } else @@ -435,49 +436,49 @@ namespace IvyBus } } Ivy.traceProtocol(Resources.IvyClient,Resources.Disconnected + appName); - Ivy.traceProtocol(Resources.IvyClient,"Thread stopped"); + Ivy.traceProtocol(Resources.IvyClient,Resources.ThreadStop); // invokes the Disconnected applicationListeners - bus.OnClientDisconnected(new IvyEventArgs(this,0, string.Empty )); + bus.OnClientDisconnected(new IvyEventArgs(this,0, string.Empty )); // first, I'm not a first class IvyClient any more - if (stream != null) - { - stream.Close(); - stream = null; - } + if (stream != null) + { + stream.Close(); + stream = null; + } bus.removeClient(this); } - void IvyProtocol.Close() - { - // never call in this side - } - bool IvyProtocol.ReceiveMsg() - { - // nerver call in this side - return false; - } - void IvyProtocol.TokenDie(int id, string arg) + void IvyProtocol.Close() + { + // never call in this side + } + bool IvyProtocol.ReceiveMsg() + { + // nerver call in this side + return false; + } + void IvyProtocol.TokenDie(int id, string arg) { Ivy.traceProtocol(Resources.IvyClient, Resources.DieReceive + appName + Resources.Reason + arg); // invokes the die applicationListeners - IvyDieEventArgs ev = new IvyDieEventArgs(this, id, arg); - bus.OnDie(ev); - // first, I'm not a first class IvyClient any more - bus.removeClient(this); - // makes the bus die + IvyDieEventArgs ev = new IvyDieEventArgs(this, id, arg); + bus.OnDie(ev); + // first, I'm not a first class IvyClient any more + bus.removeClient(this); + // makes the bus die bus.Stop(); close(false); - if (ev.ForceExit) + if (ev.ForceExit) #if (PocketPC) - System.Windows.Forms.Application.Exit(); + System.Windows.Forms.Application.Exit(); #else System.Environment.Exit(0); #endif } - void IvyProtocol.TokenBye(int err, string arg) + void IvyProtocol.TokenBye(int err, string arg) { // the peer quits - Ivy.traceProtocol(Resources.IvyClient, Resources.ByeReceive + appName + Resources.Reason + arg); + Ivy.traceProtocol(Resources.IvyClient, Resources.ByeReceive + appName + Resources.Reason + arg); // first, I'm not a first class IvyClient any more //bus.removeClient(this); // this is done in the receive thread terminaison!! // invokes the disconnect applicationListeners @@ -485,125 +486,125 @@ namespace IvyBus close(false); // will fire disconnected } - void IvyProtocol.TokenAddBinding(BindingType type, int id, string expression) + void IvyProtocol.TokenAddBinding(BindingType type, int id, string expression) { - if (type == BindingType.RegularExpression && !bus.CheckRegexp(expression)) - { - bus.OnClientFilterBinding(new IvyEventArgs(this, id, expression )); - return; - } - IvyBindingBase bind = null; - try - { - switch (type) - { - case BindingType.RegularExpression: - bind = new IvyBindingRegexp(expression); - break; - case BindingType.Simple: - bind = new IvyBindingSimple(expression); - break; - } - bus.AddBinding(id, this, bind); + if (type == BindingType.RegularExpression && !bus.CheckRegexp(expression)) + { + bus.OnClientFilterBinding(new IvyEventArgs(this, id, expression )); + return; + } + IvyBindingBase bind = null; + try + { + switch (type) + { + case BindingType.RegularExpression: + bind = new IvyBindingRegexp(expression); + break; + case BindingType.Simple: + bind = new IvyBindingSimple(expression); + break; + } + bus.AddBinding(id, this, bind); } catch (ArgumentException ex) { //throw new IvyException("binding expression error " + ex.Message); - stream.TokenError(7, Resources.BadExpression + " "+ ex.Message); + stream.TokenError(7, Resources.BadExpression + " "+ ex.Message); } } - void IvyProtocol.TokenDelBinding(int id) + void IvyProtocol.TokenDelBinding(int id) { - bus.DelBinding(id, this); + bus.DelBinding(id, this); } - void IvyProtocol.TokenMsg(int id, string[] args) + void IvyProtocol.TokenMsg(int id, string[] args) { - bus.OnMessage(new IvyMessageEventArgs(this, id, args)); + bus.OnMessage(new IvyMessageEventArgs(this, id, args)); } - void IvyProtocol.TokenError(int id, string arg) + void IvyProtocol.TokenError(int id, string arg) { - bus.OnError(new IvyEventArgs(this, id, arg)); + bus.OnError(new IvyEventArgs(this, id, arg)); Ivy.traceError(Resources.IvyClient,Resources.ErrorReceive + id + " " + arg); } - - void IvyProtocol.TokenEndRegexp() - { - bus.OnClientConnected(new IvyEventArgs(this, 0, string.Empty)); - /* - * the peer is perhaps not ready to handle this message - * an assymetric processing should be written - */ - SendReadyToPeer(); - } - - private void SendReadyToPeer() - { - lock (readyToSendLock) - { - readyToSend++; - if (bus.ReadyMessage != null && readyToSend == 2) - { - bus.SendMsgToClient(this, bus.ReadyMessage); - } - } - } - void IvyProtocol.TokenStartRegexp(int id, string arg) - { - //bool bindingToSend = appPort == 0; + + void IvyProtocol.TokenEndRegexp() + { + bus.OnClientConnected(new IvyEventArgs(this, 0, string.Empty)); + /* + * the peer is perhaps not ready to handle this message + * an assymetric processing should be written + */ + SendReadyToPeer(); + } + + private void SendReadyToPeer() + { + lock (readyToSendLock) + { + readyToSend++; + if (bus.ReadyMessage != null && readyToSend == 2) + { + bus.SendMsgToClient(this, bus.ReadyMessage); + } + } + } + void IvyProtocol.TokenStartRegexp(int id, string arg) + { + //bool bindingToSend = appPort == 0; appName = arg; appPort = id; - IvyClient target = this; - IvyClient client = bus.checkConnected(this); - if (client != null) - { - // Dilemma choose the rigth client to close - // the symetric processing will try to close each other - // only one side may be closed - //Console.WriteLine(" should close {0} this local {1} rem {2} other local {3} rem {4}", this.appName, this.localPort, this.remotePort, client.localPort, client.remotePort); - if (Math.Max(client.localPort, client.remotePort) > Math.Max( this.localPort, this.remotePort )) - { - target = client; - //Console.WriteLine("choose {0} other ports {1},{2}", target.appName, target.localPort, target.remotePort); - } - else - { - target = this; - //Console.WriteLine("choose {0} this ports {1},{2}", target.appName, target.remotePort, target.localPort); - } - bus.removeClient(target); - target.close(false); - //throw new IvyException(Resources.ConcurrentConnect + " " + appName + " " + clientId); - - } - //if ( bindingToSend && target != this) - // SendBindings(); - + IvyClient target = this; + IvyClient client = bus.checkConnected(this); + if (client != null) + { + // Dilemma choose the rigth client to close + // the symetric processing will try to close each other + // only one side may be closed + //Console.WriteLine(" should close {0} this local {1} rem {2} other local {3} rem {4}", this.appName, this.localPort, this.remotePort, client.localPort, client.remotePort); + if (Math.Max(client.localPort, client.remotePort) > Math.Max( this.localPort, this.remotePort )) + { + target = client; + //Console.WriteLine("choose {0} other ports {1},{2}", target.appName, target.localPort, target.remotePort); + } + else + { + target = this; + //Console.WriteLine("choose {0} this ports {1},{2}", target.appName, target.remotePort, target.localPort); + } + bus.removeClient(target); + target.close(false); + //throw new IvyException(Resources.ConcurrentConnect + " " + appName + " " + clientId); + + } + //if ( bindingToSend && target != this) + // SendBindings(); + } - void IvyProtocol.TokenDirectMsg(int id, string arg) + void IvyProtocol.TokenDirectMsg(int id, string arg) { - bus.OnDirectMessage(new IvyEventArgs(this,id,arg)); + bus.OnDirectMessage(new IvyEventArgs(this,id,arg)); } - void IvyProtocol.TokenPing(int id, string arg) + void IvyProtocol.TokenPing(int id, string arg) { // I receive a ping. I can answer a pong. Ivy.traceProtocol(Resources.IvyClient, Resources.PingReceive + appName + " : " + arg ); stream.TokenPong(id,arg); } - void IvyProtocol.TokenPong(int id, string arg) + void IvyProtocol.TokenPong(int id, string arg) { - Ivy.traceProtocol(Resources.IvyClient, Resources.PingReceive + appName + " : " + arg); + Ivy.traceProtocol(Resources.IvyClient, Resources.PingReceive + appName + " : " + arg); } - /// - /// return full Application name pair - /// + /// + /// return full Application name pair + /// public override String ToString() { return Resources.IvyClient+ " " + bus.appName + ":" + appName; @@ -621,58 +622,58 @@ namespace IvyBus try { Thread.Sleep(PINGTIMEOUT); - int id = (int)DateTime.Now.Ticks; + int id = (int)DateTime.Now.Ticks; stream.TokenPing( id, Resources.PingerThreadMessage); } catch (ThreadAbortException ie) { - Ivy.traceError(Resources.IvyClient,Resources.PingerThreadKilled + ie.Message); + Ivy.traceError(Resources.IvyClient,Resources.PingerThreadKilled + ie.Message); } } Ivy.traceProtocol(Resources.IvyClient,Resources.PingerThreadStopped); } - /// - /// stop the pinger Thread - /// + /// + /// stop the pinger Thread + /// public virtual void StopPinging() { isPinging = false; //pingerThread.Interrupt(); - pingerThread.Abort(); - } - - #region IDisposable Members - - //Implement IDisposable. - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - // Free other state (managed objects). - if (stream != null) - { - stream.Close(); - stream = null; - } - } - // Free your own state (unmanaged objects). - // Set large fields to null. - - } - - // Use C# destructor syntax for finalization code. - ~IvyClient() - { - // Simply call Dispose(false). - Dispose(false); - } - - #endregion - } + pingerThread.Abort(); + } + + #region IDisposable Members + + //Implement IDisposable. + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + // Free other state (managed objects). + if (stream != null) + { + stream.Close(); + stream = null; + } + } + // Free your own state (unmanaged objects). + // Set large fields to null. + + } + + // Use C# destructor syntax for finalization code. + ~IvyClient() + { + // Simply call Dispose(false). + Dispose(false); + } + + #endregion + } } \ No newline at end of file diff --git a/Ivy/IvyUDPStream.cs b/Ivy/IvyUDPStream.cs index 0e64381..91ef854 100644 --- a/Ivy/IvyUDPStream.cs +++ b/Ivy/IvyUDPStream.cs @@ -40,7 +40,7 @@ namespace IvyBus internal void receiveMsg(out IPEndPoint remote, out int version, out int port, out string appId, out string appName) { int len; - IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, 0); + IPEndPoint remoteEP = new IPEndPoint(socket.AddressFamily == AddressFamily.InterNetworkV6 ? IPAddress.IPv6Any : IPAddress.Any, 0); EndPoint tempRemoteEP = (EndPoint)remoteEP; remoteEP = null; len = socket.ReceiveFrom(buffer, ref tempRemoteEP); diff --git a/Ivy/IvyWatcher.cs b/Ivy/IvyWatcher.cs index 8764a28..f239b99 100644 --- a/Ivy/IvyWatcher.cs +++ b/Ivy/IvyWatcher.cs @@ -15,8 +15,8 @@ namespace IvyBus using System.Text.RegularExpressions; using System.Configuration; using System.Text; - using System.Diagnostics; - using IvyBus.Properties; + using System.Diagnostics; + using IvyBus.Properties; /// IvyWatcher, A private Class for the Ivy rendezvous /// @@ -26,13 +26,14 @@ namespace IvyBus /// that the broadcast is done using the same socket, which is not a good /// thing. /// - internal class IvyWatcher: IDisposable + internal class IvyWatcher //: IDisposable { private Ivy bus; /* master bus controler */ private int port; private volatile Thread listenThread; private IPAddress group; - private IvyUDPStream stream; + private IvyUDPStream stream; + private bool ipv6; /// creates an Ivy watcher /// @@ -42,38 +43,46 @@ namespace IvyBus /// /// the port number /// - internal IvyWatcher(Ivy bus, String domainaddr, int port) + internal IvyWatcher(Ivy bus, String domainaddr, int port, bool _ipv6) { - int multicast_ttl = 64; // region + int multicast_ttl = 64; // region this.bus = bus; this.port = port; + this.ipv6 = _ipv6; listenThread = new Thread(new ThreadStart(this.Run)); listenThread.Name = "Ivy UDP Listener Thread"; try { group = IPAddress.Parse(domainaddr); - /* supervision socket */ - // To do reuseaddr we must use a Socket not a udp client - Socket broadcast = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); - IPEndPoint EPhost = new IPEndPoint(IPAddress.Any, port); + /* supervision socket */ + // To do reuseaddr we must use a Socket not a udp client + Socket broadcast = new Socket(ipv6 ? AddressFamily.InterNetworkV6 : AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); + IPEndPoint EPhost = new IPEndPoint(ipv6 ? IPAddress.IPv6Any : IPAddress.Any, port); broadcast.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast,true); broadcast.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress,true); broadcast.Bind(EPhost); //test isMulticastAddress // TODO better check - //if ( group.IsIPv6Multicast ) //yes but in IPV4 how to do - byte[] addr = group.GetAddressBytes(); - if ((addr[0] & 0xf0) == 0xe0) - { - broadcast.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, multicast_ttl); - broadcast.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(group)); - - } - // TODO support the Two protocol - if (bus.protocolVersion == 4) - stream = new IvyUDPStreamV4(broadcast); - else - stream = new IvyUDPStreamV3(broadcast); + if (group.IsIPv6Multicast) //IPV6 multicast + { + broadcast.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.MulticastTimeToLive, multicast_ttl); + broadcast.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.AddMembership, new IPv6MulticastOption(group)); + } + else + { + byte[] addr = group.GetAddressBytes();//yes but in IPV4 how to do better + if ((addr[0] & 0xf0) == 0xe0) + { + broadcast.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, multicast_ttl); + broadcast.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(group)); + + } + } + // TODO support the Two protocol + if (bus.protocolVersion == 4) + stream = new IvyUDPStreamV4(broadcast); + else + stream = new IvyUDPStreamV3(broadcast); } catch (IOException e) { @@ -82,95 +91,95 @@ namespace IvyBus } /// - /// the behaviour of each thread watching the UDP socket. + /// the behaviour of each thread watching the UDP socket. /// private void Run() { - Ivy.traceProtocol(Resources.IvyWatcher, "beginning of a watcher Thread"); - - try - { - bool running = true; - while (running) - { - int version; - int appPort; - string appId; - string appName; - IPEndPoint remoteEP; - - stream.receiveMsg(out remoteEP, out version, out appPort, out appId, out appName); - IPAddress remotehost = remoteEP.Address; - - Ivy.traceProtocol(Resources.IvyWatcher, Resources.WatcherReceive + Dns.GetHostEntry(remotehost).HostName + ":" + remoteEP.Port); - - //TODO if ( !isInDomain( remotehost ) ) continue; - - if (version != stream.ProtocolVersion) - { - Ivy.traceError(Resources.IvyWatcher, Resources.BadVersion + version + " expected " + stream.ProtocolVersion); - continue; - } - - /* check if we received our own message. SHOULD ALSO TEST THE HOST */ - if (appId == bus.AppId) - continue; - if ((appPort == bus.applicationPort) && (remotehost.Equals(bus.applicationHost))) - continue; - - Ivy.traceProtocol(Resources.IvyWatcher, "reponse au Broadcast de " + Dns.GetHostEntry(remotehost).HostName + ":" + remoteEP.Port + " port " + appPort + - " version " + version + - " id " + appId + - " name " + appName); - - try - { - Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); - IPEndPoint hostEndPoint = new IPEndPoint(remoteEP.Address, appPort); - socket.Blocking = true; - socket.Connect(hostEndPoint); - IvyClient client = new IvyClient(this.bus, socket, appName, appPort); - client.SendBindings(); - } - catch (SocketException e) - { - Ivy.traceError(Resources.IvyWatcher, Resources.WatcherConnectError + remotehost + " port " + appPort + " \n" + e.Message); - } + Ivy.traceProtocol(Resources.IvyWatcher, "beginning of a watcher Thread"); - } // while - } - catch (ObjectDisposedException ex) - { - Ivy.traceError(Resources.IvyWatcher, Resources.WatcherSocketClosed + ex.Message); - } - catch (SocketException se) - { - Ivy.traceError(Resources.IvyWatcher, Resources.WatcherSocketClosed + se.Message); - } - catch (IOException ioe) - { - Ivy.traceError(Resources.IvyWatcher, Resources.WatcherIOException + ioe.Message); - } - Ivy.traceProtocol(Resources.IvyWatcher, "end of a watcher thread"); + try + { + bool running = true; + while (running) + { + int version; + int appPort; + string appId; + string appName; + IPEndPoint remoteEP; + + stream.receiveMsg(out remoteEP, out version, out appPort, out appId, out appName); + IPAddress remotehost = remoteEP.Address; + + Ivy.traceProtocol(Resources.IvyWatcher, Resources.WatcherReceive + Dns.GetHostEntry(remotehost).HostName + ":" + remoteEP.Port); + + //TODO if ( !isInDomain( remotehost ) ) continue; + + if (version != stream.ProtocolVersion) + { + Ivy.traceError(Resources.IvyWatcher, Resources.BadVersion + version + " expected " + stream.ProtocolVersion); + continue; + } + + /* check if we received our own message. SHOULD ALSO TEST THE HOST */ + if (appId == bus.AppId) + continue; + if ((appPort == bus.applicationPort) && (remotehost.Equals(bus.applicationHost))) + continue; + + Ivy.traceProtocol(Resources.IvyWatcher, "reponse au Broadcast de " + Dns.GetHostEntry(remotehost).HostName + ":" + remoteEP.Port + " port " + appPort + + " version " + version + + " id " + appId + + " name " + appName); + + try + { + Socket socket = new Socket(ipv6 ? AddressFamily.InterNetworkV6 : AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + IPEndPoint hostEndPoint = new IPEndPoint(remoteEP.Address, appPort); + socket.Blocking = true; + socket.Connect(hostEndPoint); + IvyClient client = new IvyClient(this.bus, socket, appName, appPort); + client.SendBindings(); + } + catch (SocketException e) + { + Ivy.traceError(Resources.IvyWatcher, Resources.WatcherConnectError + remotehost + " port " + appPort + " \n" + e.Message); + } + + } // while + } + catch (ObjectDisposedException ex) + { + Ivy.traceError(Resources.IvyWatcher, Resources.WatcherSocketClosed + ex.Message); + } + catch (SocketException se) + { + Ivy.traceError(Resources.IvyWatcher, Resources.WatcherSocketClosed + se.Message); + } + catch (IOException ioe) + { + Ivy.traceError(Resources.IvyWatcher, Resources.WatcherIOException + ioe.Message); + } + Ivy.traceProtocol(Resources.IvyWatcher, "end of a watcher thread"); } /// stops the thread waiting on the broadcast socket /// internal virtual void stop() { - lock (stream) + lock (stream) { - Ivy.traceProtocol(Resources.IvyWatcher, "begining stopping an IvyWatcher"); + Ivy.traceProtocol(Resources.IvyWatcher, "begining stopping an IvyWatcher"); stream.Close(); if (listenThread != null) { - // Wait for Thread to end. - bool term = listenThread.Join(10000); - if (!term && (listenThread != null)) listenThread.Abort(); + // Wait for Thread to end. + bool term = listenThread.Join(10000); + if (!term && (listenThread != null)) listenThread.Abort(); listenThread = null; } // it might not even have been created - Ivy.traceProtocol(Resources.IvyWatcher, "ending stopping an IvyWatcher"); + Ivy.traceProtocol(Resources.IvyWatcher, "ending stopping an IvyWatcher"); } } /// @@ -178,39 +187,39 @@ namespace IvyBus /// internal virtual void start() { - lock (stream) + lock (stream) { listenThread.Start(); - IPEndPoint EPhost = new IPEndPoint(group, port); - stream.sendMsg(EPhost, bus.applicationPort, bus.AppId, bus.AppName);// notifies our arrival on each domain: protocol version + port + IPEndPoint EPhost = new IPEndPoint(group, port); + stream.sendMsg(EPhost, bus.applicationPort, bus.AppId, bus.AppName);// notifies our arrival on each domain: protocol version + port } } - - - #region IDisposable Membres - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - // Free other state (managed objects). - if (stream != null) - { - stream.Close(); - stream = null; - } - } - // Free your own state (unmanaged objects). - // Set large fields to null. - - } - - #endregion - } + // Not needed for pure managed object ??!!! + + //#region IDisposable Membres + + //public void Dispose() + //{ + // Dispose(true); + // GC.SuppressFinalize(this); + //} + + //protected virtual void Dispose(bool disposing) + //{ + // if (disposing) + // { + // // Free other state (managed objects). + // if (stream != null) + // { + // stream.Close(); + // stream = null; + // } + // } + // // Free your own state (unmanaged objects). + // // Set large fields to null. + + //} + + //#endregion + } } \ No newline at end of file diff --git a/Ivy/app.config b/Ivy/app.config index 0df9489..0237982 100644 --- a/Ivy/app.config +++ b/Ivy/app.config @@ -7,24 +7,24 @@ - - 3 - - - False - - - False - - - - - - - - - - - + + 3 + + + False + + + False + + + + + + + + + + + diff --git a/IvyControl/IvyControl.cs b/IvyControl/IvyControl.cs index 20b43be..47dfd8c 100644 --- a/IvyControl/IvyControl.cs +++ b/IvyControl/IvyControl.cs @@ -183,7 +183,18 @@ namespace IvyBus } - +#if (!PocketPC) + [Category("Ivy")] +#endif + public bool IpV6 + { + get + { + return ivy.IpV6; + } + + } + /// AppName the application name #if (!PocketPC) diff --git a/IvyControl/IvyDomain.Designer.cs b/IvyControl/IvyDomain.Designer.cs index 3f89b6a..d66db15 100644 --- a/IvyControl/IvyDomain.Designer.cs +++ b/IvyControl/IvyDomain.Designer.cs @@ -28,8 +28,11 @@ namespace IvyBus /// private void InitializeComponent() { + this.components = new System.ComponentModel.Container(); this.label1 = new System.Windows.Forms.Label(); this.ivybus = new System.Windows.Forms.TextBox(); + this.errorProvider1 = new System.Windows.Forms.ErrorProvider(this.components); + ((System.ComponentModel.ISupportInitialize)(this.errorProvider1)).BeginInit(); this.SuspendLayout(); // // label1 @@ -39,6 +42,7 @@ namespace IvyBus this.label1.Location = new System.Drawing.Point(0, 5); this.label1.Name = "label1"; this.label1.Size = new System.Drawing.Size(24, 13); + this.label1.TabIndex = 0; this.label1.Text = "Ivy:"; // // ivybus @@ -50,8 +54,13 @@ namespace IvyBus this.ivybus.Name = "ivybus"; this.ivybus.Size = new System.Drawing.Size(129, 20); this.ivybus.TabIndex = 2; - this.ivybus.Validated += new System.EventHandler(this.ivybus_Validated); this.ivybus.Validating += new System.ComponentModel.CancelEventHandler(this.ivybus_Validating); + this.ivybus.Validated += new System.EventHandler(this.ivybus_Validated); + // + // errorProvider1 + // + this.errorProvider1.BlinkStyle = System.Windows.Forms.ErrorBlinkStyle.AlwaysBlink; + this.errorProvider1.ContainerControl = this; // // IvyDomain // @@ -60,10 +69,9 @@ namespace IvyBus this.Controls.Add(this.ivybus); this.Name = "IvyDomain"; this.Size = new System.Drawing.Size(159, 22); + ((System.ComponentModel.ISupportInitialize)(this.errorProvider1)).EndInit(); this.ResumeLayout(false); -#if (!PocketPC) - this.PerformLayout(); -#endif + this.PerformLayout(); } @@ -71,5 +79,6 @@ namespace IvyBus private System.Windows.Forms.Label label1; private System.Windows.Forms.TextBox ivybus; + private System.Windows.Forms.ErrorProvider errorProvider1; } } diff --git a/IvyControl/IvyDomain.cs b/IvyControl/IvyDomain.cs index 36e749a..92b7dbd 100644 --- a/IvyControl/IvyDomain.cs +++ b/IvyControl/IvyDomain.cs @@ -49,10 +49,12 @@ namespace IvyBus private void ivybus_Validating(object sender, CancelEventArgs e) { e.Cancel = !Ivy.ValidatingDomain(ivybus.Text); + errorProvider1.SetError(this.ivybus, e.Cancel ? "Bad Address":"" ); } private void ivybus_Validated(object sender, EventArgs e) { + errorProvider1.SetError(this.ivybus, ""); if ( domain != ivybus.Text ) Domain = ivybus.Text; } diff --git a/IvyControl/IvyDomain.resx b/IvyControl/IvyDomain.resx index ff31a6d..e8675cd 100644 --- a/IvyControl/IvyDomain.resx +++ b/IvyControl/IvyDomain.resx @@ -117,4 +117,7 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + 17, 17 + \ No newline at end of file diff --git a/IvyDaemon/IvyDaemon.cs b/IvyDaemon/IvyDaemon.cs index 3924df2..9ec2cea 100644 --- a/IvyDaemon/IvyDaemon.cs +++ b/IvyDaemon/IvyDaemon.cs @@ -11,7 +11,7 @@ namespace IvyDaemon using System.Net; using System.Net.Sockets; using System.Configuration; - using System.Diagnostics; + using System.Diagnostics; using IvyBus; /// IvyDaemon: simple TCP to Ivy relay. /// @@ -25,7 +25,7 @@ namespace IvyDaemon private TcpListener serviceSocket; - private static bool debug = Properties.Settings.Default.IvyDebug; + private static bool debug = Properties.Settings.Default.IvyDebug; private volatile Thread clientThread; // volatile to ensure the quick communication private Ivy bus; @@ -161,7 +161,7 @@ namespace IvyDaemon } [Conditional("DEBUG")] - private static void traceDebug(string s) + private static void traceDebug(string s) { Trace.WriteLineIf(debug, "-->IvyDaemon<-- " + s); } diff --git a/IvyProbe/IvyProbe.Designer.cs b/IvyProbe/IvyProbe.Designer.cs index af5222a..b723029 100644 --- a/IvyProbe/IvyProbe.Designer.cs +++ b/IvyProbe/IvyProbe.Designer.cs @@ -136,6 +136,7 @@ namespace IvyProbe // // busDomain // + this.busDomain.Domain = "FF02::1:2011"; this.busDomain.Location = new System.Drawing.Point(0, 0); this.busDomain.Margin = new System.Windows.Forms.Padding(0); this.busDomain.Name = "busDomain"; @@ -149,20 +150,20 @@ namespace IvyProbe this.bus.Bindings.Add(this.ivyApplicationBinding1); this.bus.Culture = new System.Globalization.CultureInfo("en-US"); this.bus.ReadyMessage = "IvyProbeC# ready"; - this.bus.BindingFilter += new System.EventHandler(this.bus_BindingFilter); - this.bus.ErrorMessage += new System.EventHandler(this.bus_ErrorMessage); - this.bus.DirectMessageReceived += new System.EventHandler(this.directMessage); - this.bus.BindingAdd += new System.EventHandler(this.bus_addBinding); this.bus.ClientConnected += new System.EventHandler(this.connect); this.bus.ClientDisconnected += new System.EventHandler(this.disconnect); - this.bus.BindingRemove += new System.EventHandler(this.bus_removeBinding); + this.bus.DirectMessageReceived += new System.EventHandler(this.directMessage); this.bus.DieReceived += new System.EventHandler(this.die); + this.bus.BindingAdd += new System.EventHandler(this.bus_addBinding); + this.bus.BindingRemove += new System.EventHandler(this.bus_removeBinding); + this.bus.BindingFilter += new System.EventHandler(this.bus_BindingFilter); + this.bus.ErrorMessage += new System.EventHandler(this.bus_ErrorMessage); // // ivyApplicationBinding1 // this.ivyApplicationBinding1.Arguments.Add("Name"); this.ivyApplicationBinding1.Binding = IvyBus.BindingType.RegularExpression; - this.ivyApplicationBinding1.Expression = "^%0%(.*)"; + this.ivyApplicationBinding1.Expression = "(^%0%.*)"; this.ivyApplicationBinding1.Callback += new System.EventHandler(this.ivyprobe); // // IvyProbe @@ -179,10 +180,9 @@ namespace IvyProbe this.Controls.Add(this.tbRegexp); this.Controls.Add(this.label2); this.Controls.Add(this.label1); - //this.DoubleBuffered = true; this.Name = "IvyProbe"; this.Text = "IvyProbe"; - this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.IvyProbe_FormClosed); + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.IvyProbe_FormClosing); this.Load += new System.EventHandler(this.IvyProbe_Load); ((System.ComponentModel.ISupportInitialize)(this.bus)).EndInit(); this.ResumeLayout(false); diff --git a/IvyProbe/IvyProbe.cs b/IvyProbe/IvyProbe.cs index 270dbd8..a066447 100644 --- a/IvyProbe/IvyProbe.cs +++ b/IvyProbe/IvyProbe.cs @@ -152,11 +152,6 @@ namespace IvyProbe bus.ivy.Start(busDomain.Domain); } - private void IvyProbe_FormClosed(object sender, FormClosedEventArgs e) - { - bus.ivy.Stop(); - } - private void IvyProbe_Load(object sender, EventArgs e) { bus.ivy.Start(busDomain.Domain); @@ -168,6 +163,12 @@ namespace IvyProbe receive(sender, e); } + private void IvyProbe_FormClosing(object sender, FormClosingEventArgs e) + { + bus.ivy.Stop(); + e.Cancel = false; + } + } } \ No newline at end of file diff --git a/IvyProbe/Properties/Settings.Designer.cs b/IvyProbe/Properties/Settings.Designer.cs index b907809..c5ef330 100644 --- a/IvyProbe/Properties/Settings.Designer.cs +++ b/IvyProbe/Properties/Settings.Designer.cs @@ -25,7 +25,7 @@ namespace IvyProbe.Properties { [global::System.Configuration.ApplicationScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("")] + [global::System.Configuration.DefaultSettingValueAttribute("ff05::1")] public string IvyBus { get { return ((string)(this["IvyBus"])); diff --git a/IvyProbe/Properties/Settings.settings b/IvyProbe/Properties/Settings.settings index 421d8f2..44eacd4 100644 --- a/IvyProbe/Properties/Settings.settings +++ b/IvyProbe/Properties/Settings.settings @@ -3,7 +3,7 @@ - + ff05::1 \ No newline at end of file diff --git a/IvyProbe/app.config b/IvyProbe/app.config index e9c8b0c..a4b7d37 100644 --- a/IvyProbe/app.config +++ b/IvyProbe/app.config @@ -8,7 +8,7 @@ - + ff05::1 -- cgit v1.1