using System; using System.Net; using System.Net.Sockets; using System.Text; using System.Collections; using System.Collections.Specialized; using System.IO; namespace IvyBus { /// /// Description résumée de IvyStream. /// internal class IvyTCPStreamV4 : NetworkStream , IvyProtocol { BinaryReader input; BinaryWriter output; IvyProtocol receiver; /* the protocol magic numbers */ internal enum MessageType : ushort { Bye = 0, /* end of the peer */ AddRegexp = 1, /* the peer adds a regexp */ Msg = 2, /* the peer sends a message */ Error = 3, /* error message */ DelBinding = 4, /* the peer removes one of his regex */ // OLD DelRegexp rename to DelBinding EndRegexp = 5, /* no more regexp in the handshake */ StartRegexp = 6, /* avoid race condition in concurrent connexions */ DirectMsg = 7, /* the peer sends a direct message */ Die = 8, /* the peer wants us to quit */ Ping = 9, /* checks the presence of the other */ Pong = 10, /* checks the presence of the other */ ApplicationId = 11, /* on start send my ID and priority */ AddBinding = 12, /* other methods for binding message based on hash table */ }; internal IvyTCPStreamV4(Socket socket, IvyProtocol _receiver) : base( socket ) { input = new BinaryReader(this, Ivy.ivyEncoding ); output = new BinaryWriter(this, Ivy.ivyEncoding ); receiver = _receiver; } /* * message Syntax: * this is a binary formated message use of network representation * * message Format: MessageType, id , length, string */ private void Serialize(short arg) { output.Write((ushort)IPAddress.HostToNetworkOrder(arg)); } private void Serialize(string arg) { short length = arg != null ? (short)arg.Length : (short)0; Serialize(length); if (length != 0) output.Write(arg.ToCharArray()); } private void Serialize(string[] arg) { /* serialize count */ Serialize((short)arg.Length); for (int i = 0; i < arg.Length; i++) { Serialize(arg[i]); } } private void sendMsg(MessageType type, int id, params string[] arg) { Serialize( (short)type ); Serialize( (short)id ); Serialize(arg); output.Flush(); } void IvyProtocol.TokenStartRegexp(ushort port, string appName) { sendMsg(MessageType.StartRegexp, port, appName); } void IvyProtocol.TokenEndRegexp() { sendMsg(MessageType.EndRegexp, 0, ""); } void IvyProtocol.TokenApplicationId(ushort priority, string appId) { sendMsg(MessageType.ApplicationId, priority, appId); } void IvyProtocol.TokenAddBinding(BindingType type, ushort id, string expression) { switch (type) { case BindingType.Regexp: sendMsg(MessageType.AddRegexp, id, expression); /* perhaps we should perform some checking here */ break; case BindingType.Simple: sendMsg(MessageType.AddBinding, id, expression); /* perhaps we should perform some checking here */ break; } } void IvyProtocol.TokenDelBinding(ushort id) { sendMsg(MessageType.DelBinding, id, null ); } void IvyProtocol.TokenDirectMsg(ushort id, string message) { sendMsg(MessageType.DirectMsg, id, message); } void IvyProtocol.TokenPong(string s) { sendMsg(MessageType.Pong, 0, s); } void IvyProtocol.TokenPing(string s) { sendMsg(MessageType.Ping, 0, s); } void IvyProtocol.TokenBye(ushort id, string message) { sendMsg(MessageType.Bye, id, message); } void IvyProtocol.TokenDie(ushort id, string message) { sendMsg(MessageType.Die, id, message); } void IvyProtocol.TokenMsg(ushort key, string[] args) { sendMsg(MessageType.Msg, key, args ); } void IvyProtocol.TokenError(ushort key, string arg) { sendMsg(MessageType.Msg, key, arg); } private short DeserializeShort() { return IPAddress.NetworkToHostOrder((short)input.ReadUInt16()); } private string DeserializeString() { string arg; int val_len; char[] data; val_len = (ushort)DeserializeShort(); if (val_len != 0) { data = input.ReadChars(val_len); arg = new String(data); } else arg = ""; return arg; } private string[] DeserializeArgument() { int nb_children; string[] arg; /* Deserialize childrens */ nb_children = (ushort)DeserializeShort(); /* deserialize Value */ arg = new string[nb_children]; for (int i = 0; i < nb_children; i++) { arg[i] = DeserializeString(); } return arg; } bool IvyProtocol.receiveMsg() { MessageType msgType = MessageType.Die; ushort msgId = 0; string[] msgData = null; try { msgType = (MessageType)(ushort)DeserializeShort(); msgId = (ushort)DeserializeShort(); msgData = DeserializeArgument(); switch (msgType) { case MessageType.Die: receiver.TokenDie(msgId, msgData[0]); break; case MessageType.Bye: receiver.TokenBye(msgId, msgData[0]); break; case MessageType.AddRegexp: receiver.TokenAddBinding(BindingType.Regexp, msgId, msgData[0]); break; case MessageType.AddBinding: receiver.TokenAddBinding(BindingType.Simple, msgId, msgData[0]); break; case MessageType.DelBinding: receiver.TokenDelBinding(msgId); break; case MessageType.EndRegexp: receiver.TokenEndRegexp(); break; case MessageType.Msg: receiver.TokenMsg( msgId, msgData ); break; case MessageType.Pong: receiver.TokenPong(msgData[0]); break; case MessageType.Ping: receiver.TokenPing(msgData[0]); break; case MessageType.Error: receiver.TokenError(msgId, msgData[0]); break; case MessageType.StartRegexp: receiver.TokenStartRegexp(msgId, msgData[0]); break; case MessageType.DirectMsg: receiver.TokenDirectMsg(msgId, msgData[0]); break; case MessageType.ApplicationId: receiver.TokenApplicationId(msgId, msgData[0]); break; default: throw new IvyException("protocol error, unknown message type " + msgType); } } catch (EndOfStreamException) { return false; } catch (FormatException) { throw new IvyException("protocol error on msgType"); } return true; } } }