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 ++++++++++++++++++++++++++ Ivy/Ivy.csproj | 189 ++++ Ivy/Ivy.csproj.vspscc | 10 + Ivy/Ivy.snippet | 43 + Ivy/IvyApplicationBinding.cs | 186 ++++ Ivy/IvyBinding.cs | 118 +++ Ivy/IvyBindingAttribute.cs | 31 + Ivy/IvyClient.cs | 592 +++++++++++++ Ivy/IvyDomain.Designer.cs | 75 ++ Ivy/IvyDomain.cs | 60 ++ Ivy/IvyDomain.resx | 120 +++ Ivy/IvyEventArgs.cs | 84 ++ Ivy/IvyException.cs | 19 + Ivy/IvyProtocol.cs | 25 + Ivy/IvyTCPStream.cs | 20 + Ivy/IvyTCPStreamV3.cs | 254 ++++++ Ivy/IvyTCPStreamV4.cs | 273 ++++++ Ivy/IvyUDPStream.cs | 66 ++ Ivy/IvyUDPStreamV3.cs | 104 +++ Ivy/IvyUDPStreamV4.cs | 80 ++ Ivy/IvyWatcher.cs | 179 ++++ Ivy/Properties/AssemblyInfo.cs | 62 ++ Ivy/Properties/Settings.Designer.cs | 80 ++ Ivy/Properties/Settings.settings | 24 + Ivy/Settings.cs | 28 + Ivy/app.config | 30 + IvyToDel/Ivy/Ivy.cs | 1183 -------------------------- IvyToDel/Ivy/Ivy.csproj | 189 ---- IvyToDel/Ivy/Ivy.csproj.vspscc | 10 - IvyToDel/Ivy/Ivy.snippet | 43 - IvyToDel/Ivy/IvyApplicationBinding.cs | 186 ---- IvyToDel/Ivy/IvyBinding.cs | 118 --- IvyToDel/Ivy/IvyBindingAttribute.cs | 31 - IvyToDel/Ivy/IvyClient.cs | 592 ------------- IvyToDel/Ivy/IvyDomain.Designer.cs | 75 -- IvyToDel/Ivy/IvyDomain.cs | 60 -- IvyToDel/Ivy/IvyDomain.resx | 120 --- IvyToDel/Ivy/IvyEventArgs.cs | 84 -- IvyToDel/Ivy/IvyException.cs | 19 - IvyToDel/Ivy/IvyProtocol.cs | 25 - IvyToDel/Ivy/IvyTCPStream.cs | 20 - IvyToDel/Ivy/IvyTCPStreamV3.cs | 254 ------ IvyToDel/Ivy/IvyTCPStreamV4.cs | 273 ------ IvyToDel/Ivy/IvyUDPStream.cs | 66 -- IvyToDel/Ivy/IvyUDPStreamV3.cs | 104 --- IvyToDel/Ivy/IvyUDPStreamV4.cs | 80 -- IvyToDel/Ivy/IvyWatcher.cs | 179 ---- IvyToDel/Ivy/Properties/AssemblyInfo.cs | 62 -- IvyToDel/Ivy/Properties/Settings.Designer.cs | 80 -- IvyToDel/Ivy/Properties/Settings.settings | 24 - IvyToDel/Ivy/Settings.cs | 28 - IvyToDel/Ivy/app.config | 30 - 52 files changed, 3935 insertions(+), 3935 deletions(-) create mode 100644 Ivy/Ivy.cs create mode 100644 Ivy/Ivy.csproj create mode 100644 Ivy/Ivy.csproj.vspscc create mode 100644 Ivy/Ivy.snippet create mode 100644 Ivy/IvyApplicationBinding.cs create mode 100644 Ivy/IvyBinding.cs create mode 100644 Ivy/IvyBindingAttribute.cs create mode 100644 Ivy/IvyClient.cs create mode 100644 Ivy/IvyDomain.Designer.cs create mode 100644 Ivy/IvyDomain.cs create mode 100644 Ivy/IvyDomain.resx create mode 100644 Ivy/IvyEventArgs.cs create mode 100644 Ivy/IvyException.cs create mode 100644 Ivy/IvyProtocol.cs create mode 100644 Ivy/IvyTCPStream.cs create mode 100644 Ivy/IvyTCPStreamV3.cs create mode 100644 Ivy/IvyTCPStreamV4.cs create mode 100644 Ivy/IvyUDPStream.cs create mode 100644 Ivy/IvyUDPStreamV3.cs create mode 100644 Ivy/IvyUDPStreamV4.cs create mode 100644 Ivy/IvyWatcher.cs create mode 100644 Ivy/Properties/AssemblyInfo.cs create mode 100644 Ivy/Properties/Settings.Designer.cs create mode 100644 Ivy/Properties/Settings.settings create mode 100644 Ivy/Settings.cs create mode 100644 Ivy/app.config delete mode 100644 IvyToDel/Ivy/Ivy.cs delete mode 100644 IvyToDel/Ivy/Ivy.csproj delete mode 100644 IvyToDel/Ivy/Ivy.csproj.vspscc delete mode 100644 IvyToDel/Ivy/Ivy.snippet delete mode 100644 IvyToDel/Ivy/IvyApplicationBinding.cs delete mode 100644 IvyToDel/Ivy/IvyBinding.cs delete mode 100644 IvyToDel/Ivy/IvyBindingAttribute.cs delete mode 100644 IvyToDel/Ivy/IvyClient.cs delete mode 100644 IvyToDel/Ivy/IvyDomain.Designer.cs delete mode 100644 IvyToDel/Ivy/IvyDomain.cs delete mode 100644 IvyToDel/Ivy/IvyDomain.resx delete mode 100644 IvyToDel/Ivy/IvyEventArgs.cs delete mode 100644 IvyToDel/Ivy/IvyException.cs delete mode 100644 IvyToDel/Ivy/IvyProtocol.cs delete mode 100644 IvyToDel/Ivy/IvyTCPStream.cs delete mode 100644 IvyToDel/Ivy/IvyTCPStreamV3.cs delete mode 100644 IvyToDel/Ivy/IvyTCPStreamV4.cs delete mode 100644 IvyToDel/Ivy/IvyUDPStream.cs delete mode 100644 IvyToDel/Ivy/IvyUDPStreamV3.cs delete mode 100644 IvyToDel/Ivy/IvyUDPStreamV4.cs delete mode 100644 IvyToDel/Ivy/IvyWatcher.cs delete mode 100644 IvyToDel/Ivy/Properties/AssemblyInfo.cs delete mode 100644 IvyToDel/Ivy/Properties/Settings.Designer.cs delete mode 100644 IvyToDel/Ivy/Properties/Settings.settings delete mode 100644 IvyToDel/Ivy/Settings.cs delete mode 100644 IvyToDel/Ivy/app.config 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 diff --git a/Ivy/Ivy.csproj b/Ivy/Ivy.csproj new file mode 100644 index 0000000..1944b08 --- /dev/null +++ b/Ivy/Ivy.csproj @@ -0,0 +1,189 @@ + + + Local + 8.0.50727 + 2.0 + {F2F03CF7-0087-4EDB-AD15-80C9E8DA2617} + SAK + SAK + SAK + SAK + Debug + AnyCPU + + + + + Ivy + + + JScript + Grid + IE50 + false + Library + IvyBus + OnBuildSuccess + + + + + + + + + bin\Debug\ + false + 285212672 + false + + + + + + + true + 4096 + false + + + false + false + false + false + 1 + full + prompt + AnyCPU + + + bin\Release\ + false + 285212672 + false + + + + + + + false + 4096 + false + + + false + false + false + false + 1 + none + prompt + + + true + bin\x86\Debug\ + 285212672 + 1 + full + x86 + prompt + + + + + bin\x86\Release\ + 285212672 + 1 + + + x86 + prompt + + + + mscorlib + + + System + + + + System.Design + + + + System.Management + + + System.Windows.Forms + + + + + + Component + + + + UserControl + + + IvyDomain.cs + + + + + + + Code + + + Component + + + Code + + + Code + + + Code + + + Code + + + + + Code + + + True + True + Settings.settings + + + + + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + Designer + IvyDomain.cs + + + + + + + + + + \ No newline at end of file diff --git a/Ivy/Ivy.csproj.vspscc b/Ivy/Ivy.csproj.vspscc new file mode 100644 index 0000000..831ab8f --- /dev/null +++ b/Ivy/Ivy.csproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "relative:Ivy" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/Ivy/Ivy.snippet b/Ivy/Ivy.snippet new file mode 100644 index 0000000..5319177 --- /dev/null +++ b/Ivy/Ivy.snippet @@ -0,0 +1,43 @@ + + + +
+ + Ivy Message Callback + +
+ + + + Ivy.dll + + + + + IvyBus + + + + + CallbackName + Replace with a function name. + bus_receive + + + Expression + Replace with a regular expression. + "^(.*)" + + + + + + +
+
diff --git a/Ivy/IvyApplicationBinding.cs b/Ivy/IvyApplicationBinding.cs new file mode 100644 index 0000000..9183850 --- /dev/null +++ b/Ivy/IvyApplicationBinding.cs @@ -0,0 +1,186 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Text; +using System.ComponentModel; +using System.Threading; + +namespace IvyBus +{ + /* This is the Application side of binding storage */ + /* association of a generated Key and a delegate and the expression */ + /* this is SEND to other client */ +#if (!PocketPC) + [PropertyTab(typeof(System.Windows.Forms.Design.EventsTab), PropertyTabScope.Component)] + [DefaultEvent("Callback")] +#endif + [DesignerCategory("Component")] + [DesignTimeVisible(false)] /* should be added via Ivy component */ + public class IvyApplicationBinding : System.ComponentModel.Component + { + private BindingType binding; + +#if (!PocketPC) + [Category("Ivy")] +#endif + public BindingType Binding + { + get { return binding; } + set { binding = value; } + } + private ushort key; + + #if (!PocketPC) + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] +#endif + public ushort Key + { + get { return key; } + set { key = value; } + } + + private object[] args; +#if (!PocketPC) + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] +#endif + public object[] Args + { + get { return args; } + set { args = value; } + } + private string expression; +#if (!PocketPC) + [Category("Ivy")] +#endif + [DefaultValue(null)] + public string Expression + { + get { return expression; } + set { expression = value; } + } + private string formated_expression; + public string FormatedExpression + { + get + { + FormatExpression(); + return formated_expression; + } + } + + private List arguments; + ///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, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", + "System.Drawing.Design.UITypeEditor,System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" + )] + + [Description("Arguments used when formating the expression")] +#endif + public List Arguments + { + get + { + return arguments; + } + } + +#if (!PocketPC) + [Category("Ivy")] + [Description("Event fired when Message Matching expression received")] +#endif + public event EventHandler Callback; + + public IvyApplicationBinding() + { + arguments = new List(); + } + public IvyApplicationBinding(IContainer container) + : this() + { + container.Add(this); + } + // translate part of expression to object property + public void FormatExpression() + { + //// Safely : +#if (!PocketPC)//TODO Pocket PC doesn't have Target Member + EventHandler temp = Callback; + if (temp != null) + { + //TODO Pocket PC doesn't have Target Member + object target = temp.Target; + if (args == null) + { + args = new object[arguments.Count]; + for (int i = 0; i < arguments.Count; i++) + { + System.Reflection.PropertyInfo prop = target.GetType().GetProperty(arguments[i]); + if (prop != null) + args[i] = prop.GetValue(target, null); + else //TODO what else BUG msgbox in desing mode !!! + args[i] = arguments[i]; + } + } + formated_expression = string.Format(expression, args); + } + else //TODO Abnormal condition Design Time +#endif + formated_expression = expression; + + } + +#if ( PocketPC ) + internal void Firevent(System.Windows.Forms.Control control, IvyMessageEventArgs e) + { + //// Safely invoke an event: + EventHandler temp = Callback; + + if (temp == null) + { + throw new IvyException("(callCallback) Not callback for id " + e.Id); + } + if (control != null) + { + control.Invoke(temp, this, e); + } + else + temp(this, e); + } +#else + internal void Firevent(System.Threading.SynchronizationContext syncContext, IvyMessageEventArgs e) + { + //// Safely invoke an event: + EventHandler temp = Callback; + + if (temp == null) + { + throw new IvyException("(callCallback) Not callback for id " + e.Id); + } + if (syncContext != null) + { + SendOrPostCallback update = delegate(object state) + { + IvyMessageEventArgs args = (IvyMessageEventArgs)state; + temp(this, args); + }; + syncContext.Post(update, e); + } + else + temp(this, e); + } + +#endif + } + +} diff --git a/Ivy/IvyBinding.cs b/Ivy/IvyBinding.cs new file mode 100644 index 0000000..624b401 --- /dev/null +++ b/Ivy/IvyBinding.cs @@ -0,0 +1,118 @@ +using System; +using System.Collections; +using System.Collections.Specialized; +using System.Text.RegularExpressions; +using System.Diagnostics; + +namespace IvyBus +{ + /* This is the Client side of binding storage */ + /* association of a generated Key and the expression and a compiled Expression matching */ + /* this is RECEIVED from other client */ + + /// + /// Description résumée de IvyBinding. + /// + internal abstract class IvyBindingBase + { + + private ushort key; + + internal ushort Key + { + get { return key; } + } + protected string expression; + + internal string Expression + { + get { return expression; } + } + + internal IvyBindingBase(ushort id, string exp) + { + key = id; + expression = exp; + } + internal abstract string[] Match(string message); + + } + internal class IvyBindingRegexp : IvyBindingBase + { + internal Regex regexp; + + public IvyBindingRegexp(ushort id, string exp) + : base(id, exp) + { + regexp = new Regex(expression, /* RegexOptions.Compiled | */RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); + //regexp.Match("###"); // for really compile the expression really slow on 3000 expression + } + internal override string[] Match(string message) + { + string[] args = null; + // use of regexp to extract info + Match result = regexp.Match(message); + if (result.Success) + { + // Start at 1 because group 0 represent entire matching + args = new string[result.Groups.Count-1]; + for (int sub = 1; sub < result.Groups.Count; sub++) + { + args[sub-1] = result.Groups[sub].Value; + } + } + return args; + } + } + internal class IvyBindingSimple : IvyBindingBase + { + internal string msgname; // message name + internal string[] msgargs; // list of message args names + static string msgtag; // send message name + static StringDictionary args_values; // send message args[name]=value + + internal IvyBindingSimple(ushort id, string exp) + : base(id, exp) + { + string[] expr = expression.Split( ' ' ); + msgname = expr[0]; + msgargs = new string[ expr.Length -1 ]; + for ( int i = 1; i < expr.Length; i++ ) + msgargs[i-1] = expr[i]; + } + static internal void Prepare(string message) + { + string[] msg = message.Split(' '); + msgtag = msg[0]; + args_values = new StringDictionary(); + for( int sub=1 ; sub < msg.Length; sub++ ) + { + string[] arg = msg[sub].Split('='); // champ = valeur + if ( arg.Length == 2 ) + args_values[arg[0]] = arg[1]; + else + { + Ivy.traceError("IvyBindingSimple" , "abnormally Formed message expected 'msg champ=valeur champ=valeur....' :" + message); + } + } + + } + internal override string[] Match(string message) + { + // the message is already parsed by prepare + // + string[] args = null; + + if (msgtag == msgname) + { + args = new string[msgargs.Length]; + for( int sub= 0; sub < msgargs.Length; sub++) + { + args[sub] = args_values[msgargs[sub]]; + } + } + return args; + } + + } +} diff --git a/Ivy/IvyBindingAttribute.cs b/Ivy/IvyBindingAttribute.cs new file mode 100644 index 0000000..90c44ce --- /dev/null +++ b/Ivy/IvyBindingAttribute.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace IvyBus +{ + [AttributeUsage(AttributeTargets.Method,AllowMultiple = true)] + public sealed class IvyBindingAttribute : Attribute + { + private string expression; + private string[] args; + + // translate part of expression to object property + public string GetExpression(object obj) + { + if (obj == null) return string.Format(expression); + object[] values = new object[args.Length]; + for (int i = 0; i < args.Length; i++) + { + values[i] = obj.GetType().GetProperty(args[i]).GetValue(obj,null); + } + return string.Format(expression,values); + } + + public IvyBindingAttribute(string expression, params string[] args) + { + this.expression = expression; + this.args = args; + } + } +} diff --git a/Ivy/IvyClient.cs b/Ivy/IvyClient.cs new file mode 100644 index 0000000..3db9f0f --- /dev/null +++ b/Ivy/IvyClient.cs @@ -0,0 +1,592 @@ +/// François-Régis Colin +/// http://www.tls.cena.fr/products/ivy/ +/// * +/// (C) CENA +/// * +namespace IvyBus +{ + using System; + using System.Collections; + 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; + + /// A Class for the the peers on the bus. + /// + /// + /// each time a connexion is made with a remote peer, the regexp are exchanged + /// once ready, a ready message is sent, and then we can send messages, + /// 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 int CompareTo(IvyClient other) + { + return (other.clientPriority - clientPriority); + } + + public String ApplicationName + { + get + { + return appName; + } + + } + + public List Regexps + { + get + { + List tab = new List(); + lock (bindings) + { + foreach (IvyBindingBase bind in bindings.Values) + tab.Add(bind.Expression); + } + return tab; + } + + } + internal int AppPort + { + get + { + return appPort; + } + + } + public IPAddress RemoteAddress + { + get + { + return remoteHost; + } + + } + public int RemotePort + { + get + { + return remotePort; + } + + } + + private Ivy bus; + private Dictionary bindings; + private int appPort; + 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 const int PINGTIMEOUT = 5000; + private volatile Thread pingerThread; + + private int remotePort; + private IPAddress remoteHost; + + // protected variables + internal String appName; + internal IvyProtocol stream; + + internal IvyClient(Ivy bus, Socket socket, string appname) + { + bindings = new Dictionary(); + appName = appname; + this.bus = bus; + + IPEndPoint endpoint = (IPEndPoint)socket.RemoteEndPoint; + + remoteHost = endpoint.Address; + remotePort = endpoint.Port; + +#if (!PocketPC ) + socket.SetSocketOption( SocketOptionLevel.Tcp, SocketOptionName.KeepAlive, 1 ); +#endif + + if ( bus.ProtocolVersion == 4 ) + stream = new IvyTCPStreamV4( socket, this ); + else + stream = new IvyTCPStreamV3(socket, this); + + clientPriority = Ivy.DEFAULT_PRIORITY; + // 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+")"; + clientThread.Start(); + + } + + internal void SendBindings() + { + try + { + stream.TokenApplicationId(bus.applicationPriority, bus.AppId); + + // 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.FormatedExpression); + } + } + stream.TokenEndRegexp(); + +#if (!PocketPC) + doping = Properties.Settings.Default.IvyPing; +#endif + if (doping) + { + pingerThread = new Thread(new ThreadStart(PingerRun)); + pingerThread.Name = "Ivy Pinger Thread"; + pingerThread.Start(); + } + + + } + catch (IOException ex) + { // the client nous a coupé l'herbe sous le pied + Ivy.traceError("IvyClient","I can't send my message to this client. He probably left " + 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 + /// given time. + /// perhaps we should implement a new IvyApplicationListener method to + /// allow the notification of regexp addition and deletion + /// + + /// sends a direct message to the peer + /// + /// the numeric value provided to the remote client + /// + /// the string that will be match-tested + /// + /// + public void SendDirectMsg(ushort id, string message) + { + try + { + stream.TokenDirectMsg( id, message); + } + catch (IOException ex) + { + Ivy.traceError("IvyClient","I can't send my message to this client. He probably left "+ex.Message); + // 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 + close(false); + } + } + + /// closes the connexion to the peer. + /// + /// should I send Bye message ? + /// the thread managing the socket is stopped + /// + /// + internal void close(bool notify) + { + Ivy.traceProtocol("IvyClient","closing connexion to " + appName); + if (doping ) + { + StopPinging(); + } + if (notify) + try + { + stream.TokenBye(0, "hasta la vista"); + } + catch (IOException ioe) + { + 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 (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; + + + } + + /// sends the substrings of a message to the peer for each matching regexp. + /// + /// the string that will be match-tested + /// + /// the number of messages sent to the peer + /// + /// + internal int sendMsg(String message) + { + int count = 0; + + lock( bindings ) + { + try + { + foreach (IvyBindingBase bind in bindings.Values) + { + string[] args = bind.Match(message); + if (stream != null && args != null) + { + stream.TokenMsg(bind.Key, args); + count++; + } + } + } + catch (IOException ex) + { + Ivy.traceError("IvyClient","I can't send my message to this client. He probably left " + ex.Message); + // first, I'm not a first class IvyClient any more + bus.removeClient(this); + // invokes the Disconnected applicationListeners + // in the receiver thread + close(false); + } + + + } + return count; + } + + /// compares two peers the id is the couple (host,service port). + /// + /// the other peer + /// + /// true if the peers are similir. This should not happen, it is bad + /// © ® (tm) + /// + /// + internal bool sameClient(IvyClient clnt) + { + return (appPort != 0 && appPort == clnt.appPort) && (RemoteAddress == clnt.RemoteAddress); + } + + /// the code of the thread handling the incoming messages. + /// + private void Run() + { + Ivy.traceProtocol("IvyClient","Connected from " + RemoteAddress + ":" + RemotePort); + + Ivy.traceProtocol("IvyClient","Thread started"); + + bool running = true; + while ( running && (stream != null) ) + { + try + { + if ( stream.receiveMsg() ) + { + // early stop during readLine() + if (doping && (pingerThread != null)) + pingerThread.Abort(); + } + else + { + Ivy.traceProtocol("IvyClient","receiveMsg false ! leaving the thread"); + running = false; + break; + } + } + catch ( ObjectDisposedException ex ) + { + Ivy.traceError("IvyClient", "socket closed "+ex.Message ); + running = false; + break; + } + catch (IvyException ie) + { + Ivy.traceError("IvyClient","socket closed IvyException" + ie.Message); + running = false; + break; + } + catch (SocketException se) + { + Ivy.traceError("IvyClient", "socket closed "+se.Message ); + running = false; + break; + } + catch (IOException ex) + { + if ( ex.InnerException is SocketException ) + { + Ivy.traceProtocol("IvyClient", "socket closed" ); + + } + else + { + Ivy.traceError("IvyClient","abnormally Disconnected from " + RemoteAddress + ":" + RemotePort); + } + running = false; + break; + } + } + Ivy.traceProtocol("IvyClient","normally Disconnected from " + appName); + Ivy.traceProtocol("IvyClient","Thread stopped"); + // invokes the Disconnected applicationListeners + bus.OnClientDisconnected(new IvyEventArgs(this,0, "" )); + // first, I'm not a first class IvyClient any more + 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(ushort id, string arg) + { + Ivy.traceProtocol("IvyClient","received die Message from " + appName + "Raison: "+ 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 + bus.Stop(); + close(false); + if (ev.ForceExit) +#if (PocketPC) + System.Windows.Forms.Application.Exit(); +#else + System.Environment.Exit(0); +#endif + } + void IvyProtocol.TokenBye(ushort err, string arg) + { + // the peer quits + Ivy.traceProtocol("IvyClient","received bye Message from " + appName + "Raison: "+ 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 + //bus.FireClientDisconnected(this); done in Running Thread + close(false); // will fire disconnected + } + + void IvyProtocol.TokenAddBinding(BindingType type, ushort id, string expression) + { + + if (type == BindingType.Regexp && !bus.CheckRegexp(expression)) + { + bus.OnClientFilterBinding(new IvyEventArgs(this, id, expression )); + return; + } + IvyBindingBase bind = null; + try + { + switch (type) + { + case BindingType.Regexp: + bind = new IvyBindingRegexp(id, expression); + break; + case BindingType.Simple: + bind = new IvyBindingSimple(id, expression); + break; + } + lock (bindings) + { + bindings.Add(id, bind); + } + + bus.OnClientAddBinding(new IvyEventArgs(this, id, expression)); + + } + catch (ArgumentException ex) + { + throw new IvyException("binding expression error " + ex.Message); + } + + } + void IvyProtocol.TokenDelBinding(ushort id) + { + lock( bindings ) + { + try + { + IvyBindingBase bind = bindings[id]; + bus.OnClientRemoveBinding(new IvyEventArgs(this, bind.Key, bind.Expression)); + bindings.Remove(id); + } + catch (KeyNotFoundException ex) + { + Ivy.traceError("IvyClient","DelBinding " + ex.Message); + } + } + } + void IvyProtocol.TokenMsg(ushort id, string[] args) + { + bus.OnMessage(new IvyMessageEventArgs(this, id, args)); + } + void IvyProtocol.TokenError(ushort id, string arg) + { + bus.OnError(new IvyEventArgs(this, id, arg)); + Ivy.traceError("IvyClient","Error msg " + id + " " + arg); + } + void IvyProtocol.TokenApplicationId(ushort id, string arg) + { + clientId = arg; + if ( clientPriority != id ) + { + clientPriority = id; + bus.SortClients(); + } + } + void IvyProtocol.TokenEndRegexp() + { + /* + * the peer is perhaps not ready to handle this message + * an assymetric processing should be written + */ + if (bus.ReadyMessage != null) + sendMsg(bus.ReadyMessage); + bus.OnClientConnected(new IvyEventArgs(this, 0, "")); + } + void IvyProtocol.TokenStartRegexp(ushort id, string arg) + { + appName = arg; + appPort = id; + if (bus.checkConnected(this)) + { + close(false); + throw new IvyException("Rare ! A concurrent connect occured"); + } + + } + void IvyProtocol.TokenDirectMsg(ushort id, string arg) + { + bus.OnDirectMessage(new IvyEventArgs(this,id,arg)); + } + void IvyProtocol.TokenPing(string arg) + { + // I receive a ping. I can answer a pong. + Ivy.traceProtocol("IvyClient","Ping msg from " + appName + " : " + arg ); + stream.TokenPong(arg); + } + void IvyProtocol.TokenPong(string arg) + { + Ivy.traceProtocol("IvyClient","Ping msg from " + appName + " : " + arg); + } + + + + public override String ToString() + { + return "IvyClient " + bus.appName + ":" + appName; + } + + /* is the Pinging Thread Runninng */ + internal bool isPinging; + + private void PingerRun() + { + isPinging = true; + Ivy.traceProtocol("IvyClient","Pinger Thread started"); + while (isPinging) + { + try + { + Thread.Sleep(PINGTIMEOUT); + stream.TokenPing("are you here ?"); + } + catch (ThreadAbortException ie) + { + Ivy.traceError("IvyClient","Pinger Thread killed "+ie.Message); + } + } + Ivy.traceProtocol("IvyClient","Pinger Thread stopped"); + } + 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). + } + // Free your own state (unmanaged objects). + // Set large fields to null. + if (stream != null) + { + stream.Close(); + stream = 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/IvyDomain.Designer.cs b/Ivy/IvyDomain.Designer.cs new file mode 100644 index 0000000..3f89b6a --- /dev/null +++ b/Ivy/IvyDomain.Designer.cs @@ -0,0 +1,75 @@ +namespace IvyBus +{ + partial class IvyDomain + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.label1 = new System.Windows.Forms.Label(); + this.ivybus = new System.Windows.Forms.TextBox(); + this.SuspendLayout(); + // + // label1 + // + this.label1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left))); + this.label1.Location = new System.Drawing.Point(0, 5); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(24, 13); + this.label1.Text = "Ivy:"; + // + // ivybus + // + this.ivybus.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.ivybus.Location = new System.Drawing.Point(30, 0); + 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); + // + // IvyDomain + // + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit; + this.Controls.Add(this.label1); + this.Controls.Add(this.ivybus); + this.Name = "IvyDomain"; + this.Size = new System.Drawing.Size(159, 22); + this.ResumeLayout(false); +#if (!PocketPC) + this.PerformLayout(); +#endif + + } + + #endregion + + private System.Windows.Forms.Label label1; + private System.Windows.Forms.TextBox ivybus; + } +} diff --git a/Ivy/IvyDomain.cs b/Ivy/IvyDomain.cs new file mode 100644 index 0000000..6c43b73 --- /dev/null +++ b/Ivy/IvyDomain.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Text; +using System.Windows.Forms; + +namespace IvyBus +{ + public partial class IvyDomain : UserControl + { + private string domain = ""; + public event EventHandler DomainChanged; +#if (!PocketPC) + [Category("Ivy")] + [DefaultValue("")] + [Bindable(true)] +#endif + public string Domain + { + get { return domain; } + set { + if (domain != value) + { + domain = value; + ivybus.Text = domain; + if (DomainChanged != null) DomainChanged(this, EventArgs.Empty); + } + } + } + + public IvyDomain() + { + InitializeComponent(); + } + public void SetDefault() + { + if (IsEmpty()) + { + domain = Ivy.GetDomain(domain); + ivybus.Text = domain; + } + } + public bool IsEmpty() + { + return String.IsNullOrEmpty( domain ); + } + + private void ivybus_Validating(object sender, CancelEventArgs e) + { + e.Cancel = !Ivy.ValidatingDomain(ivybus.Text); + } + + private void ivybus_Validated(object sender, EventArgs e) + { + if ( domain != ivybus.Text ) + Domain = ivybus.Text; + } + + } +} diff --git a/Ivy/IvyDomain.resx b/Ivy/IvyDomain.resx new file mode 100644 index 0000000..ff31a6d --- /dev/null +++ b/Ivy/IvyDomain.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Ivy/IvyEventArgs.cs b/Ivy/IvyEventArgs.cs new file mode 100644 index 0000000..e394802 --- /dev/null +++ b/Ivy/IvyEventArgs.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace IvyBus +{ + /// The EventArgs Classes + /// + /// + public class IvyEventArgs : EventArgs + { + private IvyClient client; + private int id; + private string arg; + + public IvyClient Client + { + get { return client; } + } + + public int Id + { + get { return id; } + } + + public string Argument + { + get { return arg; } + } + public IvyEventArgs(IvyClient app, int id, string arg) + { + this.client = app; + this.id = id; + this.arg = arg; + } + } + public class IvyDieEventArgs : IvyEventArgs + { + /* return value for Die Event */ + private bool forceExit; + + public bool ForceExit + { + get { return forceExit; } + set { forceExit = value; } + } + public IvyDieEventArgs(IvyClient app, int id, string arg) + : base(app, id, arg) + { + forceExit = true; + } + } + public class IvyMessageEventArgs : EventArgs + { + private IvyClient client; + private int id; + private string[] args; + + public IvyClient Client + { + get { return client; } + } + + public int Id + { + get { return id; } + } + + public string[] Arguments + { + get { return args; } + } + public string this[int i] + { + get { return args[i]; } + } + public IvyMessageEventArgs(IvyClient app, int id, string[] args) + { + this.client = app; + this.id = id; + this.args = args; + } + } +} diff --git a/Ivy/IvyException.cs b/Ivy/IvyException.cs new file mode 100644 index 0000000..90a91b8 --- /dev/null +++ b/Ivy/IvyException.cs @@ -0,0 +1,19 @@ +/// François-Régis Colin +/// http://www.tls.cena.fr/products/ivy/ +/// * +/// (C) CENA +/// * +namespace IvyBus +{ + using System; + + /// signals that an unrecoverrable Ivy exception has occured. + /// + + public class IvyException:System.Exception + { + public IvyException(System.String s):base(s) + { + } + } +} \ No newline at end of file diff --git a/Ivy/IvyProtocol.cs b/Ivy/IvyProtocol.cs new file mode 100644 index 0000000..1b1f3aa --- /dev/null +++ b/Ivy/IvyProtocol.cs @@ -0,0 +1,25 @@ +using System; +using System.Text; + +namespace IvyBus +{ + public enum BindingType { Regexp, Simple }; + + internal interface IvyProtocol + { + void Close(); + bool receiveMsg(); + void TokenStartRegexp(ushort port, string appName); + void TokenEndRegexp(); + void TokenApplicationId(ushort priority, string appId); + void TokenAddBinding(BindingType type, ushort id, string expression); + void TokenDelBinding(ushort bind); + void TokenDirectMsg(ushort id, string message); + void TokenPong(string s); + void TokenPing(string s); + void TokenBye(ushort id, string message); + void TokenDie(ushort err, string message); + void TokenMsg(ushort key, string[] args); + void TokenError(ushort id, string message); + } +} diff --git a/Ivy/IvyTCPStream.cs b/Ivy/IvyTCPStream.cs new file mode 100644 index 0000000..b8fee34 --- /dev/null +++ b/Ivy/IvyTCPStream.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Specialized; +using System.Text; +using System.Net; +using System.Net.Sockets; +using System.IO; + +namespace IvyBus +{ + abstract class IvyTCPStream : NetworkStream + { + public IvyTCPStream(Socket socket) + : base(socket, true) + { + } + + abstract internal bool receiveMsg(); + + } +} diff --git a/Ivy/IvyTCPStreamV3.cs b/Ivy/IvyTCPStreamV3.cs new file mode 100644 index 0000000..4eef12c --- /dev/null +++ b/Ivy/IvyTCPStreamV3.cs @@ -0,0 +1,254 @@ +using System; +using System.Net; +using System.Net.Sockets; +using System.Text; +using System.Collections; +using System.Collections.Specialized; +using System.IO; + +namespace IvyBus +{ + /// + /// Description résumée de IvyStream. + /// + internal class IvyTCPStreamV3 : NetworkStream, IvyProtocol + { + StreamReader input; + StreamWriter output; + IvyProtocol receiver; + + /// the protocol separator + internal const char ARG_START = '\x02'; + internal const char ARG_END = '\x03'; + internal const char MSG_END = '\n'; + + internal IvyTCPStreamV3(Socket socket, IvyProtocol _receiver) : base ( socket ) + { + output = new StreamWriter(this, Encoding.ASCII); + output.NewLine = MSG_END.ToString(); + input = new StreamReader(this, Encoding.ASCII); + receiver = _receiver; + } + /* the protocol magic numbers */ + internal enum MessageType : ushort + { + Bye = 0, /* end of the peer */ + AddRegexp = 1, /* the peer adds a regexp */ + Msg = 2, /* the peer sends a message */ + Error = 3, /* error message */ + DelBinding = 4, /* the peer removes one of his regex */ // OLD DelRegexp rename to DelBinding + EndRegexp = 5, /* no more regexp in the handshake */ + StartRegexp = 6, /* avoid race condition in concurrent connexions */ + DirectMsg = 7, /* the peer sends a direct message */ + Die = 8, /* the peer wants us to quit */ + Ping = 9, /* checks the presence of the other */ + Pong = 10, /* checks the presence of the other */ + }; + + /* + * message Syntax: + * this is text formated message 'type id STX ARG0 {[ETX] ARG1 [ETX] ARGn}\n' + * + * message Format: + MessageType, id , length, string + */ + + private void sendMsg(MessageType msgType, ushort msgId, string msgData) + { + // IOException Should be traited upstairs + output.Write((ushort)msgType); + output.Write(' '); + output.Write(msgId); + output.Write(ARG_START); + output.Write(msgData); + output.Write(MSG_END); + output.Flush(); + + } + void IvyProtocol.TokenStartRegexp(ushort port, string appName) + { + sendMsg(MessageType.StartRegexp, port, appName); + } + void IvyProtocol.TokenEndRegexp() + { + sendMsg(MessageType.EndRegexp, 0, ""); + } + void IvyProtocol.TokenApplicationId(ushort priority, string appId) + { + // NOt implemented in this protocol version + } + + void IvyProtocol.TokenAddBinding(BindingType type, ushort id, string expression) + { + switch (type) + { + case BindingType.Regexp: + sendMsg(MessageType.AddRegexp, id, expression); /* perhaps we should perform some checking here */ + break; + case BindingType.Simple: + // NO Simple Binding in this protocol + break; + } + } + + void IvyProtocol.TokenDelBinding(ushort id) + { + sendMsg(MessageType.DelBinding, id, ""); + } + + void IvyProtocol.TokenDirectMsg(ushort id, string message) + { + sendMsg(MessageType.DirectMsg, id, message); + } + void IvyProtocol.TokenPong(string s) + { + sendMsg(MessageType.Pong, 0, s); + } + void IvyProtocol.TokenPing(string s) + { + sendMsg(MessageType.Ping, 0, s); + } + + void IvyProtocol.TokenBye(ushort id, string message) + { + sendMsg(MessageType.Bye, id, message); + } + + void IvyProtocol.TokenDie(ushort id, string message) + { + sendMsg(MessageType.Die, id, message); + } + + void IvyProtocol.TokenMsg(ushort key, string[] args) + { + string delimiter = "" + ARG_END; + string data = string.Join(delimiter, args); + // a bad protocol implementation in C add a delimiter to the end of each arg + // we must add a delimiter to the end + data += delimiter; + sendMsg(MessageType.Msg, key, data); + } + + void IvyProtocol.TokenError(ushort key, string arg) + { + sendMsg(MessageType.Msg, key, arg); + } + + private ushort DeserializeShort() + { + int read; + ushort ret = 0; + char digit; + // this will eat next non digit char ie space + do + { + read = input.Read(); + if (read < 0) + throw new EndOfStreamException(); + digit = (char)read; + if (Char.IsDigit(digit)) + ret = (ushort)(ret * 10 + (digit - 0x30)); + } while (Char.IsDigit(digit)); + return ret; + } + private string DeserializeString(char sep) + { + int read; + char car; + StringBuilder str = new StringBuilder(); + // this will eat next non separator char + do + { + read = input.Read(); + if (read < 0) + throw new EndOfStreamException(); + car = (char)read; + if (car != sep ) str.Append(car); + } while (car != sep); + return str.ToString(); + } + + bool IvyProtocol.receiveMsg() + { + MessageType msgType = MessageType.Die; + ushort msgId = 0; + string msgData = null; + + try + { + msgType = (MessageType)DeserializeShort(); + msgId = DeserializeShort(); + msgData = DeserializeString(MSG_END); + + switch (msgType) + { + case MessageType.Die: + receiver.TokenDie(msgId, msgData); + break; + + case MessageType.Bye: + receiver.TokenBye(msgId, msgData); + break; + + case MessageType.AddRegexp: + receiver.TokenAddBinding(BindingType.Regexp, msgId, msgData); + break; + + case MessageType.DelBinding: + receiver.TokenDelBinding(msgId); + break; + + case MessageType.EndRegexp: + receiver.TokenEndRegexp(); + break; + + case MessageType.Msg: + // a bad protocol implementation in C add a delimiter to the end of each arg + // we must remove a delimiter to the end + if ( msgData.Length > 0 ) + msgData = msgData.Remove(msgData.Length - 1,1); + receiver.TokenMsg(msgId, msgData.Split( ARG_END )); + break; + + case MessageType.Pong: + receiver.TokenPong(msgData); + break; + + case MessageType.Ping: + receiver.TokenPing(msgData); + break; + + case MessageType.Error: + receiver.TokenError(msgId, msgData); + break; + + case MessageType.StartRegexp: + receiver.TokenStartRegexp(msgId, msgData); + break; + + case MessageType.DirectMsg: + receiver.TokenDirectMsg(msgId, msgData); + break; + default: + throw new IvyException("protocol error, unknown message type " + msgType); + + } + + + + } + catch (EndOfStreamException) + { + return false; + } + catch (FormatException) + { + throw new IvyException("protocol error on msgType"); + } + + + return true; + } + + } +} diff --git a/Ivy/IvyTCPStreamV4.cs b/Ivy/IvyTCPStreamV4.cs new file mode 100644 index 0000000..9a96d62 --- /dev/null +++ b/Ivy/IvyTCPStreamV4.cs @@ -0,0 +1,273 @@ +using System; +using System.Net; +using System.Net.Sockets; +using System.Text; +using System.Collections; +using System.Collections.Specialized; +using System.IO; + +namespace IvyBus +{ + /// + /// Description résumée de IvyStream. + /// + internal class IvyTCPStreamV4 : NetworkStream , IvyProtocol + { + BinaryReader input; + BinaryWriter output; + IvyProtocol receiver; + + /* the protocol magic numbers */ + internal enum MessageType : ushort + { + Bye = 0, /* end of the peer */ + AddRegexp = 1, /* the peer adds a regexp */ + Msg = 2, /* the peer sends a message */ + Error = 3, /* error message */ + DelBinding = 4, /* the peer removes one of his regex */ // OLD DelRegexp rename to DelBinding + EndRegexp = 5, /* no more regexp in the handshake */ + StartRegexp = 6, /* avoid race condition in concurrent connexions */ + DirectMsg = 7, /* the peer sends a direct message */ + Die = 8, /* the peer wants us to quit */ + Ping = 9, /* checks the presence of the other */ + Pong = 10, /* checks the presence of the other */ + ApplicationId = 11, /* on start send my ID and priority */ + AddBinding = 12, /* other methods for binding message based on hash table */ + + }; + + internal IvyTCPStreamV4(Socket socket, IvyProtocol _receiver) : base( socket ) + { + + input = new BinaryReader(this, Encoding.ASCII); + output = new BinaryWriter(this, Encoding.ASCII); + receiver = _receiver; + } + + + /* + * message Syntax: + * this is a binary formated message use of network representation + * + * message Format: + MessageType, id , length, string + */ + private void Serialize(short arg) + { + output.Write((ushort)IPAddress.HostToNetworkOrder(arg)); + } + private void Serialize(string arg) + { + short length = arg != null ? (short)arg.Length : (short)0; + Serialize(length); + if (length != 0) + output.Write(arg.ToCharArray()); + } + private void Serialize(string[] arg) + { + + /* serialize count */ + Serialize((short)arg.Length); + + for (int i = 0; i < arg.Length; i++) + { + Serialize(arg[i]); + } + } + private void sendMsg(MessageType type, int id, params string[] arg) + { + + Serialize( (short)type ); + Serialize( (short)id ); + Serialize(arg); + output.Flush(); + + } + void IvyProtocol.TokenStartRegexp(ushort port, string appName) + { + sendMsg(MessageType.StartRegexp, port, appName); + } + void IvyProtocol.TokenEndRegexp() + { + sendMsg(MessageType.EndRegexp, 0, ""); + } + void IvyProtocol.TokenApplicationId(ushort priority, string appId) + { + sendMsg(MessageType.ApplicationId, priority, appId); + } + + void IvyProtocol.TokenAddBinding(BindingType type, ushort id, string expression) + { + switch (type) + { + case BindingType.Regexp: + sendMsg(MessageType.AddRegexp, id, expression); /* perhaps we should perform some checking here */ + break; + case BindingType.Simple: + sendMsg(MessageType.AddBinding, id, expression); /* perhaps we should perform some checking here */ + break; + } + } + + void IvyProtocol.TokenDelBinding(ushort id) + { + sendMsg(MessageType.DelBinding, id, null ); + } + + void IvyProtocol.TokenDirectMsg(ushort id, string message) + { + sendMsg(MessageType.DirectMsg, id, message); + } + void IvyProtocol.TokenPong(string s) + { + sendMsg(MessageType.Pong, 0, s); + } + void IvyProtocol.TokenPing(string s) + { + sendMsg(MessageType.Ping, 0, s); + } + + void IvyProtocol.TokenBye(ushort id, string message) + { + sendMsg(MessageType.Bye, id, message); + } + + void IvyProtocol.TokenDie(ushort id, string message) + { + sendMsg(MessageType.Die, id, message); + } + + void IvyProtocol.TokenMsg(ushort key, string[] args) + { + sendMsg(MessageType.Msg, key, args ); + } + + void IvyProtocol.TokenError(ushort key, string arg) + { + sendMsg(MessageType.Msg, key, arg); + } + + private short DeserializeShort() + { + return IPAddress.NetworkToHostOrder((short)input.ReadUInt16()); + } + private string DeserializeString() + { + string arg; + int val_len; + char[] data; + val_len = (ushort)DeserializeShort(); + if (val_len != 0) + { + data = input.ReadChars(val_len); + arg = new String(data); + } + else + arg = ""; + return arg; + } + + + private string[] DeserializeArgument() + { + int nb_children; + string[] arg; + + /* Deserialize childrens */ + nb_children = (ushort)DeserializeShort(); + /* deserialize Value */ + arg = new string[nb_children]; + + for (int i = 0; i < nb_children; i++) + { + arg[i] = DeserializeString(); + } + return arg; + } + bool IvyProtocol.receiveMsg() + { + MessageType msgType = MessageType.Die; + ushort msgId = 0; + string[] msgData = null; + + try + { + msgType = (MessageType)(ushort)DeserializeShort(); + msgId = (ushort)DeserializeShort(); + msgData = DeserializeArgument(); + + switch (msgType) + { + case MessageType.Die: + receiver.TokenDie(msgId, msgData[0]); + break; + + case MessageType.Bye: + receiver.TokenBye(msgId, msgData[0]); + break; + + case MessageType.AddRegexp: + receiver.TokenAddBinding(BindingType.Regexp, msgId, msgData[0]); + break; + + case MessageType.AddBinding: + receiver.TokenAddBinding(BindingType.Simple, msgId, msgData[0]); + break; + + case MessageType.DelBinding: + receiver.TokenDelBinding(msgId); + break; + + case MessageType.EndRegexp: + receiver.TokenEndRegexp(); + break; + + case MessageType.Msg: + receiver.TokenMsg( msgId, msgData ); + break; + + case MessageType.Pong: + receiver.TokenPong(msgData[0]); + break; + + case MessageType.Ping: + receiver.TokenPing(msgData[0]); + break; + + case MessageType.Error: + receiver.TokenError(msgId, msgData[0]); + break; + + case MessageType.StartRegexp: + receiver.TokenStartRegexp(msgId, msgData[0]); + break; + + case MessageType.DirectMsg: + receiver.TokenDirectMsg(msgId, msgData[0]); + break; + case MessageType.ApplicationId: + receiver.TokenApplicationId(msgId, msgData[0]); + break; + default: + throw new IvyException("protocol error, unknown message type " + msgType); + + } + + + + } + catch (EndOfStreamException) + { + return false; + } + catch (FormatException) + { + throw new IvyException("protocol error on msgType"); + } + + + return true; + } + + } +} diff --git a/Ivy/IvyUDPStream.cs b/Ivy/IvyUDPStream.cs new file mode 100644 index 0000000..0e3f517 --- /dev/null +++ b/Ivy/IvyUDPStream.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Net; +using System.Net.Sockets; +using System.IO; + +namespace IvyBus +{ + abstract class IvyUDPStream + { + Socket socket; + byte[] buffer; + + protected MemoryStream out_stream; + protected MemoryStream in_stream; + + ushort protocol_version; + + public ushort ProtocolVersion + { + get { return protocol_version; } + } + + public IvyUDPStream(Socket _socket, ushort protocol) + { + socket = _socket; + buffer = new byte[4096]; + in_stream = new MemoryStream(buffer); + out_stream = new MemoryStream(); + protocol_version = protocol; + } + internal void Close() + { + in_stream.Close(); + out_stream.Close(); + socket.Shutdown(SocketShutdown.Both); + socket.Close(); + } + internal void receiveMsg(out IPEndPoint remote, out ushort version, out ushort port, out string appId, out string appName) + { + int len; + IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, 0); + EndPoint tempRemoteEP = (EndPoint)remoteEP; + remoteEP = null; + len = socket.ReceiveFrom(buffer, ref tempRemoteEP); + remote = (IPEndPoint)tempRemoteEP; + in_stream.Position = 0; + in_stream.SetLength(len); + in_stream.Seek(0, SeekOrigin.Begin); + //Call Deserialization + Deserialize( out version, out port, out appId, out appName ); + } + internal void sendMsg(IPEndPoint EPhost, ushort port, string appId, string appName) + { + // Call Serialisation + Serialize(port, appId, appName); + + byte[] hellob = out_stream.GetBuffer(); + socket.SendTo(hellob, (int)out_stream.Length, 0, EPhost); + } + abstract internal void Serialize(ushort port, string appId, string appName); + abstract internal void Deserialize(out ushort version, out ushort port, out string appId, out string appName); + + } +} diff --git a/Ivy/IvyUDPStreamV3.cs b/Ivy/IvyUDPStreamV3.cs new file mode 100644 index 0000000..63a8679 --- /dev/null +++ b/Ivy/IvyUDPStreamV3.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Net; +using System.Net.Sockets; +using System.IO; + +namespace IvyBus +{ + class IvyUDPStreamV3 : IvyUDPStream + { + StreamReader input; + StreamWriter output; + + /// the protocol version number + internal const int PROCOCOLVERSION = 3; + + public IvyUDPStreamV3(Socket _socket) : base( _socket , PROCOCOLVERSION ) + { + input = new StreamReader(in_stream, Encoding.ASCII); + output = new StreamWriter(out_stream, Encoding.ASCII); + } + /* + * message Syntax: + * this is a text formated message + * + * message Format: + protocol_version, TCP server port , appId, appName + */ + private ushort DeserializeShort() + { + int read; + ushort ret = 0; + char digit; + // this will eat next non digit car ie space + do + { + read = input.Read(); + if (read < 0) + throw new EndOfStreamException(); + digit = (char)read; + if ( Char.IsDigit(digit) ) + ret = (ushort)(ret * 10 + (digit-0x30)); + } while (Char.IsDigit(digit)); + return ret; + } + private string DeserializeString(char sep) + { + int read; + char car; + StringBuilder str = new StringBuilder(); + // this will eat next non digit car ie space + do + { + read = input.Read(); + if (read < 0) + throw new EndOfStreamException(); + if (read == 0) break; + car = (char)read; + if (car != sep) + str.Append(car); + } while (car != sep); + return str.ToString(); + } + + internal override void Deserialize(out ushort version, out ushort port, out string appId, out string appName) + { + version = 0; + port = 0; + appId = ""; + appName = ""; + try { + version = DeserializeShort(); + port = DeserializeShort(); + //Optionel in V3 protocol depend on client version + appId = DeserializeString(' '); + appName = DeserializeString('\n'); + } + catch( EndOfStreamException ) + { + // Bad protocol message receive or without appId and appName + } + input.DiscardBufferedData(); + } + private void Serialize(ushort arg, char sep) + { + output.Write(arg); + output.Write(sep); + } + private void Serialize(string arg, char sep) + { + output.Write(arg); + output.Write(sep); + } + internal override void Serialize(ushort port, string appId, string appName) + { + Serialize(PROCOCOLVERSION, ' '); + Serialize(port,' '); + Serialize(appId,' '); //No AppId in V3 + Serialize(appName, '\n'); //No Appname in V3 + output.Flush(); + } + } +} diff --git a/Ivy/IvyUDPStreamV4.cs b/Ivy/IvyUDPStreamV4.cs new file mode 100644 index 0000000..b8d329a --- /dev/null +++ b/Ivy/IvyUDPStreamV4.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Net; +using System.Net.Sockets; +using System.IO; + +namespace IvyBus +{ + class IvyUDPStreamV4 : IvyUDPStream + { + + BinaryReader input; + BinaryWriter output; + + /// the protocol version number + internal const ushort PROCOCOLVERSION = 4; + public IvyUDPStreamV4(Socket _socket) : base ( _socket, PROCOCOLVERSION) + { + input = new BinaryReader( in_stream,Encoding.ASCII); + output = new BinaryWriter(out_stream, Encoding.ASCII); + } + /* + * message Syntax: + * this is a binary formated message use of network representation + * + * message Format: + protocol_version, TCP server port , lenAppId, appId, lenAppNameId, appName + */ + private ushort DeserializeShort() + { + return (ushort)IPAddress.NetworkToHostOrder((ushort)input.ReadUInt16()); + } + private string DeserializeString() + { + string arg; + int val_len; + char[] data; + val_len = (ushort)IPAddress.NetworkToHostOrder((ushort)input.ReadUInt16()); + if (val_len != 0) + { + data = input.ReadChars(val_len); + arg = new String(data); + } + else + arg = ""; + return arg; + } + + internal override void Deserialize(out ushort version, out ushort port, out string appId, out string appName) + { + version = DeserializeShort(); + port = DeserializeShort(); + appId = DeserializeString(); + appName = DeserializeString(); + + } + private void Serialize(ushort arg) + { + output.Write((ushort)IPAddress.HostToNetworkOrder(arg)); + } + private void Serialize(string arg) + { + ushort length = arg != null ? (ushort)arg.Length : (ushort)0; + Serialize(length); + if (length != 0) + output.Write(arg.ToCharArray()); + } + + internal override void Serialize(ushort port, string appId, string appName) + { + Serialize(PROCOCOLVERSION ); + Serialize(port); + Serialize(appId); + Serialize(appName); + output.Flush(); + } + + } +} diff --git a/Ivy/IvyWatcher.cs b/Ivy/IvyWatcher.cs new file mode 100644 index 0000000..5a3afc8 --- /dev/null +++ b/Ivy/IvyWatcher.cs @@ -0,0 +1,179 @@ + +/// François-Régis Colin +/// http://www.tls.cena.fr/products/ivy/ +/// * +/// (C) CENA +/// * + +namespace IvyBus +{ + using System; + using System.Threading; + using System.IO; + using System.Net; + using System.Net.Sockets; + using System.Text.RegularExpressions; + using System.Configuration; + using System.Text; + using System.Diagnostics; + + /// IvyWatcher, A private Class for the Ivy rendezvous + /// + /// right now, the rendez vous is either an UDP socket or a TCP multicast. + /// The watcher will answer to + /// each peer advertising its arrival on the bus. The intrinsics of Unix are so + /// that the broadcast is done using the same socket, which is not a good + /// thing. + /// + internal class IvyWatcher + { + private Ivy bus; /* master bus controler */ + private int port; + private volatile Thread listenThread; + private IPAddress group; + private IvyUDPStream stream; + + /// creates an Ivy watcher + /// + /// the bus + /// + /// the domain + /// + /// the port number + /// + internal IvyWatcher(Ivy bus, String domainaddr, int port) + { + this.bus = bus; + this.port = port; + 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); + broadcast.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast,1); + broadcast.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress,1); + 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.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) + { + throw new IvyException("IvyWatcher I/O error" + e); + } + } + + /// the behaviour of each thread watching the UDP socket. + /// + public void Run() + { + Ivy.traceProtocol("IvyWatcher", "beginning of a watcher Thread"); + + try + { + bool running = true; + while (running) + { + ushort version; + ushort 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("IvyWatcher", "Receive Broadcast from " + Dns.GetHostEntry(remotehost).HostName + ":" + remoteEP.Port); + + //TODO if ( !isInDomain( remotehost ) ) continue; + + if (version != stream.ProtocolVersion) + { + Ivy.traceError("IvyWatcher","Ignoring bad protocol version " + version + " expected " + stream.ProtocolVersion); + continue; + } + + // filtrage des self Broadcast + if (appId == bus.AppId) + continue; + if ((appPort == bus.applicationPort) && (remotehost.Equals(bus.applicationHost))) + continue; + + Ivy.traceProtocol("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); + bus.addClient(socket, appName); + } + catch (Exception e) + { + Ivy.traceError("IvyWatcher","can't connect to " + remotehost + " port " + appPort + " \n" + e.Message); + } + + } // while + } + catch (SocketException se) + { + Ivy.traceError("IvyWatcher","watcher socket closed: " + se.Message); + } + catch (IOException ioe) + { + Ivy.traceError("IvyWatcher","watcher thread ended: " + ioe.Message); + } + Ivy.traceProtocol("IvyWatcher", "end of a watcher thread"); + } + + /// stops the thread waiting on the broadcast socket + /// + internal virtual void stop() + { + lock (stream) + { + Ivy.traceProtocol("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(); + listenThread = null; + } + // it might not even have been created + Ivy.traceProtocol("IvyWatcher", "ending stopping an IvyWatcher"); + } + } + + internal virtual void start() + { + 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 + } + } + + + } +} \ No newline at end of file diff --git a/Ivy/Properties/AssemblyInfo.cs b/Ivy/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..a3ce834 --- /dev/null +++ b/Ivy/Properties/AssemblyInfo.cs @@ -0,0 +1,62 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. + +[assembly: AssemblyTitle("Ivy")] +[assembly: AssemblyDescription("Dll de communications sur le bus IVY")] +[assembly: AssemblyCompany("DTI/SDER PII")] +[assembly: AssemblyProduct("Ivy")] +[assembly: AssemblyCopyright("SDER")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Revision +// Build Number +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +[assembly: AssemblyVersion("2.0.*")] + +// +// In order to sign your assembly you must specify a key to use. Refer to the +// Microsoft .NET Framework documentation for more information on assembly signing. +// +// Use the attributes below to control which key is used for signing. +// +// Notes: +// (*) If no key is specified, the assembly is not signed. +// (*) KeyName refers to a key that has been installed in the Crypto Service +// Provider (CSP) on your machine. KeyFile refers to a file which contains +// a key. +// (*) If the KeyFile and the KeyName values are both specified, the +// following processing occurs: +// (1) If the KeyName can be found in the CSP, that key is used. +// (2) If the KeyName does not exist and the KeyFile does exist, the key +// in the KeyFile is installed into the CSP and used. +// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. +// When specifying the KeyFile, the location of the KeyFile should be +// relative to the project output directory which is +// %Project Directory%\obj\. For example, if your KeyFile is +// located in the project directory, you would specify the AssemblyKeyFile +// attribute as [assembly: AssemblyKeyFile("..\..\mykey.snk")] +// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework +// documentation for more information on this. +// + +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyDelaySign(false)] +[assembly: AssemblyKeyFile("")] +[assembly: AssemblyKeyName("")] + + +[assembly: ComVisibleAttribute(false)] diff --git a/Ivy/Properties/Settings.Designer.cs b/Ivy/Properties/Settings.Designer.cs new file mode 100644 index 0000000..96b0f2d --- /dev/null +++ b/Ivy/Properties/Settings.Designer.cs @@ -0,0 +1,80 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:2.0.50727.42 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace IvyBus.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "8.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + + [global::System.Configuration.ApplicationScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("3")] + public int IvyProtocolVersion { + get { + return ((int)(this["IvyProtocolVersion"])); + } + } + + [global::System.Configuration.ApplicationScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool IvyPing { + get { + return ((bool)(this["IvyPing"])); + } + } + + [global::System.Configuration.ApplicationScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool IvyDebug { + get { + return ((bool)(this["IvyDebug"])); + } + } + + [global::System.Configuration.ApplicationScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string IvyBus { + get { + return ((string)(this["IvyBus"])); + } + } + + [global::System.Configuration.ApplicationScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string AppName { + get { + return ((string)(this["AppName"])); + } + } + + [global::System.Configuration.ApplicationScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string ReadyMessage { + get { + return ((string)(this["ReadyMessage"])); + } + } + } +} diff --git a/Ivy/Properties/Settings.settings b/Ivy/Properties/Settings.settings new file mode 100644 index 0000000..f23b946 --- /dev/null +++ b/Ivy/Properties/Settings.settings @@ -0,0 +1,24 @@ + + + + + + 3 + + + False + + + False + + + + + + + + + + + + \ No newline at end of file diff --git a/Ivy/Settings.cs b/Ivy/Settings.cs new file mode 100644 index 0000000..17744f8 --- /dev/null +++ b/Ivy/Settings.cs @@ -0,0 +1,28 @@ +namespace IvyBus.Properties { + + + // This class allows you to handle specific events on the settings class: + // The SettingChanging event is raised before a setting's value is changed. + // The PropertyChanged event is raised after a setting's value is changed. + // The SettingsLoaded event is raised after the setting values are loaded. + // The SettingsSaving event is raised before the setting values are saved. + internal sealed partial class Settings { + + public Settings() { + // // To add event handlers for saving and changing settings, uncomment the lines below: + // + // this.SettingChanging += this.SettingChangingEventHandler; + // + // this.SettingsSaving += this.SettingsSavingEventHandler; + // + } + + private void SettingChangingEventHandler(object sender, System.Configuration.SettingChangingEventArgs e) { + // Add code to handle the SettingChangingEvent event here. + } + + private void SettingsSavingEventHandler(object sender, System.ComponentModel.CancelEventArgs e) { + // Add code to handle the SettingsSaving event here. + } + } +} diff --git a/Ivy/app.config b/Ivy/app.config new file mode 100644 index 0000000..e5b53b3 --- /dev/null +++ b/Ivy/app.config @@ -0,0 +1,30 @@ + + + + +
+ + + + + + 3 + + + False + + + False + + + + + + + + + + + + + \ No newline at end of file diff --git a/IvyToDel/Ivy/Ivy.cs b/IvyToDel/Ivy/Ivy.cs deleted file mode 100644 index 1c38396..0000000 --- a/IvyToDel/Ivy/Ivy.cs +++ /dev/null @@ -1,1183 +0,0 @@ -/// 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 diff --git a/IvyToDel/Ivy/Ivy.csproj b/IvyToDel/Ivy/Ivy.csproj deleted file mode 100644 index 1944b08..0000000 --- a/IvyToDel/Ivy/Ivy.csproj +++ /dev/null @@ -1,189 +0,0 @@ - - - Local - 8.0.50727 - 2.0 - {F2F03CF7-0087-4EDB-AD15-80C9E8DA2617} - SAK - SAK - SAK - SAK - Debug - AnyCPU - - - - - Ivy - - - JScript - Grid - IE50 - false - Library - IvyBus - OnBuildSuccess - - - - - - - - - bin\Debug\ - false - 285212672 - false - - - - - - - true - 4096 - false - - - false - false - false - false - 1 - full - prompt - AnyCPU - - - bin\Release\ - false - 285212672 - false - - - - - - - false - 4096 - false - - - false - false - false - false - 1 - none - prompt - - - true - bin\x86\Debug\ - 285212672 - 1 - full - x86 - prompt - - - - - bin\x86\Release\ - 285212672 - 1 - - - x86 - prompt - - - - mscorlib - - - System - - - - System.Design - - - - System.Management - - - System.Windows.Forms - - - - - - Component - - - - UserControl - - - IvyDomain.cs - - - - - - - Code - - - Component - - - Code - - - Code - - - Code - - - Code - - - - - Code - - - True - True - Settings.settings - - - - - - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - - - Designer - IvyDomain.cs - - - - - - - - - - \ No newline at end of file diff --git a/IvyToDel/Ivy/Ivy.csproj.vspscc b/IvyToDel/Ivy/Ivy.csproj.vspscc deleted file mode 100644 index 831ab8f..0000000 --- a/IvyToDel/Ivy/Ivy.csproj.vspscc +++ /dev/null @@ -1,10 +0,0 @@ -"" -{ -"FILE_VERSION" = "9237" -"ENLISTMENT_CHOICE" = "NEVER" -"PROJECT_FILE_RELATIVE_PATH" = "relative:Ivy" -"NUMBER_OF_EXCLUDED_FILES" = "0" -"ORIGINAL_PROJECT_FILE_PATH" = "" -"NUMBER_OF_NESTED_PROJECTS" = "0" -"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" -} diff --git a/IvyToDel/Ivy/Ivy.snippet b/IvyToDel/Ivy/Ivy.snippet deleted file mode 100644 index 5319177..0000000 --- a/IvyToDel/Ivy/Ivy.snippet +++ /dev/null @@ -1,43 +0,0 @@ - - - -
- - Ivy Message Callback - -
- - - - Ivy.dll - - - - - IvyBus - - - - - CallbackName - Replace with a function name. - bus_receive - - - Expression - Replace with a regular expression. - "^(.*)" - - - - - - -
-
diff --git a/IvyToDel/Ivy/IvyApplicationBinding.cs b/IvyToDel/Ivy/IvyApplicationBinding.cs deleted file mode 100644 index 9183850..0000000 --- a/IvyToDel/Ivy/IvyApplicationBinding.cs +++ /dev/null @@ -1,186 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Text; -using System.ComponentModel; -using System.Threading; - -namespace IvyBus -{ - /* This is the Application side of binding storage */ - /* association of a generated Key and a delegate and the expression */ - /* this is SEND to other client */ -#if (!PocketPC) - [PropertyTab(typeof(System.Windows.Forms.Design.EventsTab), PropertyTabScope.Component)] - [DefaultEvent("Callback")] -#endif - [DesignerCategory("Component")] - [DesignTimeVisible(false)] /* should be added via Ivy component */ - public class IvyApplicationBinding : System.ComponentModel.Component - { - private BindingType binding; - -#if (!PocketPC) - [Category("Ivy")] -#endif - public BindingType Binding - { - get { return binding; } - set { binding = value; } - } - private ushort key; - - #if (!PocketPC) - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] -#endif - public ushort Key - { - get { return key; } - set { key = value; } - } - - private object[] args; -#if (!PocketPC) - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] -#endif - public object[] Args - { - get { return args; } - set { args = value; } - } - private string expression; -#if (!PocketPC) - [Category("Ivy")] -#endif - [DefaultValue(null)] - public string Expression - { - get { return expression; } - set { expression = value; } - } - private string formated_expression; - public string FormatedExpression - { - get - { - FormatExpression(); - return formated_expression; - } - } - - private List arguments; - ///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, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", - "System.Drawing.Design.UITypeEditor,System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" - )] - - [Description("Arguments used when formating the expression")] -#endif - public List Arguments - { - get - { - return arguments; - } - } - -#if (!PocketPC) - [Category("Ivy")] - [Description("Event fired when Message Matching expression received")] -#endif - public event EventHandler Callback; - - public IvyApplicationBinding() - { - arguments = new List(); - } - public IvyApplicationBinding(IContainer container) - : this() - { - container.Add(this); - } - // translate part of expression to object property - public void FormatExpression() - { - //// Safely : -#if (!PocketPC)//TODO Pocket PC doesn't have Target Member - EventHandler temp = Callback; - if (temp != null) - { - //TODO Pocket PC doesn't have Target Member - object target = temp.Target; - if (args == null) - { - args = new object[arguments.Count]; - for (int i = 0; i < arguments.Count; i++) - { - System.Reflection.PropertyInfo prop = target.GetType().GetProperty(arguments[i]); - if (prop != null) - args[i] = prop.GetValue(target, null); - else //TODO what else BUG msgbox in desing mode !!! - args[i] = arguments[i]; - } - } - formated_expression = string.Format(expression, args); - } - else //TODO Abnormal condition Design Time -#endif - formated_expression = expression; - - } - -#if ( PocketPC ) - internal void Firevent(System.Windows.Forms.Control control, IvyMessageEventArgs e) - { - //// Safely invoke an event: - EventHandler temp = Callback; - - if (temp == null) - { - throw new IvyException("(callCallback) Not callback for id " + e.Id); - } - if (control != null) - { - control.Invoke(temp, this, e); - } - else - temp(this, e); - } -#else - internal void Firevent(System.Threading.SynchronizationContext syncContext, IvyMessageEventArgs e) - { - //// Safely invoke an event: - EventHandler temp = Callback; - - if (temp == null) - { - throw new IvyException("(callCallback) Not callback for id " + e.Id); - } - if (syncContext != null) - { - SendOrPostCallback update = delegate(object state) - { - IvyMessageEventArgs args = (IvyMessageEventArgs)state; - temp(this, args); - }; - syncContext.Post(update, e); - } - else - temp(this, e); - } - -#endif - } - -} diff --git a/IvyToDel/Ivy/IvyBinding.cs b/IvyToDel/Ivy/IvyBinding.cs deleted file mode 100644 index 624b401..0000000 --- a/IvyToDel/Ivy/IvyBinding.cs +++ /dev/null @@ -1,118 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Specialized; -using System.Text.RegularExpressions; -using System.Diagnostics; - -namespace IvyBus -{ - /* This is the Client side of binding storage */ - /* association of a generated Key and the expression and a compiled Expression matching */ - /* this is RECEIVED from other client */ - - /// - /// Description résumée de IvyBinding. - /// - internal abstract class IvyBindingBase - { - - private ushort key; - - internal ushort Key - { - get { return key; } - } - protected string expression; - - internal string Expression - { - get { return expression; } - } - - internal IvyBindingBase(ushort id, string exp) - { - key = id; - expression = exp; - } - internal abstract string[] Match(string message); - - } - internal class IvyBindingRegexp : IvyBindingBase - { - internal Regex regexp; - - public IvyBindingRegexp(ushort id, string exp) - : base(id, exp) - { - regexp = new Regex(expression, /* RegexOptions.Compiled | */RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); - //regexp.Match("###"); // for really compile the expression really slow on 3000 expression - } - internal override string[] Match(string message) - { - string[] args = null; - // use of regexp to extract info - Match result = regexp.Match(message); - if (result.Success) - { - // Start at 1 because group 0 represent entire matching - args = new string[result.Groups.Count-1]; - for (int sub = 1; sub < result.Groups.Count; sub++) - { - args[sub-1] = result.Groups[sub].Value; - } - } - return args; - } - } - internal class IvyBindingSimple : IvyBindingBase - { - internal string msgname; // message name - internal string[] msgargs; // list of message args names - static string msgtag; // send message name - static StringDictionary args_values; // send message args[name]=value - - internal IvyBindingSimple(ushort id, string exp) - : base(id, exp) - { - string[] expr = expression.Split( ' ' ); - msgname = expr[0]; - msgargs = new string[ expr.Length -1 ]; - for ( int i = 1; i < expr.Length; i++ ) - msgargs[i-1] = expr[i]; - } - static internal void Prepare(string message) - { - string[] msg = message.Split(' '); - msgtag = msg[0]; - args_values = new StringDictionary(); - for( int sub=1 ; sub < msg.Length; sub++ ) - { - string[] arg = msg[sub].Split('='); // champ = valeur - if ( arg.Length == 2 ) - args_values[arg[0]] = arg[1]; - else - { - Ivy.traceError("IvyBindingSimple" , "abnormally Formed message expected 'msg champ=valeur champ=valeur....' :" + message); - } - } - - } - internal override string[] Match(string message) - { - // the message is already parsed by prepare - // - string[] args = null; - - if (msgtag == msgname) - { - args = new string[msgargs.Length]; - for( int sub= 0; sub < msgargs.Length; sub++) - { - args[sub] = args_values[msgargs[sub]]; - } - } - return args; - } - - } -} diff --git a/IvyToDel/Ivy/IvyBindingAttribute.cs b/IvyToDel/Ivy/IvyBindingAttribute.cs deleted file mode 100644 index 90c44ce..0000000 --- a/IvyToDel/Ivy/IvyBindingAttribute.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace IvyBus -{ - [AttributeUsage(AttributeTargets.Method,AllowMultiple = true)] - public sealed class IvyBindingAttribute : Attribute - { - private string expression; - private string[] args; - - // translate part of expression to object property - public string GetExpression(object obj) - { - if (obj == null) return string.Format(expression); - object[] values = new object[args.Length]; - for (int i = 0; i < args.Length; i++) - { - values[i] = obj.GetType().GetProperty(args[i]).GetValue(obj,null); - } - return string.Format(expression,values); - } - - public IvyBindingAttribute(string expression, params string[] args) - { - this.expression = expression; - this.args = args; - } - } -} diff --git a/IvyToDel/Ivy/IvyClient.cs b/IvyToDel/Ivy/IvyClient.cs deleted file mode 100644 index 3db9f0f..0000000 --- a/IvyToDel/Ivy/IvyClient.cs +++ /dev/null @@ -1,592 +0,0 @@ -/// François-Régis Colin -/// http://www.tls.cena.fr/products/ivy/ -/// * -/// (C) CENA -/// * -namespace IvyBus -{ - using System; - using System.Collections; - 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; - - /// A Class for the the peers on the bus. - /// - /// - /// each time a connexion is made with a remote peer, the regexp are exchanged - /// once ready, a ready message is sent, and then we can send messages, - /// 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 int CompareTo(IvyClient other) - { - return (other.clientPriority - clientPriority); - } - - public String ApplicationName - { - get - { - return appName; - } - - } - - public List Regexps - { - get - { - List tab = new List(); - lock (bindings) - { - foreach (IvyBindingBase bind in bindings.Values) - tab.Add(bind.Expression); - } - return tab; - } - - } - internal int AppPort - { - get - { - return appPort; - } - - } - public IPAddress RemoteAddress - { - get - { - return remoteHost; - } - - } - public int RemotePort - { - get - { - return remotePort; - } - - } - - private Ivy bus; - private Dictionary bindings; - private int appPort; - 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 const int PINGTIMEOUT = 5000; - private volatile Thread pingerThread; - - private int remotePort; - private IPAddress remoteHost; - - // protected variables - internal String appName; - internal IvyProtocol stream; - - internal IvyClient(Ivy bus, Socket socket, string appname) - { - bindings = new Dictionary(); - appName = appname; - this.bus = bus; - - IPEndPoint endpoint = (IPEndPoint)socket.RemoteEndPoint; - - remoteHost = endpoint.Address; - remotePort = endpoint.Port; - -#if (!PocketPC ) - socket.SetSocketOption( SocketOptionLevel.Tcp, SocketOptionName.KeepAlive, 1 ); -#endif - - if ( bus.ProtocolVersion == 4 ) - stream = new IvyTCPStreamV4( socket, this ); - else - stream = new IvyTCPStreamV3(socket, this); - - clientPriority = Ivy.DEFAULT_PRIORITY; - // 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+")"; - clientThread.Start(); - - } - - internal void SendBindings() - { - try - { - stream.TokenApplicationId(bus.applicationPriority, bus.AppId); - - // 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.FormatedExpression); - } - } - stream.TokenEndRegexp(); - -#if (!PocketPC) - doping = Properties.Settings.Default.IvyPing; -#endif - if (doping) - { - pingerThread = new Thread(new ThreadStart(PingerRun)); - pingerThread.Name = "Ivy Pinger Thread"; - pingerThread.Start(); - } - - - } - catch (IOException ex) - { // the client nous a coupé l'herbe sous le pied - Ivy.traceError("IvyClient","I can't send my message to this client. He probably left " + 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 - /// given time. - /// perhaps we should implement a new IvyApplicationListener method to - /// allow the notification of regexp addition and deletion - /// - - /// sends a direct message to the peer - /// - /// the numeric value provided to the remote client - /// - /// the string that will be match-tested - /// - /// - public void SendDirectMsg(ushort id, string message) - { - try - { - stream.TokenDirectMsg( id, message); - } - catch (IOException ex) - { - Ivy.traceError("IvyClient","I can't send my message to this client. He probably left "+ex.Message); - // 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 - close(false); - } - } - - /// closes the connexion to the peer. - /// - /// should I send Bye message ? - /// the thread managing the socket is stopped - /// - /// - internal void close(bool notify) - { - Ivy.traceProtocol("IvyClient","closing connexion to " + appName); - if (doping ) - { - StopPinging(); - } - if (notify) - try - { - stream.TokenBye(0, "hasta la vista"); - } - catch (IOException ioe) - { - 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 (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; - - - } - - /// sends the substrings of a message to the peer for each matching regexp. - /// - /// the string that will be match-tested - /// - /// the number of messages sent to the peer - /// - /// - internal int sendMsg(String message) - { - int count = 0; - - lock( bindings ) - { - try - { - foreach (IvyBindingBase bind in bindings.Values) - { - string[] args = bind.Match(message); - if (stream != null && args != null) - { - stream.TokenMsg(bind.Key, args); - count++; - } - } - } - catch (IOException ex) - { - Ivy.traceError("IvyClient","I can't send my message to this client. He probably left " + ex.Message); - // first, I'm not a first class IvyClient any more - bus.removeClient(this); - // invokes the Disconnected applicationListeners - // in the receiver thread - close(false); - } - - - } - return count; - } - - /// compares two peers the id is the couple (host,service port). - /// - /// the other peer - /// - /// true if the peers are similir. This should not happen, it is bad - /// © ® (tm) - /// - /// - internal bool sameClient(IvyClient clnt) - { - return (appPort != 0 && appPort == clnt.appPort) && (RemoteAddress == clnt.RemoteAddress); - } - - /// the code of the thread handling the incoming messages. - /// - private void Run() - { - Ivy.traceProtocol("IvyClient","Connected from " + RemoteAddress + ":" + RemotePort); - - Ivy.traceProtocol("IvyClient","Thread started"); - - bool running = true; - while ( running && (stream != null) ) - { - try - { - if ( stream.receiveMsg() ) - { - // early stop during readLine() - if (doping && (pingerThread != null)) - pingerThread.Abort(); - } - else - { - Ivy.traceProtocol("IvyClient","receiveMsg false ! leaving the thread"); - running = false; - break; - } - } - catch ( ObjectDisposedException ex ) - { - Ivy.traceError("IvyClient", "socket closed "+ex.Message ); - running = false; - break; - } - catch (IvyException ie) - { - Ivy.traceError("IvyClient","socket closed IvyException" + ie.Message); - running = false; - break; - } - catch (SocketException se) - { - Ivy.traceError("IvyClient", "socket closed "+se.Message ); - running = false; - break; - } - catch (IOException ex) - { - if ( ex.InnerException is SocketException ) - { - Ivy.traceProtocol("IvyClient", "socket closed" ); - - } - else - { - Ivy.traceError("IvyClient","abnormally Disconnected from " + RemoteAddress + ":" + RemotePort); - } - running = false; - break; - } - } - Ivy.traceProtocol("IvyClient","normally Disconnected from " + appName); - Ivy.traceProtocol("IvyClient","Thread stopped"); - // invokes the Disconnected applicationListeners - bus.OnClientDisconnected(new IvyEventArgs(this,0, "" )); - // first, I'm not a first class IvyClient any more - 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(ushort id, string arg) - { - Ivy.traceProtocol("IvyClient","received die Message from " + appName + "Raison: "+ 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 - bus.Stop(); - close(false); - if (ev.ForceExit) -#if (PocketPC) - System.Windows.Forms.Application.Exit(); -#else - System.Environment.Exit(0); -#endif - } - void IvyProtocol.TokenBye(ushort err, string arg) - { - // the peer quits - Ivy.traceProtocol("IvyClient","received bye Message from " + appName + "Raison: "+ 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 - //bus.FireClientDisconnected(this); done in Running Thread - close(false); // will fire disconnected - } - - void IvyProtocol.TokenAddBinding(BindingType type, ushort id, string expression) - { - - if (type == BindingType.Regexp && !bus.CheckRegexp(expression)) - { - bus.OnClientFilterBinding(new IvyEventArgs(this, id, expression )); - return; - } - IvyBindingBase bind = null; - try - { - switch (type) - { - case BindingType.Regexp: - bind = new IvyBindingRegexp(id, expression); - break; - case BindingType.Simple: - bind = new IvyBindingSimple(id, expression); - break; - } - lock (bindings) - { - bindings.Add(id, bind); - } - - bus.OnClientAddBinding(new IvyEventArgs(this, id, expression)); - - } - catch (ArgumentException ex) - { - throw new IvyException("binding expression error " + ex.Message); - } - - } - void IvyProtocol.TokenDelBinding(ushort id) - { - lock( bindings ) - { - try - { - IvyBindingBase bind = bindings[id]; - bus.OnClientRemoveBinding(new IvyEventArgs(this, bind.Key, bind.Expression)); - bindings.Remove(id); - } - catch (KeyNotFoundException ex) - { - Ivy.traceError("IvyClient","DelBinding " + ex.Message); - } - } - } - void IvyProtocol.TokenMsg(ushort id, string[] args) - { - bus.OnMessage(new IvyMessageEventArgs(this, id, args)); - } - void IvyProtocol.TokenError(ushort id, string arg) - { - bus.OnError(new IvyEventArgs(this, id, arg)); - Ivy.traceError("IvyClient","Error msg " + id + " " + arg); - } - void IvyProtocol.TokenApplicationId(ushort id, string arg) - { - clientId = arg; - if ( clientPriority != id ) - { - clientPriority = id; - bus.SortClients(); - } - } - void IvyProtocol.TokenEndRegexp() - { - /* - * the peer is perhaps not ready to handle this message - * an assymetric processing should be written - */ - if (bus.ReadyMessage != null) - sendMsg(bus.ReadyMessage); - bus.OnClientConnected(new IvyEventArgs(this, 0, "")); - } - void IvyProtocol.TokenStartRegexp(ushort id, string arg) - { - appName = arg; - appPort = id; - if (bus.checkConnected(this)) - { - close(false); - throw new IvyException("Rare ! A concurrent connect occured"); - } - - } - void IvyProtocol.TokenDirectMsg(ushort id, string arg) - { - bus.OnDirectMessage(new IvyEventArgs(this,id,arg)); - } - void IvyProtocol.TokenPing(string arg) - { - // I receive a ping. I can answer a pong. - Ivy.traceProtocol("IvyClient","Ping msg from " + appName + " : " + arg ); - stream.TokenPong(arg); - } - void IvyProtocol.TokenPong(string arg) - { - Ivy.traceProtocol("IvyClient","Ping msg from " + appName + " : " + arg); - } - - - - public override String ToString() - { - return "IvyClient " + bus.appName + ":" + appName; - } - - /* is the Pinging Thread Runninng */ - internal bool isPinging; - - private void PingerRun() - { - isPinging = true; - Ivy.traceProtocol("IvyClient","Pinger Thread started"); - while (isPinging) - { - try - { - Thread.Sleep(PINGTIMEOUT); - stream.TokenPing("are you here ?"); - } - catch (ThreadAbortException ie) - { - Ivy.traceError("IvyClient","Pinger Thread killed "+ie.Message); - } - } - Ivy.traceProtocol("IvyClient","Pinger Thread stopped"); - } - 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). - } - // Free your own state (unmanaged objects). - // Set large fields to null. - if (stream != null) - { - stream.Close(); - stream = 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/IvyToDel/Ivy/IvyDomain.Designer.cs b/IvyToDel/Ivy/IvyDomain.Designer.cs deleted file mode 100644 index 3f89b6a..0000000 --- a/IvyToDel/Ivy/IvyDomain.Designer.cs +++ /dev/null @@ -1,75 +0,0 @@ -namespace IvyBus -{ - partial class IvyDomain - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Component Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.label1 = new System.Windows.Forms.Label(); - this.ivybus = new System.Windows.Forms.TextBox(); - this.SuspendLayout(); - // - // label1 - // - this.label1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left))); - this.label1.Location = new System.Drawing.Point(0, 5); - this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(24, 13); - this.label1.Text = "Ivy:"; - // - // ivybus - // - this.ivybus.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.ivybus.Location = new System.Drawing.Point(30, 0); - 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); - // - // IvyDomain - // - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit; - this.Controls.Add(this.label1); - this.Controls.Add(this.ivybus); - this.Name = "IvyDomain"; - this.Size = new System.Drawing.Size(159, 22); - this.ResumeLayout(false); -#if (!PocketPC) - this.PerformLayout(); -#endif - - } - - #endregion - - private System.Windows.Forms.Label label1; - private System.Windows.Forms.TextBox ivybus; - } -} diff --git a/IvyToDel/Ivy/IvyDomain.cs b/IvyToDel/Ivy/IvyDomain.cs deleted file mode 100644 index 6c43b73..0000000 --- a/IvyToDel/Ivy/IvyDomain.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Text; -using System.Windows.Forms; - -namespace IvyBus -{ - public partial class IvyDomain : UserControl - { - private string domain = ""; - public event EventHandler DomainChanged; -#if (!PocketPC) - [Category("Ivy")] - [DefaultValue("")] - [Bindable(true)] -#endif - public string Domain - { - get { return domain; } - set { - if (domain != value) - { - domain = value; - ivybus.Text = domain; - if (DomainChanged != null) DomainChanged(this, EventArgs.Empty); - } - } - } - - public IvyDomain() - { - InitializeComponent(); - } - public void SetDefault() - { - if (IsEmpty()) - { - domain = Ivy.GetDomain(domain); - ivybus.Text = domain; - } - } - public bool IsEmpty() - { - return String.IsNullOrEmpty( domain ); - } - - private void ivybus_Validating(object sender, CancelEventArgs e) - { - e.Cancel = !Ivy.ValidatingDomain(ivybus.Text); - } - - private void ivybus_Validated(object sender, EventArgs e) - { - if ( domain != ivybus.Text ) - Domain = ivybus.Text; - } - - } -} diff --git a/IvyToDel/Ivy/IvyDomain.resx b/IvyToDel/Ivy/IvyDomain.resx deleted file mode 100644 index ff31a6d..0000000 --- a/IvyToDel/Ivy/IvyDomain.resx +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/IvyToDel/Ivy/IvyEventArgs.cs b/IvyToDel/Ivy/IvyEventArgs.cs deleted file mode 100644 index e394802..0000000 --- a/IvyToDel/Ivy/IvyEventArgs.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace IvyBus -{ - /// The EventArgs Classes - /// - /// - public class IvyEventArgs : EventArgs - { - private IvyClient client; - private int id; - private string arg; - - public IvyClient Client - { - get { return client; } - } - - public int Id - { - get { return id; } - } - - public string Argument - { - get { return arg; } - } - public IvyEventArgs(IvyClient app, int id, string arg) - { - this.client = app; - this.id = id; - this.arg = arg; - } - } - public class IvyDieEventArgs : IvyEventArgs - { - /* return value for Die Event */ - private bool forceExit; - - public bool ForceExit - { - get { return forceExit; } - set { forceExit = value; } - } - public IvyDieEventArgs(IvyClient app, int id, string arg) - : base(app, id, arg) - { - forceExit = true; - } - } - public class IvyMessageEventArgs : EventArgs - { - private IvyClient client; - private int id; - private string[] args; - - public IvyClient Client - { - get { return client; } - } - - public int Id - { - get { return id; } - } - - public string[] Arguments - { - get { return args; } - } - public string this[int i] - { - get { return args[i]; } - } - public IvyMessageEventArgs(IvyClient app, int id, string[] args) - { - this.client = app; - this.id = id; - this.args = args; - } - } -} diff --git a/IvyToDel/Ivy/IvyException.cs b/IvyToDel/Ivy/IvyException.cs deleted file mode 100644 index 90a91b8..0000000 --- a/IvyToDel/Ivy/IvyException.cs +++ /dev/null @@ -1,19 +0,0 @@ -/// François-Régis Colin -/// http://www.tls.cena.fr/products/ivy/ -/// * -/// (C) CENA -/// * -namespace IvyBus -{ - using System; - - /// signals that an unrecoverrable Ivy exception has occured. - /// - - public class IvyException:System.Exception - { - public IvyException(System.String s):base(s) - { - } - } -} \ No newline at end of file diff --git a/IvyToDel/Ivy/IvyProtocol.cs b/IvyToDel/Ivy/IvyProtocol.cs deleted file mode 100644 index 1b1f3aa..0000000 --- a/IvyToDel/Ivy/IvyProtocol.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using System.Text; - -namespace IvyBus -{ - public enum BindingType { Regexp, Simple }; - - internal interface IvyProtocol - { - void Close(); - bool receiveMsg(); - void TokenStartRegexp(ushort port, string appName); - void TokenEndRegexp(); - void TokenApplicationId(ushort priority, string appId); - void TokenAddBinding(BindingType type, ushort id, string expression); - void TokenDelBinding(ushort bind); - void TokenDirectMsg(ushort id, string message); - void TokenPong(string s); - void TokenPing(string s); - void TokenBye(ushort id, string message); - void TokenDie(ushort err, string message); - void TokenMsg(ushort key, string[] args); - void TokenError(ushort id, string message); - } -} diff --git a/IvyToDel/Ivy/IvyTCPStream.cs b/IvyToDel/Ivy/IvyTCPStream.cs deleted file mode 100644 index b8fee34..0000000 --- a/IvyToDel/Ivy/IvyTCPStream.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Collections.Specialized; -using System.Text; -using System.Net; -using System.Net.Sockets; -using System.IO; - -namespace IvyBus -{ - abstract class IvyTCPStream : NetworkStream - { - public IvyTCPStream(Socket socket) - : base(socket, true) - { - } - - abstract internal bool receiveMsg(); - - } -} diff --git a/IvyToDel/Ivy/IvyTCPStreamV3.cs b/IvyToDel/Ivy/IvyTCPStreamV3.cs deleted file mode 100644 index 4eef12c..0000000 --- a/IvyToDel/Ivy/IvyTCPStreamV3.cs +++ /dev/null @@ -1,254 +0,0 @@ -using System; -using System.Net; -using System.Net.Sockets; -using System.Text; -using System.Collections; -using System.Collections.Specialized; -using System.IO; - -namespace IvyBus -{ - /// - /// Description résumée de IvyStream. - /// - internal class IvyTCPStreamV3 : NetworkStream, IvyProtocol - { - StreamReader input; - StreamWriter output; - IvyProtocol receiver; - - /// the protocol separator - internal const char ARG_START = '\x02'; - internal const char ARG_END = '\x03'; - internal const char MSG_END = '\n'; - - internal IvyTCPStreamV3(Socket socket, IvyProtocol _receiver) : base ( socket ) - { - output = new StreamWriter(this, Encoding.ASCII); - output.NewLine = MSG_END.ToString(); - input = new StreamReader(this, Encoding.ASCII); - receiver = _receiver; - } - /* the protocol magic numbers */ - internal enum MessageType : ushort - { - Bye = 0, /* end of the peer */ - AddRegexp = 1, /* the peer adds a regexp */ - Msg = 2, /* the peer sends a message */ - Error = 3, /* error message */ - DelBinding = 4, /* the peer removes one of his regex */ // OLD DelRegexp rename to DelBinding - EndRegexp = 5, /* no more regexp in the handshake */ - StartRegexp = 6, /* avoid race condition in concurrent connexions */ - DirectMsg = 7, /* the peer sends a direct message */ - Die = 8, /* the peer wants us to quit */ - Ping = 9, /* checks the presence of the other */ - Pong = 10, /* checks the presence of the other */ - }; - - /* - * message Syntax: - * this is text formated message 'type id STX ARG0 {[ETX] ARG1 [ETX] ARGn}\n' - * - * message Format: - MessageType, id , length, string - */ - - private void sendMsg(MessageType msgType, ushort msgId, string msgData) - { - // IOException Should be traited upstairs - output.Write((ushort)msgType); - output.Write(' '); - output.Write(msgId); - output.Write(ARG_START); - output.Write(msgData); - output.Write(MSG_END); - output.Flush(); - - } - void IvyProtocol.TokenStartRegexp(ushort port, string appName) - { - sendMsg(MessageType.StartRegexp, port, appName); - } - void IvyProtocol.TokenEndRegexp() - { - sendMsg(MessageType.EndRegexp, 0, ""); - } - void IvyProtocol.TokenApplicationId(ushort priority, string appId) - { - // NOt implemented in this protocol version - } - - void IvyProtocol.TokenAddBinding(BindingType type, ushort id, string expression) - { - switch (type) - { - case BindingType.Regexp: - sendMsg(MessageType.AddRegexp, id, expression); /* perhaps we should perform some checking here */ - break; - case BindingType.Simple: - // NO Simple Binding in this protocol - break; - } - } - - void IvyProtocol.TokenDelBinding(ushort id) - { - sendMsg(MessageType.DelBinding, id, ""); - } - - void IvyProtocol.TokenDirectMsg(ushort id, string message) - { - sendMsg(MessageType.DirectMsg, id, message); - } - void IvyProtocol.TokenPong(string s) - { - sendMsg(MessageType.Pong, 0, s); - } - void IvyProtocol.TokenPing(string s) - { - sendMsg(MessageType.Ping, 0, s); - } - - void IvyProtocol.TokenBye(ushort id, string message) - { - sendMsg(MessageType.Bye, id, message); - } - - void IvyProtocol.TokenDie(ushort id, string message) - { - sendMsg(MessageType.Die, id, message); - } - - void IvyProtocol.TokenMsg(ushort key, string[] args) - { - string delimiter = "" + ARG_END; - string data = string.Join(delimiter, args); - // a bad protocol implementation in C add a delimiter to the end of each arg - // we must add a delimiter to the end - data += delimiter; - sendMsg(MessageType.Msg, key, data); - } - - void IvyProtocol.TokenError(ushort key, string arg) - { - sendMsg(MessageType.Msg, key, arg); - } - - private ushort DeserializeShort() - { - int read; - ushort ret = 0; - char digit; - // this will eat next non digit char ie space - do - { - read = input.Read(); - if (read < 0) - throw new EndOfStreamException(); - digit = (char)read; - if (Char.IsDigit(digit)) - ret = (ushort)(ret * 10 + (digit - 0x30)); - } while (Char.IsDigit(digit)); - return ret; - } - private string DeserializeString(char sep) - { - int read; - char car; - StringBuilder str = new StringBuilder(); - // this will eat next non separator char - do - { - read = input.Read(); - if (read < 0) - throw new EndOfStreamException(); - car = (char)read; - if (car != sep ) str.Append(car); - } while (car != sep); - return str.ToString(); - } - - bool IvyProtocol.receiveMsg() - { - MessageType msgType = MessageType.Die; - ushort msgId = 0; - string msgData = null; - - try - { - msgType = (MessageType)DeserializeShort(); - msgId = DeserializeShort(); - msgData = DeserializeString(MSG_END); - - switch (msgType) - { - case MessageType.Die: - receiver.TokenDie(msgId, msgData); - break; - - case MessageType.Bye: - receiver.TokenBye(msgId, msgData); - break; - - case MessageType.AddRegexp: - receiver.TokenAddBinding(BindingType.Regexp, msgId, msgData); - break; - - case MessageType.DelBinding: - receiver.TokenDelBinding(msgId); - break; - - case MessageType.EndRegexp: - receiver.TokenEndRegexp(); - break; - - case MessageType.Msg: - // a bad protocol implementation in C add a delimiter to the end of each arg - // we must remove a delimiter to the end - if ( msgData.Length > 0 ) - msgData = msgData.Remove(msgData.Length - 1,1); - receiver.TokenMsg(msgId, msgData.Split( ARG_END )); - break; - - case MessageType.Pong: - receiver.TokenPong(msgData); - break; - - case MessageType.Ping: - receiver.TokenPing(msgData); - break; - - case MessageType.Error: - receiver.TokenError(msgId, msgData); - break; - - case MessageType.StartRegexp: - receiver.TokenStartRegexp(msgId, msgData); - break; - - case MessageType.DirectMsg: - receiver.TokenDirectMsg(msgId, msgData); - break; - default: - throw new IvyException("protocol error, unknown message type " + msgType); - - } - - - - } - catch (EndOfStreamException) - { - return false; - } - catch (FormatException) - { - throw new IvyException("protocol error on msgType"); - } - - - return true; - } - - } -} diff --git a/IvyToDel/Ivy/IvyTCPStreamV4.cs b/IvyToDel/Ivy/IvyTCPStreamV4.cs deleted file mode 100644 index 9a96d62..0000000 --- a/IvyToDel/Ivy/IvyTCPStreamV4.cs +++ /dev/null @@ -1,273 +0,0 @@ -using System; -using System.Net; -using System.Net.Sockets; -using System.Text; -using System.Collections; -using System.Collections.Specialized; -using System.IO; - -namespace IvyBus -{ - /// - /// Description résumée de IvyStream. - /// - internal class IvyTCPStreamV4 : NetworkStream , IvyProtocol - { - BinaryReader input; - BinaryWriter output; - IvyProtocol receiver; - - /* the protocol magic numbers */ - internal enum MessageType : ushort - { - Bye = 0, /* end of the peer */ - AddRegexp = 1, /* the peer adds a regexp */ - Msg = 2, /* the peer sends a message */ - Error = 3, /* error message */ - DelBinding = 4, /* the peer removes one of his regex */ // OLD DelRegexp rename to DelBinding - EndRegexp = 5, /* no more regexp in the handshake */ - StartRegexp = 6, /* avoid race condition in concurrent connexions */ - DirectMsg = 7, /* the peer sends a direct message */ - Die = 8, /* the peer wants us to quit */ - Ping = 9, /* checks the presence of the other */ - Pong = 10, /* checks the presence of the other */ - ApplicationId = 11, /* on start send my ID and priority */ - AddBinding = 12, /* other methods for binding message based on hash table */ - - }; - - internal IvyTCPStreamV4(Socket socket, IvyProtocol _receiver) : base( socket ) - { - - input = new BinaryReader(this, Encoding.ASCII); - output = new BinaryWriter(this, Encoding.ASCII); - receiver = _receiver; - } - - - /* - * message Syntax: - * this is a binary formated message use of network representation - * - * message Format: - MessageType, id , length, string - */ - private void Serialize(short arg) - { - output.Write((ushort)IPAddress.HostToNetworkOrder(arg)); - } - private void Serialize(string arg) - { - short length = arg != null ? (short)arg.Length : (short)0; - Serialize(length); - if (length != 0) - output.Write(arg.ToCharArray()); - } - private void Serialize(string[] arg) - { - - /* serialize count */ - Serialize((short)arg.Length); - - for (int i = 0; i < arg.Length; i++) - { - Serialize(arg[i]); - } - } - private void sendMsg(MessageType type, int id, params string[] arg) - { - - Serialize( (short)type ); - Serialize( (short)id ); - Serialize(arg); - output.Flush(); - - } - void IvyProtocol.TokenStartRegexp(ushort port, string appName) - { - sendMsg(MessageType.StartRegexp, port, appName); - } - void IvyProtocol.TokenEndRegexp() - { - sendMsg(MessageType.EndRegexp, 0, ""); - } - void IvyProtocol.TokenApplicationId(ushort priority, string appId) - { - sendMsg(MessageType.ApplicationId, priority, appId); - } - - void IvyProtocol.TokenAddBinding(BindingType type, ushort id, string expression) - { - switch (type) - { - case BindingType.Regexp: - sendMsg(MessageType.AddRegexp, id, expression); /* perhaps we should perform some checking here */ - break; - case BindingType.Simple: - sendMsg(MessageType.AddBinding, id, expression); /* perhaps we should perform some checking here */ - break; - } - } - - void IvyProtocol.TokenDelBinding(ushort id) - { - sendMsg(MessageType.DelBinding, id, null ); - } - - void IvyProtocol.TokenDirectMsg(ushort id, string message) - { - sendMsg(MessageType.DirectMsg, id, message); - } - void IvyProtocol.TokenPong(string s) - { - sendMsg(MessageType.Pong, 0, s); - } - void IvyProtocol.TokenPing(string s) - { - sendMsg(MessageType.Ping, 0, s); - } - - void IvyProtocol.TokenBye(ushort id, string message) - { - sendMsg(MessageType.Bye, id, message); - } - - void IvyProtocol.TokenDie(ushort id, string message) - { - sendMsg(MessageType.Die, id, message); - } - - void IvyProtocol.TokenMsg(ushort key, string[] args) - { - sendMsg(MessageType.Msg, key, args ); - } - - void IvyProtocol.TokenError(ushort key, string arg) - { - sendMsg(MessageType.Msg, key, arg); - } - - private short DeserializeShort() - { - return IPAddress.NetworkToHostOrder((short)input.ReadUInt16()); - } - private string DeserializeString() - { - string arg; - int val_len; - char[] data; - val_len = (ushort)DeserializeShort(); - if (val_len != 0) - { - data = input.ReadChars(val_len); - arg = new String(data); - } - else - arg = ""; - return arg; - } - - - private string[] DeserializeArgument() - { - int nb_children; - string[] arg; - - /* Deserialize childrens */ - nb_children = (ushort)DeserializeShort(); - /* deserialize Value */ - arg = new string[nb_children]; - - for (int i = 0; i < nb_children; i++) - { - arg[i] = DeserializeString(); - } - return arg; - } - bool IvyProtocol.receiveMsg() - { - MessageType msgType = MessageType.Die; - ushort msgId = 0; - string[] msgData = null; - - try - { - msgType = (MessageType)(ushort)DeserializeShort(); - msgId = (ushort)DeserializeShort(); - msgData = DeserializeArgument(); - - switch (msgType) - { - case MessageType.Die: - receiver.TokenDie(msgId, msgData[0]); - break; - - case MessageType.Bye: - receiver.TokenBye(msgId, msgData[0]); - break; - - case MessageType.AddRegexp: - receiver.TokenAddBinding(BindingType.Regexp, msgId, msgData[0]); - break; - - case MessageType.AddBinding: - receiver.TokenAddBinding(BindingType.Simple, msgId, msgData[0]); - break; - - case MessageType.DelBinding: - receiver.TokenDelBinding(msgId); - break; - - case MessageType.EndRegexp: - receiver.TokenEndRegexp(); - break; - - case MessageType.Msg: - receiver.TokenMsg( msgId, msgData ); - break; - - case MessageType.Pong: - receiver.TokenPong(msgData[0]); - break; - - case MessageType.Ping: - receiver.TokenPing(msgData[0]); - break; - - case MessageType.Error: - receiver.TokenError(msgId, msgData[0]); - break; - - case MessageType.StartRegexp: - receiver.TokenStartRegexp(msgId, msgData[0]); - break; - - case MessageType.DirectMsg: - receiver.TokenDirectMsg(msgId, msgData[0]); - break; - case MessageType.ApplicationId: - receiver.TokenApplicationId(msgId, msgData[0]); - break; - default: - throw new IvyException("protocol error, unknown message type " + msgType); - - } - - - - } - catch (EndOfStreamException) - { - return false; - } - catch (FormatException) - { - throw new IvyException("protocol error on msgType"); - } - - - return true; - } - - } -} diff --git a/IvyToDel/Ivy/IvyUDPStream.cs b/IvyToDel/Ivy/IvyUDPStream.cs deleted file mode 100644 index 0e3f517..0000000 --- a/IvyToDel/Ivy/IvyUDPStream.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Net; -using System.Net.Sockets; -using System.IO; - -namespace IvyBus -{ - abstract class IvyUDPStream - { - Socket socket; - byte[] buffer; - - protected MemoryStream out_stream; - protected MemoryStream in_stream; - - ushort protocol_version; - - public ushort ProtocolVersion - { - get { return protocol_version; } - } - - public IvyUDPStream(Socket _socket, ushort protocol) - { - socket = _socket; - buffer = new byte[4096]; - in_stream = new MemoryStream(buffer); - out_stream = new MemoryStream(); - protocol_version = protocol; - } - internal void Close() - { - in_stream.Close(); - out_stream.Close(); - socket.Shutdown(SocketShutdown.Both); - socket.Close(); - } - internal void receiveMsg(out IPEndPoint remote, out ushort version, out ushort port, out string appId, out string appName) - { - int len; - IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, 0); - EndPoint tempRemoteEP = (EndPoint)remoteEP; - remoteEP = null; - len = socket.ReceiveFrom(buffer, ref tempRemoteEP); - remote = (IPEndPoint)tempRemoteEP; - in_stream.Position = 0; - in_stream.SetLength(len); - in_stream.Seek(0, SeekOrigin.Begin); - //Call Deserialization - Deserialize( out version, out port, out appId, out appName ); - } - internal void sendMsg(IPEndPoint EPhost, ushort port, string appId, string appName) - { - // Call Serialisation - Serialize(port, appId, appName); - - byte[] hellob = out_stream.GetBuffer(); - socket.SendTo(hellob, (int)out_stream.Length, 0, EPhost); - } - abstract internal void Serialize(ushort port, string appId, string appName); - abstract internal void Deserialize(out ushort version, out ushort port, out string appId, out string appName); - - } -} diff --git a/IvyToDel/Ivy/IvyUDPStreamV3.cs b/IvyToDel/Ivy/IvyUDPStreamV3.cs deleted file mode 100644 index 63a8679..0000000 --- a/IvyToDel/Ivy/IvyUDPStreamV3.cs +++ /dev/null @@ -1,104 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Net; -using System.Net.Sockets; -using System.IO; - -namespace IvyBus -{ - class IvyUDPStreamV3 : IvyUDPStream - { - StreamReader input; - StreamWriter output; - - /// the protocol version number - internal const int PROCOCOLVERSION = 3; - - public IvyUDPStreamV3(Socket _socket) : base( _socket , PROCOCOLVERSION ) - { - input = new StreamReader(in_stream, Encoding.ASCII); - output = new StreamWriter(out_stream, Encoding.ASCII); - } - /* - * message Syntax: - * this is a text formated message - * - * message Format: - protocol_version, TCP server port , appId, appName - */ - private ushort DeserializeShort() - { - int read; - ushort ret = 0; - char digit; - // this will eat next non digit car ie space - do - { - read = input.Read(); - if (read < 0) - throw new EndOfStreamException(); - digit = (char)read; - if ( Char.IsDigit(digit) ) - ret = (ushort)(ret * 10 + (digit-0x30)); - } while (Char.IsDigit(digit)); - return ret; - } - private string DeserializeString(char sep) - { - int read; - char car; - StringBuilder str = new StringBuilder(); - // this will eat next non digit car ie space - do - { - read = input.Read(); - if (read < 0) - throw new EndOfStreamException(); - if (read == 0) break; - car = (char)read; - if (car != sep) - str.Append(car); - } while (car != sep); - return str.ToString(); - } - - internal override void Deserialize(out ushort version, out ushort port, out string appId, out string appName) - { - version = 0; - port = 0; - appId = ""; - appName = ""; - try { - version = DeserializeShort(); - port = DeserializeShort(); - //Optionel in V3 protocol depend on client version - appId = DeserializeString(' '); - appName = DeserializeString('\n'); - } - catch( EndOfStreamException ) - { - // Bad protocol message receive or without appId and appName - } - input.DiscardBufferedData(); - } - private void Serialize(ushort arg, char sep) - { - output.Write(arg); - output.Write(sep); - } - private void Serialize(string arg, char sep) - { - output.Write(arg); - output.Write(sep); - } - internal override void Serialize(ushort port, string appId, string appName) - { - Serialize(PROCOCOLVERSION, ' '); - Serialize(port,' '); - Serialize(appId,' '); //No AppId in V3 - Serialize(appName, '\n'); //No Appname in V3 - output.Flush(); - } - } -} diff --git a/IvyToDel/Ivy/IvyUDPStreamV4.cs b/IvyToDel/Ivy/IvyUDPStreamV4.cs deleted file mode 100644 index b8d329a..0000000 --- a/IvyToDel/Ivy/IvyUDPStreamV4.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Net; -using System.Net.Sockets; -using System.IO; - -namespace IvyBus -{ - class IvyUDPStreamV4 : IvyUDPStream - { - - BinaryReader input; - BinaryWriter output; - - /// the protocol version number - internal const ushort PROCOCOLVERSION = 4; - public IvyUDPStreamV4(Socket _socket) : base ( _socket, PROCOCOLVERSION) - { - input = new BinaryReader( in_stream,Encoding.ASCII); - output = new BinaryWriter(out_stream, Encoding.ASCII); - } - /* - * message Syntax: - * this is a binary formated message use of network representation - * - * message Format: - protocol_version, TCP server port , lenAppId, appId, lenAppNameId, appName - */ - private ushort DeserializeShort() - { - return (ushort)IPAddress.NetworkToHostOrder((ushort)input.ReadUInt16()); - } - private string DeserializeString() - { - string arg; - int val_len; - char[] data; - val_len = (ushort)IPAddress.NetworkToHostOrder((ushort)input.ReadUInt16()); - if (val_len != 0) - { - data = input.ReadChars(val_len); - arg = new String(data); - } - else - arg = ""; - return arg; - } - - internal override void Deserialize(out ushort version, out ushort port, out string appId, out string appName) - { - version = DeserializeShort(); - port = DeserializeShort(); - appId = DeserializeString(); - appName = DeserializeString(); - - } - private void Serialize(ushort arg) - { - output.Write((ushort)IPAddress.HostToNetworkOrder(arg)); - } - private void Serialize(string arg) - { - ushort length = arg != null ? (ushort)arg.Length : (ushort)0; - Serialize(length); - if (length != 0) - output.Write(arg.ToCharArray()); - } - - internal override void Serialize(ushort port, string appId, string appName) - { - Serialize(PROCOCOLVERSION ); - Serialize(port); - Serialize(appId); - Serialize(appName); - output.Flush(); - } - - } -} diff --git a/IvyToDel/Ivy/IvyWatcher.cs b/IvyToDel/Ivy/IvyWatcher.cs deleted file mode 100644 index 5a3afc8..0000000 --- a/IvyToDel/Ivy/IvyWatcher.cs +++ /dev/null @@ -1,179 +0,0 @@ - -/// François-Régis Colin -/// http://www.tls.cena.fr/products/ivy/ -/// * -/// (C) CENA -/// * - -namespace IvyBus -{ - using System; - using System.Threading; - using System.IO; - using System.Net; - using System.Net.Sockets; - using System.Text.RegularExpressions; - using System.Configuration; - using System.Text; - using System.Diagnostics; - - /// IvyWatcher, A private Class for the Ivy rendezvous - /// - /// right now, the rendez vous is either an UDP socket or a TCP multicast. - /// The watcher will answer to - /// each peer advertising its arrival on the bus. The intrinsics of Unix are so - /// that the broadcast is done using the same socket, which is not a good - /// thing. - /// - internal class IvyWatcher - { - private Ivy bus; /* master bus controler */ - private int port; - private volatile Thread listenThread; - private IPAddress group; - private IvyUDPStream stream; - - /// creates an Ivy watcher - /// - /// the bus - /// - /// the domain - /// - /// the port number - /// - internal IvyWatcher(Ivy bus, String domainaddr, int port) - { - this.bus = bus; - this.port = port; - 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); - broadcast.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast,1); - broadcast.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress,1); - 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.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) - { - throw new IvyException("IvyWatcher I/O error" + e); - } - } - - /// the behaviour of each thread watching the UDP socket. - /// - public void Run() - { - Ivy.traceProtocol("IvyWatcher", "beginning of a watcher Thread"); - - try - { - bool running = true; - while (running) - { - ushort version; - ushort 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("IvyWatcher", "Receive Broadcast from " + Dns.GetHostEntry(remotehost).HostName + ":" + remoteEP.Port); - - //TODO if ( !isInDomain( remotehost ) ) continue; - - if (version != stream.ProtocolVersion) - { - Ivy.traceError("IvyWatcher","Ignoring bad protocol version " + version + " expected " + stream.ProtocolVersion); - continue; - } - - // filtrage des self Broadcast - if (appId == bus.AppId) - continue; - if ((appPort == bus.applicationPort) && (remotehost.Equals(bus.applicationHost))) - continue; - - Ivy.traceProtocol("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); - bus.addClient(socket, appName); - } - catch (Exception e) - { - Ivy.traceError("IvyWatcher","can't connect to " + remotehost + " port " + appPort + " \n" + e.Message); - } - - } // while - } - catch (SocketException se) - { - Ivy.traceError("IvyWatcher","watcher socket closed: " + se.Message); - } - catch (IOException ioe) - { - Ivy.traceError("IvyWatcher","watcher thread ended: " + ioe.Message); - } - Ivy.traceProtocol("IvyWatcher", "end of a watcher thread"); - } - - /// stops the thread waiting on the broadcast socket - /// - internal virtual void stop() - { - lock (stream) - { - Ivy.traceProtocol("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(); - listenThread = null; - } - // it might not even have been created - Ivy.traceProtocol("IvyWatcher", "ending stopping an IvyWatcher"); - } - } - - internal virtual void start() - { - 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 - } - } - - - } -} \ No newline at end of file diff --git a/IvyToDel/Ivy/Properties/AssemblyInfo.cs b/IvyToDel/Ivy/Properties/AssemblyInfo.cs deleted file mode 100644 index a3ce834..0000000 --- a/IvyToDel/Ivy/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. - -[assembly: AssemblyTitle("Ivy")] -[assembly: AssemblyDescription("Dll de communications sur le bus IVY")] -[assembly: AssemblyCompany("DTI/SDER PII")] -[assembly: AssemblyProduct("Ivy")] -[assembly: AssemblyCopyright("SDER")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Revision -// Build Number -// -// You can specify all the values or you can default the Revision and Build Numbers -// by using the '*' as shown below: - -[assembly: AssemblyVersion("2.0.*")] - -// -// In order to sign your assembly you must specify a key to use. Refer to the -// Microsoft .NET Framework documentation for more information on assembly signing. -// -// Use the attributes below to control which key is used for signing. -// -// Notes: -// (*) If no key is specified, the assembly is not signed. -// (*) KeyName refers to a key that has been installed in the Crypto Service -// Provider (CSP) on your machine. KeyFile refers to a file which contains -// a key. -// (*) If the KeyFile and the KeyName values are both specified, the -// following processing occurs: -// (1) If the KeyName can be found in the CSP, that key is used. -// (2) If the KeyName does not exist and the KeyFile does exist, the key -// in the KeyFile is installed into the CSP and used. -// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. -// When specifying the KeyFile, the location of the KeyFile should be -// relative to the project output directory which is -// %Project Directory%\obj\. For example, if your KeyFile is -// located in the project directory, you would specify the AssemblyKeyFile -// attribute as [assembly: AssemblyKeyFile("..\..\mykey.snk")] -// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework -// documentation for more information on this. -// - -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyDelaySign(false)] -[assembly: AssemblyKeyFile("")] -[assembly: AssemblyKeyName("")] - - -[assembly: ComVisibleAttribute(false)] diff --git a/IvyToDel/Ivy/Properties/Settings.Designer.cs b/IvyToDel/Ivy/Properties/Settings.Designer.cs deleted file mode 100644 index 96b0f2d..0000000 --- a/IvyToDel/Ivy/Properties/Settings.Designer.cs +++ /dev/null @@ -1,80 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:2.0.50727.42 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace IvyBus.Properties { - - - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "8.0.0.0")] - internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { - - private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); - - public static Settings Default { - get { - return defaultInstance; - } - } - - [global::System.Configuration.ApplicationScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("3")] - public int IvyProtocolVersion { - get { - return ((int)(this["IvyProtocolVersion"])); - } - } - - [global::System.Configuration.ApplicationScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("False")] - public bool IvyPing { - get { - return ((bool)(this["IvyPing"])); - } - } - - [global::System.Configuration.ApplicationScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("False")] - public bool IvyDebug { - get { - return ((bool)(this["IvyDebug"])); - } - } - - [global::System.Configuration.ApplicationScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("")] - public string IvyBus { - get { - return ((string)(this["IvyBus"])); - } - } - - [global::System.Configuration.ApplicationScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("")] - public string AppName { - get { - return ((string)(this["AppName"])); - } - } - - [global::System.Configuration.ApplicationScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("")] - public string ReadyMessage { - get { - return ((string)(this["ReadyMessage"])); - } - } - } -} diff --git a/IvyToDel/Ivy/Properties/Settings.settings b/IvyToDel/Ivy/Properties/Settings.settings deleted file mode 100644 index f23b946..0000000 --- a/IvyToDel/Ivy/Properties/Settings.settings +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - 3 - - - False - - - False - - - - - - - - - - - - \ No newline at end of file diff --git a/IvyToDel/Ivy/Settings.cs b/IvyToDel/Ivy/Settings.cs deleted file mode 100644 index 17744f8..0000000 --- a/IvyToDel/Ivy/Settings.cs +++ /dev/null @@ -1,28 +0,0 @@ -namespace IvyBus.Properties { - - - // This class allows you to handle specific events on the settings class: - // The SettingChanging event is raised before a setting's value is changed. - // The PropertyChanged event is raised after a setting's value is changed. - // The SettingsLoaded event is raised after the setting values are loaded. - // The SettingsSaving event is raised before the setting values are saved. - internal sealed partial class Settings { - - public Settings() { - // // To add event handlers for saving and changing settings, uncomment the lines below: - // - // this.SettingChanging += this.SettingChangingEventHandler; - // - // this.SettingsSaving += this.SettingsSavingEventHandler; - // - } - - private void SettingChangingEventHandler(object sender, System.Configuration.SettingChangingEventArgs e) { - // Add code to handle the SettingChangingEvent event here. - } - - private void SettingsSavingEventHandler(object sender, System.ComponentModel.CancelEventArgs e) { - // Add code to handle the SettingsSaving event here. - } - } -} diff --git a/IvyToDel/Ivy/app.config b/IvyToDel/Ivy/app.config deleted file mode 100644 index e5b53b3..0000000 --- a/IvyToDel/Ivy/app.config +++ /dev/null @@ -1,30 +0,0 @@ - - - - -
- - - - - - 3 - - - False - - - False - - - - - - - - - - - - - \ No newline at end of file -- cgit v1.1