summaryrefslogtreecommitdiff
path: root/Ivy/IvyClient.cs
diff options
context:
space:
mode:
authorfcolin2008-08-22 16:44:01 +0000
committerfcolin2008-08-22 16:44:01 +0000
commit8d10e8bbd1e19adc7c70e1101dbb69c213c910dd (patch)
treef41034ab66b1b3174277b07c8aa45791dadbaae8 /Ivy/IvyClient.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/IvyClient.cs')
-rw-r--r--Ivy/IvyClient.cs373
1 files changed, 202 insertions, 171 deletions
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()
{