summaryrefslogtreecommitdiff
path: root/Ivy
diff options
context:
space:
mode:
authorfcolin2007-02-01 11:59:19 +0000
committerfcolin2007-02-01 11:59:19 +0000
commit31a4ba441a313dca7821cae97378ac77b90068cc (patch)
tree0a1ce34e3217d3810cff6d86c8d7e215b783975c /Ivy
parentcbf21e890ed2df9dc964bd017b48da8e94e2c608 (diff)
downloadivy-csharp-31a4ba441a313dca7821cae97378ac77b90068cc.zip
ivy-csharp-31a4ba441a313dca7821cae97378ac77b90068cc.tar.gz
ivy-csharp-31a4ba441a313dca7821cae97378ac77b90068cc.tar.bz2
ivy-csharp-31a4ba441a313dca7821cae97378ac77b90068cc.tar.xz
suppression niveaux
Diffstat (limited to 'Ivy')
-rw-r--r--Ivy/Ivy.sln109
-rw-r--r--Ivy/Ivy.vssscc10
-rw-r--r--Ivy/Ivy/Ivy.cs1183
-rw-r--r--Ivy/Ivy/Ivy.csproj189
-rw-r--r--Ivy/Ivy/Ivy.csproj.vspscc10
-rw-r--r--Ivy/Ivy/Ivy.snippet43
-rw-r--r--Ivy/Ivy/IvyApplicationBinding.cs186
-rw-r--r--Ivy/Ivy/IvyBinding.cs118
-rw-r--r--Ivy/Ivy/IvyBindingAttribute.cs31
-rw-r--r--Ivy/Ivy/IvyClient.cs592
-rw-r--r--Ivy/Ivy/IvyDomain.Designer.cs75
-rw-r--r--Ivy/Ivy/IvyDomain.cs60
-rw-r--r--Ivy/Ivy/IvyDomain.resx120
-rw-r--r--Ivy/Ivy/IvyEventArgs.cs84
-rw-r--r--Ivy/Ivy/IvyException.cs19
-rw-r--r--Ivy/Ivy/IvyProtocol.cs25
-rw-r--r--Ivy/Ivy/IvyTCPStream.cs20
-rw-r--r--Ivy/Ivy/IvyTCPStreamV3.cs254
-rw-r--r--Ivy/Ivy/IvyTCPStreamV4.cs273
-rw-r--r--Ivy/Ivy/IvyUDPStream.cs66
-rw-r--r--Ivy/Ivy/IvyUDPStreamV3.cs104
-rw-r--r--Ivy/Ivy/IvyUDPStreamV4.cs80
-rw-r--r--Ivy/Ivy/IvyWatcher.cs179
-rw-r--r--Ivy/Ivy/Properties/AssemblyInfo.cs62
-rw-r--r--Ivy/Ivy/Properties/Settings.Designer.cs80
-rw-r--r--Ivy/Ivy/Properties/Settings.settings24
-rw-r--r--Ivy/Ivy/Settings.cs28
-rw-r--r--Ivy/Ivy/app.config30
-rw-r--r--Ivy/IvyDaemon/App.icobin0 -> 1078 bytes
-rw-r--r--Ivy/IvyDaemon/IvyDaemon.cs169
-rw-r--r--Ivy/IvyDaemon/IvyDaemon.csproj154
-rw-r--r--Ivy/IvyDaemon/IvyDaemon.csproj.vspscc10
-rw-r--r--Ivy/IvyDaemon/IvyDaemon_TemporaryKey.pfxbin0 -> 1676 bytes
-rw-r--r--Ivy/IvyDaemon/Properties/AssemblyInfo.cs58
-rw-r--r--Ivy/IvyDaemon/Properties/Settings.Designer.cs35
-rw-r--r--Ivy/IvyDaemon/Properties/Settings.settings9
-rw-r--r--Ivy/IvyDaemon/Settings.cs28
-rw-r--r--Ivy/IvyDaemon/app.config15
-rw-r--r--Ivy/IvyFilter/Filter.cs119
-rw-r--r--Ivy/IvyFilter/IvyFilter.csproj61
-rw-r--r--Ivy/IvyFilter/IvyFilter.csproj.vspscc10
-rw-r--r--Ivy/IvyFilter/Properties/AssemblyInfo.cs33
-rw-r--r--Ivy/IvyPPC/Ivy.cs1183
-rw-r--r--Ivy/IvyPPC/IvyApplicationBinding.cs186
-rw-r--r--Ivy/IvyPPC/IvyBinding.cs118
-rw-r--r--Ivy/IvyPPC/IvyBindingAttribute.cs31
-rw-r--r--Ivy/IvyPPC/IvyClient.cs592
-rw-r--r--Ivy/IvyPPC/IvyDomain.Designer.cs75
-rw-r--r--Ivy/IvyPPC/IvyDomain.cs60
-rw-r--r--Ivy/IvyPPC/IvyDomain.resx120
-rw-r--r--Ivy/IvyPPC/IvyEventArgs.cs84
-rw-r--r--Ivy/IvyPPC/IvyException.cs19
-rw-r--r--Ivy/IvyPPC/IvyPPC.csproj110
-rw-r--r--Ivy/IvyPPC/IvyPPC.csproj.vspscc10
-rw-r--r--Ivy/IvyPPC/IvyPPC.sln26
-rw-r--r--Ivy/IvyPPC/IvyPPC.vssscc10
-rw-r--r--Ivy/IvyPPC/IvyProtocol.cs25
-rw-r--r--Ivy/IvyPPC/IvyTCPStream.cs20
-rw-r--r--Ivy/IvyPPC/IvyTCPStreamV3.cs254
-rw-r--r--Ivy/IvyPPC/IvyTCPStreamV4.cs273
-rw-r--r--Ivy/IvyPPC/IvyUDPStream.cs66
-rw-r--r--Ivy/IvyPPC/IvyUDPStreamV3.cs104
-rw-r--r--Ivy/IvyPPC/IvyUDPStreamV4.cs80
-rw-r--r--Ivy/IvyPPC/IvyWatcher.cs179
-rw-r--r--Ivy/IvyPPC/Pcre.cs36
-rw-r--r--Ivy/IvyPPC/Properties/AssemblyInfo.cs62
-rw-r--r--Ivy/IvyPPC/Settings.cs28
-rw-r--r--Ivy/IvyPPC/app.config30
-rw-r--r--Ivy/IvyPerf/App.icobin0 -> 1078 bytes
-rw-r--r--Ivy/IvyPerf/AssemblyInfo.cs58
-rw-r--r--Ivy/IvyPerf/IvyPerf.cs74
-rw-r--r--Ivy/IvyPerf/IvyPerf.csproj140
-rw-r--r--Ivy/IvyPerf/IvyPerf.csproj.vspscc10
-rw-r--r--Ivy/IvyPerf/IvyPerf_TemporaryKey.pfxbin0 -> 1676 bytes
-rw-r--r--Ivy/IvyProbe/App.icobin0 -> 1078 bytes
-rw-r--r--Ivy/IvyProbe/IvyProbe.Designer.cs212
-rw-r--r--Ivy/IvyProbe/IvyProbe.cs166
-rw-r--r--Ivy/IvyProbe/IvyProbe.csproj164
-rw-r--r--Ivy/IvyProbe/IvyProbe.csproj.vspscc10
-rw-r--r--Ivy/IvyProbe/IvyProbe.resx123
-rw-r--r--Ivy/IvyProbe/IvyProbe_TemporaryKey.pfxbin0 -> 1676 bytes
-rw-r--r--Ivy/IvyProbe/Properties/AssemblyInfo.cs58
-rw-r--r--Ivy/IvyProbe/Properties/Settings.Designer.cs35
-rw-r--r--Ivy/IvyProbe/Properties/Settings.settings9
-rw-r--r--Ivy/IvyProbe/app.config15
-rw-r--r--Ivy/IvyProbeConsole/App.icobin0 -> 1078 bytes
-rw-r--r--Ivy/IvyProbeConsole/IvyProbeConsole.cs373
-rw-r--r--Ivy/IvyProbeConsole/IvyProbeConsole.csproj158
-rw-r--r--Ivy/IvyProbeConsole/IvyProbeConsole.csproj.vspscc10
-rw-r--r--Ivy/IvyProbeConsole/IvyProbe_TemporaryKey.pfxbin0 -> 1676 bytes
-rw-r--r--Ivy/IvyProbeConsole/Properties/AssemblyInfo.cs59
-rw-r--r--Ivy/IvyProbeConsole/Properties/Settings.Designer.cs71
-rw-r--r--Ivy/IvyProbeConsole/Properties/Settings.settings21
-rw-r--r--Ivy/IvyProbeConsole/Properties/app.manifest11
-rw-r--r--Ivy/IvyProbeConsole/Settings.cs28
-rw-r--r--Ivy/IvyProbeConsole/app.config27
96 files changed, 10368 insertions, 0 deletions
diff --git a/Ivy/Ivy.sln b/Ivy/Ivy.sln
new file mode 100644
index 0000000..6090322
--- /dev/null
+++ b/Ivy/Ivy.sln
@@ -0,0 +1,109 @@
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IvyDaemon", "IvyDaemon\IvyDaemon.csproj", "{B10AB29F-D678-4472-9BA3-D627262E14E1}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IvyPerf", "IvyPerf\IvyPerf.csproj", "{839C9A55-7EFD-4326-95C3-2960DF390FF2}"
+ ProjectSection(ProjectDependencies) = postProject
+ {F2F03CF7-0087-4EDB-AD15-80C9E8DA2617} = {F2F03CF7-0087-4EDB-AD15-80C9E8DA2617}
+ EndProjectSection
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IvyProbe", "IvyProbe\IvyProbe.csproj", "{5EFDDE31-9A31-43EB-8E56-6C29F7EAAD48}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IvyProbeConsole", "IvyProbeConsole\IvyProbeConsole.csproj", "{19023DE7-AAD8-4EC4-8FAF-D793868F8861}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ivy", "Ivy\Ivy.csproj", "{F2F03CF7-0087-4EDB-AD15-80C9E8DA2617}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IvyFilter", "IvyFilter\IvyFilter.csproj", "{151B7DDB-279B-4E1E-903B-E09B079FA0A5}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "getopt", "..\getopt\getopt.csproj", "{228B5F0B-31AE-488F-A916-B7CBB269D25F}"
+EndProject
+Global
+ GlobalSection(SourceCodeControl) = preSolution
+ SccNumberOfProjects = 8
+ SccLocalPath0 = .
+ CanCheckoutShared = false
+ SccProjectUniqueName1 = IvyDaemon\\IvyDaemon.csproj
+ SccProjectName1 = \u0022$/CSharp/Ivy/IvyDaemon\u0022,\u0020GLFAAAAA
+ SccLocalPath1 = IvyDaemon
+ CanCheckoutShared = false
+ SccProjectUniqueName2 = IvyPerf\\IvyPerf.csproj
+ SccProjectName2 = \u0022$/CSharp/Ivy/IvyPerf\u0022,\u0020HNHAAAAA
+ SccLocalPath2 = IvyPerf
+ CanCheckoutShared = false
+ SccProjectUniqueName3 = IvyProbe\\IvyProbe.csproj
+ SccProjectName3 = \u0022$/CSharp/Ivy/IvyProbe\u0022,\u0020SLFAAAAA
+ SccLocalPath3 = IvyProbe
+ CanCheckoutShared = false
+ SccProjectUniqueName4 = IvyProbeConsole\\IvyProbeConsole.csproj
+ SccProjectName4 = \u0022$/CSharp/Ivy/IvyProbeConsole\u0022,\u0020MLFAAAAA
+ SccLocalPath4 = IvyProbeConsole
+ CanCheckoutShared = false
+ SccProjectUniqueName5 = Ivy\\Ivy.csproj
+ SccProjectName5 = \u0022$/CSharp/Ivy/Ivy\u0022,\u0020QQHAAAAA
+ SccLocalPath5 = Ivy
+ CanCheckoutShared = false
+ SccProjectUniqueName6 = ..\\getopt\\getopt.csproj
+ SccProjectName6 = \u0022$/CSharp/getopt\u0022,\u0020RBIAAAAA
+ SccLocalPath6 = ..\\getopt
+ CanCheckoutShared = false
+ SccProjectUniqueName7 = IvyFilter\\IvyFilter.csproj
+ SccLocalPath7 = .
+ CanCheckoutShared = false
+ SccProjectFilePathRelativizedFromConnection7 = IvyFilter\\
+ EndGlobalSection
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Debug|x86 = Debug|x86
+ Release|Any CPU = Release|Any CPU
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {B10AB29F-D678-4472-9BA3-D627262E14E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B10AB29F-D678-4472-9BA3-D627262E14E1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B10AB29F-D678-4472-9BA3-D627262E14E1}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {B10AB29F-D678-4472-9BA3-D627262E14E1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B10AB29F-D678-4472-9BA3-D627262E14E1}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B10AB29F-D678-4472-9BA3-D627262E14E1}.Release|x86.ActiveCfg = Release|Any CPU
+ {839C9A55-7EFD-4326-95C3-2960DF390FF2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {839C9A55-7EFD-4326-95C3-2960DF390FF2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {839C9A55-7EFD-4326-95C3-2960DF390FF2}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {839C9A55-7EFD-4326-95C3-2960DF390FF2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {839C9A55-7EFD-4326-95C3-2960DF390FF2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {839C9A55-7EFD-4326-95C3-2960DF390FF2}.Release|x86.ActiveCfg = Release|Any CPU
+ {5EFDDE31-9A31-43EB-8E56-6C29F7EAAD48}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5EFDDE31-9A31-43EB-8E56-6C29F7EAAD48}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5EFDDE31-9A31-43EB-8E56-6C29F7EAAD48}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {5EFDDE31-9A31-43EB-8E56-6C29F7EAAD48}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5EFDDE31-9A31-43EB-8E56-6C29F7EAAD48}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5EFDDE31-9A31-43EB-8E56-6C29F7EAAD48}.Release|x86.ActiveCfg = Release|Any CPU
+ {19023DE7-AAD8-4EC4-8FAF-D793868F8861}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {19023DE7-AAD8-4EC4-8FAF-D793868F8861}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {19023DE7-AAD8-4EC4-8FAF-D793868F8861}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {19023DE7-AAD8-4EC4-8FAF-D793868F8861}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {19023DE7-AAD8-4EC4-8FAF-D793868F8861}.Release|Any CPU.Build.0 = Release|Any CPU
+ {19023DE7-AAD8-4EC4-8FAF-D793868F8861}.Release|x86.ActiveCfg = Release|Any CPU
+ {F2F03CF7-0087-4EDB-AD15-80C9E8DA2617}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F2F03CF7-0087-4EDB-AD15-80C9E8DA2617}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F2F03CF7-0087-4EDB-AD15-80C9E8DA2617}.Debug|x86.ActiveCfg = Debug|x86
+ {F2F03CF7-0087-4EDB-AD15-80C9E8DA2617}.Debug|x86.Build.0 = Debug|x86
+ {F2F03CF7-0087-4EDB-AD15-80C9E8DA2617}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F2F03CF7-0087-4EDB-AD15-80C9E8DA2617}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F2F03CF7-0087-4EDB-AD15-80C9E8DA2617}.Release|x86.ActiveCfg = Release|x86
+ {F2F03CF7-0087-4EDB-AD15-80C9E8DA2617}.Release|x86.Build.0 = Release|x86
+ {151B7DDB-279B-4E1E-903B-E09B079FA0A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {151B7DDB-279B-4E1E-903B-E09B079FA0A5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {151B7DDB-279B-4E1E-903B-E09B079FA0A5}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {151B7DDB-279B-4E1E-903B-E09B079FA0A5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {151B7DDB-279B-4E1E-903B-E09B079FA0A5}.Release|Any CPU.Build.0 = Release|Any CPU
+ {151B7DDB-279B-4E1E-903B-E09B079FA0A5}.Release|x86.ActiveCfg = Release|Any CPU
+ {228B5F0B-31AE-488F-A916-B7CBB269D25F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {228B5F0B-31AE-488F-A916-B7CBB269D25F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {228B5F0B-31AE-488F-A916-B7CBB269D25F}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {228B5F0B-31AE-488F-A916-B7CBB269D25F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {228B5F0B-31AE-488F-A916-B7CBB269D25F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {228B5F0B-31AE-488F-A916-B7CBB269D25F}.Release|x86.ActiveCfg = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/Ivy/Ivy.vssscc b/Ivy/Ivy.vssscc
new file mode 100644
index 0000000..794f014
--- /dev/null
+++ b/Ivy/Ivy.vssscc
@@ -0,0 +1,10 @@
+""
+{
+"FILE_VERSION" = "9237"
+"ENLISTMENT_CHOICE" = "NEVER"
+"PROJECT_FILE_RELATIVE_PATH" = ""
+"NUMBER_OF_EXCLUDED_FILES" = "0"
+"ORIGINAL_PROJECT_FILE_PATH" = ""
+"NUMBER_OF_NESTED_PROJECTS" = "0"
+"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT"
+}
diff --git a/Ivy/Ivy/Ivy.cs b/Ivy/Ivy/Ivy.cs
new file mode 100644
index 0000000..1c38396
--- /dev/null
+++ b/Ivy/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;
+
+
+ /// <summary> The Main bus Class
+ /// </summary>
+ ///
+#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 */
+ /// <summary>fires when a new client connect to the bus</summary>
+ public event EventHandler<IvyEventArgs> ClientConnected;
+ /// <summary>fires when a client discconnect from the bus</summary>
+ public event EventHandler<IvyEventArgs> ClientDisconnected;
+ /// <summary>fires when a client receive a direct message from another client</summary>
+ public event EventHandler<IvyEventArgs> DirectMessageReceived;
+ /// <summary>fires when somebody ask for killing every client on the bus</summary>
+ public event EventHandler<IvyDieEventArgs> DieReceived;
+ /// <summary>fires when a client receive a add binding from another client</summary>
+ public event EventHandler<IvyEventArgs> BindingAdd;
+ /// <summary>fires when a client receive a remove binding from another client</summary>
+ public event EventHandler<IvyEventArgs> BindingRemove;
+ /// <summary>fires when a client receive a binding from another client and it as been filtered </summary>
+ public event EventHandler<IvyEventArgs> BindingFilter;
+ /// <summary>fires when a client receive a remove binding from another client</summary>
+ public event EventHandler<IvyEventArgs> 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;
+ }
+
+ }
+
+ /// <summary>IvyClients accesses the list of the connected clients</summary>
+#if (!PocketPC)
+ [Browsable(false)]
+#endif
+ public List<IvyClient> IvyClients
+ {
+ get
+ {
+ return clients;
+ }
+
+ }
+
+ /// <summary>AppName the application name</summary>
+
+#if (!PocketPC)
+ [Category("Ivy")]
+ [Bindable(true)]
+#endif
+ [DefaultValue(null)]
+ public string AppName
+ {
+ set
+ {
+ appName = value;
+ }
+ get
+ {
+ return appName;
+ }
+
+ }
+ /// <summary>AppId the Application Unique ID</summary>
+
+#if (!PocketPC)
+ [Browsable(false)]
+#endif
+ public string AppId
+ {
+ get
+ {
+ return applicationUniqueId;
+ }
+
+ }
+ /// <summary>AppPriority the Application Priority: the clients list is sorted against priority</summary>
+#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;
+ }
+
+ }
+
+ /// <summary>IsRunning is the bus Started and connected ?</summary>
+
+#if (!PocketPC)
+ [Browsable(false)]
+#endif
+ public bool IsRunning
+ {
+ get
+ {
+ return !stopped;
+ }
+
+ }
+ ///<summary>SentMessageClasses the first word token of sent messages
+ ///<remarks> optimise the parsing process when sending messages </remarks>
+ ///</summary>
+#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<string> SentMessageFilter
+ {
+ get
+ {
+ return sent_messageFilter;
+ }
+ }
+ /// <summary>ReadyMessage message send when Application receive all the regexp at the connection of the client</summary>
+
+#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<IvyApplicationBinding> 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<IvyWatcher> watchers;
+ private volatile Thread serverThread; // to ensure quick communication of the end
+
+ internal Dictionary<int, IvyApplicationBinding> bindings;
+ //TODO should be remove samve as above
+ private List<IvyApplicationBinding> app_bindings;
+ private List<IvyClient> clients;
+ private List<string> 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
+
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="T:Ivy"/> class.
+ /// </summary>
+ public Ivy()
+ {
+#if (!PocketPC)
+ syncContext = SynchronizationContext.Current;
+#endif
+ clients = new List<IvyClient>();
+ bindings = new Dictionary<int, IvyApplicationBinding>();
+ app_bindings = new List<IvyApplicationBinding>();
+ sent_messageFilter = new List<string>();
+#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);
+ }
+ /// <summary>
+ /// Readies the structures for the software bus connexion.
+ /// </summary>
+ /// <example> This sample shows how to start working with Ivy.
+ /// <code>
+ /// Ivy bus = new Ivy("Dummy agent","ready");
+ /// bus.bindMsg("(.*)",myMessageListener);
+ /// bus.start(null);
+ /// </code>
+ /// How to send & receive:
+ /// the Ivy agent A performs <c>b.bindMsg("^Hello (*)",cb);</c>
+ /// the Ivy agent B performs <c>b2.sendMsg("Hello world");</c>
+ /// a thread in A will run the callback cb with its second argument set
+ /// to a array of string, with one single element, "world"
+ /// </example>
+ /// <remarks>
+ /// the real work begin in the start() method
+ /// </remarks>
+ /// <seealso cref=" Ivy.start"/>
+ /// <param name='name'>The name of your Ivy agent on the software bus
+ /// </param>
+ /// <param name='message'>The hellow message you will send once ready
+ /// </param>
+ 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<IvyMessageEventArgs> handler;
+#if (PocketPC)
+ //Createdelegate mydlg = new Createdelegate(m, null, EventArgs.Empty);
+ //bindMsg(attr.GetExpression(null), mydlg);
+ handler = null;
+#else
+ handler = (EventHandler<IvyMessageEventArgs>)Delegate.CreateDelegate(typeof(EventHandler<IvyMessageEventArgs>), 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<IvyMessageEventArgs> handler;
+#if (PocketPC)
+ handler = null; // TODO
+#else
+ handler = (EventHandler<IvyMessageEventArgs>)Delegate.CreateDelegate(typeof(EventHandler<IvyMessageEventArgs>), 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);
+ }
+
+ }
+ /// <summary>
+ /// connects the Ivy bus to a domain or list of domains.
+ /// </summary>
+ /// <param name="domainbus">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.</param>
+ /// <remarks>
+ /// 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.
+ /// </remarks>
+ 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<IvyWatcher>();
+
+ 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;
+ }
+
+ /// <summary>
+ /// disconnects from the Ivy bus
+ /// </summary>
+ 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");
+ }
+ }
+
+
+ /// <summary>
+ /// Send a formated message to someone on the bus
+ /// </summary>
+ /// <remarks>
+ /// 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.
+ /// </remarks>
+ /// <param name='format'>A string message format to build the message
+ /// <param name='args'>args used in message format
+ /// <returns>
+ /// the number of messages actually sent
+ /// </returns>
+ 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;
+ }
+ /// <summary>
+ /// Subscribes to a regular expression.
+ /// </summary>
+ /// <param name="regexp">a regular expression, groups are done with parenthesis</param>
+ /// <param name="callback">any objects implementing the Ivy.MessageListener</param>
+ /// <param name="args">The args.</param>
+ /// <returns>the id of the regular expression</returns>
+ /// <remarks>
+ /// 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.
+ /// </remarks>
+ //
+ public ushort BindMsg(string regexp, EventHandler<IvyMessageEventArgs> 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);
+ }
+
+ /// <summary>
+ /// unsubscribes a regular expression
+ /// </summary>
+ /// <param name="id">the id of the regular expression, returned when it was bound</param>
+ 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);
+ }
+
+ /// <summary>
+ /// unsubscribes a regular expression
+ /// </summary>
+ /// <param name="re">the string for the regular expression</param>
+ /// <returns>
+ /// a boolean, true if the regexp existed, false otherwise or
+ /// whenever an exception occured during unbinding
+ /// </returns>
+ 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;
+ }
+
+
+ /// <summary>
+ /// Subscribes to a simple expression ( msg ar1 arg2 arg3 etc).
+ /// </summary>
+ /// <remarks>
+ /// 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.
+ /// </remarks>
+ ///
+ /// <param name='regexp'>a regular expression, groups are done with parenthesis
+ /// <param name='callback'>any objects implementing the EventHandler<IvyMessageEventArgs>
+ /// <returns>
+ /// the id of the regular expression
+ /// </returns>
+ public int BindSimpleMsg(string expression, EventHandler<IvyMessageEventArgs> 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);
+ }
+ /// <summary>
+ /// Dies the specified target.
+ /// </summary>
+ /// <param name="target">The target.</param>
+ /// <param name="message">The reason message.</param>
+ /// <returns></returns>
+ public int Die(string target, string message)
+ {
+ List<IvyClient> v = GetClientsByName(target);
+ for (int i = 0; i < v.Count; i++)
+ v[i].stream.TokenDie(0, message);
+ return v.Count;
+ }
+ /// <summary>
+ /// Pings the specified target.
+ /// </summary>
+ /// <param name="target">The target.</param>
+ /// <param name="message">The message.</param>
+ /// <returns></returns>
+ public int Ping(string target, string message)
+ {
+ List<IvyClient> 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<IvyEventArgs> ev, IvyEventArgs e)
+ {
+ if (ev != null)
+ {
+ if (parentControl != null)
+ {
+ parentControl.Invoke(ev, this, e);
+ }
+ else
+ ev(this, e);
+ }
+ }
+#else
+ internal virtual void FireEvent(EventHandler<IvyEventArgs> 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<IvyEventArgs> temp = DirectMessageReceived;
+ FireEvent(temp,e);
+ }
+ internal virtual void OnClientConnected(IvyEventArgs e)
+ {
+ // Copy to a temporary variable to be thread-safe.
+ EventHandler<IvyEventArgs> temp = ClientConnected;
+ FireEvent(temp,e);
+ }
+ internal virtual void OnClientDisconnected(IvyEventArgs e)
+ {
+ // Copy to a temporary variable to be thread-safe.
+ EventHandler<IvyEventArgs> 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<IvyEventArgs> temp = BindingAdd;
+ FireEvent(temp,e);
+ }
+ internal virtual void OnClientRemoveBinding(IvyEventArgs e)
+ {
+ // Copy to a temporary variable to be thread-safe.
+ EventHandler<IvyEventArgs> temp = BindingRemove;
+ FireEvent(temp,e);
+ }
+ internal virtual void OnClientFilterBinding(IvyEventArgs e)
+ {
+ // Copy to a temporary variable to be thread-safe.
+ EventHandler<IvyEventArgs> temp = BindingFilter;
+ FireEvent(temp,e);
+ }
+ internal virtual void OnError(IvyEventArgs e)
+ {
+ // Copy to a temporary variable to be thread-safe.
+ EventHandler<IvyEventArgs> temp = ErrorMessage;
+ FireEvent(temp, e);
+ }
+#if (PocketPC)
+ internal virtual void OnDie(IvyDieEventArgs e)
+ {
+ // Copy to a temporary variable to be thread-safe.
+ EventHandler<IvyDieEventArgs> 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<IvyDieEventArgs> 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);
+ }
+ }
+
+
+ /// <summary>
+ /// gives a list of IvyClient(s) with the name given in parameter
+ /// </summary>
+ /// <param name="name">The name of the Ivy agent you're looking for</param>
+ /// <returns></returns>
+ public List<IvyClient> GetClientsByName(string name)
+ {
+ List<IvyClient> v = new List<IvyClient>();
+ 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, @"^\^(?<token>[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/Ivy.csproj b/Ivy/Ivy/Ivy.csproj
new file mode 100644
index 0000000..1944b08
--- /dev/null
+++ b/Ivy/Ivy/Ivy.csproj
@@ -0,0 +1,189 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <ProjectType>Local</ProjectType>
+ <ProductVersion>8.0.50727</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{F2F03CF7-0087-4EDB-AD15-80C9E8DA2617}</ProjectGuid>
+ <SccProjectName>SAK</SccProjectName>
+ <SccLocalPath>SAK</SccLocalPath>
+ <SccAuxPath>SAK</SccAuxPath>
+ <SccProvider>SAK</SccProvider>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ApplicationIcon>
+ </ApplicationIcon>
+ <AssemblyKeyContainerName>
+ </AssemblyKeyContainerName>
+ <AssemblyName>Ivy</AssemblyName>
+ <AssemblyOriginatorKeyFile>
+ </AssemblyOriginatorKeyFile>
+ <DefaultClientScript>JScript</DefaultClientScript>
+ <DefaultHTMLPageLayout>Grid</DefaultHTMLPageLayout>
+ <DefaultTargetSchema>IE50</DefaultTargetSchema>
+ <DelaySign>false</DelaySign>
+ <OutputType>Library</OutputType>
+ <RootNamespace>IvyBus</RootNamespace>
+ <RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
+ <StartupObject>
+ </StartupObject>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <UpgradeBackupLocation>
+ </UpgradeBackupLocation>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <OutputPath>bin\Debug\</OutputPath>
+ <AllowUnsafeBlocks>false</AllowUnsafeBlocks>
+ <BaseAddress>285212672</BaseAddress>
+ <CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
+ <ConfigurationOverrideFile>
+ </ConfigurationOverrideFile>
+ <DefineConstants>
+ </DefineConstants>
+ <DocumentationFile>
+ </DocumentationFile>
+ <DebugSymbols>true</DebugSymbols>
+ <FileAlignment>4096</FileAlignment>
+ <NoStdLib>false</NoStdLib>
+ <NoWarn>
+ </NoWarn>
+ <Optimize>false</Optimize>
+ <RegisterForComInterop>false</RegisterForComInterop>
+ <RemoveIntegerChecks>false</RemoveIntegerChecks>
+ <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
+ <WarningLevel>1</WarningLevel>
+ <DebugType>full</DebugType>
+ <ErrorReport>prompt</ErrorReport>
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <OutputPath>bin\Release\</OutputPath>
+ <AllowUnsafeBlocks>false</AllowUnsafeBlocks>
+ <BaseAddress>285212672</BaseAddress>
+ <CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
+ <ConfigurationOverrideFile>
+ </ConfigurationOverrideFile>
+ <DefineConstants>
+ </DefineConstants>
+ <DocumentationFile>
+ </DocumentationFile>
+ <DebugSymbols>false</DebugSymbols>
+ <FileAlignment>4096</FileAlignment>
+ <NoStdLib>false</NoStdLib>
+ <NoWarn>
+ </NoWarn>
+ <Optimize>false</Optimize>
+ <RegisterForComInterop>false</RegisterForComInterop>
+ <RemoveIntegerChecks>false</RemoveIntegerChecks>
+ <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
+ <WarningLevel>1</WarningLevel>
+ <DebugType>none</DebugType>
+ <ErrorReport>prompt</ErrorReport>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+ <DebugSymbols>true</DebugSymbols>
+ <OutputPath>bin\x86\Debug\</OutputPath>
+ <BaseAddress>285212672</BaseAddress>
+ <WarningLevel>1</WarningLevel>
+ <DebugType>full</DebugType>
+ <PlatformTarget>x86</PlatformTarget>
+ <ErrorReport>prompt</ErrorReport>
+ <DefineConstants>
+ </DefineConstants>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+ <OutputPath>bin\x86\Release\</OutputPath>
+ <BaseAddress>285212672</BaseAddress>
+ <WarningLevel>1</WarningLevel>
+ <DebugType>
+ </DebugType>
+ <PlatformTarget>x86</PlatformTarget>
+ <ErrorReport>prompt</ErrorReport>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="mscorlib">
+ <Name>mscorlib</Name>
+ </Reference>
+ <Reference Include="System">
+ <Name>System</Name>
+ </Reference>
+ <Reference Include="System.Data" />
+ <Reference Include="System.Design">
+ <Name>System.Design</Name>
+ </Reference>
+ <Reference Include="System.Drawing" />
+ <Reference Include="System.Management">
+ <Name>System.Management</Name>
+ </Reference>
+ <Reference Include="System.Windows.Forms">
+ <Name>System.Windows.Forms</Name>
+ </Reference>
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="IvyApplicationBinding.cs">
+ <SubType>Component</SubType>
+ </Compile>
+ <Compile Include="IvyBindingAttribute.cs" />
+ <Compile Include="IvyDomain.cs">
+ <SubType>UserControl</SubType>
+ </Compile>
+ <Compile Include="IvyDomain.Designer.cs">
+ <DependentUpon>IvyDomain.cs</DependentUpon>
+ </Compile>
+ <Compile Include="IvyEventArgs.cs" />
+ <Compile Include="IvyProtocol.cs" />
+ <Compile Include="IvyTCPStreamV3.cs" />
+ <Compile Include="IvyUDPStream.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="Ivy.cs">
+ <SubType>Component</SubType>
+ </Compile>
+ <Compile Include="IvyBinding.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="IvyClient.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="IvyException.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="IvyTCPStreamV4.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="IvyUDPStreamV3.cs" />
+ <Compile Include="IvyUDPStreamV4.cs" />
+ <Compile Include="IvyWatcher.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="Properties\Settings.Designer.cs">
+ <AutoGen>True</AutoGen>
+ <DesignTimeSharedInput>True</DesignTimeSharedInput>
+ <DependentUpon>Settings.settings</DependentUpon>
+ </Compile>
+ <Compile Include="Settings.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="app.config" />
+ <None Include="Ivy.snippet" />
+ <None Include="Properties\Settings.settings">
+ <Generator>SettingsSingleFileGenerator</Generator>
+ <LastGenOutput>Settings.Designer.cs</LastGenOutput>
+ </None>
+ </ItemGroup>
+ <ItemGroup>
+ <EmbeddedResource Include="IvyDomain.resx">
+ <SubType>Designer</SubType>
+ <DependentUpon>IvyDomain.cs</DependentUpon>
+ </EmbeddedResource>
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <PropertyGroup>
+ <PreBuildEvent>
+ </PreBuildEvent>
+ <PostBuildEvent>
+ </PostBuildEvent>
+ </PropertyGroup>
+</Project> \ No newline at end of file
diff --git a/Ivy/Ivy/Ivy.csproj.vspscc b/Ivy/Ivy/Ivy.csproj.vspscc
new file mode 100644
index 0000000..831ab8f
--- /dev/null
+++ b/Ivy/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/Ivy.snippet b/Ivy/Ivy/Ivy.snippet
new file mode 100644
index 0000000..5319177
--- /dev/null
+++ b/Ivy/Ivy/Ivy.snippet
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<CodeSnippets
+ xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
+ <CodeSnippet Format="1.0.0">
+ <Header>
+ <Title>
+ Ivy Message Callback
+ </Title>
+ </Header>
+ <Snippet>
+ <References>
+ <Reference>
+ <Assembly>Ivy.dll</Assembly>
+ </Reference>
+ </References>
+ <Imports>
+ <Import>
+ <Namespace>IvyBus</Namespace>
+ </Import>
+ </Imports>
+ <Declarations>
+ <Literal>
+ <ID>CallbackName</ID>
+ <ToolTip>Replace with a function name.</ToolTip>
+ <Default>bus_receive</Default>
+ </Literal>
+ <Literal>
+ <ID>Expression</ID>
+ <ToolTip>Replace with a regular expression.</ToolTip>
+ <Default>"^(.*)"</Default>
+ </Literal>
+ </Declarations>
+ <Code Language="CSharp">
+ <![CDATA[
+ [IvyBinding($Expression$)]
+ private void $CallbackName$(object sender, IvyMessageEventArgs e)
+ {
+ }
+ ]]>
+ </Code>
+ </Snippet>
+ </CodeSnippet>
+</CodeSnippets>
diff --git a/Ivy/Ivy/IvyApplicationBinding.cs b/Ivy/Ivy/IvyApplicationBinding.cs
new file mode 100644
index 0000000..9183850
--- /dev/null
+++ b/Ivy/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<string> arguments;
+ ///<summary>SentMessageClasses the first word token of sent messages
+ ///<remarks> optimise the parsing process when sending messages </remarks>
+ ///</summary>
+#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<string> Arguments
+ {
+ get
+ {
+ return arguments;
+ }
+ }
+
+#if (!PocketPC)
+ [Category("Ivy")]
+ [Description("Event fired when Message Matching expression received")]
+#endif
+ public event EventHandler<IvyMessageEventArgs> Callback;
+
+ public IvyApplicationBinding()
+ {
+ arguments = new List<string>();
+ }
+ 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<IvyMessageEventArgs> 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<IvyMessageEventArgs> 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<IvyMessageEventArgs> 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/Ivy/IvyBinding.cs b/Ivy/Ivy/IvyBinding.cs
new file mode 100644
index 0000000..624b401
--- /dev/null
+++ b/Ivy/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 */
+
+ /// <summary>
+ /// Description résumée de IvyBinding.
+ /// </summary>
+ 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/Ivy/IvyBindingAttribute.cs b/Ivy/Ivy/IvyBindingAttribute.cs
new file mode 100644
index 0000000..90c44ce
--- /dev/null
+++ b/Ivy/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/Ivy/IvyClient.cs b/Ivy/Ivy/IvyClient.cs
new file mode 100644
index 0000000..3db9f0f
--- /dev/null
+++ b/Ivy/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;
+
+ /// <summary> A Class for the the peers on the bus.
+ /// </summary>
+ /// <remarks>
+ /// 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.
+ /// </remarks>
+ public class IvyClient : IvyProtocol, IComparable<IvyClient>, IDisposable
+ {
+ public int CompareTo(IvyClient other)
+ {
+ return (other.clientPriority - clientPriority);
+ }
+
+ public String ApplicationName
+ {
+ get
+ {
+ return appName;
+ }
+
+ }
+
+ public List<string> Regexps
+ {
+ get
+ {
+ List<string> tab = new List<string>();
+ 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<ushort,IvyBindingBase> 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<ushort,IvyBindingBase>();
+ 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);
+ }
+ }
+
+ /// <summary> 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
+ /// </summary>
+
+ /// <summary> sends a direct message to the peer
+ /// </summary>
+ /// <param name='id'>the numeric value provided to the remote client
+ /// </param>
+ /// <param name='message'>the string that will be match-tested
+ ///
+ /// </param>
+ 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);
+ }
+ }
+
+ /// <summary> closes the connexion to the peer.
+ /// </summary>
+ /// <param name='notify'>should I send Bye message ?
+ /// the thread managing the socket is stopped
+ ///
+ /// </param>
+ 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;
+
+
+ }
+
+ /// <summary> sends the substrings of a message to the peer for each matching regexp.
+ /// </summary>
+ /// <param name='message'>the string that will be match-tested
+ /// </param>
+ /// <returns>the number of messages sent to the peer
+ ///
+ /// </returns>
+ 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;
+ }
+
+ /// <summary> compares two peers the id is the couple (host,service port).
+ /// </summary>
+ /// <param name='clnt'>the other peer
+ /// </param>
+ /// <returns>true if the peers are similir. This should not happen, it is bad
+ /// © ® (tm)
+ ///
+ /// </returns>
+ internal bool sameClient(IvyClient clnt)
+ {
+ return (appPort != 0 && appPort == clnt.appPort) && (RemoteAddress == clnt.RemoteAddress);
+ }
+
+ /// <summary> the code of the thread handling the incoming messages.
+ /// </summary>
+ 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/Ivy/IvyDomain.Designer.cs b/Ivy/Ivy/IvyDomain.Designer.cs
new file mode 100644
index 0000000..3f89b6a
--- /dev/null
+++ b/Ivy/Ivy/IvyDomain.Designer.cs
@@ -0,0 +1,75 @@
+namespace IvyBus
+{
+ partial class IvyDomain
+ {
+ /// <summary>
+ /// Required designer variable.
+ /// </summary>
+ private System.ComponentModel.IContainer components = null;
+
+ /// <summary>
+ /// Clean up any resources being used.
+ /// </summary>
+ /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Component Designer generated code
+
+ /// <summary>
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ /// </summary>
+ 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/Ivy/IvyDomain.cs b/Ivy/Ivy/IvyDomain.cs
new file mode 100644
index 0000000..6c43b73
--- /dev/null
+++ b/Ivy/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/Ivy/IvyDomain.resx b/Ivy/Ivy/IvyDomain.resx
new file mode 100644
index 0000000..ff31a6d
--- /dev/null
+++ b/Ivy/Ivy/IvyDomain.resx
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+ <!--
+ Microsoft ResX Schema
+
+ Version 2.0
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
+ associated with the data types.
+
+ Example:
+
+ ... ado.net/XML headers & schema ...
+ <resheader name="resmimetype">text/microsoft-resx</resheader>
+ <resheader name="version">2.0</resheader>
+ <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+ <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+ <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+ <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+ <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+ <value>[base64 mime encoded serialized .NET Framework object]</value>
+ </data>
+ <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+ <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+ <comment>This is a comment</comment>
+ </data>
+
+ There are any number of "resheader" rows that contain simple
+ name/value pairs.
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
+ mimetype set.
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
+ extensible. For a given mimetype the value must be set accordingly:
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
+ read any of the formats listed below.
+
+ mimetype: application/x-microsoft.net.object.binary.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.soap.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.bytearray.base64
+ value : The object must be serialized into a byte array
+ : using a System.ComponentModel.TypeConverter
+ : and then encoded with base64 encoding.
+ -->
+ <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+ <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+ <xsd:element name="root" msdata:IsDataSet="true">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded">
+ <xsd:element name="metadata">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="name" use="required" type="xsd:string" />
+ <xsd:attribute name="type" type="xsd:string" />
+ <xsd:attribute name="mimetype" type="xsd:string" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="assembly">
+ <xsd:complexType>
+ <xsd:attribute name="alias" type="xsd:string" />
+ <xsd:attribute name="name" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="data">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+ <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+ <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="resheader">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ <resheader name="resmimetype">
+ <value>text/microsoft-resx</value>
+ </resheader>
+ <resheader name="version">
+ <value>2.0</value>
+ </resheader>
+ <resheader name="reader">
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <resheader name="writer">
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+</root> \ No newline at end of file
diff --git a/Ivy/Ivy/IvyEventArgs.cs b/Ivy/Ivy/IvyEventArgs.cs
new file mode 100644
index 0000000..e394802
--- /dev/null
+++ b/Ivy/Ivy/IvyEventArgs.cs
@@ -0,0 +1,84 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace IvyBus
+{
+ /// <summary> The EventArgs Classes
+ /// </summary>
+ ///
+ 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/Ivy/IvyException.cs b/Ivy/Ivy/IvyException.cs
new file mode 100644
index 0000000..90a91b8
--- /dev/null
+++ b/Ivy/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;
+
+ /// <summary> signals that an unrecoverrable Ivy exception has occured.
+ /// </summary>
+
+ public class IvyException:System.Exception
+ {
+ public IvyException(System.String s):base(s)
+ {
+ }
+ }
+} \ No newline at end of file
diff --git a/Ivy/Ivy/IvyProtocol.cs b/Ivy/Ivy/IvyProtocol.cs
new file mode 100644
index 0000000..1b1f3aa
--- /dev/null
+++ b/Ivy/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/Ivy/IvyTCPStream.cs b/Ivy/Ivy/IvyTCPStream.cs
new file mode 100644
index 0000000..b8fee34
--- /dev/null
+++ b/Ivy/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/Ivy/IvyTCPStreamV3.cs b/Ivy/Ivy/IvyTCPStreamV3.cs
new file mode 100644
index 0000000..4eef12c
--- /dev/null
+++ b/Ivy/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
+{
+ /// <summary>
+ /// Description résumée de IvyStream.
+ /// </summary>
+ 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/Ivy/IvyTCPStreamV4.cs b/Ivy/Ivy/IvyTCPStreamV4.cs
new file mode 100644
index 0000000..9a96d62
--- /dev/null
+++ b/Ivy/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
+{
+ /// <summary>
+ /// Description résumée de IvyStream.
+ /// </summary>
+ 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/Ivy/IvyUDPStream.cs b/Ivy/Ivy/IvyUDPStream.cs
new file mode 100644
index 0000000..0e3f517
--- /dev/null
+++ b/Ivy/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/Ivy/IvyUDPStreamV3.cs b/Ivy/Ivy/IvyUDPStreamV3.cs
new file mode 100644
index 0000000..63a8679
--- /dev/null
+++ b/Ivy/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/Ivy/IvyUDPStreamV4.cs b/Ivy/Ivy/IvyUDPStreamV4.cs
new file mode 100644
index 0000000..b8d329a
--- /dev/null
+++ b/Ivy/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/Ivy/IvyWatcher.cs b/Ivy/Ivy/IvyWatcher.cs
new file mode 100644
index 0000000..5a3afc8
--- /dev/null
+++ b/Ivy/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;
+
+ /// <summary> IvyWatcher, A private Class for the Ivy rendezvous
+ /// </summary>
+ /// <remarks> 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.
+ /// </remarks>
+ internal class IvyWatcher
+ {
+ private Ivy bus; /* master bus controler */
+ private int port;
+ private volatile Thread listenThread;
+ private IPAddress group;
+ private IvyUDPStream stream;
+
+ /// <summary> creates an Ivy watcher
+ /// </summary>
+ /// <param name='bus'>the bus
+ /// </param>
+ /// <param name='domainaddr'>the domain
+ /// </param>
+ /// <param name='port'>the port number
+ /// </param>
+ 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);
+ }
+ }
+
+ /// <summary> the behaviour of each thread watching the UDP socket.
+ /// </summary>
+ 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");
+ }
+
+ /// <summary> stops the thread waiting on the broadcast socket
+ /// </summary>
+ 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/Ivy/Properties/AssemblyInfo.cs b/Ivy/Ivy/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..a3ce834
--- /dev/null
+++ b/Ivy/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\<configuration>. 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/Ivy/Properties/Settings.Designer.cs b/Ivy/Ivy/Properties/Settings.Designer.cs
new file mode 100644
index 0000000..96b0f2d
--- /dev/null
+++ b/Ivy/Ivy/Properties/Settings.Designer.cs
@@ -0,0 +1,80 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+// 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.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+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/Ivy/Properties/Settings.settings b/Ivy/Ivy/Properties/Settings.settings
new file mode 100644
index 0000000..f23b946
--- /dev/null
+++ b/Ivy/Ivy/Properties/Settings.settings
@@ -0,0 +1,24 @@
+<?xml version='1.0' encoding='utf-8'?>
+<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="IvyBus.Properties" GeneratedClassName="Settings">
+ <Profiles />
+ <Settings>
+ <Setting Name="IvyProtocolVersion" Type="System.Int32" Scope="Application">
+ <Value Profile="(Default)">3</Value>
+ </Setting>
+ <Setting Name="IvyPing" Type="System.Boolean" Scope="Application">
+ <Value Profile="(Default)">False</Value>
+ </Setting>
+ <Setting Name="IvyDebug" Type="System.Boolean" Scope="Application">
+ <Value Profile="(Default)">False</Value>
+ </Setting>
+ <Setting Name="IvyBus" Type="System.String" Scope="Application">
+ <Value Profile="(Default)" />
+ </Setting>
+ <Setting Name="AppName" Type="System.String" Scope="Application">
+ <Value Profile="(Default)" />
+ </Setting>
+ <Setting Name="ReadyMessage" Type="System.String" Scope="Application">
+ <Value Profile="(Default)" />
+ </Setting>
+ </Settings>
+</SettingsFile> \ No newline at end of file
diff --git a/Ivy/Ivy/Settings.cs b/Ivy/Ivy/Settings.cs
new file mode 100644
index 0000000..17744f8
--- /dev/null
+++ b/Ivy/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/Ivy/app.config b/Ivy/Ivy/app.config
new file mode 100644
index 0000000..e5b53b3
--- /dev/null
+++ b/Ivy/Ivy/app.config
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<configuration>
+ <configSections>
+ <sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
+ <section name="IvyBus.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
+ </sectionGroup>
+ </configSections>
+ <applicationSettings>
+ <IvyBus.Properties.Settings>
+ <setting name="IvyProtocolVersion" serializeAs="String">
+ <value>3</value>
+ </setting>
+ <setting name="IvyPing" serializeAs="String">
+ <value>False</value>
+ </setting>
+ <setting name="IvyDebug" serializeAs="String">
+ <value>False</value>
+ </setting>
+ <setting name="IvyBus" serializeAs="String">
+ <value />
+ </setting>
+ <setting name="AppName" serializeAs="String">
+ <value />
+ </setting>
+ <setting name="ReadyMessage" serializeAs="String">
+ <value />
+ </setting>
+ </IvyBus.Properties.Settings>
+ </applicationSettings>
+</configuration> \ No newline at end of file
diff --git a/Ivy/IvyDaemon/App.ico b/Ivy/IvyDaemon/App.ico
new file mode 100644
index 0000000..3a5525f
--- /dev/null
+++ b/Ivy/IvyDaemon/App.ico
Binary files differ
diff --git a/Ivy/IvyDaemon/IvyDaemon.cs b/Ivy/IvyDaemon/IvyDaemon.cs
new file mode 100644
index 0000000..8c0b069
--- /dev/null
+++ b/Ivy/IvyDaemon/IvyDaemon.cs
@@ -0,0 +1,169 @@
+/// François-Régis Colin
+/// http://www.tls.cena.fr/products/ivy/
+/// *
+/// (C) CENA
+/// *
+namespace IvyDaemon
+{
+ using System;
+ using System.IO;
+ using System.Threading;
+ using System.Net;
+ using System.Net.Sockets;
+ using System.Configuration;
+ using System.Diagnostics;
+ using IvyBus;
+ /// <summary> IvyDaemon: simple TCP to Ivy relay.
+ /// </summary>
+ /// <remarks>
+ /// This is a sample implementation of an Ivy Daemon, like ivyd
+ /// sends anonymous messages to an Ivy bus through a simple tcp socket,
+ /// line by line. The default port is 3456.
+ /// </remarks>
+ public class IvyDaemon
+ {
+
+
+ private TcpListener serviceSocket;
+ private static bool debug = Properties.Settings.Default.IvyDebug;
+ private volatile Thread clientThread; // volatile to ensure the quick communication
+ private Ivy bus;
+
+ public static int DEFAULT_SERVICE_PORT = 3456;
+ public const System.String DEFAULTNAME = "IvyDaemon";
+ public static System.String helpmsg = "usage: IvyDaemon [options]\n\t-b BUS\tspecifies the Ivy bus domain\n\t-p\tport number, default " + DEFAULT_SERVICE_PORT + "\n\t-n ivyname (default " + DEFAULTNAME + ")\n\t-q\tquiet, no tty output\n\t-d\tdebug\n\t-h\thelp\nListens on the TCP port, and sends each line read on the Ivy bus. It is useful to launch one Ivy Daemon and let scripts send their message on the bus.\n";
+ [STAThread]
+ public static void Main(System.String[] args)
+ {
+ Ivy bus;
+ int servicePort = DEFAULT_SERVICE_PORT;
+ System.String name = DEFAULTNAME;
+ bool quiet = false;
+ System.String domain = Ivy.GetDomain(null);
+/* Getopt opt = new Getopt("IvyDaemon", args, "n:b:dqp:h");
+ int c;
+ while ((c = opt.getopt()) != - 1)
+ {
+ switch (c)
+ {
+ case 'n':
+ name = opt.Optarg;
+ break;
+
+ case 'b':
+ domain = opt.Optarg;
+ break;
+
+ case 'q':
+ quiet = true;
+ break;
+
+ case 'd':
+ //UPGRADE_ISSUE: Method 'java.lang.System.getProperties' was not converted. 'ms-help://MS.VSCC/commoner/redir/redirect.htm?keyword="jlca1000_javalangSystemgetProperties"'
+ //System.Configuration.AppSettingsReader sysProp = System.getProperties();
+ //SupportClass.PutElement(sysProp, "IVY_DEBUG", "yes");
+ break;
+
+ case 'p':
+ System.String s = "";
+ try
+ {
+ servicePort = System.Int32.Parse(s = opt.Optarg);
+ }
+ catch (System.FormatException nfe)
+ {
+ System.Console.Out.WriteLine("Invalid port number: " + s);
+ System.Environment.Exit(0);
+ }
+ break;
+
+ case 'h': default:
+ System.Console.Out.WriteLine(helpmsg);
+ System.Environment.Exit(0);
+ break;
+
+ }
+ }
+*/
+ bus = new Ivy(name, name + " ready");
+ if (!quiet)
+ System.Console.Out.WriteLine("broadcasting on " + Ivy.Domains(domain));
+ bus.Start(domain);
+ if (!quiet)
+ System.Console.Out.WriteLine("listening on " + servicePort);
+ IvyDaemon d = new IvyDaemon(bus, servicePort);
+ }
+
+ public IvyDaemon(Ivy bus, int servicePort)
+ {
+ this.bus = bus;
+ IPAddress localAddr = IPAddress.Any;
+ serviceSocket = new TcpListener(localAddr, servicePort);
+ clientThread = new Thread(new ThreadStart(this.Run));
+ clientThread.Start();
+ }
+
+ /*
+ * the service socket reader.
+ * it could be a thread, but as long as we've got one ....
+ */
+ public void Run()
+ {
+ Thread thisThread = Thread.CurrentThread;
+ traceDebug("Thread started");
+ while (clientThread == thisThread)
+ {
+ try
+ {
+ SubReader generatedAux2 = new SubReader(serviceSocket.AcceptTcpClient(),bus);
+ }
+ catch (IOException e)
+ {
+ traceDebug("TCP socket reader caught an exception " + e.Message);
+ }
+ }
+ traceDebug("Thread stopped");
+ }
+
+ internal class SubReader
+ {
+ internal StreamReader in_Renamed;
+ internal Thread looperThread;
+ internal Ivy bus;
+ internal SubReader(TcpClient socket, Ivy bus)
+ {
+ this.bus = bus;
+ in_Renamed = new StreamReader(socket.GetStream());
+ looperThread = new Thread(new ThreadStart(this.Run));
+ looperThread.Start();
+ }
+ public void Run()
+ {
+ traceDebug("Subreader Thread started");
+ String msg = null;
+ try
+ {
+ while (true)
+ {
+ msg = in_Renamed.ReadLine();
+ if (msg == null)
+ break;
+ bus.SendMsg(msg);
+ }
+ }
+ catch (IOException ioe)
+ {
+ traceDebug("Subreader exception:" + ioe.Message);
+ System.Environment.Exit(0);
+ }
+ traceDebug("Subreader Thread stopped");
+ }
+
+ }
+ [Conditional("DEBUG")]
+ private static void traceDebug(string s)
+ {
+ Trace.WriteLineIf(debug, "-->IvyDaemon<-- " + s);
+ }
+ }
+} \ No newline at end of file
diff --git a/Ivy/IvyDaemon/IvyDaemon.csproj b/Ivy/IvyDaemon/IvyDaemon.csproj
new file mode 100644
index 0000000..1dc6409
--- /dev/null
+++ b/Ivy/IvyDaemon/IvyDaemon.csproj
@@ -0,0 +1,154 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <ProjectType>Local</ProjectType>
+ <ProductVersion>8.0.50727</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{B10AB29F-D678-4472-9BA3-D627262E14E1}</ProjectGuid>
+ <SccProjectName>SAK</SccProjectName>
+ <SccLocalPath>SAK</SccLocalPath>
+ <SccAuxPath>SAK</SccAuxPath>
+ <SccProvider>SAK</SccProvider>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ApplicationIcon>App.ico</ApplicationIcon>
+ <AssemblyKeyContainerName>
+ </AssemblyKeyContainerName>
+ <AssemblyName>IvyDaemon</AssemblyName>
+ <AssemblyOriginatorKeyFile>
+ </AssemblyOriginatorKeyFile>
+ <DefaultClientScript>JScript</DefaultClientScript>
+ <DefaultHTMLPageLayout>Grid</DefaultHTMLPageLayout>
+ <DefaultTargetSchema>IE50</DefaultTargetSchema>
+ <DelaySign>false</DelaySign>
+ <OutputType>Exe</OutputType>
+ <RootNamespace>IvyDaemon</RootNamespace>
+ <RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
+ <StartupObject>
+ </StartupObject>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <UpgradeBackupLocation>
+ </UpgradeBackupLocation>
+ <ManifestCertificateThumbprint>A4751EEE69A15B9F42D2EF22930B195D367E5103</ManifestCertificateThumbprint>
+ <ManifestKeyFile>IvyDaemon_TemporaryKey.pfx</ManifestKeyFile>
+ <GenerateManifests>true</GenerateManifests>
+ <SignManifests>true</SignManifests>
+ <IsWebBootstrapper>true</IsWebBootstrapper>
+ <PublishUrl>\\samba\fcolin\public_html\ClickOnce\IvyDaemon\</PublishUrl>
+ <Install>true</Install>
+ <InstallFrom>Web</InstallFrom>
+ <UpdateEnabled>false</UpdateEnabled>
+ <UpdateMode>Foreground</UpdateMode>
+ <UpdateInterval>7</UpdateInterval>
+ <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+ <UpdatePeriodically>false</UpdatePeriodically>
+ <UpdateRequired>false</UpdateRequired>
+ <MapFileExtensions>true</MapFileExtensions>
+ <InstallUrl>http://www.tls.cena.fr/~fcolin/ClickOnce/IvyDaemon/</InstallUrl>
+ <CreateWebPageOnPublish>true</CreateWebPageOnPublish>
+ <WebPage>publish.htm</WebPage>
+ <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+ <BootstrapperEnabled>true</BootstrapperEnabled>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <OutputPath>bin\Debug\</OutputPath>
+ <AllowUnsafeBlocks>false</AllowUnsafeBlocks>
+ <BaseAddress>285212672</BaseAddress>
+ <CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
+ <ConfigurationOverrideFile>
+ </ConfigurationOverrideFile>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <DocumentationFile>
+ </DocumentationFile>
+ <DebugSymbols>true</DebugSymbols>
+ <FileAlignment>4096</FileAlignment>
+ <NoStdLib>false</NoStdLib>
+ <NoWarn>
+ </NoWarn>
+ <Optimize>false</Optimize>
+ <RegisterForComInterop>false</RegisterForComInterop>
+ <RemoveIntegerChecks>false</RemoveIntegerChecks>
+ <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
+ <WarningLevel>4</WarningLevel>
+ <DebugType>full</DebugType>
+ <ErrorReport>prompt</ErrorReport>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <OutputPath>bin\Release\</OutputPath>
+ <AllowUnsafeBlocks>false</AllowUnsafeBlocks>
+ <BaseAddress>285212672</BaseAddress>
+ <CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
+ <ConfigurationOverrideFile>
+ </ConfigurationOverrideFile>
+ <DefineConstants>TRACE</DefineConstants>
+ <DocumentationFile>
+ </DocumentationFile>
+ <DebugSymbols>false</DebugSymbols>
+ <FileAlignment>4096</FileAlignment>
+ <NoStdLib>false</NoStdLib>
+ <NoWarn>
+ </NoWarn>
+ <Optimize>true</Optimize>
+ <RegisterForComInterop>false</RegisterForComInterop>
+ <RemoveIntegerChecks>false</RemoveIntegerChecks>
+ <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
+ <WarningLevel>4</WarningLevel>
+ <DebugType>none</DebugType>
+ <ErrorReport>prompt</ErrorReport>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System">
+ <Name>System</Name>
+ </Reference>
+ <Reference Include="System.configuration" />
+ <Reference Include="System.Data">
+ <Name>System.Data</Name>
+ </Reference>
+ <Reference Include="System.Xml">
+ <Name>System.XML</Name>
+ </Reference>
+ </ItemGroup>
+ <ItemGroup>
+ <Content Include="App.ico" />
+ <Compile Include="Properties\AssemblyInfo.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="IvyDaemon.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="Properties\Settings.Designer.cs">
+ <AutoGen>True</AutoGen>
+ <DesignTimeSharedInput>True</DesignTimeSharedInput>
+ <DependentUpon>Settings.settings</DependentUpon>
+ </Compile>
+ <Compile Include="Settings.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="app.config" />
+ <None Include="IvyDaemon_TemporaryKey.pfx" />
+ <None Include="Properties\Settings.settings">
+ <Generator>SettingsSingleFileGenerator</Generator>
+ <LastGenOutput>Settings.Designer.cs</LastGenOutput>
+ </None>
+ </ItemGroup>
+ <ItemGroup>
+ <BootstrapperPackage Include="Microsoft.Net.Framework.2.0">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 2.0</ProductName>
+ <Install>false</Install>
+ </BootstrapperPackage>
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Ivy\Ivy.csproj">
+ <Project>{F2F03CF7-0087-4EDB-AD15-80C9E8DA2617}</Project>
+ <Name>Ivy</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <PropertyGroup>
+ <PreBuildEvent>
+ </PreBuildEvent>
+ <PostBuildEvent>
+ </PostBuildEvent>
+ </PropertyGroup>
+</Project> \ No newline at end of file
diff --git a/Ivy/IvyDaemon/IvyDaemon.csproj.vspscc b/Ivy/IvyDaemon/IvyDaemon.csproj.vspscc
new file mode 100644
index 0000000..a2a1a1c
--- /dev/null
+++ b/Ivy/IvyDaemon/IvyDaemon.csproj.vspscc
@@ -0,0 +1,10 @@
+""
+{
+"FILE_VERSION" = "9237"
+"ENLISTMENT_CHOICE" = "NEVER"
+"PROJECT_FILE_RELATIVE_PATH" = "relative:IvyDaemon"
+"NUMBER_OF_EXCLUDED_FILES" = "0"
+"ORIGINAL_PROJECT_FILE_PATH" = ""
+"NUMBER_OF_NESTED_PROJECTS" = "0"
+"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
+}
diff --git a/Ivy/IvyDaemon/IvyDaemon_TemporaryKey.pfx b/Ivy/IvyDaemon/IvyDaemon_TemporaryKey.pfx
new file mode 100644
index 0000000..b280243
--- /dev/null
+++ b/Ivy/IvyDaemon/IvyDaemon_TemporaryKey.pfx
Binary files differ
diff --git a/Ivy/IvyDaemon/Properties/AssemblyInfo.cs b/Ivy/IvyDaemon/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..65a2ee8
--- /dev/null
+++ b/Ivy/IvyDaemon/Properties/AssemblyInfo.cs
@@ -0,0 +1,58 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+//
+// Les informations générales relatives à un assembly dépendent de
+// l'ensemble d'attributs suivant. Pour modifier les informations
+// associées à un assembly, changez les valeurs de ces attributs.
+//
+[assembly: AssemblyTitle("")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+//
+// Les informations de version pour un assembly se composent des quatre valeurs suivantes :
+//
+// Version principale
+// Version secondaire
+// Numéro de build
+// Révision
+//
+// Vous pouvez spécifier toutes les valeurs ou indiquer des numéros de révision et de build par défaut
+// en utilisant '*', comme ci-dessous :
+
+[assembly: AssemblyVersion("2.0.*")]
+
+//
+// Pour signer votre assembly, vous devez spécifier la clé à utiliser. Consultez
+// la documentation Microsoft .NET Framework pour plus d'informations sur la signature d'un assembly.
+//
+// Utilisez les attributs ci-dessous pour contrôler la clé utilisée lors de la signature.
+//
+// Remarques :
+// (*) Si aucune clé n'est spécifiée, l'assembly n'est pas signé.
+// (*) KeyName fait référence à une clé installée dans le fournisseur de
+// services cryptographiques (CSP) de votre ordinateur. KeyFile fait référence à un fichier qui contient
+// une clé.
+// (*) Si les valeurs de KeyFile et de KeyName sont spécifiées, le
+// traitement suivant se produit :
+// (1) Si KeyName se trouve dans le CSP, la clé est utilisée.
+// (2) Si KeyName n'existe pas mais que KeyFile existe, la clé
+// de KeyFile est installée dans le CSP et utilisée.
+// (*) Pour créer KeyFile, vous pouvez utiliser l'utilitaire sn.exe (Strong Name, Nom fort).
+// Lors de la spécification de KeyFile, son emplacement doit être
+// relatif au répertoire de sortie du projet qui est
+// %Project Directory%\obj\<configuration>. Par exemple, si votre KeyFile se trouve
+// dans le répertoire du projet, vous devez spécifier l'attribut
+// AssemblyKeyFile sous la forme [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
+// (*) DelaySign (signature différée) est une option avancée. Pour plus d'informations, consultez la
+// documentation Microsoft .NET Framework.
+//
+[assembly: AssemblyDelaySign(false)]
+[assembly: AssemblyKeyFile("")]
+[assembly: AssemblyKeyName("")]
diff --git a/Ivy/IvyDaemon/Properties/Settings.Designer.cs b/Ivy/IvyDaemon/Properties/Settings.Designer.cs
new file mode 100644
index 0000000..7555e19
--- /dev/null
+++ b/Ivy/IvyDaemon/Properties/Settings.Designer.cs
@@ -0,0 +1,35 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+// 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.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace IvyDaemon.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("False")]
+ public bool IvyDebug {
+ get {
+ return ((bool)(this["IvyDebug"]));
+ }
+ }
+ }
+}
diff --git a/Ivy/IvyDaemon/Properties/Settings.settings b/Ivy/IvyDaemon/Properties/Settings.settings
new file mode 100644
index 0000000..046036c
--- /dev/null
+++ b/Ivy/IvyDaemon/Properties/Settings.settings
@@ -0,0 +1,9 @@
+<?xml version='1.0' encoding='utf-8'?>
+<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="IvyDaemon.Properties" GeneratedClassName="Settings">
+ <Profiles />
+ <Settings>
+ <Setting Name="IvyDebug" Type="System.Boolean" Scope="Application">
+ <Value Profile="(Default)">False</Value>
+ </Setting>
+ </Settings>
+</SettingsFile> \ No newline at end of file
diff --git a/Ivy/IvyDaemon/Settings.cs b/Ivy/IvyDaemon/Settings.cs
new file mode 100644
index 0000000..6ac518c
--- /dev/null
+++ b/Ivy/IvyDaemon/Settings.cs
@@ -0,0 +1,28 @@
+namespace IvyDaemon.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/IvyDaemon/app.config b/Ivy/IvyDaemon/app.config
new file mode 100644
index 0000000..df27cc0
--- /dev/null
+++ b/Ivy/IvyDaemon/app.config
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<configuration>
+ <configSections>
+ <sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
+ <section name="IvyDaemon.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
+ </sectionGroup>
+ </configSections>
+ <applicationSettings>
+ <IvyDaemon.Properties.Settings>
+ <setting name="IvyDebug" serializeAs="String">
+ <value>False</value>
+ </setting>
+ </IvyDaemon.Properties.Settings>
+ </applicationSettings>
+</configuration> \ No newline at end of file
diff --git a/Ivy/IvyFilter/Filter.cs b/Ivy/IvyFilter/Filter.cs
new file mode 100644
index 0000000..03e2435
--- /dev/null
+++ b/Ivy/IvyFilter/Filter.cs
@@ -0,0 +1,119 @@
+
+using System;
+using IvyBus;
+using System.Threading;
+using Gnu;
+
+namespace IvyFilter
+{
+ class Filter
+ {
+
+ internal Ivy bus;
+
+ [STAThread]
+ public static void Main(System.String[] args)
+ {
+ GetOpt opt = new GetOpt(args, "b:n:t:");
+ System.String domain = Ivy.GetDomain(null);
+ int nb = 10000;
+ int t = 1000;
+ Arg a;
+ while ((a = opt.NextArg() )!= null)
+ {
+ switch (a.Flag)
+ {
+
+ case 'b':
+ domain = a.Parameter;
+ break;
+
+ case 't':
+ t = int.Parse(a.Parameter);
+ break;
+
+ case 'n':
+ nb = int.Parse(a.Parameter);
+ break;
+
+ default:
+ System.Environment.Exit(0);
+ break;
+
+ }
+ }
+ new Filter(domain, nb, t, true);
+ }
+
+ private int nbmsg;
+ private int bounded = 0, unbounded = 0;
+ private string[] filter = new string[] { "GetDummy" };
+
+ public Filter(string domain, int n, int t, bool f)
+ {
+ System.Console.Out.WriteLine("trying Filter on " + n + " messages, " + t + " ms delay");
+ nbmsg = n;
+ bus = new Ivy("Filter", "Filter ready");
+ if (f)
+ bus.SentMessageFilter.AddRange(filter);
+ bus.BindingAdd += new EventHandler<IvyEventArgs>(bus_BindingAdd);
+ bus.BindingRemove += new EventHandler<IvyEventArgs>(bus_BindingRemove);
+ bus.BindingFilter += new EventHandler<IvyEventArgs>(bus_BindingFilter);
+ bus.Start(domain);
+ /* attend une seconde ou deux */
+ try
+ {
+ Thread.Sleep(2000);
+ }
+ catch (System.Threading.ThreadInterruptedException )
+ {
+ }
+ System.Console.Out.WriteLine(bounded + " bounded subscriptions, " + unbounded + " unbounded");
+ System.Console.Out.WriteLine(bus.IvyClients.Count + " clients");
+ DateTime debut = System.DateTime.Now;
+ TimeSpan total = new TimeSpan();
+ DateTime debutlocal = System.DateTime.Now;
+ DateTime finlocal = System.DateTime.Now;
+ for (int i = 0; i < n; i++)
+ {
+ try
+ {
+ // System.out.println("sending msg");
+ debutlocal = System.DateTime.Now;
+ bus.SendMsg("GetDummy message");
+ finlocal = System.DateTime.Now;
+ total += finlocal - debutlocal;
+ Thread.Sleep( t );
+ }
+ catch (IvyException )
+ {
+ System.Environment.Exit(-1);
+ }
+ catch (ThreadInterruptedException )
+ {
+ }
+ }
+ System.Console.Out.WriteLine(((f) ? "[filtered] " : "[non filtered] ") + total.TotalMilliseconds + "ms elapsed, " + (finlocal - debut).TotalMilliseconds + " ms total out of " + n * t);
+ bus.Stop();
+ if (f == true)
+ new Filter(domain, n, t, false); // relance le même test sans filtre
+ System.Console.ReadLine();
+ }
+
+ void bus_BindingFilter(object sender, IvyEventArgs e)
+ {
+ unbounded++;
+ }
+
+ void bus_BindingRemove(object sender, IvyEventArgs e)
+ {
+ bounded--;
+ }
+
+ void bus_BindingAdd(object sender, IvyEventArgs e)
+ {
+ bounded++;
+ }
+
+ }
+} \ No newline at end of file
diff --git a/Ivy/IvyFilter/IvyFilter.csproj b/Ivy/IvyFilter/IvyFilter.csproj
new file mode 100644
index 0000000..1d3c263
--- /dev/null
+++ b/Ivy/IvyFilter/IvyFilter.csproj
@@ -0,0 +1,61 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>8.0.50727</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{151B7DDB-279B-4E1E-903B-E09B079FA0A5}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>IvyFilter</RootNamespace>
+ <AssemblyName>IvyFilter</AssemblyName>
+ <SccProjectName>SAK</SccProjectName>
+ <SccLocalPath>SAK</SccLocalPath>
+ <SccAuxPath>SAK</SccAuxPath>
+ <SccProvider>SAK</SccProvider>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Filter.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\getopt\getopt.csproj">
+ <Project>{228B5F0B-31AE-488F-A916-B7CBB269D25F}</Project>
+ <Name>getopt</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Ivy\Ivy.csproj">
+ <Project>{F2F03CF7-0087-4EDB-AD15-80C9E8DA2617}</Project>
+ <Name>Ivy</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project> \ No newline at end of file
diff --git a/Ivy/IvyFilter/IvyFilter.csproj.vspscc b/Ivy/IvyFilter/IvyFilter.csproj.vspscc
new file mode 100644
index 0000000..353c834
--- /dev/null
+++ b/Ivy/IvyFilter/IvyFilter.csproj.vspscc
@@ -0,0 +1,10 @@
+""
+{
+"FILE_VERSION" = "9237"
+"ENLISTMENT_CHOICE" = "NEVER"
+"PROJECT_FILE_RELATIVE_PATH" = "relative:IvyFilter"
+"NUMBER_OF_EXCLUDED_FILES" = "0"
+"ORIGINAL_PROJECT_FILE_PATH" = ""
+"NUMBER_OF_NESTED_PROJECTS" = "0"
+"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
+}
diff --git a/Ivy/IvyFilter/Properties/AssemblyInfo.cs b/Ivy/IvyFilter/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..723881f
--- /dev/null
+++ b/Ivy/IvyFilter/Properties/AssemblyInfo.cs
@@ -0,0 +1,33 @@
+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("IvyFilter")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("DTI/SDER")]
+[assembly: AssemblyProduct("IvyFilter")]
+[assembly: AssemblyCopyright("Copyright © DTI/SDER 2006")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("7d041760-bc83-40d7-a534-b90993c58737")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/Ivy/IvyPPC/Ivy.cs b/Ivy/IvyPPC/Ivy.cs
new file mode 100644
index 0000000..1c38396
--- /dev/null
+++ b/Ivy/IvyPPC/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;
+
+
+ /// <summary> The Main bus Class
+ /// </summary>
+ ///
+#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 */
+ /// <summary>fires when a new client connect to the bus</summary>
+ public event EventHandler<IvyEventArgs> ClientConnected;
+ /// <summary>fires when a client discconnect from the bus</summary>
+ public event EventHandler<IvyEventArgs> ClientDisconnected;
+ /// <summary>fires when a client receive a direct message from another client</summary>
+ public event EventHandler<IvyEventArgs> DirectMessageReceived;
+ /// <summary>fires when somebody ask for killing every client on the bus</summary>
+ public event EventHandler<IvyDieEventArgs> DieReceived;
+ /// <summary>fires when a client receive a add binding from another client</summary>
+ public event EventHandler<IvyEventArgs> BindingAdd;
+ /// <summary>fires when a client receive a remove binding from another client</summary>
+ public event EventHandler<IvyEventArgs> BindingRemove;
+ /// <summary>fires when a client receive a binding from another client and it as been filtered </summary>
+ public event EventHandler<IvyEventArgs> BindingFilter;
+ /// <summary>fires when a client receive a remove binding from another client</summary>
+ public event EventHandler<IvyEventArgs> 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;
+ }
+
+ }
+
+ /// <summary>IvyClients accesses the list of the connected clients</summary>
+#if (!PocketPC)
+ [Browsable(false)]
+#endif
+ public List<IvyClient> IvyClients
+ {
+ get
+ {
+ return clients;
+ }
+
+ }
+
+ /// <summary>AppName the application name</summary>
+
+#if (!PocketPC)
+ [Category("Ivy")]
+ [Bindable(true)]
+#endif
+ [DefaultValue(null)]
+ public string AppName
+ {
+ set
+ {
+ appName = value;
+ }
+ get
+ {
+ return appName;
+ }
+
+ }
+ /// <summary>AppId the Application Unique ID</summary>
+
+#if (!PocketPC)
+ [Browsable(false)]
+#endif
+ public string AppId
+ {
+ get
+ {
+ return applicationUniqueId;
+ }
+
+ }
+ /// <summary>AppPriority the Application Priority: the clients list is sorted against priority</summary>
+#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;
+ }
+
+ }
+
+ /// <summary>IsRunning is the bus Started and connected ?</summary>
+
+#if (!PocketPC)
+ [Browsable(false)]
+#endif
+ public bool IsRunning
+ {
+ get
+ {
+ return !stopped;
+ }
+
+ }
+ ///<summary>SentMessageClasses the first word token of sent messages
+ ///<remarks> optimise the parsing process when sending messages </remarks>
+ ///</summary>
+#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<string> SentMessageFilter
+ {
+ get
+ {
+ return sent_messageFilter;
+ }
+ }
+ /// <summary>ReadyMessage message send when Application receive all the regexp at the connection of the client</summary>
+
+#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<IvyApplicationBinding> 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<IvyWatcher> watchers;
+ private volatile Thread serverThread; // to ensure quick communication of the end
+
+ internal Dictionary<int, IvyApplicationBinding> bindings;
+ //TODO should be remove samve as above
+ private List<IvyApplicationBinding> app_bindings;
+ private List<IvyClient> clients;
+ private List<string> 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
+
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="T:Ivy"/> class.
+ /// </summary>
+ public Ivy()
+ {
+#if (!PocketPC)
+ syncContext = SynchronizationContext.Current;
+#endif
+ clients = new List<IvyClient>();
+ bindings = new Dictionary<int, IvyApplicationBinding>();
+ app_bindings = new List<IvyApplicationBinding>();
+ sent_messageFilter = new List<string>();
+#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);
+ }
+ /// <summary>
+ /// Readies the structures for the software bus connexion.
+ /// </summary>
+ /// <example> This sample shows how to start working with Ivy.
+ /// <code>
+ /// Ivy bus = new Ivy("Dummy agent","ready");
+ /// bus.bindMsg("(.*)",myMessageListener);
+ /// bus.start(null);
+ /// </code>
+ /// How to send & receive:
+ /// the Ivy agent A performs <c>b.bindMsg("^Hello (*)",cb);</c>
+ /// the Ivy agent B performs <c>b2.sendMsg("Hello world");</c>
+ /// a thread in A will run the callback cb with its second argument set
+ /// to a array of string, with one single element, "world"
+ /// </example>
+ /// <remarks>
+ /// the real work begin in the start() method
+ /// </remarks>
+ /// <seealso cref=" Ivy.start"/>
+ /// <param name='name'>The name of your Ivy agent on the software bus
+ /// </param>
+ /// <param name='message'>The hellow message you will send once ready
+ /// </param>
+ 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<IvyMessageEventArgs> handler;
+#if (PocketPC)
+ //Createdelegate mydlg = new Createdelegate(m, null, EventArgs.Empty);
+ //bindMsg(attr.GetExpression(null), mydlg);
+ handler = null;
+#else
+ handler = (EventHandler<IvyMessageEventArgs>)Delegate.CreateDelegate(typeof(EventHandler<IvyMessageEventArgs>), 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<IvyMessageEventArgs> handler;
+#if (PocketPC)
+ handler = null; // TODO
+#else
+ handler = (EventHandler<IvyMessageEventArgs>)Delegate.CreateDelegate(typeof(EventHandler<IvyMessageEventArgs>), 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);
+ }
+
+ }
+ /// <summary>
+ /// connects the Ivy bus to a domain or list of domains.
+ /// </summary>
+ /// <param name="domainbus">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.</param>
+ /// <remarks>
+ /// 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.
+ /// </remarks>
+ 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<IvyWatcher>();
+
+ 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;
+ }
+
+ /// <summary>
+ /// disconnects from the Ivy bus
+ /// </summary>
+ 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");
+ }
+ }
+
+
+ /// <summary>
+ /// Send a formated message to someone on the bus
+ /// </summary>
+ /// <remarks>
+ /// 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.
+ /// </remarks>
+ /// <param name='format'>A string message format to build the message
+ /// <param name='args'>args used in message format
+ /// <returns>
+ /// the number of messages actually sent
+ /// </returns>
+ 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;
+ }
+ /// <summary>
+ /// Subscribes to a regular expression.
+ /// </summary>
+ /// <param name="regexp">a regular expression, groups are done with parenthesis</param>
+ /// <param name="callback">any objects implementing the Ivy.MessageListener</param>
+ /// <param name="args">The args.</param>
+ /// <returns>the id of the regular expression</returns>
+ /// <remarks>
+ /// 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.
+ /// </remarks>
+ //
+ public ushort BindMsg(string regexp, EventHandler<IvyMessageEventArgs> 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);
+ }
+
+ /// <summary>
+ /// unsubscribes a regular expression
+ /// </summary>
+ /// <param name="id">the id of the regular expression, returned when it was bound</param>
+ 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);
+ }
+
+ /// <summary>
+ /// unsubscribes a regular expression
+ /// </summary>
+ /// <param name="re">the string for the regular expression</param>
+ /// <returns>
+ /// a boolean, true if the regexp existed, false otherwise or
+ /// whenever an exception occured during unbinding
+ /// </returns>
+ 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;
+ }
+
+
+ /// <summary>
+ /// Subscribes to a simple expression ( msg ar1 arg2 arg3 etc).
+ /// </summary>
+ /// <remarks>
+ /// 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.
+ /// </remarks>
+ ///
+ /// <param name='regexp'>a regular expression, groups are done with parenthesis
+ /// <param name='callback'>any objects implementing the EventHandler<IvyMessageEventArgs>
+ /// <returns>
+ /// the id of the regular expression
+ /// </returns>
+ public int BindSimpleMsg(string expression, EventHandler<IvyMessageEventArgs> 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);
+ }
+ /// <summary>
+ /// Dies the specified target.
+ /// </summary>
+ /// <param name="target">The target.</param>
+ /// <param name="message">The reason message.</param>
+ /// <returns></returns>
+ public int Die(string target, string message)
+ {
+ List<IvyClient> v = GetClientsByName(target);
+ for (int i = 0; i < v.Count; i++)
+ v[i].stream.TokenDie(0, message);
+ return v.Count;
+ }
+ /// <summary>
+ /// Pings the specified target.
+ /// </summary>
+ /// <param name="target">The target.</param>
+ /// <param name="message">The message.</param>
+ /// <returns></returns>
+ public int Ping(string target, string message)
+ {
+ List<IvyClient> 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<IvyEventArgs> ev, IvyEventArgs e)
+ {
+ if (ev != null)
+ {
+ if (parentControl != null)
+ {
+ parentControl.Invoke(ev, this, e);
+ }
+ else
+ ev(this, e);
+ }
+ }
+#else
+ internal virtual void FireEvent(EventHandler<IvyEventArgs> 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<IvyEventArgs> temp = DirectMessageReceived;
+ FireEvent(temp,e);
+ }
+ internal virtual void OnClientConnected(IvyEventArgs e)
+ {
+ // Copy to a temporary variable to be thread-safe.
+ EventHandler<IvyEventArgs> temp = ClientConnected;
+ FireEvent(temp,e);
+ }
+ internal virtual void OnClientDisconnected(IvyEventArgs e)
+ {
+ // Copy to a temporary variable to be thread-safe.
+ EventHandler<IvyEventArgs> 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<IvyEventArgs> temp = BindingAdd;
+ FireEvent(temp,e);
+ }
+ internal virtual void OnClientRemoveBinding(IvyEventArgs e)
+ {
+ // Copy to a temporary variable to be thread-safe.
+ EventHandler<IvyEventArgs> temp = BindingRemove;
+ FireEvent(temp,e);
+ }
+ internal virtual void OnClientFilterBinding(IvyEventArgs e)
+ {
+ // Copy to a temporary variable to be thread-safe.
+ EventHandler<IvyEventArgs> temp = BindingFilter;
+ FireEvent(temp,e);
+ }
+ internal virtual void OnError(IvyEventArgs e)
+ {
+ // Copy to a temporary variable to be thread-safe.
+ EventHandler<IvyEventArgs> temp = ErrorMessage;
+ FireEvent(temp, e);
+ }
+#if (PocketPC)
+ internal virtual void OnDie(IvyDieEventArgs e)
+ {
+ // Copy to a temporary variable to be thread-safe.
+ EventHandler<IvyDieEventArgs> 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<IvyDieEventArgs> 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);
+ }
+ }
+
+
+ /// <summary>
+ /// gives a list of IvyClient(s) with the name given in parameter
+ /// </summary>
+ /// <param name="name">The name of the Ivy agent you're looking for</param>
+ /// <returns></returns>
+ public List<IvyClient> GetClientsByName(string name)
+ {
+ List<IvyClient> v = new List<IvyClient>();
+ 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, @"^\^(?<token>[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/IvyPPC/IvyApplicationBinding.cs b/Ivy/IvyPPC/IvyApplicationBinding.cs
new file mode 100644
index 0000000..9183850
--- /dev/null
+++ b/Ivy/IvyPPC/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<string> arguments;
+ ///<summary>SentMessageClasses the first word token of sent messages
+ ///<remarks> optimise the parsing process when sending messages </remarks>
+ ///</summary>
+#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<string> Arguments
+ {
+ get
+ {
+ return arguments;
+ }
+ }
+
+#if (!PocketPC)
+ [Category("Ivy")]
+ [Description("Event fired when Message Matching expression received")]
+#endif
+ public event EventHandler<IvyMessageEventArgs> Callback;
+
+ public IvyApplicationBinding()
+ {
+ arguments = new List<string>();
+ }
+ 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<IvyMessageEventArgs> 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<IvyMessageEventArgs> 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<IvyMessageEventArgs> 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/IvyPPC/IvyBinding.cs b/Ivy/IvyPPC/IvyBinding.cs
new file mode 100644
index 0000000..624b401
--- /dev/null
+++ b/Ivy/IvyPPC/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 */
+
+ /// <summary>
+ /// Description résumée de IvyBinding.
+ /// </summary>
+ 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/IvyPPC/IvyBindingAttribute.cs b/Ivy/IvyPPC/IvyBindingAttribute.cs
new file mode 100644
index 0000000..90c44ce
--- /dev/null
+++ b/Ivy/IvyPPC/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/IvyPPC/IvyClient.cs b/Ivy/IvyPPC/IvyClient.cs
new file mode 100644
index 0000000..3db9f0f
--- /dev/null
+++ b/Ivy/IvyPPC/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;
+
+ /// <summary> A Class for the the peers on the bus.
+ /// </summary>
+ /// <remarks>
+ /// 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.
+ /// </remarks>
+ public class IvyClient : IvyProtocol, IComparable<IvyClient>, IDisposable
+ {
+ public int CompareTo(IvyClient other)
+ {
+ return (other.clientPriority - clientPriority);
+ }
+
+ public String ApplicationName
+ {
+ get
+ {
+ return appName;
+ }
+
+ }
+
+ public List<string> Regexps
+ {
+ get
+ {
+ List<string> tab = new List<string>();
+ 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<ushort,IvyBindingBase> 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<ushort,IvyBindingBase>();
+ 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);
+ }
+ }
+
+ /// <summary> 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
+ /// </summary>
+
+ /// <summary> sends a direct message to the peer
+ /// </summary>
+ /// <param name='id'>the numeric value provided to the remote client
+ /// </param>
+ /// <param name='message'>the string that will be match-tested
+ ///
+ /// </param>
+ 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);
+ }
+ }
+
+ /// <summary> closes the connexion to the peer.
+ /// </summary>
+ /// <param name='notify'>should I send Bye message ?
+ /// the thread managing the socket is stopped
+ ///
+ /// </param>
+ 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;
+
+
+ }
+
+ /// <summary> sends the substrings of a message to the peer for each matching regexp.
+ /// </summary>
+ /// <param name='message'>the string that will be match-tested
+ /// </param>
+ /// <returns>the number of messages sent to the peer
+ ///
+ /// </returns>
+ 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;
+ }
+
+ /// <summary> compares two peers the id is the couple (host,service port).
+ /// </summary>
+ /// <param name='clnt'>the other peer
+ /// </param>
+ /// <returns>true if the peers are similir. This should not happen, it is bad
+ /// © ® (tm)
+ ///
+ /// </returns>
+ internal bool sameClient(IvyClient clnt)
+ {
+ return (appPort != 0 && appPort == clnt.appPort) && (RemoteAddress == clnt.RemoteAddress);
+ }
+
+ /// <summary> the code of the thread handling the incoming messages.
+ /// </summary>
+ 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/IvyPPC/IvyDomain.Designer.cs b/Ivy/IvyPPC/IvyDomain.Designer.cs
new file mode 100644
index 0000000..3f89b6a
--- /dev/null
+++ b/Ivy/IvyPPC/IvyDomain.Designer.cs
@@ -0,0 +1,75 @@
+namespace IvyBus
+{
+ partial class IvyDomain
+ {
+ /// <summary>
+ /// Required designer variable.
+ /// </summary>
+ private System.ComponentModel.IContainer components = null;
+
+ /// <summary>
+ /// Clean up any resources being used.
+ /// </summary>
+ /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Component Designer generated code
+
+ /// <summary>
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ /// </summary>
+ 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/IvyPPC/IvyDomain.cs b/Ivy/IvyPPC/IvyDomain.cs
new file mode 100644
index 0000000..6c43b73
--- /dev/null
+++ b/Ivy/IvyPPC/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/IvyPPC/IvyDomain.resx b/Ivy/IvyPPC/IvyDomain.resx
new file mode 100644
index 0000000..ff31a6d
--- /dev/null
+++ b/Ivy/IvyPPC/IvyDomain.resx
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+ <!--
+ Microsoft ResX Schema
+
+ Version 2.0
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
+ associated with the data types.
+
+ Example:
+
+ ... ado.net/XML headers & schema ...
+ <resheader name="resmimetype">text/microsoft-resx</resheader>
+ <resheader name="version">2.0</resheader>
+ <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+ <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+ <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+ <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+ <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+ <value>[base64 mime encoded serialized .NET Framework object]</value>
+ </data>
+ <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+ <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+ <comment>This is a comment</comment>
+ </data>
+
+ There are any number of "resheader" rows that contain simple
+ name/value pairs.
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
+ mimetype set.
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
+ extensible. For a given mimetype the value must be set accordingly:
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
+ read any of the formats listed below.
+
+ mimetype: application/x-microsoft.net.object.binary.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.soap.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.bytearray.base64
+ value : The object must be serialized into a byte array
+ : using a System.ComponentModel.TypeConverter
+ : and then encoded with base64 encoding.
+ -->
+ <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+ <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+ <xsd:element name="root" msdata:IsDataSet="true">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded">
+ <xsd:element name="metadata">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="name" use="required" type="xsd:string" />
+ <xsd:attribute name="type" type="xsd:string" />
+ <xsd:attribute name="mimetype" type="xsd:string" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="assembly">
+ <xsd:complexType>
+ <xsd:attribute name="alias" type="xsd:string" />
+ <xsd:attribute name="name" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="data">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+ <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+ <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="resheader">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ <resheader name="resmimetype">
+ <value>text/microsoft-resx</value>
+ </resheader>
+ <resheader name="version">
+ <value>2.0</value>
+ </resheader>
+ <resheader name="reader">
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <resheader name="writer">
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+</root> \ No newline at end of file
diff --git a/Ivy/IvyPPC/IvyEventArgs.cs b/Ivy/IvyPPC/IvyEventArgs.cs
new file mode 100644
index 0000000..e394802
--- /dev/null
+++ b/Ivy/IvyPPC/IvyEventArgs.cs
@@ -0,0 +1,84 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace IvyBus
+{
+ /// <summary> The EventArgs Classes
+ /// </summary>
+ ///
+ 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/IvyPPC/IvyException.cs b/Ivy/IvyPPC/IvyException.cs
new file mode 100644
index 0000000..90a91b8
--- /dev/null
+++ b/Ivy/IvyPPC/IvyException.cs
@@ -0,0 +1,19 @@
+/// François-Régis Colin
+/// http://www.tls.cena.fr/products/ivy/
+/// *
+/// (C) CENA
+/// *
+namespace IvyBus
+{
+ using System;
+
+ /// <summary> signals that an unrecoverrable Ivy exception has occured.
+ /// </summary>
+
+ public class IvyException:System.Exception
+ {
+ public IvyException(System.String s):base(s)
+ {
+ }
+ }
+} \ No newline at end of file
diff --git a/Ivy/IvyPPC/IvyPPC.csproj b/Ivy/IvyPPC/IvyPPC.csproj
new file mode 100644
index 0000000..c1c8af8
--- /dev/null
+++ b/Ivy/IvyPPC/IvyPPC.csproj
@@ -0,0 +1,110 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>8.0.50727</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{7E5552BD-0262-4C02-B0CE-E96305CFCD6D}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>IvyBus</RootNamespace>
+ <AssemblyName>Ivy</AssemblyName>
+ <ProjectTypeGuids>{4D628B5B-2FBC-4AA6-8C16-197242AEB884};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <PlatformFamilyName>PocketPC</PlatformFamilyName>
+ <PlatformID>3C41C503-53EF-4c2a-8DD4-A8217CAD115E</PlatformID>
+ <OSVersion>4.20</OSVersion>
+ <DeployDirSuffix>IvyPPC</DeployDirSuffix>
+ <TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
+ <FormFactorID>
+ </FormFactorID>
+ <SccProjectName>SAK</SccProjectName>
+ <SccLocalPath>SAK</SccLocalPath>
+ <SccAuxPath>SAK</SccAuxPath>
+ <SccProvider>SAK</SccProvider>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>TRACE;DEBUG;PocketPC</DefineConstants>
+ <NoStdLib>true</NoStdLib>
+ <NoConfig>true</NoConfig>
+ <ErrorReport>prompt</ErrorReport>
+ <FileAlignment>512</FileAlignment>
+ <WarningLevel>4</WarningLevel>
+ <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE;$(PlatformFamilyName)</DefineConstants>
+ <NoStdLib>true</NoStdLib>
+ <NoConfig>true</NoConfig>
+ <ErrorReport>prompt</ErrorReport>
+ <FileAlignment>512</FileAlignment>
+ <WarningLevel>4</WarningLevel>
+ <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="Ivy.cs">
+ <SubType>Component</SubType>
+ </Compile>
+ <Compile Include="IvyApplicationBinding.cs">
+ <SubType>Component</SubType>
+ </Compile>
+ <Compile Include="IvyBinding.cs" />
+ <Compile Include="IvyBindingAttribute.cs" />
+ <Compile Include="IvyClient.cs" />
+ <Compile Include="IvyDomain.cs">
+ <SubType>UserControl</SubType>
+ </Compile>
+ <Compile Include="IvyDomain.designer.cs">
+ <DependentUpon>IvyDomain.cs</DependentUpon>
+ </Compile>
+ <Compile Include="IvyEventArgs.cs" />
+ <Compile Include="IvyException.cs" />
+ <Compile Include="IvyProtocol.cs" />
+ <Compile Include="IvyTCPStream.cs" />
+ <Compile Include="IvyTCPStreamV3.cs" />
+ <Compile Include="IvyTCPStreamV4.cs" />
+ <Compile Include="IvyUDPStream.cs" />
+ <Compile Include="IvyUDPStreamV3.cs" />
+ <Compile Include="IvyUDPStreamV4.cs" />
+ <Compile Include="IvyWatcher.cs" />
+ <None Include="Pcre.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <None Include="Settings.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <Reference Include="CustomMarshalers" />
+ <Reference Include="mscorlib" />
+ <Reference Include="System" />
+ <Reference Include="System.Drawing" />
+ <Reference Include="System.Windows.Forms" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <EmbeddedResource Include="IvyDomain.resx">
+ <DependentUpon>IvyDomain.cs</DependentUpon>
+ <SubType>Designer</SubType>
+ </EmbeddedResource>
+ </ItemGroup>
+ <Import Condition="'$(TargetFrameworkVersion)' == 'v1.0'" Project="$(MSBuildBinPath)\Microsoft.CompactFramework.CSharp.v1.targets" />
+ <Import Condition="'$(TargetFrameworkVersion)' == 'v2.0'" Project="$(MSBuildBinPath)\Microsoft.CompactFramework.CSharp.targets" />
+ <ProjectExtensions>
+ <VisualStudio>
+ <FlavorProperties GUID="{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}">
+ <HostingProcess disable="1" />
+ </FlavorProperties>
+ </VisualStudio>
+ </ProjectExtensions>
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project> \ No newline at end of file
diff --git a/Ivy/IvyPPC/IvyPPC.csproj.vspscc b/Ivy/IvyPPC/IvyPPC.csproj.vspscc
new file mode 100644
index 0000000..feffdec
--- /dev/null
+++ b/Ivy/IvyPPC/IvyPPC.csproj.vspscc
@@ -0,0 +1,10 @@
+""
+{
+"FILE_VERSION" = "9237"
+"ENLISTMENT_CHOICE" = "NEVER"
+"PROJECT_FILE_RELATIVE_PATH" = ""
+"NUMBER_OF_EXCLUDED_FILES" = "0"
+"ORIGINAL_PROJECT_FILE_PATH" = ""
+"NUMBER_OF_NESTED_PROJECTS" = "0"
+"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
+}
diff --git a/Ivy/IvyPPC/IvyPPC.sln b/Ivy/IvyPPC/IvyPPC.sln
new file mode 100644
index 0000000..75d6fff
--- /dev/null
+++ b/Ivy/IvyPPC/IvyPPC.sln
@@ -0,0 +1,26 @@
+
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IvyPPC", "IvyPPC.csproj", "{7E5552BD-0262-4C02-B0CE-E96305CFCD6D}"
+EndProject
+Global
+ GlobalSection(SourceCodeControl) = preSolution
+ SccNumberOfProjects = 2
+ SccProjectUniqueName0 = IvyPPC.csproj
+ SccLocalPath0 = .
+ SccLocalPath1 = .
+ EndGlobalSection
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {7E5552BD-0262-4C02-B0CE-E96305CFCD6D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7E5552BD-0262-4C02-B0CE-E96305CFCD6D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7E5552BD-0262-4C02-B0CE-E96305CFCD6D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7E5552BD-0262-4C02-B0CE-E96305CFCD6D}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/Ivy/IvyPPC/IvyPPC.vssscc b/Ivy/IvyPPC/IvyPPC.vssscc
new file mode 100644
index 0000000..794f014
--- /dev/null
+++ b/Ivy/IvyPPC/IvyPPC.vssscc
@@ -0,0 +1,10 @@
+""
+{
+"FILE_VERSION" = "9237"
+"ENLISTMENT_CHOICE" = "NEVER"
+"PROJECT_FILE_RELATIVE_PATH" = ""
+"NUMBER_OF_EXCLUDED_FILES" = "0"
+"ORIGINAL_PROJECT_FILE_PATH" = ""
+"NUMBER_OF_NESTED_PROJECTS" = "0"
+"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT"
+}
diff --git a/Ivy/IvyPPC/IvyProtocol.cs b/Ivy/IvyPPC/IvyProtocol.cs
new file mode 100644
index 0000000..1b1f3aa
--- /dev/null
+++ b/Ivy/IvyPPC/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/IvyPPC/IvyTCPStream.cs b/Ivy/IvyPPC/IvyTCPStream.cs
new file mode 100644
index 0000000..b8fee34
--- /dev/null
+++ b/Ivy/IvyPPC/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/IvyPPC/IvyTCPStreamV3.cs b/Ivy/IvyPPC/IvyTCPStreamV3.cs
new file mode 100644
index 0000000..4eef12c
--- /dev/null
+++ b/Ivy/IvyPPC/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
+{
+ /// <summary>
+ /// Description résumée de IvyStream.
+ /// </summary>
+ 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/IvyPPC/IvyTCPStreamV4.cs b/Ivy/IvyPPC/IvyTCPStreamV4.cs
new file mode 100644
index 0000000..9a96d62
--- /dev/null
+++ b/Ivy/IvyPPC/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
+{
+ /// <summary>
+ /// Description résumée de IvyStream.
+ /// </summary>
+ 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/IvyPPC/IvyUDPStream.cs b/Ivy/IvyPPC/IvyUDPStream.cs
new file mode 100644
index 0000000..0e3f517
--- /dev/null
+++ b/Ivy/IvyPPC/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/IvyPPC/IvyUDPStreamV3.cs b/Ivy/IvyPPC/IvyUDPStreamV3.cs
new file mode 100644
index 0000000..63a8679
--- /dev/null
+++ b/Ivy/IvyPPC/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/IvyPPC/IvyUDPStreamV4.cs b/Ivy/IvyPPC/IvyUDPStreamV4.cs
new file mode 100644
index 0000000..b8d329a
--- /dev/null
+++ b/Ivy/IvyPPC/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/IvyPPC/IvyWatcher.cs b/Ivy/IvyPPC/IvyWatcher.cs
new file mode 100644
index 0000000..5a3afc8
--- /dev/null
+++ b/Ivy/IvyPPC/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;
+
+ /// <summary> IvyWatcher, A private Class for the Ivy rendezvous
+ /// </summary>
+ /// <remarks> 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.
+ /// </remarks>
+ internal class IvyWatcher
+ {
+ private Ivy bus; /* master bus controler */
+ private int port;
+ private volatile Thread listenThread;
+ private IPAddress group;
+ private IvyUDPStream stream;
+
+ /// <summary> creates an Ivy watcher
+ /// </summary>
+ /// <param name='bus'>the bus
+ /// </param>
+ /// <param name='domainaddr'>the domain
+ /// </param>
+ /// <param name='port'>the port number
+ /// </param>
+ 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);
+ }
+ }
+
+ /// <summary> the behaviour of each thread watching the UDP socket.
+ /// </summary>
+ 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");
+ }
+
+ /// <summary> stops the thread waiting on the broadcast socket
+ /// </summary>
+ 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/IvyPPC/Pcre.cs b/Ivy/IvyPPC/Pcre.cs
new file mode 100644
index 0000000..9286b65
--- /dev/null
+++ b/Ivy/IvyPPC/Pcre.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace IvyBus
+{
+ /// <summary>
+ /// Description résumée de Pcre.
+ /// </summary>
+ public class Pcre
+ {
+ [DllImport("pcre.dll")]
+ public static extern void *pcre_compile( string pattern, int options,
+ out string errptr, out int erroffset,
+ string tableptr);
+ [DllImport("pcre.dll")]
+ internal static extern void pcre_free(void *pcre);
+
+ [DllImport("pcre.dll")]
+ internal static extern int pcre_exec( void *code, string extra,
+ string subject, int length, int startoffset,
+ int options, out int[] ovector, int ovecsize);
+
+ [DllImport("pcre.dll")]
+ internal static extern int pcre_get_substring_list(string subject,
+ int *ovector, int stringcount, out string[] listptr);
+ [DllImport("pcre.dll")]
+ internal static extern void pcre_free_substring_list( ref string[] stringptr);
+
+ public Pcre()
+ {
+ //
+ // TODO : ajoutez ici la logique du constructeur
+ //
+ }
+ }
+}
diff --git a/Ivy/IvyPPC/Properties/AssemblyInfo.cs b/Ivy/IvyPPC/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..a3ce834
--- /dev/null
+++ b/Ivy/IvyPPC/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\<configuration>. 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/IvyPPC/Settings.cs b/Ivy/IvyPPC/Settings.cs
new file mode 100644
index 0000000..17744f8
--- /dev/null
+++ b/Ivy/IvyPPC/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/IvyPPC/app.config b/Ivy/IvyPPC/app.config
new file mode 100644
index 0000000..e5b53b3
--- /dev/null
+++ b/Ivy/IvyPPC/app.config
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<configuration>
+ <configSections>
+ <sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
+ <section name="IvyBus.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
+ </sectionGroup>
+ </configSections>
+ <applicationSettings>
+ <IvyBus.Properties.Settings>
+ <setting name="IvyProtocolVersion" serializeAs="String">
+ <value>3</value>
+ </setting>
+ <setting name="IvyPing" serializeAs="String">
+ <value>False</value>
+ </setting>
+ <setting name="IvyDebug" serializeAs="String">
+ <value>False</value>
+ </setting>
+ <setting name="IvyBus" serializeAs="String">
+ <value />
+ </setting>
+ <setting name="AppName" serializeAs="String">
+ <value />
+ </setting>
+ <setting name="ReadyMessage" serializeAs="String">
+ <value />
+ </setting>
+ </IvyBus.Properties.Settings>
+ </applicationSettings>
+</configuration> \ No newline at end of file
diff --git a/Ivy/IvyPerf/App.ico b/Ivy/IvyPerf/App.ico
new file mode 100644
index 0000000..3a5525f
--- /dev/null
+++ b/Ivy/IvyPerf/App.ico
Binary files differ
diff --git a/Ivy/IvyPerf/AssemblyInfo.cs b/Ivy/IvyPerf/AssemblyInfo.cs
new file mode 100644
index 0000000..65a2ee8
--- /dev/null
+++ b/Ivy/IvyPerf/AssemblyInfo.cs
@@ -0,0 +1,58 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+//
+// Les informations générales relatives à un assembly dépendent de
+// l'ensemble d'attributs suivant. Pour modifier les informations
+// associées à un assembly, changez les valeurs de ces attributs.
+//
+[assembly: AssemblyTitle("")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+//
+// Les informations de version pour un assembly se composent des quatre valeurs suivantes :
+//
+// Version principale
+// Version secondaire
+// Numéro de build
+// Révision
+//
+// Vous pouvez spécifier toutes les valeurs ou indiquer des numéros de révision et de build par défaut
+// en utilisant '*', comme ci-dessous :
+
+[assembly: AssemblyVersion("2.0.*")]
+
+//
+// Pour signer votre assembly, vous devez spécifier la clé à utiliser. Consultez
+// la documentation Microsoft .NET Framework pour plus d'informations sur la signature d'un assembly.
+//
+// Utilisez les attributs ci-dessous pour contrôler la clé utilisée lors de la signature.
+//
+// Remarques :
+// (*) Si aucune clé n'est spécifiée, l'assembly n'est pas signé.
+// (*) KeyName fait référence à une clé installée dans le fournisseur de
+// services cryptographiques (CSP) de votre ordinateur. KeyFile fait référence à un fichier qui contient
+// une clé.
+// (*) Si les valeurs de KeyFile et de KeyName sont spécifiées, le
+// traitement suivant se produit :
+// (1) Si KeyName se trouve dans le CSP, la clé est utilisée.
+// (2) Si KeyName n'existe pas mais que KeyFile existe, la clé
+// de KeyFile est installée dans le CSP et utilisée.
+// (*) Pour créer KeyFile, vous pouvez utiliser l'utilitaire sn.exe (Strong Name, Nom fort).
+// Lors de la spécification de KeyFile, son emplacement doit être
+// relatif au répertoire de sortie du projet qui est
+// %Project Directory%\obj\<configuration>. Par exemple, si votre KeyFile se trouve
+// dans le répertoire du projet, vous devez spécifier l'attribut
+// AssemblyKeyFile sous la forme [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
+// (*) DelaySign (signature différée) est une option avancée. Pour plus d'informations, consultez la
+// documentation Microsoft .NET Framework.
+//
+[assembly: AssemblyDelaySign(false)]
+[assembly: AssemblyKeyFile("")]
+[assembly: AssemblyKeyName("")]
diff --git a/Ivy/IvyPerf/IvyPerf.cs b/Ivy/IvyPerf/IvyPerf.cs
new file mode 100644
index 0000000..9d37883
--- /dev/null
+++ b/Ivy/IvyPerf/IvyPerf.cs
@@ -0,0 +1,74 @@
+using System;
+using IvyBus;
+using System.Threading;
+using System.Globalization;
+using System.Collections.Specialized;
+
+namespace IvyPerf
+{
+ /// <summary>
+ /// Description résumée de IvyPerf.
+ /// mesure des perfo de round trip entre deux applis
+ /// </summary>
+ class IvyPerf
+ {
+ static Ivy bus;
+ static double origin = 0;
+
+ static double currentTime() // en ms
+ {
+ double time;
+ time = (double)(DateTime.Now.Ticks) / (double)(TimeSpan.TicksPerMillisecond);
+ //time = Environment.TickCount;
+ return time;
+ }
+ [IvyBinding("^ping ts=(.*)")]
+ static void Reply(object sender, IvyMessageEventArgs args)
+ {
+ bus.SendMsg("pong ts={0} tr={1}", args[0], currentTime() - origin );
+ }
+ [IvyBinding("^pong ts=(.*) tr=(.*)")]
+ static void Pong(object sender, IvyMessageEventArgs args)
+ {
+ double current = currentTime() - origin;
+ double ts = double.Parse(args[0], bus.Culture );
+ double tr = double.Parse(args[1], bus.Culture );
+ double roundtrip1 = tr - ts;
+ double roundtrip2 = current - tr;
+ double roundtrip3 = current - ts;
+ Console.WriteLine("round trip {0} {1} {2}", roundtrip1, roundtrip2, roundtrip3);
+ }
+ /// <summary>
+ /// Point d'entrée principal de l'application.
+ /// </summary>
+ [STAThread]
+ static void Main(string[] args)
+ {
+ int timeout = 1000;
+ if (args.Length > 0)
+ timeout = int.Parse(args[0]);
+ bus = new Ivy("IvyPerf", "IvyPref ready");
+ bus.SentMessageFilter.Add("ping");
+ bus.SentMessageFilter.Add("pong");
+ bus.SentMessageFilter.Add("IvyPref");
+ bus.BindingFilter += new EventHandler<IvyEventArgs>(bus_BindingFilter);
+ //TODO how to autobind
+ //bus.BindAttibute(typeof(IvyPerf));
+ //TODO auto generation of testtarget ?? how to
+ //bus.BindMsg("test", new EventHandler<IvyMessageEventArgs>(testtarget));
+ bus.Start(null);
+ origin = currentTime();
+ while( true )
+ {
+ Thread.Sleep( timeout );
+ int count = bus.SendMsg("ping ts={0}", currentTime() - origin );
+ if ( count == 0 ) Console.Write( "." );
+ }
+ }
+
+ static void bus_BindingFilter(object sender, IvyEventArgs e)
+ {
+ Console.WriteLine( "The app {0} regexp {1} was Filtred.", e.Client.ApplicationName,e.Argument);
+ }
+ }
+}
diff --git a/Ivy/IvyPerf/IvyPerf.csproj b/Ivy/IvyPerf/IvyPerf.csproj
new file mode 100644
index 0000000..c3742e6
--- /dev/null
+++ b/Ivy/IvyPerf/IvyPerf.csproj
@@ -0,0 +1,140 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <ProjectType>Local</ProjectType>
+ <ProductVersion>8.0.50727</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{839C9A55-7EFD-4326-95C3-2960DF390FF2}</ProjectGuid>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ApplicationIcon>App.ico</ApplicationIcon>
+ <AssemblyKeyContainerName>
+ </AssemblyKeyContainerName>
+ <AssemblyName>IvyPerf</AssemblyName>
+ <AssemblyOriginatorKeyFile>
+ </AssemblyOriginatorKeyFile>
+ <DefaultClientScript>JScript</DefaultClientScript>
+ <DefaultHTMLPageLayout>Grid</DefaultHTMLPageLayout>
+ <DefaultTargetSchema>IE50</DefaultTargetSchema>
+ <DelaySign>false</DelaySign>
+ <OutputType>Exe</OutputType>
+ <RootNamespace>IvyPerf</RootNamespace>
+ <RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
+ <StartupObject>
+ </StartupObject>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <UpgradeBackupLocation>
+ </UpgradeBackupLocation>
+ <SccProjectName>SAK</SccProjectName>
+ <SccLocalPath>SAK</SccLocalPath>
+ <SccAuxPath>SAK</SccAuxPath>
+ <SccProvider>SAK</SccProvider>
+ <ManifestCertificateThumbprint>51C861139B0DCA6D2FAD5BDB1D5280AAE1E59696</ManifestCertificateThumbprint>
+ <ManifestKeyFile>IvyPerf_TemporaryKey.pfx</ManifestKeyFile>
+ <GenerateManifests>true</GenerateManifests>
+ <SignManifests>true</SignManifests>
+ <PublishUrl>\\samba\fcolin\public_html\ClickOnce\IvyPerf\</PublishUrl>
+ <Install>true</Install>
+ <InstallFrom>Web</InstallFrom>
+ <UpdateEnabled>true</UpdateEnabled>
+ <UpdateMode>Foreground</UpdateMode>
+ <UpdateInterval>7</UpdateInterval>
+ <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+ <UpdatePeriodically>false</UpdatePeriodically>
+ <UpdateRequired>false</UpdateRequired>
+ <MapFileExtensions>true</MapFileExtensions>
+ <InstallUrl>http://www.tls.cena.fr/~fcolin/ClickOnce/IvyPerf/</InstallUrl>
+ <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+ <IsWebBootstrapper>true</IsWebBootstrapper>
+ <BootstrapperEnabled>true</BootstrapperEnabled>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <OutputPath>bin\Debug\</OutputPath>
+ <AllowUnsafeBlocks>false</AllowUnsafeBlocks>
+ <BaseAddress>285212672</BaseAddress>
+ <CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
+ <ConfigurationOverrideFile>
+ </ConfigurationOverrideFile>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <DocumentationFile>
+ </DocumentationFile>
+ <DebugSymbols>true</DebugSymbols>
+ <FileAlignment>4096</FileAlignment>
+ <NoStdLib>false</NoStdLib>
+ <NoWarn>
+ </NoWarn>
+ <Optimize>false</Optimize>
+ <RegisterForComInterop>false</RegisterForComInterop>
+ <RemoveIntegerChecks>false</RemoveIntegerChecks>
+ <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
+ <WarningLevel>4</WarningLevel>
+ <DebugType>full</DebugType>
+ <ErrorReport>prompt</ErrorReport>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <OutputPath>bin\Release\</OutputPath>
+ <AllowUnsafeBlocks>false</AllowUnsafeBlocks>
+ <BaseAddress>285212672</BaseAddress>
+ <CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
+ <ConfigurationOverrideFile>
+ </ConfigurationOverrideFile>
+ <DefineConstants>TRACE</DefineConstants>
+ <DocumentationFile>
+ </DocumentationFile>
+ <DebugSymbols>false</DebugSymbols>
+ <FileAlignment>4096</FileAlignment>
+ <NoStdLib>false</NoStdLib>
+ <NoWarn>
+ </NoWarn>
+ <Optimize>true</Optimize>
+ <RegisterForComInterop>false</RegisterForComInterop>
+ <RemoveIntegerChecks>false</RemoveIntegerChecks>
+ <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
+ <WarningLevel>4</WarningLevel>
+ <DebugType>none</DebugType>
+ <ErrorReport>prompt</ErrorReport>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System">
+ <Name>System</Name>
+ </Reference>
+ <Reference Include="System.Data">
+ <Name>System.Data</Name>
+ </Reference>
+ <Reference Include="System.XML">
+ <Name>System.XML</Name>
+ </Reference>
+ </ItemGroup>
+ <ItemGroup>
+ <Content Include="App.ico" />
+ <Compile Include="AssemblyInfo.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="IvyPerf.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Ivy\Ivy.csproj">
+ <Project>{F2F03CF7-0087-4EDB-AD15-80C9E8DA2617}</Project>
+ <Name>Ivy</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="IvyPerf_TemporaryKey.pfx" />
+ </ItemGroup>
+ <ItemGroup>
+ <BootstrapperPackage Include="Microsoft.Net.Framework.2.0">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 2.0</ProductName>
+ <Install>true</Install>
+ </BootstrapperPackage>
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <PropertyGroup>
+ <PreBuildEvent>
+ </PreBuildEvent>
+ <PostBuildEvent>
+ </PostBuildEvent>
+ </PropertyGroup>
+</Project> \ No newline at end of file
diff --git a/Ivy/IvyPerf/IvyPerf.csproj.vspscc b/Ivy/IvyPerf/IvyPerf.csproj.vspscc
new file mode 100644
index 0000000..5ee9e23
--- /dev/null
+++ b/Ivy/IvyPerf/IvyPerf.csproj.vspscc
@@ -0,0 +1,10 @@
+""
+{
+"FILE_VERSION" = "9237"
+"ENLISTMENT_CHOICE" = "NEVER"
+"PROJECT_FILE_RELATIVE_PATH" = "relative:IvyPerf"
+"NUMBER_OF_EXCLUDED_FILES" = "0"
+"ORIGINAL_PROJECT_FILE_PATH" = ""
+"NUMBER_OF_NESTED_PROJECTS" = "0"
+"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
+}
diff --git a/Ivy/IvyPerf/IvyPerf_TemporaryKey.pfx b/Ivy/IvyPerf/IvyPerf_TemporaryKey.pfx
new file mode 100644
index 0000000..db02b60
--- /dev/null
+++ b/Ivy/IvyPerf/IvyPerf_TemporaryKey.pfx
Binary files differ
diff --git a/Ivy/IvyProbe/App.ico b/Ivy/IvyProbe/App.ico
new file mode 100644
index 0000000..3a5525f
--- /dev/null
+++ b/Ivy/IvyProbe/App.ico
Binary files differ
diff --git a/Ivy/IvyProbe/IvyProbe.Designer.cs b/Ivy/IvyProbe/IvyProbe.Designer.cs
new file mode 100644
index 0000000..be00720
--- /dev/null
+++ b/Ivy/IvyProbe/IvyProbe.Designer.cs
@@ -0,0 +1,212 @@
+namespace IvyProbe
+{
+ partial class IvyProbe
+ {
+ /// <summary>
+ /// Required designer variable.
+ /// </summary>
+ private System.ComponentModel.IContainer components = null;
+
+ /// <summary>
+ /// Clean up any resources being used.
+ /// </summary>
+ /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ /// <summary>
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ /// </summary>
+ private void InitializeComponent()
+ {
+ this.components = new System.ComponentModel.Container();
+ this.label1 = new System.Windows.Forms.Label();
+ this.label2 = new System.Windows.Forms.Label();
+ this.tbRegexp = new System.Windows.Forms.TextBox();
+ this.tbMsg = new System.Windows.Forms.TextBox();
+ this.ta = new System.Windows.Forms.TextBox();
+ this.btBind = new System.Windows.Forms.Button();
+ this.btSend = new System.Windows.Forms.Button();
+ this.btUnbind = new System.Windows.Forms.Button();
+ this.btBindSimple = new System.Windows.Forms.Button();
+ this.busDomain = new IvyBus.IvyDomain();
+ this.bus = new IvyBus.Ivy(this.components);
+ this.ivyApplicationBinding1 = new IvyBus.IvyApplicationBinding(this.components);
+ ((System.ComponentModel.ISupportInitialize)(this.bus)).BeginInit();
+ this.SuspendLayout();
+ //
+ // label1
+ //
+ this.label1.Location = new System.Drawing.Point(4, 31);
+ this.label1.Name = "label1";
+ this.label1.Size = new System.Drawing.Size(24, 16);
+ this.label1.TabIndex = 0;
+ this.label1.Text = "exp:";
+ //
+ // label2
+ //
+ this.label2.Location = new System.Drawing.Point(8, 244);
+ this.label2.Name = "label2";
+ this.label2.Size = new System.Drawing.Size(56, 16);
+ this.label2.TabIndex = 1;
+ this.label2.Text = "Msg:";
+ //
+ // tbRegexp
+ //
+ this.tbRegexp.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.tbRegexp.Location = new System.Drawing.Point(28, 27);
+ this.tbRegexp.Name = "tbRegexp";
+ this.tbRegexp.Size = new System.Drawing.Size(228, 20);
+ this.tbRegexp.TabIndex = 2;
+ this.tbRegexp.Text = "(.*)";
+ this.tbRegexp.TextChanged += new System.EventHandler(this.tbRegexp_TextChanged);
+ //
+ // tbMsg
+ //
+ this.tbMsg.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.tbMsg.Location = new System.Drawing.Point(72, 240);
+ this.tbMsg.Name = "tbMsg";
+ this.tbMsg.Size = new System.Drawing.Size(326, 20);
+ this.tbMsg.TabIndex = 3;
+ this.tbMsg.Text = "msg";
+ this.tbMsg.TextChanged += new System.EventHandler(this.tbMsg_TextChanged);
+ //
+ // ta
+ //
+ this.ta.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.ta.Location = new System.Drawing.Point(0, 50);
+ this.ta.Multiline = true;
+ this.ta.Name = "ta";
+ this.ta.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
+ this.ta.Size = new System.Drawing.Size(478, 184);
+ this.ta.TabIndex = 4;
+ //
+ // btBind
+ //
+ this.btBind.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.btBind.Location = new System.Drawing.Point(262, 27);
+ this.btBind.Name = "btBind";
+ this.btBind.Size = new System.Drawing.Size(73, 20);
+ this.btBind.TabIndex = 5;
+ this.btBind.Text = "bind regexp";
+ this.btBind.Click += new System.EventHandler(this.RegexpCB);
+ //
+ // btSend
+ //
+ this.btSend.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
+ this.btSend.Location = new System.Drawing.Point(406, 240);
+ this.btSend.Name = "btSend";
+ this.btSend.Size = new System.Drawing.Size(64, 24);
+ this.btSend.TabIndex = 6;
+ this.btSend.Text = "Send";
+ this.btSend.Click += new System.EventHandler(this.SendCB);
+ //
+ // btUnbind
+ //
+ this.btUnbind.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.btUnbind.Location = new System.Drawing.Point(426, 27);
+ this.btUnbind.Name = "btUnbind";
+ this.btUnbind.Size = new System.Drawing.Size(48, 20);
+ this.btUnbind.TabIndex = 7;
+ this.btUnbind.Text = "unbind";
+ this.btUnbind.Click += new System.EventHandler(this.btUnbind_Click);
+ //
+ // btBindSimple
+ //
+ this.btBindSimple.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.btBindSimple.Location = new System.Drawing.Point(341, 27);
+ this.btBindSimple.Name = "btBindSimple";
+ this.btBindSimple.Size = new System.Drawing.Size(77, 20);
+ this.btBindSimple.TabIndex = 8;
+ this.btBindSimple.Text = "bind simple";
+ this.btBindSimple.Click += new System.EventHandler(this.ExpressionCB);
+ //
+ // busDomain
+ //
+ this.busDomain.Domain = "10.192.36.255:2011";
+ this.busDomain.Location = new System.Drawing.Point(0, 0);
+ this.busDomain.Margin = new System.Windows.Forms.Padding(0);
+ this.busDomain.Name = "busDomain";
+ this.busDomain.Size = new System.Drawing.Size(256, 24);
+ this.busDomain.TabIndex = 0;
+ this.busDomain.DomainChanged += new System.EventHandler(this.busDomain_DomainChanged);
+ //
+ // bus
+ //
+ this.bus.AppName = "IvyProbeC#";
+ this.bus.AppPriority = ((ushort)(100));
+ this.bus.Bindings.Add(this.ivyApplicationBinding1);
+ this.bus.Culture = new System.Globalization.CultureInfo("en-US");
+ this.bus.ReadyMessage = "IvyProbeC# ready";
+ this.bus.BindingFilter += new System.EventHandler<IvyBus.IvyEventArgs>(this.bus_BindingFilter);
+ this.bus.ErrorMessage += new System.EventHandler<IvyBus.IvyEventArgs>(this.bus_ErrorMessage);
+ this.bus.DirectMessageReceived += new System.EventHandler<IvyBus.IvyEventArgs>(this.directMessage);
+ this.bus.BindingAdd += new System.EventHandler<IvyBus.IvyEventArgs>(this.bus_addBinding);
+ this.bus.ClientConnected += new System.EventHandler<IvyBus.IvyEventArgs>(this.connect);
+ this.bus.ClientDisconnected += new System.EventHandler<IvyBus.IvyEventArgs>(this.disconnect);
+ this.bus.BindingRemove += new System.EventHandler<IvyBus.IvyEventArgs>(this.bus_removeBinding);
+ this.bus.DieReceived += new System.EventHandler<IvyBus.IvyDieEventArgs>(this.die);
+ //
+ // ivyApplicationBinding1
+ //
+ this.ivyApplicationBinding1.Arguments.Add("Name");
+ this.ivyApplicationBinding1.Binding = IvyBus.BindingType.Regexp;
+ this.ivyApplicationBinding1.Expression = "^{0}(.*)";
+ this.ivyApplicationBinding1.Callback += new System.EventHandler<IvyBus.IvyMessageEventArgs>(this.ivyprobe);
+ //
+ // IvyProbe
+ //
+ this.AcceptButton = this.btSend;
+ this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
+ this.ClientSize = new System.Drawing.Size(478, 266);
+ this.Controls.Add(this.busDomain);
+ this.Controls.Add(this.btBindSimple);
+ this.Controls.Add(this.btUnbind);
+ this.Controls.Add(this.btSend);
+ this.Controls.Add(this.btBind);
+ this.Controls.Add(this.ta);
+ this.Controls.Add(this.tbMsg);
+ this.Controls.Add(this.tbRegexp);
+ this.Controls.Add(this.label2);
+ this.Controls.Add(this.label1);
+ this.DoubleBuffered = true;
+ this.Name = "IvyProbe";
+ this.Text = "IvyProbe";
+ this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.IvyProbe_FormClosed);
+ this.Load += new System.EventHandler(this.IvyProbe_Load);
+ ((System.ComponentModel.ISupportInitialize)(this.bus)).EndInit();
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.Label label1;
+ private System.Windows.Forms.Label label2;
+ private System.Windows.Forms.TextBox tbRegexp;
+ private System.Windows.Forms.TextBox tbMsg;
+ private System.Windows.Forms.Button btBind;
+ private System.Windows.Forms.Button btSend;
+ private System.Windows.Forms.TextBox ta;
+ private System.Windows.Forms.Button btBindSimple;
+ private System.Windows.Forms.Button btUnbind;
+ private IvyBus.IvyDomain busDomain;
+ private IvyBus.Ivy bus;
+ private IvyBus.IvyApplicationBinding ivyApplicationBinding1;
+ }
+}
+
diff --git a/Ivy/IvyProbe/IvyProbe.cs b/Ivy/IvyProbe/IvyProbe.cs
new file mode 100644
index 0000000..31c024a
--- /dev/null
+++ b/Ivy/IvyProbe/IvyProbe.cs
@@ -0,0 +1,166 @@
+namespace IvyProbe
+{
+ using System;
+ using System.Windows.Forms;
+ using IvyBus;
+ using System.IO;
+ using System.Runtime.Serialization;
+ using System.Runtime.Serialization.Formatters.Binary;
+ using System.Reflection;
+ using System.Net;
+
+ partial class IvyProbe : System.Windows.Forms.Form
+ {
+
+ public IvyProbe()
+ {
+ //
+ // Requis pour la prise en charge du Concepteur Windows Forms
+ //
+ InitializeComponent();
+ }
+
+ private void append(string s)
+ {
+ // je mettrais bien la date, aussi.
+ ta.AppendText(s + "\r\n");
+ }
+
+ private void connect(object sender, IvyEventArgs e)
+ {
+ append(e.Client.ApplicationName + " connected from " + Dns.GetHostEntry(e.Client.RemoteAddress).HostName);
+ }
+ private void disconnect(object sender, IvyEventArgs e)
+ {
+ append(e.Client.ApplicationName + " disconnected from " + Dns.GetHostEntry(e.Client.RemoteAddress).HostName);
+ }
+ private void die(object sender, IvyDieEventArgs e)
+ {
+ append("receive die from " + e.Client.ApplicationName + " cause: " + e.Argument);
+ }
+ private void directMessage(object sender, IvyEventArgs e)
+ {
+ append(e.Client.ApplicationName + " direct Message " + e.Id + e.Argument);
+ }
+ private void receive(object sender, IvyMessageEventArgs e)
+ {
+ string receive_str = "client " + e.Client.ApplicationName + " envoie: [";
+ receive_str += string.Join(",", e.Arguments);
+ receive_str += "]";
+ receive_str += " for '" + ((IvyApplicationBinding)sender).FormatedExpression + "'";
+ append(receive_str);
+ }
+ public void RegexpCB(System.Object event_sender, System.EventArgs e)
+ {
+ // ajoute la nouvelle regex
+ string regexp = tbRegexp.Text;
+ regexp.Trim();
+ int regexp_id = bus.BindMsg(regexp, receive);
+ tbRegexp.Text = "";
+ append( "bind("+regexp_id+") ->"+regexp);
+ }
+ public void ExpressionCB(System.Object event_sender, System.EventArgs e)
+ {
+ // ajoute la nouvelle regex
+ string expression = tbRegexp.Text;
+ expression.Trim();
+ int regexp_id = bus.BindSimpleMsg(expression, receive);
+ tbRegexp.Text = "";
+ append( "bind("+regexp_id+") ->"+expression);
+ }
+
+
+ public void SendCB(System.Object event_sender, System.EventArgs e)
+ {
+ int count;
+ System.String tosend = tbMsg.Text;
+ tbMsg.Text = "";
+ DateTime debut = DateTime.Now;
+ count = bus.SendMsg(tosend);
+ TimeSpan duree = DateTime.Now - debut;
+ append("Sending '" + tosend + "' count " + count + " in " + duree.TotalMilliseconds + " ms");
+ }
+
+ [STAThread]
+ public static void Main(System.String[] args)
+ {
+ Application.EnableVisualStyles();
+ Application.SetCompatibleTextRenderingDefault(false);
+ Application.Run(new IvyProbe());
+
+ }
+
+ private void tbMsg_TextChanged(object sender, System.EventArgs e)
+ {
+ btSend.Enabled = (tbMsg.Text != "");
+ }
+
+ private void tbRegexp_TextChanged(object sender, System.EventArgs e)
+ {
+ bool enable = (tbRegexp.Text != "");
+ btBind.Enabled = enable;
+ btBindSimple.Enabled = enable;
+ btUnbind.Enabled = enable;
+ }
+
+ private void btUnbind_Click(object sender, System.EventArgs e)
+ {
+ // enleve la regex
+ string regexp = tbRegexp.Text;
+ bool removed = bus.UnbindMsg( regexp );
+ if ( removed )
+ {
+ append( "unbind("+regexp+")");
+ tbRegexp.Text = "";
+ }
+ else
+ {
+ append( "unbind can't find binding ("+regexp+")");
+ }
+ }
+
+ private void bus_addBinding(object sender, IvyEventArgs e)
+ {
+ append(e.Client.ApplicationName + " add binding '" + e.Argument + "'");
+ }
+
+ private void bus_removeBinding(object sender, IvyEventArgs e)
+ {
+ append(e.Client.ApplicationName + " remove binding '" + e.Argument + "'");
+ }
+
+ private void bus_BindingFilter(object sender, IvyEventArgs e)
+ {
+ // should not appen in this application because no messages classes declared
+ append(e.Client.ApplicationName + " filter binding '" + e.Argument + "'");
+ }
+ private void bus_ErrorMessage(object sender, IvyEventArgs e)
+ {
+ append(e.Client.ApplicationName + " error message " + e.Id + " '" + e.Argument + "'");
+ }
+
+ private void busDomain_DomainChanged(object sender, EventArgs e)
+ {
+ bus.Stop();
+ bus.Start(busDomain.Domain);
+ }
+
+ private void IvyProbe_FormClosed(object sender, FormClosedEventArgs e)
+ {
+ bus.Stop();
+ }
+
+ private void IvyProbe_Load(object sender, EventArgs e)
+ {
+ bus.Start(busDomain.Domain);
+ }
+
+ private void ivyprobe(object sender, IvyMessageEventArgs e)
+ {
+ // just for testing of Desin Bindings
+ receive(sender, e);
+ }
+
+
+ }
+} \ No newline at end of file
diff --git a/Ivy/IvyProbe/IvyProbe.csproj b/Ivy/IvyProbe/IvyProbe.csproj
new file mode 100644
index 0000000..39a800b
--- /dev/null
+++ b/Ivy/IvyProbe/IvyProbe.csproj
@@ -0,0 +1,164 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <ProjectType>Local</ProjectType>
+ <ProductVersion>8.0.50727</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{5EFDDE31-9A31-43EB-8E56-6C29F7EAAD48}</ProjectGuid>
+ <SccProjectName>SAK</SccProjectName>
+ <SccLocalPath>SAK</SccLocalPath>
+ <SccAuxPath>SAK</SccAuxPath>
+ <SccProvider>SAK</SccProvider>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ApplicationIcon>App.ico</ApplicationIcon>
+ <AssemblyKeyContainerName>
+ </AssemblyKeyContainerName>
+ <AssemblyName>IvyProbe</AssemblyName>
+ <AssemblyOriginatorKeyFile>
+ </AssemblyOriginatorKeyFile>
+ <DefaultClientScript>JScript</DefaultClientScript>
+ <DefaultHTMLPageLayout>Grid</DefaultHTMLPageLayout>
+ <DefaultTargetSchema>IE50</DefaultTargetSchema>
+ <DelaySign>false</DelaySign>
+ <OutputType>WinExe</OutputType>
+ <RootNamespace>IvyProbe</RootNamespace>
+ <RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
+ <StartupObject>
+ </StartupObject>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <UpgradeBackupLocation>
+ </UpgradeBackupLocation>
+ <IsWebBootstrapper>true</IsWebBootstrapper>
+ <ManifestCertificateThumbprint>B0F2EC88A4EE5408BAC0B7041F239A7265AA2FAA</ManifestCertificateThumbprint>
+ <ManifestKeyFile>IvyProbe_TemporaryKey.pfx</ManifestKeyFile>
+ <GenerateManifests>true</GenerateManifests>
+ <SignManifests>true</SignManifests>
+ <PublishUrl>\\samba\fcolin\public_html\ClickOnce\IvyProbe\</PublishUrl>
+ <Install>true</Install>
+ <InstallFrom>Web</InstallFrom>
+ <UpdateEnabled>true</UpdateEnabled>
+ <UpdateMode>Foreground</UpdateMode>
+ <UpdateInterval>7</UpdateInterval>
+ <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+ <UpdatePeriodically>false</UpdatePeriodically>
+ <UpdateRequired>false</UpdateRequired>
+ <MapFileExtensions>true</MapFileExtensions>
+ <InstallUrl>http://www.tls.cena.fr/~fcolin/ClickOnce/IvyProbe/</InstallUrl>
+ <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+ <BootstrapperEnabled>true</BootstrapperEnabled>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <OutputPath>bin\Debug\</OutputPath>
+ <AllowUnsafeBlocks>false</AllowUnsafeBlocks>
+ <BaseAddress>285212672</BaseAddress>
+ <CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
+ <ConfigurationOverrideFile>
+ </ConfigurationOverrideFile>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <DocumentationFile>
+ </DocumentationFile>
+ <DebugSymbols>true</DebugSymbols>
+ <FileAlignment>4096</FileAlignment>
+ <NoStdLib>false</NoStdLib>
+ <NoWarn>
+ </NoWarn>
+ <Optimize>false</Optimize>
+ <RegisterForComInterop>false</RegisterForComInterop>
+ <RemoveIntegerChecks>false</RemoveIntegerChecks>
+ <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
+ <WarningLevel>4</WarningLevel>
+ <DebugType>full</DebugType>
+ <ErrorReport>prompt</ErrorReport>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <OutputPath>bin\Release\</OutputPath>
+ <AllowUnsafeBlocks>false</AllowUnsafeBlocks>
+ <BaseAddress>285212672</BaseAddress>
+ <CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
+ <ConfigurationOverrideFile>
+ </ConfigurationOverrideFile>
+ <DefineConstants>TRACE</DefineConstants>
+ <DocumentationFile>
+ </DocumentationFile>
+ <DebugSymbols>false</DebugSymbols>
+ <FileAlignment>4096</FileAlignment>
+ <NoStdLib>false</NoStdLib>
+ <NoWarn>
+ </NoWarn>
+ <Optimize>true</Optimize>
+ <RegisterForComInterop>false</RegisterForComInterop>
+ <RemoveIntegerChecks>false</RemoveIntegerChecks>
+ <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
+ <WarningLevel>4</WarningLevel>
+ <DebugType>none</DebugType>
+ <ErrorReport>prompt</ErrorReport>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System">
+ <Name>System</Name>
+ </Reference>
+ <Reference Include="System.Data">
+ <Name>System.Data</Name>
+ </Reference>
+ <Reference Include="System.Drawing">
+ <Name>System.Drawing</Name>
+ </Reference>
+ <Reference Include="System.Messaging" />
+ <Reference Include="System.Windows.Forms">
+ <Name>System.Windows.Forms</Name>
+ </Reference>
+ <Reference Include="System.Xml">
+ <Name>System.XML</Name>
+ </Reference>
+ </ItemGroup>
+ <ItemGroup>
+ <Content Include="App.ico" />
+ <Compile Include="IvyProbe.Designer.cs">
+ <DependentUpon>IvyProbe.cs</DependentUpon>
+ </Compile>
+ <Compile Include="Properties\AssemblyInfo.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="IvyProbe.cs">
+ <SubType>Form</SubType>
+ </Compile>
+ <Compile Include="Properties\Settings.Designer.cs">
+ <AutoGen>True</AutoGen>
+ <DesignTimeSharedInput>True</DesignTimeSharedInput>
+ <DependentUpon>Settings.settings</DependentUpon>
+ </Compile>
+ <EmbeddedResource Include="IvyProbe.resx">
+ <DependentUpon>IvyProbe.cs</DependentUpon>
+ <SubType>Designer</SubType>
+ </EmbeddedResource>
+ </ItemGroup>
+ <ItemGroup>
+ <BootstrapperPackage Include="Microsoft.Net.Framework.2.0">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 2.0</ProductName>
+ <Install>true</Install>
+ </BootstrapperPackage>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="app.config" />
+ <None Include="IvyProbe_TemporaryKey.pfx" />
+ <None Include="Properties\Settings.settings">
+ <Generator>SettingsSingleFileGenerator</Generator>
+ <LastGenOutput>Settings.Designer.cs</LastGenOutput>
+ </None>
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Ivy\Ivy.csproj">
+ <Project>{F2F03CF7-0087-4EDB-AD15-80C9E8DA2617}</Project>
+ <Name>Ivy</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <PropertyGroup>
+ <PreBuildEvent>
+ </PreBuildEvent>
+ <PostBuildEvent>
+ </PostBuildEvent>
+ </PropertyGroup>
+</Project> \ No newline at end of file
diff --git a/Ivy/IvyProbe/IvyProbe.csproj.vspscc b/Ivy/IvyProbe/IvyProbe.csproj.vspscc
new file mode 100644
index 0000000..b9b6fea
--- /dev/null
+++ b/Ivy/IvyProbe/IvyProbe.csproj.vspscc
@@ -0,0 +1,10 @@
+""
+{
+"FILE_VERSION" = "9237"
+"ENLISTMENT_CHOICE" = "NEVER"
+"PROJECT_FILE_RELATIVE_PATH" = "relative:IvyTest"
+"NUMBER_OF_EXCLUDED_FILES" = "0"
+"ORIGINAL_PROJECT_FILE_PATH" = ""
+"NUMBER_OF_NESTED_PROJECTS" = "0"
+"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
+}
diff --git a/Ivy/IvyProbe/IvyProbe.resx b/Ivy/IvyProbe/IvyProbe.resx
new file mode 100644
index 0000000..b3f4b38
--- /dev/null
+++ b/Ivy/IvyProbe/IvyProbe.resx
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+ <!--
+ Microsoft ResX Schema
+
+ Version 2.0
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
+ associated with the data types.
+
+ Example:
+
+ ... ado.net/XML headers & schema ...
+ <resheader name="resmimetype">text/microsoft-resx</resheader>
+ <resheader name="version">2.0</resheader>
+ <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+ <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+ <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+ <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+ <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+ <value>[base64 mime encoded serialized .NET Framework object]</value>
+ </data>
+ <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+ <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+ <comment>This is a comment</comment>
+ </data>
+
+ There are any number of "resheader" rows that contain simple
+ name/value pairs.
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
+ mimetype set.
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
+ extensible. For a given mimetype the value must be set accordingly:
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
+ read any of the formats listed below.
+
+ mimetype: application/x-microsoft.net.object.binary.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.soap.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.bytearray.base64
+ value : The object must be serialized into a byte array
+ : using a System.ComponentModel.TypeConverter
+ : and then encoded with base64 encoding.
+ -->
+ <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+ <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+ <xsd:element name="root" msdata:IsDataSet="true">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded">
+ <xsd:element name="metadata">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="name" use="required" type="xsd:string" />
+ <xsd:attribute name="type" type="xsd:string" />
+ <xsd:attribute name="mimetype" type="xsd:string" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="assembly">
+ <xsd:complexType>
+ <xsd:attribute name="alias" type="xsd:string" />
+ <xsd:attribute name="name" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="data">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+ <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+ <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="resheader">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ <resheader name="resmimetype">
+ <value>text/microsoft-resx</value>
+ </resheader>
+ <resheader name="version">
+ <value>2.0</value>
+ </resheader>
+ <resheader name="reader">
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <resheader name="writer">
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <metadata name="bus.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+ <value>217, 17</value>
+ </metadata>
+</root> \ No newline at end of file
diff --git a/Ivy/IvyProbe/IvyProbe_TemporaryKey.pfx b/Ivy/IvyProbe/IvyProbe_TemporaryKey.pfx
new file mode 100644
index 0000000..0a205ff
--- /dev/null
+++ b/Ivy/IvyProbe/IvyProbe_TemporaryKey.pfx
Binary files differ
diff --git a/Ivy/IvyProbe/Properties/AssemblyInfo.cs b/Ivy/IvyProbe/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..839f52a
--- /dev/null
+++ b/Ivy/IvyProbe/Properties/AssemblyInfo.cs
@@ -0,0 +1,58 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+//
+// Les informations générales relatives à un assembly dépendent de
+// l'ensemble d'attributs suivant. Pour modifier les informations
+// associées à un assembly, changez les valeurs de ces attributs.
+//
+[assembly: AssemblyTitle("IvyProbe")]
+[assembly: AssemblyDescription("Ivy Debug Tool")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("DTI/SDER")]
+[assembly: AssemblyProduct("Ivy")]
+[assembly: AssemblyCopyright("")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+//
+// Les informations de version pour un assembly se composent des quatre valeurs suivantes :
+//
+// Version principale
+// Version secondaire
+// Numéro de build
+// Révision
+//
+// Vous pouvez spécifier toutes les valeurs ou indiquer des numéros de révision et de build par défaut
+// en utilisant '*', comme ci-dessous :
+
+[assembly: AssemblyVersion("2.0.*")]
+
+//
+// Pour signer votre assembly, vous devez spécifier la clé à utiliser. Consultez
+// la documentation Microsoft .NET Framework pour plus d'informations sur la signature d'un assembly.
+//
+// Utilisez les attributs ci-dessous pour contrôler la clé utilisée lors de la signature.
+//
+// Remarques :
+// (*) Si aucune clé n'est spécifiée, l'assembly n'est pas signé.
+// (*) KeyName fait référence à une clé installée dans le fournisseur de
+// services cryptographiques (CSP) de votre ordinateur. KeyFile fait référence à un fichier qui contient
+// une clé.
+// (*) Si les valeurs de KeyFile et de KeyName sont spécifiées, le
+// traitement suivant se produit :
+// (1) Si KeyName se trouve dans le CSP, la clé est utilisée.
+// (2) Si KeyName n'existe pas mais que KeyFile existe, la clé
+// de KeyFile est installée dans le CSP et utilisée.
+// (*) Pour créer KeyFile, vous pouvez utiliser l'utilitaire sn.exe (Strong Name, Nom fort).
+// Lors de la spécification de KeyFile, son emplacement doit être
+// relatif au répertoire de sortie du projet qui est
+// %Project Directory%\obj\<configuration>. Par exemple, si votre KeyFile se trouve
+// dans le répertoire du projet, vous devez spécifier l'attribut
+// AssemblyKeyFile sous la forme [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
+// (*) DelaySign (signature différée) est une option avancée. Pour plus d'informations, consultez la
+// documentation Microsoft .NET Framework.
+//
+[assembly: AssemblyDelaySign(false)]
+[assembly: AssemblyKeyFile("")]
+[assembly: AssemblyKeyName("")]
diff --git a/Ivy/IvyProbe/Properties/Settings.Designer.cs b/Ivy/IvyProbe/Properties/Settings.Designer.cs
new file mode 100644
index 0000000..f2b2c1a
--- /dev/null
+++ b/Ivy/IvyProbe/Properties/Settings.Designer.cs
@@ -0,0 +1,35 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+// 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.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace IvyProbe.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("")]
+ public string IvyBus {
+ get {
+ return ((string)(this["IvyBus"]));
+ }
+ }
+ }
+}
diff --git a/Ivy/IvyProbe/Properties/Settings.settings b/Ivy/IvyProbe/Properties/Settings.settings
new file mode 100644
index 0000000..421d8f2
--- /dev/null
+++ b/Ivy/IvyProbe/Properties/Settings.settings
@@ -0,0 +1,9 @@
+<?xml version='1.0' encoding='utf-8'?>
+<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="IvyProbe.Properties" GeneratedClassName="Settings">
+ <Profiles />
+ <Settings>
+ <Setting Name="IvyBus" Type="System.String" Scope="Application">
+ <Value Profile="(Default)" />
+ </Setting>
+ </Settings>
+</SettingsFile> \ No newline at end of file
diff --git a/Ivy/IvyProbe/app.config b/Ivy/IvyProbe/app.config
new file mode 100644
index 0000000..e9c8b0c
--- /dev/null
+++ b/Ivy/IvyProbe/app.config
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<configuration>
+ <configSections>
+ <sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
+ <section name="IvyProbe.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
+ </sectionGroup>
+ </configSections>
+ <applicationSettings>
+ <IvyProbe.Properties.Settings>
+ <setting name="IvyBus" serializeAs="String">
+ <value />
+ </setting>
+ </IvyProbe.Properties.Settings>
+ </applicationSettings>
+</configuration> \ No newline at end of file
diff --git a/Ivy/IvyProbeConsole/App.ico b/Ivy/IvyProbeConsole/App.ico
new file mode 100644
index 0000000..3a5525f
--- /dev/null
+++ b/Ivy/IvyProbeConsole/App.ico
Binary files differ
diff --git a/Ivy/IvyProbeConsole/IvyProbeConsole.cs b/Ivy/IvyProbeConsole/IvyProbeConsole.cs
new file mode 100644
index 0000000..516d702
--- /dev/null
+++ b/Ivy/IvyProbeConsole/IvyProbeConsole.cs
@@ -0,0 +1,373 @@
+/// François-Régis Colin
+/// http://www.tls.cena.fr/products/ivy/
+/// *
+/// (C) CENA
+/// *
+namespace IvyProbeConsole
+{
+ using System;
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.Threading;
+ using System.Text.RegularExpressions;
+ using System.IO;
+ using System.Configuration;
+ using System.Diagnostics;
+ using IvyBus;
+ using Gnu;
+
+ /// <summary> Console implementation of the ivyprobe test program.
+ /// </summary>
+ /// <remarks>Mainly used for testing and debugging purpose</remarks>
+ public class IvyProbeConsole
+ {
+ public virtual bool ExitOnDie
+ {
+ set
+ {
+ exitOnDie = value;
+ }
+
+ }
+ public void BindFromFile(string name)
+ {
+ string line;
+ try
+ {
+ FileStream file = new FileStream(name, FileMode.Open, FileAccess.Read);
+ TextReader reader = new StreamReader(file);
+ while ((line = reader.ReadLine()) != null)
+ {
+ bus.BindMsg(line, receive);
+ }
+ }
+ catch (FileNotFoundException e)
+ {
+ Console.WriteLine(e.Message);
+ }
+ }
+ public const string helpCommands =
+ "Available commands:\n"+
+ ".die CLIENTNAME sends a die message\n" +
+ ".direct CLIENTNAME ID MESSAGE sends the direct message to the client, with a message id set to the numerical ID\n" +
+ ".bye quits the application\n" +
+ ".quit idem\n" +
+ ".list lists the available clients\n" +
+ ".ping sends a ping request if IVY_PING is enabled\n" +
+ ".bind REGEXP binds to a regexp at runtime\n" +
+ ".unbind REGEXP unbinds to a regexp at runtime";
+
+ public const String helpmsg =
+ "usage: IvyProbe [options] [regexp]\n" +
+ "\t-b BUS\tspecifies the Ivy bus domain\n" +
+ "\t-n ivyname (default JPROBE)\n" +
+ "\t-q\tquiet, no tty output\n" +
+ "\t-d\tdebug\n" +
+ "\t-t\ttime stamp each message\n" +
+ "\t-h\thelp\n\n" +
+ "\t regexp is a Perl5 compatible regular expression";
+
+ private TextReader in_Renamed;
+ private volatile Thread looperThread;
+ private Ivy bus;
+ private bool timestamp, quiet, debug, exitOnDie = false;
+ enum Command {
+ direct,
+ die,
+ unbind,
+ bind,
+ ping,
+ quit,
+ bye,
+ list,
+ help};
+ const string reg_parse =
+ @"^\.(?<cmd>direct) (?<target>[^ ]*) (?<id>[0-9]+) (?<message>.*)$|" +
+ @"^\.(?<cmd>die) (?<target>.*)$|" +
+ @"^\.(?<cmd>unbind) (?<target>.*)$|" +
+ @"^\.(?<cmd>bind) (?<target>.*)$|" +
+ @"^\.(?<cmd>ping) (?<target>.*)$|" +
+ @"^\.(?<cmd>quit)$|" +
+ @"^\.(?<cmd>bye)$|" +
+ @"^\.(?<cmd>list)$|" +
+ @"^\.(?<cmd>help)$|";
+ private Regex cmd_regexp;
+
+ [STAThread]
+ public static void Main(String[] args)
+ {
+ string name = "C#PROBE";
+ string fname = null;
+ bool quiet = false;
+ bool timestamp = false;
+ string domain = Ivy.GetDomain(null);
+ bool debug = false;
+
+ domain = Properties.Settings.Default.domain;
+ name = Properties.Settings.Default.name;
+ quiet = Properties.Settings.Default.quiet;
+ timestamp = Properties.Settings.Default.timestamp;
+ debug = Properties.Settings.Default.IvyDebug;
+
+
+ GetOpt opt = new GetOpt(args, "f:n:b:dqht");
+ Arg a;
+ while ((a = opt.NextArg()) != null)
+ {
+ switch (a.Flag)
+ {
+ case 'd':
+ debug = true;
+ break;
+
+ case 'b':
+ domain = a.Parameter;
+ break;
+
+ case 'n':
+ name = a.Parameter;
+ break;
+ case 'f':
+ fname = a.Parameter;
+ break;
+
+ case 'q':
+ quiet = true;
+ break;
+
+ case 't':
+ timestamp = true;
+ break;
+
+ case 'h': default:
+ System.Console.Out.WriteLine(helpmsg);
+ System.Environment.Exit(0);
+ break;
+
+ }
+ }
+
+
+ IvyProbeConsole p = new IvyProbeConsole(System.Console.In, timestamp, quiet, debug );
+ p.ExitOnDie = true;
+ Ivy bus = new Ivy(name, name + " ready");
+ p.start(bus);
+
+ if (fname != null)
+ p.BindFromFile(fname);
+
+ foreach(string ex in opt.Extras)
+ {
+ if (!quiet)
+ System.Console.Out.WriteLine("you want to subscribe to " + ex);
+ bus.BindMsg(ex, p.receive);
+ }
+
+ if (!quiet)
+ System.Console.Out.WriteLine(Ivy.Domains(domain));
+
+ bus.Start(domain);
+
+ }
+
+
+
+
+ public IvyProbeConsole(TextReader in_Renamed, bool timestamp, bool quiet, bool debug)
+ {
+ this.in_Renamed = in_Renamed;
+ this.timestamp = timestamp;
+ this.quiet = quiet;
+ this.debug = debug;
+ try
+ {
+ cmd_regexp = new Regex(reg_parse, RegexOptions.IgnoreCase);
+ }
+ catch (ArgumentException ree)
+ {
+ System.Console.Error.WriteLine("Regexp fatal error in the Probe program.");
+ System.Console.Error.WriteLine(ree.StackTrace);
+ System.Environment.Exit(0);
+ }
+ }
+
+ public virtual void start(Ivy bus)
+ {
+ if (looperThread != null)
+ throw new IvyException("Probe already started");
+ this.bus = bus;
+
+ bus.ClientConnected += connect;
+ bus.ClientDisconnected += disconnect;
+ bus.DieReceived += die ;
+ bus.DirectMessageReceived += directMessage;
+ bus.BindingAdd += new EventHandler<IvyEventArgs>(bus_BindingAdd);
+ bus.BindingRemove += new EventHandler<IvyEventArgs>(bus_BindingRemove);
+ bus.BindingFilter += new EventHandler<IvyEventArgs>(bus_BindingFilter);
+
+ looperThread = new Thread(new ThreadStart(Run));
+ looperThread.Name = "Keyboard Input Thread";
+ looperThread.Start();
+ }
+
+ void bus_BindingFilter(object sender, IvyEventArgs e)
+ {
+ println("filtred regexp {0} from {1}", e.Argument, e.Client.ApplicationName);
+ }
+
+ void bus_BindingRemove(object sender, IvyEventArgs e)
+ {
+ println("Removed regexp {0} from {1}", e.Argument, e.Client.ApplicationName);
+ }
+
+ void bus_BindingAdd(object sender, IvyEventArgs e)
+ {
+ println("Added regexp {0} from {1}", e.Argument, e.Client.ApplicationName);
+ }
+
+
+ public void Run()
+ {
+ traceDebug("Thread started");
+ Thread thisThread = Thread.CurrentThread;
+ String s;
+ // "infinite" loop on keyboard input
+ while (looperThread == thisThread)
+ {
+ s = in_Renamed.ReadLine();
+ if (s == null)
+ break;
+ if (s.Length == 0) continue;
+ if ( s.StartsWith( ".") )
+ parseCommand(s);
+ else
+ {
+ println("-> Sent to " + bus.SendMsg(s) + " peers");
+ }
+ }
+ println("End of input. Good bye !");
+ bus.Stop();
+ traceDebug("Probe Thread stopped");
+ }
+
+ internal void parseCommand(string s)
+ {
+ Match result;
+ traceDebug("parsing the [" + s + "] (length " + s.Length + ") string");
+
+ result = cmd_regexp.Match(s);
+
+
+ if (result.Success)
+ {
+ string cmd = result.Groups["cmd"].Value;
+ string target;
+ try
+ {
+ Command TheCommand = (Command)Enum.Parse(typeof(Command), cmd);
+
+ switch ( TheCommand )
+ {
+ case Command.direct:
+ {
+ target = result.Groups["target"].Value;
+ ushort id = ushort.Parse(result.Groups["id"].Value);
+ string message = result.Groups["message"].Value;
+ List<IvyClient> v = bus.GetClientsByName(target);
+ if (v.Count == 0)
+ println("no Ivy client with the name \"" + target + "\"");
+ for (int i = 0; i < v.Count; i++)
+ v[i].SendDirectMsg(id, message);
+ }
+ break;
+ case Command.die:
+ target = result.Groups["target"].Value;
+ if (bus.Die(target, ".die command") == 0)
+ println("no Ivy client with the name \"" + target + "\"");
+ break;
+ case Command.unbind:
+ target = result.Groups["target"].Value;
+ if (bus.UnbindMsg(target))
+ println("you want to unsubscribe to " + target);
+ else
+ println("you can't unsubscribe to " + target + ", your're not subscribed to it");
+ break;
+ case Command.bind:
+ target = result.Groups["target"].Value;
+ println("you want to subscribe to " + target);
+ bus.BindMsg(target, receive);
+ break;
+ case Command.ping:
+ target = result.Groups["target"].Value;
+ if (bus.Ping(target, "test") == 0)
+ println("no Ivy client with the name \"" + target + "\"");
+ break;
+ case Command.quit:
+ case Command.bye:
+ bus.Stop();
+ System.Environment.Exit(0);
+ break;
+ case Command.list:
+ println(bus.IvyClients.Count + " clients on the bus");
+ foreach (IvyClient client in bus.IvyClients )
+ println("-> " + client.ApplicationName);
+ break;
+ case Command.help:
+ println(helpCommands);
+ break;
+ }
+ }
+ catch (ArgumentException)
+ {
+ Console.WriteLine("manque de la commande dans l'enum");
+ }
+ }
+
+ }
+ // parseCommand
+
+ private void connect(object sender, IvyEventArgs e)
+ {
+ println(e.Client.ApplicationName + " connected from "+e.Client.RemoteAddress+":"+e.Client.RemotePort);
+ }
+
+ private void disconnect(object sender, IvyEventArgs e)
+ {
+ println(e.Client.ApplicationName + " disconnected ");
+ }
+
+ private void die(object sender, IvyDieEventArgs e)
+ {
+ println("received die msg from " + e.Client.ApplicationName + " good bye cause: "+e.Argument);
+ /* I cannot stop the readLine(), because it is native code */
+ if (exitOnDie)
+ System.Environment.Exit(0);
+ }
+
+ private void directMessage(object sender, IvyEventArgs e)
+ {
+ println(e.Client.ApplicationName + " direct Message " + e.Id + e.Argument);
+ }
+
+ private void receive(object sender, IvyMessageEventArgs e)
+ {
+ String s = e.Client.ApplicationName + " sent ";
+ s += string.Join(",", e.Arguments);
+ println(s);
+ }
+ [Conditional("DEBUG")]
+ private void traceDebug(String s)
+ {
+ Trace.WriteLineIf(debug, "-->Probe<-- " + s);
+ }
+ private void println(string format, params object[] args)
+ {
+ if (!quiet)
+ {
+ if (timestamp) System.Console.Out.Write(string.Format("[ {0|HH:mm:ss.fff} ]",System.DateTime.Now ));
+ System.Console.Out.WriteLine(string.Format(format,args));
+ }
+ }
+
+ }
+} \ No newline at end of file
diff --git a/Ivy/IvyProbeConsole/IvyProbeConsole.csproj b/Ivy/IvyProbeConsole/IvyProbeConsole.csproj
new file mode 100644
index 0000000..4551387
--- /dev/null
+++ b/Ivy/IvyProbeConsole/IvyProbeConsole.csproj
@@ -0,0 +1,158 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <ProjectType>Local</ProjectType>
+ <ProductVersion>8.0.50727</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{19023DE7-AAD8-4EC4-8FAF-D793868F8861}</ProjectGuid>
+ <SccProjectName>SAK</SccProjectName>
+ <SccLocalPath>SAK</SccLocalPath>
+ <SccAuxPath>SAK</SccAuxPath>
+ <SccProvider>SAK</SccProvider>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ApplicationIcon>App.ico</ApplicationIcon>
+ <AssemblyKeyContainerName>
+ </AssemblyKeyContainerName>
+ <AssemblyName>IvyProbeConsole</AssemblyName>
+ <AssemblyOriginatorKeyFile>
+ </AssemblyOriginatorKeyFile>
+ <DefaultClientScript>JScript</DefaultClientScript>
+ <DefaultHTMLPageLayout>Grid</DefaultHTMLPageLayout>
+ <DefaultTargetSchema>IE50</DefaultTargetSchema>
+ <DelaySign>false</DelaySign>
+ <OutputType>Exe</OutputType>
+ <RootNamespace>IvyProbeConsole</RootNamespace>
+ <RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
+ <StartupObject>
+ </StartupObject>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <UpgradeBackupLocation>
+ </UpgradeBackupLocation>
+ <IsWebBootstrapper>true</IsWebBootstrapper>
+ <ManifestCertificateThumbprint>85867DC3A6B10DFCF74BB49E782A1BC517B0086D</ManifestCertificateThumbprint>
+ <ManifestKeyFile>IvyProbe_TemporaryKey.pfx</ManifestKeyFile>
+ <GenerateManifests>true</GenerateManifests>
+ <SignManifests>true</SignManifests>
+ <TargetZone>LocalIntranet</TargetZone>
+ <PublishUrl>\\samba\fcolin\public_html\ClickOnce\IvyProbeConsole\</PublishUrl>
+ <Install>true</Install>
+ <InstallFrom>Web</InstallFrom>
+ <UpdateEnabled>false</UpdateEnabled>
+ <UpdateMode>Foreground</UpdateMode>
+ <UpdateInterval>7</UpdateInterval>
+ <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+ <UpdatePeriodically>false</UpdatePeriodically>
+ <UpdateRequired>false</UpdateRequired>
+ <MapFileExtensions>true</MapFileExtensions>
+ <InstallUrl>http://www.tls.cena.fr/~fcolin/ClickOnce/IvyProbeConsole/</InstallUrl>
+ <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+ <BootstrapperEnabled>true</BootstrapperEnabled>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <OutputPath>bin\Debug\</OutputPath>
+ <AllowUnsafeBlocks>false</AllowUnsafeBlocks>
+ <BaseAddress>285212672</BaseAddress>
+ <CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
+ <ConfigurationOverrideFile>
+ </ConfigurationOverrideFile>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <DocumentationFile>
+ </DocumentationFile>
+ <DebugSymbols>true</DebugSymbols>
+ <FileAlignment>4096</FileAlignment>
+ <NoStdLib>false</NoStdLib>
+ <NoWarn>
+ </NoWarn>
+ <Optimize>false</Optimize>
+ <RegisterForComInterop>false</RegisterForComInterop>
+ <RemoveIntegerChecks>false</RemoveIntegerChecks>
+ <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
+ <WarningLevel>4</WarningLevel>
+ <DebugType>full</DebugType>
+ <ErrorReport>prompt</ErrorReport>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <OutputPath>bin\Release\</OutputPath>
+ <AllowUnsafeBlocks>false</AllowUnsafeBlocks>
+ <BaseAddress>285212672</BaseAddress>
+ <CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
+ <ConfigurationOverrideFile>
+ </ConfigurationOverrideFile>
+ <DefineConstants>TRACE</DefineConstants>
+ <DocumentationFile>
+ </DocumentationFile>
+ <DebugSymbols>false</DebugSymbols>
+ <FileAlignment>4096</FileAlignment>
+ <NoStdLib>false</NoStdLib>
+ <NoWarn>
+ </NoWarn>
+ <Optimize>true</Optimize>
+ <RegisterForComInterop>false</RegisterForComInterop>
+ <RemoveIntegerChecks>false</RemoveIntegerChecks>
+ <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
+ <WarningLevel>4</WarningLevel>
+ <DebugType>none</DebugType>
+ <ErrorReport>prompt</ErrorReport>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System">
+ <Name>System</Name>
+ </Reference>
+ <Reference Include="System.configuration" />
+ <Reference Include="System.Data">
+ <Name>System.Data</Name>
+ </Reference>
+ <Reference Include="System.Xml">
+ <Name>System.XML</Name>
+ </Reference>
+ </ItemGroup>
+ <ItemGroup>
+ <Content Include="App.ico" />
+ <Compile Include="Properties\AssemblyInfo.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="IvyProbeConsole.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="Properties\Settings.Designer.cs">
+ <AutoGen>True</AutoGen>
+ <DesignTimeSharedInput>True</DesignTimeSharedInput>
+ <DependentUpon>Settings.settings</DependentUpon>
+ </Compile>
+ <Compile Include="Settings.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <BootstrapperPackage Include="Microsoft.Net.Framework.2.0">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 2.0</ProductName>
+ <Install>true</Install>
+ </BootstrapperPackage>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="app.config" />
+ <None Include="IvyProbe_TemporaryKey.pfx" />
+ <BaseApplicationManifest Include="Properties\app.manifest" />
+ <None Include="Properties\Settings.settings">
+ <Generator>SettingsSingleFileGenerator</Generator>
+ <LastGenOutput>Settings.Designer.cs</LastGenOutput>
+ </None>
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\getopt\getopt.csproj">
+ <Project>{228B5F0B-31AE-488F-A916-B7CBB269D25F}</Project>
+ <Name>getopt</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Ivy\Ivy.csproj">
+ <Project>{F2F03CF7-0087-4EDB-AD15-80C9E8DA2617}</Project>
+ <Name>Ivy</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <PropertyGroup>
+ <PreBuildEvent>
+ </PreBuildEvent>
+ <PostBuildEvent>
+ </PostBuildEvent>
+ </PropertyGroup>
+</Project> \ No newline at end of file
diff --git a/Ivy/IvyProbeConsole/IvyProbeConsole.csproj.vspscc b/Ivy/IvyProbeConsole/IvyProbeConsole.csproj.vspscc
new file mode 100644
index 0000000..62ab500
--- /dev/null
+++ b/Ivy/IvyProbeConsole/IvyProbeConsole.csproj.vspscc
@@ -0,0 +1,10 @@
+""
+{
+"FILE_VERSION" = "9237"
+"ENLISTMENT_CHOICE" = "NEVER"
+"PROJECT_FILE_RELATIVE_PATH" = "relative:IvyProbe"
+"NUMBER_OF_EXCLUDED_FILES" = "0"
+"ORIGINAL_PROJECT_FILE_PATH" = ""
+"NUMBER_OF_NESTED_PROJECTS" = "0"
+"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
+}
diff --git a/Ivy/IvyProbeConsole/IvyProbe_TemporaryKey.pfx b/Ivy/IvyProbeConsole/IvyProbe_TemporaryKey.pfx
new file mode 100644
index 0000000..0aaa160
--- /dev/null
+++ b/Ivy/IvyProbeConsole/IvyProbe_TemporaryKey.pfx
Binary files differ
diff --git a/Ivy/IvyProbeConsole/Properties/AssemblyInfo.cs b/Ivy/IvyProbeConsole/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..2661a2b
--- /dev/null
+++ b/Ivy/IvyProbeConsole/Properties/AssemblyInfo.cs
@@ -0,0 +1,59 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+//
+// Les informations générales relatives à un assembly dépendent de
+// l'ensemble d'attributs suivant. Pour modifier les informations
+// associées à un assembly, changez les valeurs de ces attributs.
+//
+[assembly: AssemblyTitle("IvyProbeConsole")]
+[assembly: AssemblyDescription("IvyProbe Console mode")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("DTI/SDER")]
+[assembly: AssemblyProduct("Ivy")]
+[assembly: AssemblyCopyright("DTI/SDER 205")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+//
+// Les informations de version pour un assembly se composent des quatre valeurs suivantes :
+//
+// Version principale
+// Version secondaire
+// Numéro de build
+// Révision
+//
+// Vous pouvez spécifier toutes les valeurs ou indiquer des numéros de révision et de build par défaut
+// en utilisant '*', comme ci-dessous :
+
+[assembly: AssemblyVersion("2.0.*")]
+
+//
+// Pour signer votre assembly, vous devez spécifier la clé à utiliser. Consultez
+// la documentation Microsoft .NET Framework pour plus d'informations sur la signature d'un assembly.
+//
+// Utilisez les attributs ci-dessous pour contrôler la clé utilisée lors de la signature.
+//
+// Remarques :
+// (*) Si aucune clé n'est spécifiée, l'assembly n'est pas signé.
+// (*) KeyName fait référence à une clé installée dans le fournisseur de
+// services cryptographiques (CSP) de votre ordinateur. KeyFile fait référence à un fichier qui contient
+// une clé.
+// (*) Si les valeurs de KeyFile et de KeyName sont spécifiées, le
+// traitement suivant se produit :
+// (1) Si KeyName se trouve dans le CSP, la clé est utilisée.
+// (2) Si KeyName n'existe pas mais que KeyFile existe, la clé
+// de KeyFile est installée dans le CSP et utilisée.
+// (*) Pour créer KeyFile, vous pouvez utiliser l'utilitaire sn.exe (Strong Name, Nom fort).
+// Lors de la spécification de KeyFile, son emplacement doit être
+// relatif au répertoire de sortie du projet qui est
+// %Project Directory%\obj\<configuration>. Par exemple, si votre KeyFile se trouve
+// dans le répertoire du projet, vous devez spécifier l'attribut
+// AssemblyKeyFile sous la forme [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
+// (*) DelaySign (signature différée) est une option avancée. Pour plus d'informations, consultez la
+// documentation Microsoft .NET Framework.
+//
+[assembly: AssemblyDelaySign(false)]
+[assembly: AssemblyKeyFile("")]
+[assembly: AssemblyKeyName("")]
+[assembly: AssemblyFileVersionAttribute("1.0.0.0")]
diff --git a/Ivy/IvyProbeConsole/Properties/Settings.Designer.cs b/Ivy/IvyProbeConsole/Properties/Settings.Designer.cs
new file mode 100644
index 0000000..4d05e34
--- /dev/null
+++ b/Ivy/IvyProbeConsole/Properties/Settings.Designer.cs
@@ -0,0 +1,71 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+// 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.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace IvyProbeConsole.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("")]
+ public string domain {
+ get {
+ return ((string)(this["domain"]));
+ }
+ }
+
+ [global::System.Configuration.ApplicationScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("C#ProbeConsole")]
+ public string name {
+ get {
+ return ((string)(this["name"]));
+ }
+ }
+
+ [global::System.Configuration.ApplicationScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("False")]
+ public bool quiet {
+ get {
+ return ((bool)(this["quiet"]));
+ }
+ }
+
+ [global::System.Configuration.ApplicationScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("False")]
+ public bool timestamp {
+ get {
+ return ((bool)(this["timestamp"]));
+ }
+ }
+
+ [global::System.Configuration.ApplicationScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("False")]
+ public bool IvyDebug {
+ get {
+ return ((bool)(this["IvyDebug"]));
+ }
+ }
+ }
+}
diff --git a/Ivy/IvyProbeConsole/Properties/Settings.settings b/Ivy/IvyProbeConsole/Properties/Settings.settings
new file mode 100644
index 0000000..b0c75fd
--- /dev/null
+++ b/Ivy/IvyProbeConsole/Properties/Settings.settings
@@ -0,0 +1,21 @@
+<?xml version='1.0' encoding='utf-8'?>
+<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="IvyProbeConsole.Properties" GeneratedClassName="Settings">
+ <Profiles />
+ <Settings>
+ <Setting Name="domain" Type="System.String" Scope="Application">
+ <Value Profile="(Default)" />
+ </Setting>
+ <Setting Name="name" Type="System.String" Scope="Application">
+ <Value Profile="(Default)">C#ProbeConsole</Value>
+ </Setting>
+ <Setting Name="quiet" Type="System.Boolean" Scope="Application">
+ <Value Profile="(Default)">False</Value>
+ </Setting>
+ <Setting Name="timestamp" Type="System.Boolean" Scope="Application">
+ <Value Profile="(Default)">False</Value>
+ </Setting>
+ <Setting Name="IvyDebug" Type="System.Boolean" Scope="Application">
+ <Value Profile="(Default)">False</Value>
+ </Setting>
+ </Settings>
+</SettingsFile> \ No newline at end of file
diff --git a/Ivy/IvyProbeConsole/Properties/app.manifest b/Ivy/IvyProbeConsole/Properties/app.manifest
new file mode 100644
index 0000000..ec82d19
--- /dev/null
+++ b/Ivy/IvyProbeConsole/Properties/app.manifest
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<asmv1:assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
+ <security>
+ <applicationRequestMinimum>
+ <defaultAssemblyRequest permissionSetReference="Custom" />
+ <PermissionSet class="System.Security.PermissionSet" version="1" Unrestricted="true" ID="Custom" SameSite="site" />
+ </applicationRequestMinimum>
+ </security>
+ </trustInfo>
+</asmv1:assembly> \ No newline at end of file
diff --git a/Ivy/IvyProbeConsole/Settings.cs b/Ivy/IvyProbeConsole/Settings.cs
new file mode 100644
index 0000000..e0f5232
--- /dev/null
+++ b/Ivy/IvyProbeConsole/Settings.cs
@@ -0,0 +1,28 @@
+namespace IvyProbeConsole.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/IvyProbeConsole/app.config b/Ivy/IvyProbeConsole/app.config
new file mode 100644
index 0000000..fef7919
--- /dev/null
+++ b/Ivy/IvyProbeConsole/app.config
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<configuration>
+ <configSections>
+ <sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
+ <section name="IvyProbeConsole.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
+ </sectionGroup>
+ </configSections>
+ <applicationSettings>
+ <IvyProbeConsole.Properties.Settings>
+ <setting name="domain" serializeAs="String">
+ <value />
+ </setting>
+ <setting name="name" serializeAs="String">
+ <value>C#ProbeConsole</value>
+ </setting>
+ <setting name="quiet" serializeAs="String">
+ <value>False</value>
+ </setting>
+ <setting name="timestamp" serializeAs="String">
+ <value>False</value>
+ </setting>
+ <setting name="IvyDebug" serializeAs="String">
+ <value>False</value>
+ </setting>
+ </IvyProbeConsole.Properties.Settings>
+ </applicationSettings>
+</configuration> \ No newline at end of file