summaryrefslogtreecommitdiff
path: root/Ivy
diff options
context:
space:
mode:
authorfcolin2008-08-22 16:44:01 +0000
committerfcolin2008-08-22 16:44:01 +0000
commit8d10e8bbd1e19adc7c70e1101dbb69c213c910dd (patch)
treef41034ab66b1b3174277b07c8aa45791dadbaae8 /Ivy
parent7053d3d604920ab708076e107be4b55666c5af80 (diff)
downloadivy-csharp-8d10e8bbd1e19adc7c70e1101dbb69c213c910dd.zip
ivy-csharp-8d10e8bbd1e19adc7c70e1101dbb69c213c910dd.tar.gz
ivy-csharp-8d10e8bbd1e19adc7c70e1101dbb69c213c910dd.tar.bz2
ivy-csharp-8d10e8bbd1e19adc7c70e1101dbb69c213c910dd.tar.xz
optimisation for parsing same regular expression from multiple client
using fxCop for code beauty fix bug on concurrent connect
Diffstat (limited to 'Ivy')
-rw-r--r--Ivy/Ivy.cs556
-rw-r--r--Ivy/Ivy.csproj57
-rw-r--r--Ivy/IvyApplicationBinding.cs69
-rw-r--r--Ivy/IvyBinding.cs39
-rw-r--r--Ivy/IvyBindingAttribute.cs47
-rw-r--r--Ivy/IvyClient.cs373
-rw-r--r--Ivy/IvyEventArgs.cs16
-rw-r--r--Ivy/IvyException.cs26
-rw-r--r--Ivy/IvyProtocol.cs29
-rw-r--r--Ivy/IvyTCPStreamV3.cs170
-rw-r--r--Ivy/IvyTCPStreamV4.cs107
-rw-r--r--Ivy/IvyUDPStream.cs72
-rw-r--r--Ivy/IvyUDPStreamV3.cs29
-rw-r--r--Ivy/IvyUDPStreamV4.cs20
-rw-r--r--Ivy/IvyWatcher.cs109
-rw-r--r--Ivy/Properties/AssemblyInfo.cs6
-rw-r--r--Ivy/Properties/Settings.Designer.cs4
17 files changed, 1082 insertions, 647 deletions
diff --git a/Ivy/Ivy.cs b/Ivy/Ivy.cs
index 14a3918..bfef8ab 100644
--- a/Ivy/Ivy.cs
+++ b/Ivy/Ivy.cs
@@ -4,7 +4,7 @@
/// (C) CENA
/// *
///
-
+[assembly: System.CLSCompliant(true)]
namespace IvyBus
{
using System;
@@ -21,11 +21,12 @@ namespace IvyBus
using System.Text;
using System.Reflection;
using System.Diagnostics;
+ using System.Collections.ObjectModel;
+ using IvyBus.Properties;
/// <summary> The Main bus Class
/// </summary>
///
-
public class Ivy
{
/* Event */
@@ -36,6 +37,7 @@ namespace IvyBus
public event EventHandler<IvyEventArgs> BindingAdd;
public event EventHandler<IvyEventArgs> BindingRemove;
public event EventHandler<IvyEventArgs> BindingFilter;
+ public event EventHandler<IvyEventArgs> BindingChange;
public event EventHandler<IvyEventArgs> ErrorMessage;
@@ -67,11 +69,11 @@ namespace IvyBus
/// <summary>IvyClients accesses the list of the connected clients</summary>
- public List<IvyClient> IvyClients
+ public ReadOnlyCollection<IvyClient> IvyClients
{
get
{
- return clients;
+ return new ReadOnlyCollection<IvyClient>(clients);
}
}
@@ -100,28 +102,7 @@ namespace IvyBus
}
}
- /// <summary>AppPriority the Application Priority: the clients list is sorted against priority</summary>
-
- public ushort AppPriority
- {
- set
- {
- applicationPriority = value;
- lock (clients)
- {
- foreach (IvyClient client in clients)
- {
- client.stream.TokenApplicationId(applicationPriority, AppId);
- }
- }
-
- }
- get
- {
- return applicationPriority;
- }
-
- }
+
public int ProtocolVersion
{
@@ -146,7 +127,7 @@ namespace IvyBus
///<remarks> optimise the parsing process when sending messages </remarks>
///</summary>
- public List<string> SentMessageFilter
+ public Collection<string> SentMessageFilter
{
get
{
@@ -175,26 +156,37 @@ namespace IvyBus
/// 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
- public const ushort DEFAULT_PRIORITY = 100;
+ internal const ushort DefaultPort = 2010;
/// the domain for the UDP rendez vous
- private static readonly string DEFAULT_DOMAIN = "127.255.255.255:" + DEFAULT_PORT;
+ private static readonly string DefaultDomain = "127.255.255.255:" + DefaultPort;
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 static int 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
+ private Thread serverThread; // to ensure quick communication of the end
+ private AutoResetEvent tcplistener_running;
+ static public Version Version
+ {
+ get { return Assembly.GetExecutingAssembly().GetName().Version; }
+ }
+ // Class representing Ivy Binding receive from client
+ internal class IvyClientBinding
+ {
+ internal IvyBindingBase binding;
+ internal Dictionary<IvyClient, List<int>> client_bindind_ids;
+ }
+ // The Application bindings
internal Dictionary<int, IvyApplicationBinding> bindings;
+ // the clients bindings
+ private Dictionary<string, IvyClientBinding > client_bindings;
private List<IvyClient> clients;
- private List<string> sent_messageFilter;
+ private Collection<string> sent_messageFilter;
private bool stopped = true;
- internal ushort applicationPort; /* Application port number */
+ internal int 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");
internal static Encoding ivyEncoding = Encoding.GetEncoding("iso-8859-15"); // ASCII 8 bits iso-8859-2
@@ -212,13 +204,12 @@ namespace IvyBus
/// </summary>
public Ivy()
{
-#if (!PocketPC)
- syncContext = SynchronizationContext.Current;
-#endif
clients = new List<IvyClient>();
bindings = new Dictionary<int, IvyApplicationBinding>();
- sent_messageFilter = new List<string>();
+ client_bindings = new Dictionary<string, IvyClientBinding>();
+ sent_messageFilter = new Collection<string>();
#if (!PocketPC)
+ syncContext = SynchronizationContext.Current;
debugProtocol = Properties.Settings.Default.IvyDebug;
protocolVersion = Properties.Settings.Default.IvyProtocolVersion;
#endif
@@ -230,7 +221,7 @@ namespace IvyBus
#endif
Assembly assembly = Assembly.GetCallingAssembly();
if ( assembly != this.GetType().Assembly )
- BindAttibute(assembly);
+ BindAttribute(assembly);
}
/// <summary>
@@ -256,21 +247,112 @@ namespace IvyBus
/// </param>
/// <param name='message'>The hellow message you will send once ready
/// </param>
- public Ivy(string name, string rdy_message)
+ public Ivy(string name, string readyMessage)
: this()
{
appName = name;
- ready_message = rdy_message;
+ this.ready_message = readyMessage;
// get binding from Attribute IvyBinding
//TODO Autobinding attribute
Assembly assembly = Assembly.GetCallingAssembly();
if (assembly != this.GetType().Assembly)
- BindAttibute(assembly);
+ BindAttribute(assembly);
}
-
+ internal void AddBinding(int id, IvyClient clnt, IvyBindingBase bindexp)
+ {
+ bool change = false;
+ IvyClientBinding clientbind;
+ lock (client_bindings)
+ {
+ if (client_bindings.ContainsKey(bindexp.Expression))
+ {
+ // check if id exits to remove it
+
+ clientbind = client_bindings[bindexp.Expression];
+
+ foreach (IvyClientBinding clbind in client_bindings.Values)
+ {
+ lock (clbind.client_bindind_ids)
+ {
+ if (clbind.client_bindind_ids.ContainsKey(clnt))
+ {
+ if (clbind.client_bindind_ids[clnt].Contains(id))
+ {
+ // remove from old
+ clbind.client_bindind_ids[clnt].Remove(id);
+ // add to new later
+ change = true; //mark to call right handler
+ break;
+ }
+ }
+ }
+
+ }
+
+ }
+ else
+ {
+ clientbind = new IvyClientBinding();
+ clientbind.binding = bindexp;
+ clientbind.client_bindind_ids = new Dictionary<IvyClient, List<int>>();
+ clientbind.client_bindind_ids[clnt] = new List<int>();
+ client_bindings[bindexp.Expression] = clientbind;
+
+ }
+ }
+
+ lock (clientbind.client_bindind_ids)
+ {
+ if (!clientbind.client_bindind_ids.ContainsKey(clnt))
+ {
+ clientbind.client_bindind_ids[clnt] = new List<int>();
+ }
+ clientbind.client_bindind_ids[clnt].Add(id);
+ }
+ if (change)
+ {
+ OnClientChangeBinding(new IvyEventArgs(clnt, id, bindexp.Expression));
+ }
+ else
+ {
+ OnClientAddBinding(new IvyEventArgs(clnt, id, bindexp.Expression));
+ }
+ }
+ internal void DelBinding(int id, IvyClient clnt)
+ {
+ IvyClientBinding clientbind = null;
+ lock (client_bindings)
+ {
+ foreach (IvyClientBinding clbind in client_bindings.Values)
+ {
+ lock (clbind.client_bindind_ids)
+ {
+ if (clbind.client_bindind_ids.ContainsKey(clnt))
+ {
+ clbind.client_bindind_ids[clnt].Remove(id);
+ clientbind = clbind;
+ break;
+ }
+ }
+ }
+ if (clientbind != null)
+ {
+ lock (clientbind.client_bindind_ids)
+ {
+ if (clientbind.client_bindind_ids.Count == 0)
+ {
+ client_bindings.Remove(clientbind.binding.Expression);
+ }
+ }
+ }
+ }
+ if (clientbind != null )
+ OnClientRemoveBinding(new IvyEventArgs(clnt, id, clientbind.binding.Expression));
+
+ }
// Autobinding on static method
- public void BindAttibute(Type type)
+ public void BindAttribute(Type type)
{
if (type == null) return;
//Get instance of the IvyBindingAttribute.
@@ -279,7 +361,7 @@ namespace IvyBus
foreach (IvyBindingAttribute attr in Attribute.GetCustomAttributes(m, typeof(IvyBindingAttribute)))
{
//TODO check paramater type MessageHandler
- Debug.WriteLine("IvyBinding '" + attr.GetExpression(null) + "' to Method " + m.Name);
+ Debug.WriteLine("IvyBinding '" + attr.GetFormattedExpression(null) + "' to Method " + m.Name);
EventHandler<IvyMessageEventArgs> handler;
#if (PocketPC)
//Createdelegate mydlg = new Createdelegate(m, null, EventArgs.Empty);
@@ -288,41 +370,43 @@ namespace IvyBus
#else
handler = (EventHandler<IvyMessageEventArgs>)Delegate.CreateDelegate(typeof(EventHandler<IvyMessageEventArgs>), m);
#endif
- BindMsg(attr.GetExpression(null), handler);
+ BindMsg(attr.GetFormattedExpression(null), handler);
}
}
}
// Autobinding on instance method
- public void BindAttibute(object obj)
+ public void BindAttribute(object target)
{
- if (obj == null) return;
- Type type = obj.GetType();
+ if (target == null) return;
+ Type type = target.GetType();
//Get instance of the IvyBindingAttribute.
foreach (MethodInfo m in type.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic))
{
foreach (IvyBindingAttribute attr in Attribute.GetCustomAttributes(m, typeof(IvyBindingAttribute)))
{
//TODO check paramater type MessageHandler
- Ivy.traceProtocol("Ivy", "BindAttibute " + attr.GetExpression(obj) + "' to Method " + m.Name);
+ Ivy.traceProtocol(Resources.Ivy, "BindAttibute " + attr.GetFormattedExpression(target) + "' to Method " + m.Name);
EventHandler<IvyMessageEventArgs> handler;
#if (PocketPC)
handler = null; // TODO
#else
- handler = (EventHandler<IvyMessageEventArgs>)Delegate.CreateDelegate(typeof(EventHandler<IvyMessageEventArgs>), obj, m);
+ handler = (EventHandler<IvyMessageEventArgs>)Delegate.CreateDelegate(typeof(EventHandler<IvyMessageEventArgs>), target, m);
#endif
- BindMsg(attr.GetExpression(obj), handler);
+ BindMsg(attr.GetFormattedExpression(target), handler);
}
}
}
// Autobinding on IvyBindingAttribute method
- public void BindAttibute(Assembly assy)
+ public void BindAttribute(Assembly target)
{
- foreach (Type typ in assy.GetTypes())
+ if (target != null)
{
- BindAttibute(typ);
+ foreach (Type typ in target.GetTypes())
+ {
+ BindAttribute(typ);
+ }
}
-
}
/// <summary>
/// connects the Ivy bus to a domain or list of domains.
@@ -337,9 +421,9 @@ namespace IvyBus
/// 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)
+ public void Start(string domainBus)
{
- domainbus = GetDomain(domainbus);
+ domainBus = GetDomain(domainBus);
try
{
long seed = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
@@ -347,8 +431,8 @@ namespace IvyBus
app = new MyTcpListener(IPAddress.Any, 0);
app.Start(); // should be started before getting port
- applicationHost = GetLocalIP();
- applicationPort = (ushort)((IPEndPoint)app.LocalEndpoint).Port;
+ applicationHost = LocalIP;
+ applicationPort = ((IPEndPoint)app.LocalEndpoint).Port;
applicationUniqueId = string.Format(culture,"{0}:{1}:{2}",
rand.Next(),
seed,
@@ -363,29 +447,22 @@ namespace IvyBus
Ivy.traceProtocol("BindAttibute", "Ivy protocol: " + ProtocolVersion + " TCP service open on port " + applicationPort);
watchers = new List<IvyWatcher>();
- Domain[] d = parseDomains(domainbus);
+ 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 = new Thread(new ThreadStart(this.TcpListener));
serverThread.Name = "Ivy Tcp Server Thread";
stopped = false;
+ tcplistener_running = new AutoResetEvent(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
+ tcplistener_running.WaitOne();
+
// sends the broadcasts and listen to incoming connexions
for (int i = 0; i < watchers.Count; i++)
{
@@ -402,9 +479,9 @@ namespace IvyBus
}
/* a small private method for debbugging purposes */
- public static string Domains(string toparse)
+ public static string Domains(string toParse)
{
- string domainbus = GetDomain(toparse);
+ string domainbus = GetDomain(toParse);
StringBuilder s = new StringBuilder("broadcasting on ");
Ivy.Domain[] d = parseDomains(domainbus);
for (int index = 0; index < d.Length; index++)
@@ -438,7 +515,7 @@ namespace IvyBus
lock (app)
{
stopped = true;
- Ivy.traceProtocol("Ivy", "beginning stopping the bus");
+ Ivy.traceProtocol(Resources.Ivy, "beginning stopping the bus");
try
{
// stopping the serverThread
@@ -464,10 +541,10 @@ namespace IvyBus
if (clients.Count != 0)
{
IvyClient[] copyClient;
- copyClient = new IvyClient[clients.Count];
lock (clients)
{
- clients.CopyTo(copyClient, 0);
+ copyClient = new IvyClient[clients.Count];
+ clients.CopyTo(copyClient);
}
foreach (IvyClient client in copyClient)
{
@@ -478,13 +555,35 @@ namespace IvyBus
}
catch (IOException e)
{
- Ivy.traceError("Ivy", "IOexception Stop " + e.Message);
+ Ivy.traceError(Resources.Ivy, "IOexception Stop " + e.Message);
}
- Ivy.traceProtocol("Ivy", "the bus should have stopped so far");
+ Ivy.traceProtocol(Resources.Ivy, "the bus should have stopped so far");
}
}
-
-
+ /// <summary>
+ /// join the main thread of Ivy ( ie wait until stopped )
+ /// </summary>
+ /// <remarks>
+ /// Performs a join on the Principal Thread.
+ /// </remarks>
+ /// <param name='millisecondsTimeout'>Number of millisecondes to wait before the Thread Stop.
+ /// <returns>
+ /// true if the thread stopped; false if it did not stop after the expiry of the period specified by the parameter millisecondsTimeout
+ /// </returns>
+ public bool Join(int millisecondsTimeout)
+ {
+ return serverThread.Join(millisecondsTimeout);
+ }
+ /// <summary>
+ /// Block the calling Thread until Ivy Stop
+ /// </summary>
+ /// <remarks>
+ /// Performs a join on the Principal Thread.
+ /// </remarks>
+ public void MainLoop()
+ {
+ this.Join(Timeout.Infinite);
+ }
/// <summary>
/// Send a formated message to someone on the bus
/// </summary>
@@ -501,60 +600,116 @@ namespace IvyBus
/// </returns>
public int SendMsg(string format, params object[] args)
{
+ // send to everybody
string msg = string.Format(culture, format, args);
int count = 0;
+ // hash message in V4 protocol only
+ if (ProtocolVersion == 4)
+ IvyBindingSimple.Prepare(msg);
// an alternate implementation would one sender thread per client
// instead of one for all the clients. It might be a performance issue
- lock (clients)
+ // Tentative of using BeginInvoke EndInvoke is slower
+ lock (client_bindings)
{
- // hash message in V4 protocol only
- if (ProtocolVersion == 4)
- IvyBindingSimple.Prepare(msg);
- foreach (IvyClient client in clients)
+ foreach (IvyClientBinding clbind in client_bindings.Values)
{
- count += client.sendMsg(msg);
+ string[] matches = clbind.binding.Match(msg);
+ if (matches != null)
+ {
+ lock (clbind.client_bindind_ids)
+ {
+
+ foreach (KeyValuePair<IvyClient, List<int>> assoc in clbind.client_bindind_ids)
+ {
+ foreach (ushort id in assoc.Value)
+ {
+ count += assoc.Key.sendMsg(id, matches);
+ }
+
+ }
+
+ }
+ }
+
}
+
}
+
+ return count;
+ }
+
+ internal int SendMsgToClient(IvyClient clnt, string format, params object[] args)
+ {
+ string msg = string.Format(culture, format, args);
+ int count = 0;
+ // hash message in V4 protocol only
+ if (ProtocolVersion == 4)
+ IvyBindingSimple.Prepare(msg);
+ // an alternate implementation would one sender thread per client
+ // instead of one for all the clients. It might be a performance issue
+ lock (client_bindings)
+ {
+
+ foreach (IvyClientBinding clbind in client_bindings.Values)
+ {
+ string[] matches = clbind.binding.Match(msg);
+ if (matches != null)
+ {
+ lock (clbind.client_bindind_ids)
+ {
+ if (clbind.client_bindind_ids.ContainsKey(clnt))
+ {
+ List<int> ids = clbind.client_bindind_ids[clnt];
+ foreach (ushort id in ids)
+ {
+ count += clnt.sendMsg(id, matches);
+ }
+ }
+ }
+ }
+ }
+ }
+
+
return count;
}
//
- public ushort BindMsg(IvyApplicationBinding newbind)
+ public int BindMsg(IvyApplicationBinding newBinding)
{
- newbind.Key = serial++;
+ newBinding.Key = Interlocked.Increment(ref serial);
- lock (bindings) bindings.Add(newbind.Key, newbind);
+ lock (bindings) bindings.Add(newBinding.Key, newBinding);
// notifies the other clients this new regexp
lock (clients)
{
foreach (IvyClient c in clients)
{
- c.stream.TokenAddBinding(newbind.Binding, newbind.Key, newbind.FormatedExpression);
+ c.stream.TokenAddBinding(newBinding.Binding, newBinding.Key, newBinding.FormattedExpression);
}
}
- return newbind.Key;
+ return newBinding.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="callback">any objects implementing the EventHandler<IvyMessageEventArgs> </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.
+ /// the expression cant containt some dynamics argument replacement of the form %number[:objectFormat]%
+ /// the string will be replaced by arg[number].ToString(objectFormat)
/// </remarks>
//
- public ushort BindMsg(string regexp, EventHandler<IvyMessageEventArgs> callback, params object[] args)
+ public int BindMsg(string expression, 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 = new IvyApplicationBinding(BindingType.RegularExpression, expression, args);
newbind.Callback += callback;
- newbind.Args = args;
return BindMsg(newbind);
}
@@ -562,7 +717,7 @@ namespace IvyBus
/// 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)
+ public void UnbindMsg(int id)
{
if (!bindings.ContainsKey(id))
{
@@ -572,11 +727,43 @@ namespace IvyBus
{
foreach (IvyClient c in clients)
{
- c.stream.TokenDelBinding(id);
+ try
+ {
+ c.stream.TokenDelBinding(id);
+ }
+ catch (IOException)
+ {
+ // client closed ignore it
+ }
}
}
lock (bindings) bindings.Remove(id);
}
+ public int ChangeMsg(int id, string expression)
+ {
+ IvyApplicationBinding newbind;
+ if (!bindings.ContainsKey(id))
+ {
+ throw new IvyException("client wants to change an unexistant regexp " + id);
+ }
+
+ // change binding (regexp,callback)
+ lock (bindings)
+ {
+ newbind = bindings[id];
+ newbind.Expression = expression;
+ }
+ // notifies the other clients this new regexp
+ lock (clients)
+ {
+ foreach (IvyClient c in clients)
+ {
+ c.stream.TokenAddBinding(newbind.Binding, newbind.Key, newbind.FormattedExpression);
+ }
+ }
+ return id;
+ }
+
/// <summary>
/// unsubscribes a regular expression
@@ -625,11 +812,8 @@ namespace IvyBus
{
// creates a new binding (regexp,callback)
IvyApplicationBinding newbind;
- newbind = new IvyApplicationBinding();
- newbind.Binding = BindingType.Simple;
- newbind.Expression = expression;
+ newbind = new IvyApplicationBinding(BindingType.Simple, expression, args);
newbind.Callback += callback;
- newbind.Args = args;
return BindMsg(newbind);
}
/// <summary>
@@ -640,9 +824,9 @@ namespace IvyBus
/// <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);
+ ReadOnlyCollection<IvyClient> v = GetClientsByName(target);
+ foreach (IvyClient clnt in v)
+ clnt.stream.TokenDie(0, message);
return v.Count;
}
/// <summary>
@@ -653,29 +837,23 @@ namespace IvyBus
/// <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);
+ ReadOnlyCollection<IvyClient> v = GetClientsByName(target);
+ foreach (IvyClient clnt in v)
+ clnt.stream.TokenPing(message);
return v.Count;
}
-#if (PocketPC)
+
+
internal virtual void FireEvent(EventHandler<IvyEventArgs> ev, IvyEventArgs e)
{
if (ev != null)
{
+#if (PocketPC)
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)
@@ -685,12 +863,13 @@ namespace IvyBus
};
syncContext.Post(update, e);
}
+#endif
else
ev(this, e);
}
}
-#endif
+
internal virtual void OnDirectMessage(IvyEventArgs e)
{
// Copy to a temporary variable to be thread-safe.
@@ -712,7 +891,7 @@ namespace IvyBus
FireEvent(temp,e);
}
#if (!PocketPC)
- catch (SynchronizationLockException ex)
+ catch (SynchronizationLockException)
{
// protect terminaison
}
@@ -735,6 +914,12 @@ namespace IvyBus
EventHandler<IvyEventArgs> temp = BindingRemove;
FireEvent(temp,e);
}
+ internal virtual void OnClientChangeBinding(IvyEventArgs e)
+ {
+ // Copy to a temporary variable to be thread-safe.
+ EventHandler<IvyEventArgs> temp = BindingChange;
+ FireEvent(temp, e);
+ }
internal virtual void OnClientFilterBinding(IvyEventArgs e)
{
// Copy to a temporary variable to be thread-safe.
@@ -786,12 +971,12 @@ namespace IvyBus
#endif
internal void OnMessage(IvyMessageEventArgs e)
{
- IvyApplicationBinding bind = bindings[e.Id];
-
- if (bind == null)
+ if (!bindings.ContainsKey( e.Id))
{
throw new IvyException("(callCallback) Not regexp matching id " + e.Id);
}
+ IvyApplicationBinding bind = bindings[e.Id];
+
#if(PocketPC)
bind.Firevent(parentControl, e);
#else
@@ -808,6 +993,24 @@ namespace IvyBus
{
clients.Remove(c);
}
+ List<string> purge_bind = new List<string>();
+ lock (client_bindings)
+ {
+ foreach (IvyClientBinding clbind in client_bindings.Values)
+ {
+ lock (clbind.client_bindind_ids)
+ {
+ clbind.client_bindind_ids.Remove(c);
+ if ( clbind.client_bindind_ids.Count == 0 )
+ purge_bind.Add( clbind.binding.Expression);
+ }
+ }
+ // remove Binding if no client
+ foreach ( string expr in purge_bind )
+ {
+ client_bindings.Remove(expr);
+ }
+ }
}
@@ -816,7 +1019,7 @@ namespace IvyBus
/// </summary>
/// <param name="name">The name of the Ivy agent you're looking for</param>
/// <returns></returns>
- public List<IvyClient> GetClientsByName(string name)
+ public ReadOnlyCollection<IvyClient> GetClientsByName(string name)
{
List<IvyClient> v = new List<IvyClient>();
foreach (IvyClient ic in clients)
@@ -824,7 +1027,7 @@ namespace IvyBus
if (ic.ApplicationName.CompareTo(name) == 0)
v.Add(ic);
}
- return v;
+ return new ReadOnlyCollection<IvyClient>(v);
}
/////////////////////////////////////////////////////////////////:
@@ -833,34 +1036,37 @@ namespace IvyBus
//
/////////////////////////////////////////////////////////////////:
- internal void addClient(Socket socket, string appname)
+ internal void addClient(IvyClient client)
{
if (stopped)
return;
- IvyClient client = new IvyClient(this, socket, appname);
+
lock (clients)
{
clients.Add(client);
}
- client.SendBindings();
+
}
- public static IPAddress GetLocalIP()
+ public static IPAddress LocalIP
{
- IPAddress returnaddr = null;
- //TODO remove ALL reverse DNS search !!!!
- IPHostEntry ip = Dns.GetHostEntry(Dns.GetHostName());
- foreach (IPAddress addr in ip.AddressList)
+ get
{
- returnaddr = addr;
- if (IPAddress.IsLoopback(addr)) continue;
- break;
+ 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;
}
- return returnaddr;
}
- public static string GetDomain(string domainbus)
+ public static string GetDomain(string domainBus)
{
#if (PocketPC) // TODO integrate in normal version
if (domainbus == null || domainbus.Length == 0)
@@ -885,19 +1091,19 @@ namespace IvyBus
domainbus = bcast + ":" + Domain.getPort(domainbus);
}
#else
- if (domainbus == null || domainbus.Length == 0 )
+ if (domainBus == null || domainBus.Length == 0 )
{
- domainbus = Environment.GetEnvironmentVariable("IVYBUS");
+ domainBus = Environment.GetEnvironmentVariable("IVYBUS");
}
- if (domainbus == null || domainbus.Length == 0)
+ if (domainBus == null || domainBus.Length == 0)
{
- domainbus = Properties.Settings.Default.IvyBus;
+ domainBus = Properties.Settings.Default.IvyBus;
}
#endif
- if (domainbus == null || domainbus.Length == 0)
- domainbus = DEFAULT_DOMAIN;
- return domainbus;
+ if (domainBus == null || domainBus.Length == 0)
+ domainBus = DefaultDomain;
+ return domainBus;
}
@@ -928,50 +1134,61 @@ namespace IvyBus
* 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)
+ internal IvyClient checkConnected(IvyClient clnt)
{
+ IvyClient sameClnt = null;
if (clnt.AppPort == 0)
- return false;
+ {
+ Console.WriteLine(" client {0} port == 0 ", clnt.appName);
+ return sameClnt;
+ }
lock (clients)
{
foreach (IvyClient client in clients)
{
- if (clnt != client && client.sameClient(clnt))
- return true;
+ if (clnt == client) continue; // SKIP himself
+ if (client.sameIvyClient(clnt))
+ {
+ sameClnt = client;
+ break;
+ }
}
}
- return false;
+ return sameClnt;
}
/*
* the service socket thread reader main loop
*/
- private void Run()
+ private void TcpListener()
{
- Ivy.traceProtocol("Ivy", "Ivy service Thread started");
+ Ivy.traceProtocol(Resources.Ivy, "Ivy service Thread started");
bool running = true;
+ tcplistener_running.Set();
while (running)
{
try
{
Socket socket = app.AcceptSocket();
+ // early disconnexion
if (stopped)
break;
- // early disconnexion
- addClient(socket, "Unkown(waiting for name reception)"); // the peer called me
+ // the peer called me
+ IvyClient client = new IvyClient(this, socket, "Unkown(waiting for name reception)",0);
+ client.SendBindings(); //TODO in a Thread or wait for the peer to sent his before sending mine
+
}
catch (IOException e)
{
- Ivy.traceError("Ivy","Ivy server socket reader caught an exception: " + e.Message);
+ Ivy.traceError(Resources.Ivy,Resources.IvyIOException + e.Message);
}
catch (SocketException e)
{
- Ivy.traceError("Ivy","my server socket has been closed " + e.Message);
+ Ivy.traceError(Resources.Ivy,Resources.IvySocketException + e.Message);
running = false;
}
}
- Ivy.traceProtocol("Ivy", "Ivy service Thread stopped");
+ Ivy.traceProtocol(Resources.Ivy, "Ivy service Thread stopped");
}
[Conditional("DEBUG")]
@@ -1005,14 +1222,13 @@ namespace IvyBus
}
private string domainaddr;
private int port;
- public Domain(string net)
+ public Domain(string net):this( getDomain(net),getPort(net))
{
- this.domainaddr = getDomain(net);
- this.port = getPort(net);
}
public Domain(string domainaddr, int port)
{
- this.domainaddr = domainaddr; this.port = port;
+ this.domainaddr = domainaddr;
+ this.port = port;
}
public override string ToString()
{
@@ -1033,7 +1249,7 @@ namespace IvyBus
}
catch (ArgumentException e)
{
- Ivy.traceError("Ivy","Bad broascat addr " + net + "error " + e.Message);
+ Ivy.traceError(Resources.Ivy,Resources.BadBroadcast + net + "error " + e.Message);
return null;
}
return net;
@@ -1041,18 +1257,18 @@ namespace IvyBus
public static int getPort(string net)
{
- if (net == null) return Ivy.DEFAULT_PORT;
+ if (net == null) { return Ivy.DefaultPort; }
int sep_index = net.LastIndexOf(":");
- int port = (sep_index == -1) ? Ivy.DEFAULT_PORT : Int32.Parse(net.Substring(sep_index + 1));
+ int port = (sep_index == -1) ? Ivy.DefaultPort : Int32.Parse(net.Substring(sep_index + 1));
return port;
}
}
- public static bool ValidatingDomain(string p)
+ public static bool ValidatingDomain(string domain)
{
// domain if of the form ip1[:port][,ip2[:port]] with ip of the form n1.n2.n3.n4
- return Regex.IsMatch(p, @"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+");
+ return Regex.IsMatch(domain, @"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+");
}
}
diff --git a/Ivy/Ivy.csproj b/Ivy/Ivy.csproj
index 4977434..5076a47 100644
--- a/Ivy/Ivy.csproj
+++ b/Ivy/Ivy.csproj
@@ -1,7 +1,7 @@
-<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
<PropertyGroup>
<ProjectType>Local</ProjectType>
- <ProductVersion>8.0.50727</ProductVersion>
+ <ProductVersion>9.0.21022</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{F2F03CF7-0087-4EDB-AD15-80C9E8DA2617}</ProjectGuid>
<SccProjectName>SAK</SccProjectName>
@@ -15,7 +15,8 @@
<AssemblyKeyContainerName>
</AssemblyKeyContainerName>
<AssemblyName>IvyBus.Ivy</AssemblyName>
- <AssemblyOriginatorKeyFile>IvySignKey.pfx</AssemblyOriginatorKeyFile>
+ <AssemblyOriginatorKeyFile>
+ </AssemblyOriginatorKeyFile>
<DefaultClientScript>JScript</DefaultClientScript>
<DefaultHTMLPageLayout>Grid</DefaultHTMLPageLayout>
<DefaultTargetSchema>IE50</DefaultTargetSchema>
@@ -30,6 +31,23 @@
<UpgradeBackupLocation>
</UpgradeBackupLocation>
<SignAssembly>true</SignAssembly>
+ <OldToolsVersion>3.5</OldToolsVersion>
+ <PublishUrl>publish\</PublishUrl>
+ <Install>true</Install>
+ <InstallFrom>Disk</InstallFrom>
+ <UpdateEnabled>false</UpdateEnabled>
+ <UpdateMode>Foreground</UpdateMode>
+ <UpdateInterval>7</UpdateInterval>
+ <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+ <UpdatePeriodically>false</UpdatePeriodically>
+ <UpdateRequired>false</UpdateRequired>
+ <MapFileExtensions>true</MapFileExtensions>
+ <ApplicationRevision>0</ApplicationRevision>
+ <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+ <IsWebBootstrapper>false</IsWebBootstrapper>
+ <UseApplicationTrust>false</UseApplicationTrust>
+ <BootstrapperEnabled>true</BootstrapperEnabled>
+ <TargetFrameworkVersion>v3.0</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<OutputPath>bin\Debug\</OutputPath>
@@ -38,8 +56,7 @@
<CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
<ConfigurationOverrideFile>
</ConfigurationOverrideFile>
- <DefineConstants>
- </DefineConstants>
+ <DefineConstants>DEBUG</DefineConstants>
<DocumentationFile>
</DocumentationFile>
<DebugSymbols>true</DebugSymbols>
@@ -140,6 +157,11 @@
<Compile Include="IvyWatcher.cs">
<SubType>Code</SubType>
</Compile>
+ <Compile Include="Properties\Resources.Designer.cs">
+ <AutoGen>True</AutoGen>
+ <DesignTime>True</DesignTime>
+ <DependentUpon>Resources.resx</DependentUpon>
+ </Compile>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
@@ -150,12 +172,35 @@
<ItemGroup>
<None Include="app.config" />
<None Include="Ivy.snippet" />
- <None Include="IvySignKey.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 %28x86%29</ProductName>
+ <Install>true</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Net.Framework.3.0">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.0 %28x86%29</ProductName>
+ <Install>false</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Net.Framework.3.5">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.5</ProductName>
+ <Install>false</Install>
+ </BootstrapperPackage>
+ </ItemGroup>
+ <ItemGroup>
+ <EmbeddedResource Include="Properties\Resources.resx">
+ <Generator>ResXFileCodeGenerator</Generator>
+ <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+ <SubType>Designer</SubType>
+ </EmbeddedResource>
+ </ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PreBuildEvent>
diff --git a/Ivy/IvyApplicationBinding.cs b/Ivy/IvyApplicationBinding.cs
index 299f459..b5fe303 100644
--- a/Ivy/IvyApplicationBinding.cs
+++ b/Ivy/IvyApplicationBinding.cs
@@ -1,11 +1,14 @@
-using System;
-using System.Collections.Generic;
-using System.Collections.Specialized;
-using System.Text;
-using System.Threading;
namespace IvyBus
{
+ using System;
+ using System.Collections.Generic;
+ using System.Collections.Specialized;
+ using System.Text;
+ using System.Threading;
+ using System.Text.RegularExpressions;
+ using System.Collections.ObjectModel;
+
/* 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 */
@@ -14,15 +17,20 @@ namespace IvyBus
{
private BindingType binding;
+ // Argument formatting Expression to replace argument in in regular expresion binding
+ // format %number[:objectFormat]%
+ // where number in argument index and objectFormat the ToString format passed to argument
+ private Regex re = new Regex(@"%(\d+)(|:(.*))%");
+
public BindingType Binding
{
get { return binding; }
set { binding = value; }
}
- private ushort key;
+ private int key;
- public ushort Key
+ public int Key
{
get { return key; }
set { key = value; }
@@ -30,11 +38,6 @@ namespace IvyBus
private object[] args;
- public object[] Args
- {
- get { return args; }
- set { args = value; }
- }
private string expression;
public string Expression
@@ -42,22 +45,22 @@ namespace IvyBus
get { return expression; }
set { expression = value; }
}
- private string formated_expression;
- public string FormatedExpression
+ private string formatted_expression;
+ public string FormattedExpression
{
get
{
FormatExpression();
- return formated_expression;
+ return formatted_expression;
}
}
- private List<string> arguments;
+ private Collection<string> arguments;
///<summary>SentMessageClasses the first word token of sent messages
///<remarks> optimise the parsing process when sending messages </remarks>
///</summary>
- public List<string> Arguments
+ public Collection<string> Arguments
{
get
{
@@ -66,12 +69,35 @@ namespace IvyBus
}
public event EventHandler<IvyMessageEventArgs> Callback;
-
+
public IvyApplicationBinding()
+ :this(BindingType.RegularExpression,string.Empty,null)
{
- arguments = new List<string>();
+
+ }
+ public IvyApplicationBinding(BindingType type, string expression, params object[] args)
+ {
+ arguments = new Collection<string>();
+ this.Binding = type;
+ this.Expression = expression;
+ this.args = args;
}
+ private string ReplaceArgs(Match m)
+ {
+ string s = string.Empty;
+ // Get the matched string. convert to argindex
+ int argindex = int.Parse(m.Groups[1].Value);
+ // use %... to specify formating
+ object arg = args[argindex];
+ IFormattable fmt = arg as IFormattable;
+ if (fmt != null)
+ s = fmt.ToString(m.Groups[3].Value, null);
+ else if (arg != null)
+ s = arg.ToString();
+
+ return s;
+ }
// translate part of expression to object property
public void FormatExpression()
{
@@ -94,11 +120,12 @@ namespace IvyBus
args[i] = arguments[i];
}
}
- formated_expression = string.Format(expression, args);
+
+ formatted_expression = re.Replace(expression, ReplaceArgs);
}
else //TODO Abnormal condition Design Time
#endif
- formated_expression = expression;
+ formatted_expression = expression;
}
diff --git a/Ivy/IvyBinding.cs b/Ivy/IvyBinding.cs
index 624b401..bb2498a 100644
--- a/Ivy/IvyBinding.cs
+++ b/Ivy/IvyBinding.cs
@@ -1,11 +1,13 @@
-using System;
-using System.Collections;
-using System.Collections.Specialized;
-using System.Text.RegularExpressions;
-using System.Diagnostics;
-
+
namespace IvyBus
{
+ using System;
+ using System.Collections;
+ using System.Collections.Specialized;
+ using System.Text.RegularExpressions;
+ using System.Diagnostics;
+ using IvyBus.Properties;
+
/* 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 */
@@ -16,22 +18,15 @@ namespace IvyBus
internal abstract class IvyBindingBase
{
- private ushort key;
-
- internal ushort Key
- {
- get { return key; }
- }
- protected string expression;
+ private string expression;
internal string Expression
{
get { return expression; }
}
- internal IvyBindingBase(ushort id, string exp)
+ internal IvyBindingBase(string exp)
{
- key = id;
expression = exp;
}
internal abstract string[] Match(string message);
@@ -41,10 +36,10 @@ namespace IvyBus
{
internal Regex regexp;
- public IvyBindingRegexp(ushort id, string exp)
- : base(id, exp)
+ public IvyBindingRegexp( string exp)
+ : base(exp)
{
- regexp = new Regex(expression, /* RegexOptions.Compiled | */RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
+ 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)
@@ -71,10 +66,10 @@ namespace IvyBus
static string msgtag; // send message name
static StringDictionary args_values; // send message args[name]=value
- internal IvyBindingSimple(ushort id, string exp)
- : base(id, exp)
+ internal IvyBindingSimple(string exp)
+ : base(exp)
{
- string[] expr = expression.Split( ' ' );
+ string[] expr = Expression.Split( ' ' );
msgname = expr[0];
msgargs = new string[ expr.Length -1 ];
for ( int i = 1; i < expr.Length; i++ )
@@ -92,7 +87,7 @@ namespace IvyBus
args_values[arg[0]] = arg[1];
else
{
- Ivy.traceError("IvyBindingSimple" , "abnormally Formed message expected 'msg champ=valeur champ=valeur....' :" + message);
+ Ivy.traceError("IvyBindingSimple" , Resources.BadSimpleBinding + message);
}
}
diff --git a/Ivy/IvyBindingAttribute.cs b/Ivy/IvyBindingAttribute.cs
index 90c44ce..1380f0f 100644
--- a/Ivy/IvyBindingAttribute.cs
+++ b/Ivy/IvyBindingAttribute.cs
@@ -1,31 +1,50 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
+
namespace IvyBus
{
- [AttributeUsage(AttributeTargets.Method,AllowMultiple = true)]
+ using System;
+ using System.Collections.Generic;
+ using System.Text;
+ using System.Collections.ObjectModel;
+ using System.Globalization;
+
+ [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)
+ public string Expression
{
- 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);
+ get { return this.expression; }
}
-
+
+ public ReadOnlyCollection<string> Args
+ {
+ get { return new ReadOnlyCollection<string>(args); }
+ }
+
public IvyBindingAttribute(string expression, params string[] args)
{
this.expression = expression;
this.args = args;
}
+
+ // translate part of expression to object property
+ public string GetFormattedExpression(object target)
+ {
+ if (target == null)
+ {
+ return string.Format(this.expression);
+ }
+
+ object[] values = new object[this.args.Length];
+ for (int i = 0; i < values.Length; i++)
+ {
+ values[i] = target.GetType().GetProperty(args[i]).GetValue(target, null);
+ }
+
+ return string.Format(this.expression, values);
+ }
}
}
diff --git a/Ivy/IvyClient.cs b/Ivy/IvyClient.cs
index 63dc77e..7f29e91 100644
--- a/Ivy/IvyClient.cs
+++ b/Ivy/IvyClient.cs
@@ -16,6 +16,8 @@ namespace IvyBus
using System.Net.Sockets;
using System.Configuration;
using System.Diagnostics;
+ using System.Collections.ObjectModel;
+ using IvyBus.Properties;
/// <summary> A Class for the the peers on the bus.
/// </summary>
@@ -29,7 +31,10 @@ namespace IvyBus
{
public int CompareTo(IvyClient other)
{
- return (other.clientPriority - clientPriority);
+ if (other == null)
+ return clientPriority;
+ else
+ return (other.clientPriority - clientPriority);
}
public String ApplicationName
@@ -41,20 +46,20 @@ namespace IvyBus
}
- 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;
- }
+ //public ReadOnlyCollection<string> Regexps
+ //{
+ // get
+ // {
+ // List<string> tab = new List<string>();
+ // lock (bindings)
+ // {
+ // foreach (IvyBindingBase bind in bindings.Values)
+ // tab.Add(bind.Expression);
+ // }
+ // return new ReadOnlyCollection<string>(tab);
+ // }
- }
+ //}
internal int AppPort
{
get
@@ -81,16 +86,18 @@ namespace IvyBus
}
private Ivy bus;
- private Dictionary<ushort,IvyBindingBase> bindings;
+ //private Dictionary<ushort,IvyBindingBase> bindings;
private int appPort;
- private string clientId; /* an unique ID for each IvyClient */
+ private string clientId; /* an unique ID for each IvyClient */
private int clientPriority; /* client priority */
-
+
private volatile Thread clientThread; // volatile to ensure the quick communication
private bool doping; // false by runtime default
private const int PINGTIMEOUT = 5000;
private volatile Thread pingerThread;
+ private int localPort;
+
private int remotePort;
private IPAddress remoteHost;
@@ -98,38 +105,31 @@ namespace IvyBus
internal String appName;
internal IvyProtocol stream;
- internal IvyClient(Ivy bus, Socket socket, string appname)
+ internal IvyClient(Ivy bus, Socket socket, string appname, int appPort)
{
- bindings = new Dictionary<ushort,IvyBindingBase>();
- appName = appname;
+ //bindings = new Dictionary<ushort,IvyBindingBase>();
+ this.appName = appname;
+ this.appPort = appPort;
this.bus = bus;
+
+ localPort = ((IPEndPoint)socket.LocalEndPoint).Port;
IPEndPoint endpoint = (IPEndPoint)socket.RemoteEndPoint;
-
remoteHost = endpoint.Address;
remotePort = endpoint.Port;
-#if (!PocketPC )
- // try to position Keep Alive
- //try
- //{
- // socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.KeepAlive, 1);
- //}
- //catch (SocketException)
- //{
- //}
-#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
+ // spawns a thread to manage the incoming traffic on this
// socket. We should be ready to receive messages now.
clientThread = new Thread(new ThreadStart(this.Run));
clientThread.Name = "Ivy Tcp Client Reader Thread ("+appname+")";
+
+ bus.addClient(this);
+
clientThread.Start();
}
@@ -137,44 +137,62 @@ namespace IvyBus
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)
+
+ // 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)
{
- stream.TokenAddBinding(bind.Binding, bind.Key, bind.FormatedExpression);
+ foreach (IvyApplicationBinding bind in bus.bindings.Values)
+ {
+ stream.TokenAddBinding(bind.Binding, bind.Key, bind.FormattedExpression);
+ }
}
- }
- stream.TokenEndRegexp();
-
+ // send end of bindings peers can now send ReadyMessage
+ stream.TokenEndRegexp();
+
#if (!PocketPC)
- doping = Properties.Settings.Default.IvyPing;
+ doping = Properties.Settings.Default.IvyPing;
#endif
- if (doping)
- {
- pingerThread = new Thread(new ThreadStart(PingerRun));
- pingerThread.Name = "Ivy Pinger Thread";
- pingerThread.Start();
- }
+ 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);
- }
+ }
+ catch (NullReferenceException ex)
+ {
+ // the client nous a coupé l'herbe sous le pied
+ Ivy.traceError(Resources.IvyClient, Resources.IvyClientLeft + " " + appName + " " + ex.Message);
+ // connexion close in rare concurrent connexion
+ close(false);
+ }
+ catch (ObjectDisposedException ex)
+ {
+ // the client nous a coupé l'herbe sous le pied
+ Ivy.traceError(Resources.IvyClient, Resources.IvyClientLeft + " " + appName + " " + ex.Message);
+ // invokes the Disconnected applicationListeners
+ //bus.OnClientDisconnected(new IvyEventArgs(this,id, message ));
+ // called by the receiver Thread
+ close(false);
+ }
+ catch (IOException ex)
+ {
+ // the client nous a coupé l'herbe sous le pied
+ Ivy.traceError(Resources.IvyClient, Resources.IvyClientLeft + " " + appName + " " + ex.Message);
+ // invokes the Disconnected applicationListeners
+ //bus.OnClientDisconnected(new IvyEventArgs(this,id, message ));
+ // called by the receiver Thread
+ close(false);
+ }
+
}
/// <summary> returns the name of the remote agent.
@@ -191,7 +209,7 @@ namespace IvyBus
/// <param name='message'>the string that will be match-tested
///
/// </param>
- public void SendDirectMsg(ushort id, string message)
+ public void SendDirectMsg(int id, string message)
{
try
{
@@ -199,7 +217,7 @@ namespace IvyBus
}
catch (IOException ex)
{
- Ivy.traceError("IvyClient","I can't send my message to this client. He probably left "+ex.Message);
+ Ivy.traceError(Resources.IvyClient,Resources.IvyClientLeft+ex.Message);
// first, I'm not a first class IvyClient any more
bus.removeClient(this);
// invokes the Disconnected applicationListeners
@@ -217,19 +235,27 @@ namespace IvyBus
/// </param>
internal void close(bool notify)
{
- Ivy.traceProtocol("IvyClient","closing connexion to " + appName);
- if (doping )
+ Ivy.traceProtocol(Resources.IvyClient,Resources.Closing + appName);
+ if (doping )
{
StopPinging();
}
if (notify)
try
{
- stream.TokenBye(0, "hasta la vista");
+ if (stream != null)
+ stream.TokenBye(0, Resources.ByeMessage);
+ }
+ catch (ObjectDisposedException)
+ {
}
catch (IOException ioe)
{
- throw new IvyException(ioe.Message);
+ if (!(ioe.InnerException is SocketException))
+ throw new IvyException(ioe.Message);
+ if (((SocketException)ioe.InnerException).SocketErrorCode != SocketError.ConnectionReset)
+ throw new IvyException(ioe.Message);
+
}
// stop the thread and close the stream
if (clientThread == null)
@@ -268,36 +294,37 @@ namespace IvyBus
/// <returns>the number of messages sent to the peer
///
/// </returns>
- internal int sendMsg(String message)
+ internal int sendMsg(ushort id, string[] args)
{
int count = 0;
-
- lock( bindings )
+
+
+ try
{
- 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);
- }
+ stream.TokenMsg(id, args);
+ count++;
+ }
+ catch (ObjectDisposedException ex)
+ {
+ Ivy.traceError(Resources.IvyClient, Resources.IvyClientLeft + ex.Message);
+ // first, I'm not a first class IvyClient any more
+ bus.removeClient(this); //TODO trouble in upper loop iter
+ // invokes the Disconnected applicationListeners
+ // in the receiver thread
+ close(false);
+ }
+ catch (IOException ex)
+ {
+ Ivy.traceError(Resources.IvyClient, Resources.IvyClientLeft + ex.Message);
+ // first, I'm not a first class IvyClient any more
+ bus.removeClient(this); //TODO trouble in upper loop iter
+ // invokes the Disconnected applicationListeners
+ // in the receiver thread
+ close(false);
+ }
- }
+
return count;
}
@@ -309,25 +336,28 @@ namespace IvyBus
/// © ® (tm)
///
/// </returns>
- internal bool sameClient(IvyClient clnt)
+ internal bool sameIvyClient(IvyClient clnt)
{
- return (appPort != 0 && appPort == clnt.appPort) && (RemoteAddress == clnt.RemoteAddress);
+ // clientId est null si le protocol n'envoie pas le client ID
+ if (clnt.clientId != null && this.clientId != null && clnt.clientId == this.clientId)
+ return true;
+ return (this.appPort != 0) && (this.appPort == clnt.appPort) && (this.RemoteAddress.Equals(clnt.RemoteAddress));
}
/// <summary> the code of the thread handling the incoming messages.
/// </summary>
private void Run()
{
- Ivy.traceProtocol("IvyClient","Connected from " + RemoteAddress + ":" + RemotePort);
+ Ivy.traceProtocol(Resources.IvyClient, Resources.Connected + RemoteAddress + ":" + RemotePort);
- Ivy.traceProtocol("IvyClient","Thread started");
-
- bool running = true;
+ Ivy.traceProtocol(Resources.IvyClient,"Thread started");
+
+ bool running = true;
while ( running && (stream != null) )
{
try
{
- if ( stream.receiveMsg() )
+ if ( stream.ReceiveMsg() )
{
// early stop during readLine()
if (doping && (pingerThread != null))
@@ -335,26 +365,26 @@ namespace IvyBus
}
else
{
- Ivy.traceProtocol("IvyClient","receiveMsg false ! leaving the thread");
+ Ivy.traceProtocol(Resources.IvyClient, Resources.BadReceive);
running = false;
break;
}
}
catch ( ObjectDisposedException ex )
{
- Ivy.traceError("IvyClient", "socket closed "+ex.Message );
+ Ivy.traceError(Resources.IvyClient, Resources.SocketClosed + ex.Message);
running = false;
break;
}
catch (IvyException ie)
{
- Ivy.traceError("IvyClient","socket closed IvyException" + ie.Message);
+ Ivy.traceError(Resources.IvyClient, Resources.SocketClosed + ie.Message);
running = false;
break;
}
catch (SocketException se)
{
- Ivy.traceError("IvyClient", "socket closed "+se.Message );
+ Ivy.traceError(Resources.IvyClient, Resources.SocketClosed + se.Message );
running = false;
break;
}
@@ -362,21 +392,21 @@ namespace IvyBus
{
if ( ex.InnerException is SocketException )
{
- Ivy.traceProtocol("IvyClient", "socket closed" );
+ Ivy.traceProtocol(Resources.IvyClient, Resources.SocketClosed );
}
else
{
- Ivy.traceError("IvyClient","abnormally Disconnected from " + RemoteAddress + ":" + RemotePort);
+ Ivy.traceError(Resources.IvyClient, Resources.AbDisconnect + RemoteAddress + ":" + RemotePort);
}
running = false;
break;
}
}
- Ivy.traceProtocol("IvyClient","normally Disconnected from " + appName);
- Ivy.traceProtocol("IvyClient","Thread stopped");
+ Ivy.traceProtocol(Resources.IvyClient,Resources.Disconnected + appName);
+ Ivy.traceProtocol(Resources.IvyClient,"Thread stopped");
// invokes the Disconnected applicationListeners
- bus.OnClientDisconnected(new IvyEventArgs(this,0, "" ));
+ bus.OnClientDisconnected(new IvyEventArgs(this,0, string.Empty ));
// first, I'm not a first class IvyClient any more
if (stream != null)
{
@@ -390,14 +420,14 @@ namespace IvyBus
{
// never call in this side
}
- bool IvyProtocol.receiveMsg()
+ bool IvyProtocol.ReceiveMsg()
{
// nerver call in this side
return false;
}
- void IvyProtocol.TokenDie(ushort id, string arg)
+ void IvyProtocol.TokenDie(int id, string arg)
{
- Ivy.traceProtocol("IvyClient","received die Message from " + appName + "Raison: "+ arg);
+ Ivy.traceProtocol(Resources.IvyClient, Resources.DieReceive + appName + Resources.Reason + arg);
// invokes the die applicationListeners
IvyDieEventArgs ev = new IvyDieEventArgs(this, id, arg);
bus.OnDie(ev);
@@ -413,10 +443,10 @@ namespace IvyBus
System.Environment.Exit(0);
#endif
}
- void IvyProtocol.TokenBye(ushort err, string arg)
+ void IvyProtocol.TokenBye(int err, string arg)
{
// the peer quits
- Ivy.traceProtocol("IvyClient","received bye Message from " + appName + "Raison: "+ arg);
+ Ivy.traceProtocol(Resources.IvyClient, Resources.ByeReceive + appName + Resources.Reason + arg);
// first, I'm not a first class IvyClient any more
//bus.removeClient(this); // this is done in the receive thread terminaison!!
// invokes the disconnect applicationListeners
@@ -424,10 +454,10 @@ namespace IvyBus
close(false); // will fire disconnected
}
- void IvyProtocol.TokenAddBinding(BindingType type, ushort id, string expression)
+ void IvyProtocol.TokenAddBinding(BindingType type, int id, string expression)
{
- if (type == BindingType.Regexp && !bus.CheckRegexp(expression))
+ if (type == BindingType.RegularExpression && !bus.CheckRegexp(expression))
{
bus.OnClientFilterBinding(new IvyEventArgs(this, id, expression ));
return;
@@ -437,20 +467,14 @@ namespace IvyBus
{
switch (type)
{
- case BindingType.Regexp:
- bind = new IvyBindingRegexp(id, expression);
+ case BindingType.RegularExpression:
+ bind = new IvyBindingRegexp(expression);
break;
case BindingType.Simple:
- bind = new IvyBindingSimple(id, expression);
+ bind = new IvyBindingSimple(expression);
break;
}
- lock (bindings)
- {
- bindings.Add(id, bind);
- }
-
- bus.OnClientAddBinding(new IvyEventArgs(this, id, expression));
-
+ bus.AddBinding(id, this, bind);
}
catch (ArgumentException ex)
{
@@ -458,81 +482,88 @@ namespace IvyBus
}
}
- void IvyProtocol.TokenDelBinding(ushort id)
+
+
+ void IvyProtocol.TokenDelBinding(int 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);
- }
- }
+ bus.DelBinding(id, this);
}
- void IvyProtocol.TokenMsg(ushort id, string[] args)
+ void IvyProtocol.TokenMsg(int id, string[] args)
{
bus.OnMessage(new IvyMessageEventArgs(this, id, args));
}
- void IvyProtocol.TokenError(ushort id, string arg)
+ void IvyProtocol.TokenError(int 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();
- }
+ Ivy.traceError(Resources.IvyClient,Resources.ErrorReceive + id + " " + arg);
}
+
void IvyProtocol.TokenEndRegexp()
{
+ bus.OnClientConnected(new IvyEventArgs(this, 0, string.Empty));
/*
* the peer is perhaps not ready to handle this message
* an assymetric processing should be written
*/
if (bus.ReadyMessage != null)
- sendMsg(bus.ReadyMessage);
- bus.OnClientConnected(new IvyEventArgs(this, 0, ""));
+ {
+ bus.SendMsgToClient(this, bus.ReadyMessage);
+ }
+
}
- void IvyProtocol.TokenStartRegexp(ushort id, string arg)
+ void IvyProtocol.TokenStartRegexp(int id, string arg)
{
+ //bool bindingToSend = appPort == 0;
appName = arg;
appPort = id;
- if (bus.checkConnected(this))
- {
- close(false);
- throw new IvyException("Rare ! A concurrent connect occured");
- }
+ IvyClient target = this;
+ IvyClient client = bus.checkConnected(this);
+ if (client != null)
+ {
+ // Dilemma choose the rigth client to close
+ // the symetric processing will try to close each other
+ // only one side may be closed
+ //Console.WriteLine(" should close {0} this local {1} rem {2} other local {3} rem {4}", this.appName, this.localPort, this.remotePort, client.localPort, client.remotePort);
+ if (Math.Max(client.localPort, client.remotePort) > Math.Max( this.localPort, this.remotePort ))
+ {
+ target = client;
+ //Console.WriteLine("choose {0} other ports {1},{2}", target.appName, target.localPort, target.remotePort);
+ }
+ else
+ {
+ target = this;
+ //Console.WriteLine("choose {0} this ports {1},{2}", target.appName, target.remotePort, target.localPort);
+ }
+ bus.removeClient(target);
+ target.close(false);
+ //throw new IvyException(Resources.ConcurrentConnect + " " + appName + " " + clientId);
+
+ }
+ //if ( bindingToSend && target != this)
+ // SendBindings();
+
}
- void IvyProtocol.TokenDirectMsg(ushort id, string arg)
+ void IvyProtocol.TokenDirectMsg(int 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 );
+ Ivy.traceProtocol(Resources.IvyClient, Resources.PingReceive + appName + " : " + arg );
stream.TokenPong(arg);
}
void IvyProtocol.TokenPong(string arg)
{
- Ivy.traceProtocol("IvyClient","Ping msg from " + appName + " : " + arg);
+ Ivy.traceProtocol(Resources.IvyClient, Resources.PingReceive + appName + " : " + arg);
}
public override String ToString()
{
- return "IvyClient " + bus.appName + ":" + appName;
+ return Resources.IvyClient+ " " + bus.appName + ":" + appName;
}
/* is the Pinging Thread Runninng */
@@ -541,20 +572,20 @@ namespace IvyBus
private void PingerRun()
{
isPinging = true;
- Ivy.traceProtocol("IvyClient","Pinger Thread started");
+ Ivy.traceProtocol(Resources.IvyClient,Resources.PingerThreadStarted);
while (isPinging)
{
try
{
Thread.Sleep(PINGTIMEOUT);
- stream.TokenPing("are you here ?");
+ stream.TokenPing(Resources.PingerThreadMessage);
}
catch (ThreadAbortException ie)
{
- Ivy.traceError("IvyClient","Pinger Thread killed "+ie.Message);
+ Ivy.traceError(Resources.IvyClient,Resources.PingerThreadKilled + ie.Message);
}
}
- Ivy.traceProtocol("IvyClient","Pinger Thread stopped");
+ Ivy.traceProtocol(Resources.IvyClient,Resources.PingerThreadStopped);
}
public virtual void StopPinging()
{
diff --git a/Ivy/IvyEventArgs.cs b/Ivy/IvyEventArgs.cs
index e394802..a08f314 100644
--- a/Ivy/IvyEventArgs.cs
+++ b/Ivy/IvyEventArgs.cs
@@ -1,9 +1,11 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
namespace IvyBus
{
+ using System;
+ using System.Collections.Generic;
+ using System.Text;
+ using System.Collections.ObjectModel;
+
/// <summary> The EventArgs Classes
/// </summary>
///
@@ -66,13 +68,13 @@ namespace IvyBus
get { return id; }
}
- public string[] Arguments
+ public string[] GetArguments()
{
- get { return args; }
+ return (string[])args.Clone();
}
- public string this[int i]
+ public string this[int index]
{
- get { return args[i]; }
+ get { return args[index]; }
}
public IvyMessageEventArgs(IvyClient app, int id, string[] args)
{
diff --git a/Ivy/IvyException.cs b/Ivy/IvyException.cs
index 90a91b8..2bdf066 100644
--- a/Ivy/IvyException.cs
+++ b/Ivy/IvyException.cs
@@ -5,14 +5,30 @@
/// *
namespace IvyBus
{
- using System;
-
+ using System;
+ using System.Runtime.Serialization;
+
/// <summary> signals that an unrecoverrable Ivy exception has occured.
/// </summary>
-
- public class IvyException:System.Exception
+ [Serializable]
+ public class IvyException : System.Exception
{
- public IvyException(System.String s):base(s)
+ public IvyException()
+ : base()
+ {
+ }
+
+ protected IvyException(SerializationInfo info, StreamingContext context)
+ : base(info, context)
+ {
+ }
+
+ public IvyException(string message, Exception exp)
+ : base(message,exp)
+ {
+ }
+
+ public IvyException(string message) : base(message)
{
}
}
diff --git a/Ivy/IvyProtocol.cs b/Ivy/IvyProtocol.cs
index 1b1f3aa..6c276e3 100644
--- a/Ivy/IvyProtocol.cs
+++ b/Ivy/IvyProtocol.cs
@@ -1,25 +1,28 @@
-using System;
-using System.Text;
namespace IvyBus
{
- public enum BindingType { Regexp, Simple };
+ using System;
+ using System.Text;
+
+ public enum BindingType
+ {
+ RegularExpression, Simple
+ }
internal interface IvyProtocol
{
void Close();
- bool receiveMsg();
- void TokenStartRegexp(ushort port, string appName);
+ bool ReceiveMsg();
+ void TokenStartRegexp(int 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 TokenAddBinding(BindingType type, int id, string expression);
+ void TokenDelBinding(int bind);
+ void TokenDirectMsg(int 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);
+ void TokenBye(int id, string message);
+ void TokenDie(int err, string message);
+ void TokenMsg(int key, string[] args);
+ void TokenError(int id, string message);
}
}
diff --git a/Ivy/IvyTCPStreamV3.cs b/Ivy/IvyTCPStreamV3.cs
index 594f9de..7f90a94 100644
--- a/Ivy/IvyTCPStreamV3.cs
+++ b/Ivy/IvyTCPStreamV3.cs
@@ -1,36 +1,45 @@
-using System;
-using System.Net;
-using System.Net.Sockets;
-using System.Text;
-using System.Collections;
-using System.Collections.Specialized;
-using System.IO;
namespace IvyBus
{
+ using System;
+ using System.Net;
+ using System.Net.Sockets;
+ using System.Text;
+ using System.Collections;
+ using System.Collections.Specialized;
+ using System.IO;
+ using IvyBus.Properties;
+
/// <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 const char ArgStart = '\x02';
+ internal const char ArgEnd = '\x03';
+ internal const char MsgEnd = '\n';
+
+ private StreamReader input;
+ private StreamWriter output;
+ private IvyProtocol receiver;
- internal IvyTCPStreamV3(Socket socket, IvyProtocol _receiver) : base ( socket )
+ internal IvyTCPStreamV3(Socket socket, IvyProtocol receiver) : base(socket)
{
- output = new StreamWriter(this, Ivy.ivyEncoding);
- output.NewLine = MSG_END.ToString();
- input = new StreamReader(this, Ivy.ivyEncoding);
- receiver = _receiver;
+ this.output = new StreamWriter(this, Ivy.ivyEncoding);
+ this.output.NewLine = MsgEnd.ToString();
+ this.input = new StreamReader(this, Ivy.ivyEncoding);
+ this.receiver = receiver;
}
+ internal void Close()
+ {
+ this.input.Close();
+ this.output.Close();
+ base.Close();
+ }
+
/* the protocol magic numbers */
- internal enum MessageType : ushort
+ internal enum MessageType : int
{
Bye = 0, /* end of the peer */
AddRegexp = 1, /* the peer adds a regexp */
@@ -43,7 +52,7 @@ namespace IvyBus
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:
@@ -53,37 +62,37 @@ namespace IvyBus
MessageType, id , length, string
*/
- private void sendMsg(MessageType msgType, ushort msgId, string msgData)
+ private void SendMsg(MessageType msgType, int 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();
-
+ lock (this.output)
+ {
+ this.output.Write((int)msgType);
+ this.output.Write(' ');
+ this.output.Write(msgId);
+ this.output.Write(ArgStart);
+ this.output.Write(msgData);
+ this.output.Write(MsgEnd);
+ this.output.Flush();
+ }
}
- void IvyProtocol.TokenStartRegexp(ushort port, string appName)
+
+ void IvyProtocol.TokenStartRegexp(int port, string appName)
{
- sendMsg(MessageType.StartRegexp, port, appName);
+ this.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
+ this.SendMsg(MessageType.EndRegexp, 0, string.Empty);
}
- void IvyProtocol.TokenAddBinding(BindingType type, ushort id, string expression)
+ void IvyProtocol.TokenAddBinding(BindingType type, int id, string expression)
{
switch (type)
{
- case BindingType.Regexp:
- sendMsg(MessageType.AddRegexp, id, expression); /* perhaps we should perform some checking here */
+ case BindingType.RegularExpression:
+ this.SendMsg(MessageType.AddRegexp, id, expression); /* perhaps we should perform some checking here */
break;
case BindingType.Simple:
// NO Simple Binding in this protocol
@@ -91,66 +100,69 @@ namespace IvyBus
}
}
- void IvyProtocol.TokenDelBinding(ushort id)
+ void IvyProtocol.TokenDelBinding(int id)
{
- sendMsg(MessageType.DelBinding, id, "");
+ this.SendMsg(MessageType.DelBinding, id, string.Empty);
}
- void IvyProtocol.TokenDirectMsg(ushort id, string message)
+ void IvyProtocol.TokenDirectMsg(int id, string message)
{
- sendMsg(MessageType.DirectMsg, id, message);
+ this.SendMsg(MessageType.DirectMsg, id, message);
}
+
void IvyProtocol.TokenPong(string s)
{
- sendMsg(MessageType.Pong, 0, s);
+ this.SendMsg(MessageType.Pong, 0, s);
}
+
void IvyProtocol.TokenPing(string s)
{
- sendMsg(MessageType.Ping, 0, s);
+ this.SendMsg(MessageType.Ping, 0, s);
}
- void IvyProtocol.TokenBye(ushort id, string message)
+ void IvyProtocol.TokenBye(int id, string message)
{
- sendMsg(MessageType.Bye, id, message);
+ this.SendMsg(MessageType.Bye, id, message);
}
- void IvyProtocol.TokenDie(ushort id, string message)
+ void IvyProtocol.TokenDie(int id, string message)
{
- sendMsg(MessageType.Die, id, message);
+ this.SendMsg(MessageType.Die, id, message);
}
- void IvyProtocol.TokenMsg(ushort key, string[] args)
+ void IvyProtocol.TokenMsg(int key, string[] args)
{
- string delimiter = "" + ARG_END;
+ string delimiter = string.Empty + ArgEnd;
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);
+ this.SendMsg(MessageType.Msg, key, data);
}
- void IvyProtocol.TokenError(ushort key, string arg)
+ void IvyProtocol.TokenError(int key, string arg)
{
- sendMsg(MessageType.Msg, key, arg);
+ this.SendMsg(MessageType.Msg, key, arg);
}
- private ushort DeserializeShort()
+ private int DeserializeInt()
{
int read;
- ushort ret = 0;
+ int ret = 0;
char digit;
// this will eat next non digit char ie space
do
{
- read = input.Read();
+ read = this.input.Read();
if (read < 0)
throw new EndOfStreamException();
digit = (char)read;
if (Char.IsDigit(digit))
- ret = (ushort)(ret * 10 + (digit - 0x30));
+ ret = (int)(ret * 10 + (digit - 0x30));
} while (Char.IsDigit(digit));
return ret;
}
+
private string DeserializeString(char sep)
{
int read;
@@ -168,38 +180,38 @@ namespace IvyBus
return str.ToString();
}
- bool IvyProtocol.receiveMsg()
+ bool IvyProtocol.ReceiveMsg()
{
MessageType msgType = MessageType.Die;
- ushort msgId = 0;
+ int msgId = 0;
string msgData = null;
try
{
- msgType = (MessageType)DeserializeShort();
- msgId = DeserializeShort();
- msgData = DeserializeString(MSG_END);
+ msgType = (MessageType)DeserializeInt();
+ msgId = DeserializeInt();
+ msgData = DeserializeString(MsgEnd);
switch (msgType)
{
case MessageType.Die:
- receiver.TokenDie(msgId, msgData);
+ this.receiver.TokenDie(msgId, msgData);
break;
case MessageType.Bye:
- receiver.TokenBye(msgId, msgData);
+ this.receiver.TokenBye(msgId, msgData);
break;
- case MessageType.AddRegexp:
- receiver.TokenAddBinding(BindingType.Regexp, msgId, msgData);
+ case MessageType.AddRegexp:
+ this.receiver.TokenAddBinding(BindingType.RegularExpression, msgId, msgData);
break;
case MessageType.DelBinding:
- receiver.TokenDelBinding(msgId);
+ this.receiver.TokenDelBinding(msgId);
break;
case MessageType.EndRegexp:
- receiver.TokenEndRegexp();
+ this.receiver.TokenEndRegexp();
break;
case MessageType.Msg:
@@ -207,30 +219,30 @@ namespace IvyBus
// 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 ));
+ this.receiver.TokenMsg(msgId, msgData.Split( ArgEnd ));
break;
case MessageType.Pong:
- receiver.TokenPong(msgData);
+ this.receiver.TokenPong(msgData);
break;
case MessageType.Ping:
- receiver.TokenPing(msgData);
+ this.receiver.TokenPing(msgData);
break;
case MessageType.Error:
- receiver.TokenError(msgId, msgData);
+ this.receiver.TokenError(msgId, msgData);
break;
case MessageType.StartRegexp:
- receiver.TokenStartRegexp(msgId, msgData);
+ this.receiver.TokenStartRegexp(msgId, msgData);
break;
case MessageType.DirectMsg:
- receiver.TokenDirectMsg(msgId, msgData);
+ this.receiver.TokenDirectMsg(msgId, msgData);
break;
default:
- throw new IvyException("protocol error, unknown message type " + msgType);
+ throw new IvyException(Resources.UnknownMessage + msgType);
}
@@ -243,7 +255,7 @@ namespace IvyBus
}
catch (FormatException)
{
- throw new IvyException("protocol error on msgType");
+ throw new IvyException(Resources.ProtocolError);
}
diff --git a/Ivy/IvyTCPStreamV4.cs b/Ivy/IvyTCPStreamV4.cs
index d477908..2b1640a 100644
--- a/Ivy/IvyTCPStreamV4.cs
+++ b/Ivy/IvyTCPStreamV4.cs
@@ -1,17 +1,20 @@
-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>
+ using System;
+ using System.Net;
+ using System.Net.Sockets;
+ using System.Text;
+ using System.Collections;
+ using System.Collections.Specialized;
+ using System.IO;
+ using IvyBus.Properties;
+
+ /// <summary>
/// Description résumée de IvyStream.
/// </summary>
- internal class IvyTCPStreamV4 : NetworkStream , IvyProtocol
+ internal class IvyTCPStreamV4 : NetworkStream, IvyProtocol
{
BinaryReader input;
BinaryWriter output;
@@ -31,19 +34,24 @@ namespace IvyBus
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 */
+ AddBinding = 11, /* other methods for binding message based on hash table */
};
internal IvyTCPStreamV4(Socket socket, IvyProtocol _receiver) : base( socket )
{
- input = new BinaryReader(this, Ivy.ivyEncoding );
- output = new BinaryWriter(this, Ivy.ivyEncoding );
- receiver = _receiver;
+ this.input = new BinaryReader(this, Ivy.ivyEncoding);
+ this.output = new BinaryWriter(this, Ivy.ivyEncoding);
+ this.receiver = _receiver;
}
+ internal void Close()
+ {
+ this.input.Close();
+ this.output.Close();
+ base.Close();
+ }
/*
* message Syntax:
@@ -52,9 +60,9 @@ namespace IvyBus
* message Format:
MessageType, id , length, string
*/
- private void Serialize(short arg)
+ private void Serialize(int arg)
{
- output.Write((ushort)IPAddress.HostToNetworkOrder(arg));
+ output.Write((short)IPAddress.HostToNetworkOrder(arg));
}
private void Serialize(string arg)
{
@@ -67,7 +75,7 @@ namespace IvyBus
{
/* serialize count */
- Serialize((short)arg.Length);
+ Serialize(arg.Length);
for (int i = 0; i < arg.Length; i++)
{
@@ -76,31 +84,29 @@ namespace IvyBus
}
private void sendMsg(MessageType type, int id, params string[] arg)
{
-
- Serialize( (short)type );
- Serialize( (short)id );
- Serialize(arg);
- output.Flush();
-
+ lock (this.output)
+ {
+ Serialize((int)type);
+ Serialize(id);
+ Serialize(arg);
+ output.Flush();
+ }
}
- void IvyProtocol.TokenStartRegexp(ushort port, string appName)
+ void IvyProtocol.TokenStartRegexp(int 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);
+ sendMsg(MessageType.EndRegexp, 0, string.Empty);
}
+
- void IvyProtocol.TokenAddBinding(BindingType type, ushort id, string expression)
+ void IvyProtocol.TokenAddBinding(BindingType type, int id, string expression)
{
switch (type)
{
- case BindingType.Regexp:
+ case BindingType.RegularExpression:
sendMsg(MessageType.AddRegexp, id, expression); /* perhaps we should perform some checking here */
break;
case BindingType.Simple:
@@ -109,12 +115,12 @@ namespace IvyBus
}
}
- void IvyProtocol.TokenDelBinding(ushort id)
+ void IvyProtocol.TokenDelBinding(int id)
{
sendMsg(MessageType.DelBinding, id, null );
}
- void IvyProtocol.TokenDirectMsg(ushort id, string message)
+ void IvyProtocol.TokenDirectMsg(int id, string message)
{
sendMsg(MessageType.DirectMsg, id, message);
}
@@ -127,43 +133,43 @@ namespace IvyBus
sendMsg(MessageType.Ping, 0, s);
}
- void IvyProtocol.TokenBye(ushort id, string message)
+ void IvyProtocol.TokenBye(int id, string message)
{
sendMsg(MessageType.Bye, id, message);
}
- void IvyProtocol.TokenDie(ushort id, string message)
+ void IvyProtocol.TokenDie(int id, string message)
{
sendMsg(MessageType.Die, id, message);
}
- void IvyProtocol.TokenMsg(ushort key, string[] args)
+ void IvyProtocol.TokenMsg(int key, string[] args)
{
sendMsg(MessageType.Msg, key, args );
}
- void IvyProtocol.TokenError(ushort key, string arg)
+ void IvyProtocol.TokenError(int key, string arg)
{
sendMsg(MessageType.Msg, key, arg);
}
- private short DeserializeShort()
+ private int DeserializeInt()
{
- return IPAddress.NetworkToHostOrder((short)input.ReadUInt16());
+ return IPAddress.NetworkToHostOrder((short)input.ReadInt16());
}
private string DeserializeString()
{
string arg;
int val_len;
char[] data;
- val_len = (ushort)DeserializeShort();
+ val_len = DeserializeInt();
if (val_len != 0)
{
data = input.ReadChars(val_len);
arg = new String(data);
}
else
- arg = "";
+ arg = string.Empty;
return arg;
}
@@ -174,7 +180,7 @@ namespace IvyBus
string[] arg;
/* Deserialize childrens */
- nb_children = (ushort)DeserializeShort();
+ nb_children = DeserializeInt();
/* deserialize Value */
arg = new string[nb_children];
@@ -184,16 +190,16 @@ namespace IvyBus
}
return arg;
}
- bool IvyProtocol.receiveMsg()
+ bool IvyProtocol.ReceiveMsg()
{
MessageType msgType = MessageType.Die;
- ushort msgId = 0;
+ int msgId = 0;
string[] msgData = null;
try
{
- msgType = (MessageType)(ushort)DeserializeShort();
- msgId = (ushort)DeserializeShort();
+ msgType = (MessageType)DeserializeInt();
+ msgId = DeserializeInt();
msgData = DeserializeArgument();
switch (msgType)
@@ -207,7 +213,7 @@ namespace IvyBus
break;
case MessageType.AddRegexp:
- receiver.TokenAddBinding(BindingType.Regexp, msgId, msgData[0]);
+ receiver.TokenAddBinding(BindingType.RegularExpression, msgId, msgData[0]);
break;
case MessageType.AddBinding:
@@ -245,11 +251,8 @@ namespace IvyBus
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);
+ throw new IvyException(Resources.UnknownMessage + msgType);
}
@@ -262,7 +265,7 @@ namespace IvyBus
}
catch (FormatException)
{
- throw new IvyException("protocol error on msgType");
+ throw new IvyException(Resources.ProtocolError);
}
diff --git a/Ivy/IvyUDPStream.cs b/Ivy/IvyUDPStream.cs
index 0e3f517..986a550 100644
--- a/Ivy/IvyUDPStream.cs
+++ b/Ivy/IvyUDPStream.cs
@@ -1,34 +1,34 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-using System.Net;
-using System.Net.Sockets;
-using System.IO;
namespace IvyBus
{
- abstract class IvyUDPStream
+ using System;
+ using System.Collections.Generic;
+ using System.Text;
+ using System.Net;
+ using System.Net.Sockets;
+ using System.IO;
+
+ abstract class IvyUDPStream: IDisposable
{
- Socket socket;
- byte[] buffer;
-
protected MemoryStream out_stream;
protected MemoryStream in_stream;
+ private Socket socket;
+ private byte[] buffer;
+
+ private int protocolVersion;
- ushort protocol_version;
-
- public ushort ProtocolVersion
+ public int ProtocolVersion
{
- get { return protocol_version; }
+ get { return protocolVersion; }
}
- public IvyUDPStream(Socket _socket, ushort protocol)
+ public IvyUDPStream(Socket _socket, int protocol)
{
socket = _socket;
buffer = new byte[4096];
in_stream = new MemoryStream(buffer);
out_stream = new MemoryStream();
- protocol_version = protocol;
+ protocolVersion = protocol;
}
internal void Close()
{
@@ -37,7 +37,7 @@ namespace IvyBus
socket.Shutdown(SocketShutdown.Both);
socket.Close();
}
- internal void receiveMsg(out IPEndPoint remote, out ushort version, out ushort port, out string appId, out string appName)
+ internal void receiveMsg(out IPEndPoint remote, out int version, out int port, out string appId, out string appName)
{
int len;
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, 0);
@@ -51,7 +51,7 @@ namespace IvyBus
//Call Deserialization
Deserialize( out version, out port, out appId, out appName );
}
- internal void sendMsg(IPEndPoint EPhost, ushort port, string appId, string appName)
+ internal void sendMsg(IPEndPoint EPhost, int port, string appId, string appName)
{
// Call Serialisation
Serialize(port, appId, appName);
@@ -59,8 +59,38 @@ namespace IvyBus
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);
-
+ abstract internal void Serialize(int port, string appId, string appName);
+ abstract internal void Deserialize(out int version, out int port, out string appId, out string appName);
+
+
+ #region IDisposable Membres
+
+ //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 (out_stream != null)
+ {
+ out_stream.Close();
+ out_stream = null;
+ }
+ if (in_stream != null)
+ {
+ in_stream.Close();
+ in_stream = null;
+ }
+ }
+ #endregion
}
}
diff --git a/Ivy/IvyUDPStreamV3.cs b/Ivy/IvyUDPStreamV3.cs
index 8f48f3b..a47ad3f 100644
--- a/Ivy/IvyUDPStreamV3.cs
+++ b/Ivy/IvyUDPStreamV3.cs
@@ -1,12 +1,13 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-using System.Net;
-using System.Net.Sockets;
-using System.IO;
namespace IvyBus
{
+ using System;
+ using System.Collections.Generic;
+ using System.Text;
+ using System.Net;
+ using System.Net.Sockets;
+ using System.IO;
+
class IvyUDPStreamV3 : IvyUDPStream
{
StreamReader input;
@@ -27,7 +28,7 @@ namespace IvyBus
* message Format:
protocol_version, TCP server port , appId, appName
*/
- private ushort DeserializeShort()
+ private int DeserializeInt()
{
int read;
ushort ret = 0;
@@ -63,15 +64,15 @@ namespace IvyBus
return str.ToString();
}
- internal override void Deserialize(out ushort version, out ushort port, out string appId, out string appName)
+ internal override void Deserialize(out int version, out int port, out string appId, out string appName)
{
version = 0;
port = 0;
- appId = "";
- appName = "";
+ appId = string.Empty;
+ appName = string.Empty;
try {
- version = DeserializeShort();
- port = DeserializeShort();
+ version = DeserializeInt();
+ port = DeserializeInt();
//Optionel in V3 protocol depend on client version
appId = DeserializeString(' ');
appName = DeserializeString('\n');
@@ -82,7 +83,7 @@ namespace IvyBus
}
input.DiscardBufferedData();
}
- private void Serialize(ushort arg, char sep)
+ private void Serialize(int arg, char sep)
{
output.Write(arg);
output.Write(sep);
@@ -92,7 +93,7 @@ namespace IvyBus
output.Write(arg);
output.Write(sep);
}
- internal override void Serialize(ushort port, string appId, string appName)
+ internal override void Serialize(int port, string appId, string appName)
{
Serialize(PROCOCOLVERSION, ' ');
Serialize(port,' ');
diff --git a/Ivy/IvyUDPStreamV4.cs b/Ivy/IvyUDPStreamV4.cs
index 4f0a8fc..4cd5cee 100644
--- a/Ivy/IvyUDPStreamV4.cs
+++ b/Ivy/IvyUDPStreamV4.cs
@@ -27,37 +27,37 @@ namespace IvyBus
* message Format:
protocol_version, TCP server port , lenAppId, appId, lenAppNameId, appName
*/
- private ushort DeserializeShort()
+ private int DeserializeInt()
{
- return (ushort)IPAddress.NetworkToHostOrder((ushort)input.ReadUInt16());
+ return IPAddress.NetworkToHostOrder((short)input.ReadInt16());
}
private string DeserializeString()
{
string arg;
int val_len;
char[] data;
- val_len = (ushort)IPAddress.NetworkToHostOrder((ushort)input.ReadUInt16());
+ val_len = DeserializeInt();
if (val_len != 0)
{
data = input.ReadChars(val_len);
arg = new String(data);
}
else
- arg = "";
+ arg = string.Empty;
return arg;
}
- internal override void Deserialize(out ushort version, out ushort port, out string appId, out string appName)
+ internal override void Deserialize(out int version, out int port, out string appId, out string appName)
{
- version = DeserializeShort();
- port = DeserializeShort();
+ version = DeserializeInt();
+ port = DeserializeInt();
appId = DeserializeString();
appName = DeserializeString();
}
- private void Serialize(ushort arg)
+ private void Serialize(int arg)
{
- output.Write((ushort)IPAddress.HostToNetworkOrder(arg));
+ output.Write((short)IPAddress.HostToNetworkOrder(arg));
}
private void Serialize(string arg)
{
@@ -67,7 +67,7 @@ namespace IvyBus
output.Write(arg.ToCharArray());
}
- internal override void Serialize(ushort port, string appId, string appName)
+ internal override void Serialize(int port, string appId, string appName)
{
Serialize(PROCOCOLVERSION );
Serialize(port);
diff --git a/Ivy/IvyWatcher.cs b/Ivy/IvyWatcher.cs
index 5a3afc8..b985ada 100644
--- a/Ivy/IvyWatcher.cs
+++ b/Ivy/IvyWatcher.cs
@@ -16,6 +16,7 @@ namespace IvyBus
using System.Configuration;
using System.Text;
using System.Diagnostics;
+ using IvyBus.Properties;
/// <summary> IvyWatcher, A private Class for the Ivy rendezvous
/// </summary>
@@ -25,7 +26,7 @@ namespace IvyBus
/// that the broadcast is done using the same socket, which is not a good
/// thing.
/// </remarks>
- internal class IvyWatcher
+ internal class IvyWatcher: IDisposable
{
private Ivy bus; /* master bus controler */
private int port;
@@ -43,6 +44,7 @@ namespace IvyBus
/// </param>
internal IvyWatcher(Ivy bus, String domainaddr, int port)
{
+ int multicast_ttl = 64; // region
this.bus = bus;
this.port = port;
listenThread = new Thread(new ThreadStart(this.Run));
@@ -59,11 +61,13 @@ namespace IvyBus
broadcast.Bind(EPhost);
//test isMulticastAddress // TODO better check
- //if ( group.IsIPv6Multicast ) yes but in IPV4 how to do
+ //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 ));
+ broadcast.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, multicast_ttl);
+ broadcast.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(group));
+
}
// TODO support the Two protocol
if (bus.protocolVersion == 4)
@@ -73,7 +77,7 @@ namespace IvyBus
}
catch (IOException e)
{
- throw new IvyException("IvyWatcher I/O error" + e);
+ throw new IvyException(Resources.WatcherIOError + e);
}
}
@@ -81,15 +85,15 @@ namespace IvyBus
/// </summary>
public void Run()
{
- Ivy.traceProtocol("IvyWatcher", "beginning of a watcher Thread");
-
- try
- {
- bool running = true;
- while (running)
- {
- ushort version;
- ushort appPort;
+ Ivy.traceProtocol(Resources.IvyWatcher, "beginning of a watcher Thread");
+
+ try
+ {
+ bool running = true;
+ while (running)
+ {
+ int version;
+ int appPort;
string appId;
string appName;
IPEndPoint remoteEP;
@@ -97,26 +101,26 @@ namespace IvyBus
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);
-
+ Ivy.traceProtocol(Resources.IvyWatcher, Resources.WatcherReceive + 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);
+ Ivy.traceError(Resources.IvyWatcher, Resources.BadVersion + version + " expected " + stream.ProtocolVersion);
continue;
}
- // filtrage des self Broadcast
+ /* check if we received our own message. SHOULD ALSO TEST THE HOST */
if (appId == bus.AppId)
continue;
if ((appPort == bus.applicationPort) && (remotehost.Equals(bus.applicationHost)))
continue;
- Ivy.traceProtocol("IvyWatcher", "reponse au Broadcast de " + Dns.GetHostEntry(remotehost).HostName + ":" + remoteEP.Port + " port " + appPort +
+ Ivy.traceProtocol(Resources.IvyWatcher, "reponse au Broadcast de " + Dns.GetHostEntry(remotehost).HostName + ":" + remoteEP.Port + " port " + appPort +
" version " + version +
" id " + appId +
- " name " + appName);
+ " name " + appName);
try
{
@@ -124,24 +128,29 @@ namespace IvyBus
IPEndPoint hostEndPoint = new IPEndPoint(remoteEP.Address, appPort);
socket.Blocking = true;
socket.Connect(hostEndPoint);
- bus.addClient(socket, appName);
+ IvyClient client = new IvyClient(this.bus, socket, appName, appPort);
+ client.SendBindings();
}
- catch (Exception e)
+ catch (SocketException e)
{
- Ivy.traceError("IvyWatcher","can't connect to " + remotehost + " port " + appPort + " \n" + e.Message);
+ Ivy.traceError(Resources.IvyWatcher, Resources.WatcherConnectError + 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");
+
+ } // while
+ }
+ catch (ObjectDisposedException ex)
+ {
+ Ivy.traceError(Resources.IvyWatcher, Resources.WatcherSocketClosed + ex.Message);
+ }
+ catch (SocketException se)
+ {
+ Ivy.traceError(Resources.IvyWatcher, Resources.WatcherSocketClosed + se.Message);
+ }
+ catch (IOException ioe)
+ {
+ Ivy.traceError(Resources.IvyWatcher, Resources.WatcherIOException + ioe.Message);
+ }
+ Ivy.traceProtocol(Resources.IvyWatcher, "end of a watcher thread");
}
/// <summary> stops the thread waiting on the broadcast socket
@@ -150,7 +159,7 @@ namespace IvyBus
{
lock (stream)
{
- Ivy.traceProtocol("IvyWatcher", "begining stopping an IvyWatcher");
+ Ivy.traceProtocol(Resources.IvyWatcher, "begining stopping an IvyWatcher");
stream.Close();
if (listenThread != null)
{
@@ -160,7 +169,7 @@ namespace IvyBus
listenThread = null;
}
// it might not even have been created
- Ivy.traceProtocol("IvyWatcher", "ending stopping an IvyWatcher");
+ Ivy.traceProtocol(Resources.IvyWatcher, "ending stopping an IvyWatcher");
}
}
@@ -174,6 +183,30 @@ namespace IvyBus
}
}
-
- }
+
+ #region IDisposable Membres
+
+ 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;
+ }
+ }
+
+ #endregion
+ }
} \ No newline at end of file
diff --git a/Ivy/Properties/AssemblyInfo.cs b/Ivy/Properties/AssemblyInfo.cs
index 96176ce..79c0aa6 100644
--- a/Ivy/Properties/AssemblyInfo.cs
+++ b/Ivy/Properties/AssemblyInfo.cs
@@ -1,6 +1,7 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
+using System.Resources;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
@@ -10,7 +11,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyDescription("Dll de communications sur le bus IVY")]
[assembly: AssemblyCompany("DTI/R&D PII")]
[assembly: AssemblyProduct("Ivy")]
-[assembly: AssemblyCopyright("SDER")]
+[assembly: AssemblyCopyright("DTI/R&D")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
@@ -25,7 +26,7 @@ using System.Runtime.InteropServices;
// 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.*")]
+[assembly: AssemblyVersion("2.2.*")]
//
// In order to sign your assembly you must specify a key to use. Refer to the
@@ -60,3 +61,4 @@ using System.Runtime.InteropServices;
[assembly: ComVisibleAttribute(false)]
+[assembly: NeutralResourcesLanguageAttribute("en")]
diff --git a/Ivy/Properties/Settings.Designer.cs b/Ivy/Properties/Settings.Designer.cs
index 3356385..6e12b49 100644
--- a/Ivy/Properties/Settings.Designer.cs
+++ b/Ivy/Properties/Settings.Designer.cs
@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// Ce code a été généré par un outil.
-// Version du runtime :2.0.50727.312
+// Version du runtime :2.0.50727.1434
//
// Les modifications apportées à ce fichier peuvent provoquer un comportement incorrect et seront perdues si
// le code est régénéré.
@@ -12,7 +12,7 @@ namespace IvyBus.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
- [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "8.0.0.0")]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "9.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));