summaryrefslogtreecommitdiff
path: root/Ivy/Ivy.cs
diff options
context:
space:
mode:
authorfcolin2008-08-22 16:44:01 +0000
committerfcolin2008-08-22 16:44:01 +0000
commit8d10e8bbd1e19adc7c70e1101dbb69c213c910dd (patch)
treef41034ab66b1b3174277b07c8aa45791dadbaae8 /Ivy/Ivy.cs
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/Ivy.cs')
-rw-r--r--Ivy/Ivy.cs556
1 files changed, 386 insertions, 170 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+");
}
}