From 92757a8d629812303ff3665343bd098917cca611 Mon Sep 17 00:00:00 2001 From: fcolin Date: Thu, 1 Feb 2007 12:04:16 +0000 Subject: modification structure svn --- Ivy/Ivy.cs | 1183 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1183 insertions(+) create mode 100644 Ivy/Ivy.cs (limited to 'Ivy/Ivy.cs') diff --git a/Ivy/Ivy.cs b/Ivy/Ivy.cs new file mode 100644 index 0000000..1c38396 --- /dev/null +++ b/Ivy/Ivy.cs @@ -0,0 +1,1183 @@ +/// François-Régis Colin +/// http://www.tls.cena.fr/products/ivy/ +/// * +/// (C) CENA +/// * +/// + +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.ComponentModel; + using System.Diagnostics; + +#if (!PocketPC) + using System.ComponentModel.Design; +#endif +// using System.Drawing.Design; + + + /// The Main bus Class + /// + /// +#if (!PocketPC) + // Show this property in the property grid. + [ToolboxItemFilter("System.Windows.Forms.Form", ToolboxItemFilterType.Allow)] + [Description("IVY Main API")] +#endif + [DesignerCategory("Component")] + public class Ivy : System.ComponentModel.Component, ISupportInitialize + { + /* Event */ + /// fires when a new client connect to the bus + public event EventHandler ClientConnected; + /// fires when a client discconnect from the bus + public event EventHandler ClientDisconnected; + /// fires when a client receive a direct message from another client + public event EventHandler DirectMessageReceived; + /// fires when somebody ask for killing every client on the bus + public event EventHandler DieReceived; + /// fires when a client receive a add binding from another client + public event EventHandler BindingAdd; + /// fires when a client receive a remove binding from another client + public event EventHandler BindingRemove; + /// fires when a client receive a binding from another client and it as been filtered + public event EventHandler BindingFilter; + /// fires when a client receive a remove binding from another client + public event EventHandler ErrorMessage; + +#if (!PocketPC) + [Bindable(true)] + [Category("Ivy")] +#endif + [DefaultValue(false)] + public static bool DebugProtocol + { + get + { + return debugProtocol; + } + set + { + debugProtocol = value; + } + + } +#if (!PocketPC) + [Category("Ivy")] +#endif + public CultureInfo Culture + { + get + { + return culture; + } + set + { + culture = value; + } + + } + + /// IvyClients accesses the list of the connected clients +#if (!PocketPC) + [Browsable(false)] +#endif + public List IvyClients + { + get + { + return clients; + } + + } + + /// AppName the application name + +#if (!PocketPC) + [Category("Ivy")] + [Bindable(true)] +#endif + [DefaultValue(null)] + public string AppName + { + set + { + appName = value; + } + get + { + return appName; + } + + } + /// AppId the Application Unique ID + +#if (!PocketPC) + [Browsable(false)] +#endif + public string AppId + { + get + { + return applicationUniqueId; + } + + } + /// AppPriority the Application Priority: the clients list is sorted against priority +#if (!PocketPC) + [Category("Ivy")] +#endif + [DefaultValue(DEFAULT_PRIORITY)] + public ushort AppPriority + { + set + { + applicationPriority = value; + lock (clients) + { + foreach (IvyClient client in clients) + { + client.stream.TokenApplicationId(applicationPriority, AppId); + } + } + + } + get + { + return applicationPriority; + } + + } + +#if (!PocketPC) + [Browsable(false)] +#endif + public int ProtocolVersion + { + get + { + return protocolVersion; + } + + } + + /// IsRunning is the bus Started and connected ? + +#if (!PocketPC) + [Browsable(false)] +#endif + public bool IsRunning + { + get + { + return !stopped; + } + + } + ///SentMessageClasses the first word token of sent messages + /// optimise the parsing process when sending messages + /// +#if (!PocketPC) + [Category("Ivy")] + + [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] + // sinon bug System.String constructor not found ! + [Editor("System.Windows.Forms.Design.StringCollectionEditor, System.Design", "System.Drawing.Design.UITypeEditor, System.Drawing")] +#endif + public List SentMessageFilter + { + get + { + return sent_messageFilter; + } + } + /// ReadyMessage message send when Application receive all the regexp at the connection of the client + +#if (!PocketPC) + [Bindable(true)] + [Category("Ivy")] +#endif + [DefaultValue(null)] + public string ReadyMessage + { + get { return ready_message; } + set { ready_message = value; } + } + + + + +#if (PocketPC) +#if (!PocketPC) + [Category("Ivy")] +#endif + [DefaultValue(null)] + public System.Windows.Forms.ContainerControl ContainerControl + { + get { return parentControl; } + set + { + parentControl = value; + } + } +#endif +#if (!PocketPC) + [Category("Ivy")] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] +#endif + public List Bindings + { + get { return app_bindings; } + } + + 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 DEFAULT_PORT = 2010; + // client default priority + internal const ushort DEFAULT_PRIORITY = 100; + /// the domain for the UDP rendez vous + private static readonly string DEFAULT_DOMAIN = "127.255.255.255:" + DEFAULT_PORT; + internal int protocolVersion = 3; + private static bool debugProtocol; // false by default runtime + private static ushort serial; /* an unique ID for each regexp */ // 0 by default runtime + private MyTcpListener app; + private List watchers; + private volatile Thread serverThread; // to ensure quick communication of the end + + internal Dictionary bindings; + //TODO should be remove samve as above + private List app_bindings; + private List clients; + private List sent_messageFilter; + private bool stopped = true; + internal ushort applicationPort; /* Application port number */ + internal IPAddress applicationHost; /* Application host number */ + internal string applicationUniqueId; /* identifier Application unique timestamp-ipaddress-port */ + internal ushort applicationPriority = DEFAULT_PRIORITY; + private string ready_message; + private CultureInfo culture = new CultureInfo("en-us"); + // for synchronous event +#if (PocketPC) + private System.Windows.Forms.ContainerControl parentControl; +#else + private readonly SynchronizationContext syncContext; +#endif + + + /// + /// Initializes a new instance of the class. + /// + public Ivy() + { +#if (!PocketPC) + syncContext = SynchronizationContext.Current; +#endif + clients = new List(); + bindings = new Dictionary(); + app_bindings = new List(); + sent_messageFilter = new List(); +#if (!PocketPC) + debugProtocol = Properties.Settings.Default.IvyDebug; + protocolVersion = Properties.Settings.Default.IvyProtocolVersion; +#endif + // get binding from Attribute IvyBinding + //TODO Autobinding attribute +#if (PocketPC) + if (parentControl != null) + BindAttibute(parentControl); +#endif + Assembly assembly = Assembly.GetCallingAssembly(); + if ( assembly != this.GetType().Assembly ) + BindAttibute(assembly); + } + public Ivy(IContainer container) + : this() + { + container.Add(this); + // get binding from Attribute IvyBinding + //TODO Autobinding attribute + Assembly assembly = Assembly.GetCallingAssembly(); + if (assembly != this.GetType().Assembly) + BindAttibute(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 rdy_message) + : this() + { + appName = name; + ready_message = rdy_message; + // get binding from Attribute IvyBinding + //TODO Autobinding attribute + Assembly assembly = Assembly.GetCallingAssembly(); + if (assembly != this.GetType().Assembly) + BindAttibute(assembly); + } + + protected override void Dispose(bool disposing) + { + try + { + if (disposing) + { + Stop(); + } + } + finally + { + base.Dispose(disposing); + } + } + + // Autobinding on static method + public void BindAttibute(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.GetExpression(null) + "' to Method " + m.Name); + EventHandler handler; +#if (PocketPC) + //Createdelegate mydlg = new Createdelegate(m, null, EventArgs.Empty); + //bindMsg(attr.GetExpression(null), mydlg); + handler = null; +#else + handler = (EventHandler)Delegate.CreateDelegate(typeof(EventHandler), m); +#endif + BindMsg(attr.GetExpression(null), handler); + } + } + } + // Autobinding on instance method + public void BindAttibute(object obj) + { + if (obj == null) return; + Type type = obj.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("Ivy", "BindAttibute " + attr.GetExpression(obj) + "' to Method " + m.Name); + EventHandler handler; +#if (PocketPC) + handler = null; // TODO +#else + handler = (EventHandler)Delegate.CreateDelegate(typeof(EventHandler), obj, m); +#endif + BindMsg(attr.GetExpression(obj), handler); + } + } + + } + // Autobinding on IvyBindingAttribute method + public void BindAttibute(Assembly assy) + { + foreach (Type typ in assy.GetTypes()) + { + BindAttibute(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 = GetLocalIP(); + applicationPort = (ushort)((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(); + + 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.Run)); + serverThread.Name = "Ivy Tcp Server Thread"; + stopped = false; + serverThread.Start(); + +#if (PocketPC ) + Ivy.traceProtocol("Ivy", "Threading start in progress..."); + Thread.Sleep(100); +#else + // Wait for readyness + while ( serverThread.ThreadState != System.Threading.ThreadState.Running || !app.IsActive()) + { + Ivy.traceError("BindAttibute", " Ivy Threading start in progress..." ); + Thread.Sleep( 100 ); + } +#endif + // 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(); + } + } + /* a small private method for debbugging purposes */ + + public static string Domains(string toparse) + { + string domainbus = GetDomain(toparse); + StringBuilder s = new StringBuilder("broadcasting on "); + Ivy.Domain[] d = parseDomains(domainbus); + for (int index = 0; index < d.Length; index++) + { + s.Append(d[index].Domainaddr); + s.Append(":"); + s.Append(d[index].Port); + s.Append(" "); + } + return s.ToString(); + } + + 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("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; + copyClient = new IvyClient[clients.Count]; + lock (clients) + { + clients.CopyTo(copyClient, 0); + } + 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("Ivy", "IOexception Stop " + e.Message); + } + Ivy.traceProtocol("Ivy", "the bus should have stopped so far"); + } + } + + + /// + /// 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) + { + string msg = string.Format(culture, format, args); + int count = 0; + // an alternate implementation would one sender thread per client + // instead of one for all the clients. It might be a performance issue + lock (clients) + { + // hash message in V4 protocol only + if (ProtocolVersion == 4) + IvyBindingSimple.Prepare(msg); + foreach (IvyClient client in clients) + { + count += client.sendMsg(msg); + } + } + return count; + } + // + public ushort BindMsg(IvyApplicationBinding newbind) + { + newbind.Key = serial++; + + lock (bindings) bindings.Add(newbind.Key, newbind); + // notifies the other clients this new regexp + lock (clients) + { + foreach (IvyClient c in clients) + { + c.stream.TokenAddBinding(newbind.Binding, newbind.Key, newbind.FormatedExpression); + } + } + return newbind.Key; + } + /// + /// Subscribes to a regular expression. + /// + /// a regular expression, groups are done with parenthesis + /// any objects implementing the Ivy.MessageListener + /// 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. + /// + // + public ushort BindMsg(string regexp, EventHandler callback, params object[] args) + { + // creates a new binding (regexp,callback) + IvyApplicationBinding newbind; + newbind = new IvyApplicationBinding(); + newbind.Binding = BindingType.Regexp; + newbind.Expression = regexp; + newbind.Callback += callback; + newbind.Args = args; + return BindMsg(newbind); + } + + /// + /// unsubscribes a regular expression + /// + /// the id of the regular expression, returned when it was bound + public void UnbindMsg(ushort id) + { + if (!bindings.ContainsKey(id)) + { + throw new IvyException("client wants to remove an unexistant regexp " + id); + } + lock (clients) + { + foreach (IvyClient c in clients) + { + c.stream.TokenDelBinding(id); + } + } + lock (bindings) bindings.Remove(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(); + newbind.Binding = BindingType.Simple; + newbind.Expression = expression; + newbind.Callback += callback; + newbind.Args = args; + return BindMsg(newbind); + } + /// + /// Dies the specified target. + /// + /// The target. + /// The reason message. + /// + public int Die(string target, string message) + { + List v = GetClientsByName(target); + for (int i = 0; i < v.Count; i++) + v[i].stream.TokenDie(0, message); + return v.Count; + } + /// + /// Pings the specified target. + /// + /// The target. + /// The message. + /// + public int Ping(string target, string message) + { + List v = GetClientsByName(target); + for (int i = 0; i < v.Count; i++) + v[i].stream.TokenPing(message); + return v.Count; + } +#if (PocketPC) + internal virtual void FireEvent(EventHandler ev, IvyEventArgs e) + { + if (ev != null) + { + if (parentControl != null) + { + parentControl.Invoke(ev, this, e); + } + else + ev(this, e); + } + } +#else + internal virtual void FireEvent(EventHandler ev, IvyEventArgs e) + { + if (ev != null) + { + if (syncContext != null) + { + SendOrPostCallback update = delegate(object state) + { + IvyEventArgs args = (IvyEventArgs)state; + ev(this, args); + }; + syncContext.Post(update, e); + } + else + ev(this, e); + } + } + +#endif + 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 ex) + { + // 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 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); + } + } + +#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); + } + } +#endif + internal void OnMessage(IvyMessageEventArgs e) + { + IvyApplicationBinding bind = bindings[e.Id]; + + if (bind == null) + { + throw new IvyException("(callCallback) Not regexp matching id " + e.Id); + } +#if(PocketPC) + bind.Firevent(parentControl, e); +#else + bind.Firevent(syncContext, e); +#endif + } + + /* + * removes a client from the list + */ + internal void removeClient(IvyClient c) + { + lock (clients) + { + clients.Remove(c); + } + } + + + /// + /// gives a list of IvyClient(s) with the name given in parameter + /// + /// The name of the Ivy agent you're looking for + /// + public List GetClientsByName(string name) + { + List v = new List(); + foreach (IvyClient ic in clients) + { + if (ic.ApplicationName.CompareTo(name) == 0) + v.Add(ic); + } + return v; + } + + /////////////////////////////////////////////////////////////////: + // + // Protected methods + // + /////////////////////////////////////////////////////////////////: + + internal void addClient(Socket socket, string appname) + { + if (stopped) + return; + IvyClient client = new IvyClient(this, socket, appname); + lock (clients) + { + clients.Add(client); + } + client.SendBindings(); + } + + + public static IPAddress GetLocalIP() + { + 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; + } + + 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); + } +#else + if (domainbus == null || domainbus.Length == 0 ) + { + domainbus = Environment.GetEnvironmentVariable("IVYBUS"); + } + + if (domainbus == null || domainbus.Length == 0) + { + domainbus = Properties.Settings.Default.IvyBus; + } +#endif + if (domainbus == null || domainbus.Length == 0) + domainbus = DEFAULT_DOMAIN; + 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. + */ + //TODO bug multiple instance Reco car en 127.0.0.1 + internal bool checkConnected(IvyClient clnt) + { + if (clnt.AppPort == 0) + return false; + lock (clients) + { + foreach (IvyClient client in clients) + { + if (clnt != client && client.sameClient(clnt)) + return true; + } + } + return false; + } + + /* + * the service socket thread reader main loop + */ + private void Run() + { + Ivy.traceProtocol("Ivy", "Ivy service Thread started"); + bool running = true; + while (running) + { + try + { + Socket socket = app.AcceptSocket(); + if (stopped) + break; + // early disconnexion + addClient(socket, "Unkown(waiting for name reception)"); // the peer called me + } + catch (IOException e) + { + Ivy.traceError("Ivy","Ivy server socket reader caught an exception: " + e.Message); + } + catch (SocketException e) + { + Ivy.traceError("Ivy","my server socket has been closed " + e.Message); + running = false; + } + } + Ivy.traceProtocol("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; + } + + } + public virtual int Port + { + get + { + return port; + } + + } + private string domainaddr; + private int port; + public Domain(string net) + { + this.domainaddr = getDomain(net); + this.port = 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 + { + net += ".255.255.255"; + Regex exp = new Regex("^(\\d+\\.\\d+\\.\\d+\\.\\d+).*"); + net = exp.Replace(net, "$1"); + } + catch (ArgumentException e) + { + Ivy.traceError("Ivy","Bad broascat addr " + net + "error " + e.Message); + return null; + } + return net; + } + + public static int getPort(string net) + { + if (net == null) return Ivy.DEFAULT_PORT; + int sep_index = net.LastIndexOf(":"); + int port = (sep_index == -1) ? Ivy.DEFAULT_PORT : Int32.Parse(net.Substring(sep_index + 1)); + return port; + } + } + + + public static bool ValidatingDomain(string p) + { + // domain if of the form ip1[:port][,ip2[:port]] with ip of the form n1.n2.n3.n4 + return Regex.IsMatch(p, @"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+"); + } + + #region ISupportInitialize Members + + public void BeginInit() + { + + } + + public void EndInit() + { + // TODO ugly should be added directly the bindings Dictionary ! + foreach (IvyApplicationBinding bind in app_bindings) + { + BindMsg(bind); + } + } + + #endregion + + } +} \ No newline at end of file -- cgit v1.1