/RTMPConnector/SharedObject.cs
C# | 670 lines | 633 code | 16 blank | 21 comment | 113 complexity | d984c739d3a39acbf49ec0fa7d7b4ece MD5 | raw file
- /*
- * Created by SharpDevelop.
- * User: sanmadmin
- * Date: 6/29/2011
- * Time: 5:57 PM
- *
- * To change this template use Tools | Options | Coding | Edit Standard Headers.
- */
- using System;
- using System.Collections.Generic;
- using System.Net.Security;
- using System.Net;
- using System.Text;
- using System.Reflection;
- using System.Runtime.Serialization;
- using System.Runtime.Serialization.Formatters.Binary;
- using System.IO;
- namespace RTMP
- {
- /// <summary>
- /// Description of SharedObject.
- /// </summary>
- public enum SOEvents : int
- {
- Use=1, // Client --> Server inform creation of a named shared object
- Release=2, // Client --> Server SO deleted client side
- RequestChange=3, // Client --> Server request of changing the value of a named parameter
- Change=4, // Server --> Client notify all clients (except requester) about changing the vale of a named parameter
- Success=5, // Server --> Client inform requester about accepting change of the parameter
- SendMessage=6, // Client --> Server broadcast a message
- // Server --> Client broadcast a message to all clients(including originator)
- Status=7, // Server --> Client inform error status
- Clear=8, // Server --> Client clear shared object
- Remove=9, // Server --> Client delete a named parameter
- RequestRemove=10, // Client --> Client request of deleting a named parameter
- UseSuccess=11 // Server --> Client successful connection
- };
- public class SharedObject
- {
- private NetConnection con;
- public string name="";
- public bool IsConnected=false;
- public bool IsPersistant=false;
- public Logger logger=new Logger();
- private object data;
- public object client=null;
- private Dictionary<object, object>PendingData=new Dictionary<object, object>();
- public delegate void SyncEventHandler(string name,object oldData,object newData);
- public delegate void ConnectEventHandler();
- public delegate void ClearEventHandler();
- public delegate void StatusEventHandler(string status,string message);
- public event SyncEventHandler Sync;
- public event ConnectEventHandler Connected;
- public event ClearEventHandler Cleared;
- public event StatusEventHandler Status;
- private bool initrunning=false;
- public SharedObject()
- {
- }
- public Dictionary<object, object> getData()
- {
- if(data==null)
- return null;
- IFormatter formatter = new BinaryFormatter();
- Stream stream = new MemoryStream();
- formatter.Serialize(stream, data);
- stream.Seek(0, SeekOrigin.Begin);
- return (Dictionary<object, object>)formatter.Deserialize(stream);
- //return new Dictionary<object, object>((Dictionary<object, object>)data);
- }
- public bool setProperty(string property, object objValue)
- {
- if(PendingData.ContainsKey((object)property))
- return false;
- PendingData.Add((object)property,objValue);
- return true;
- }
- public void getRemote(NetConnection con,string name,bool bPersistent=false)
- {
- this.con=con;
- this.name=name;
- this.IsPersistant=bPersistent;
- if(!con.SOList.ContainsKey(name))
- con.SOList.Add(name,this);
-
- RTMPPacket packet=new RTMPPacket();
- packet.m_nChannel = 0x03; // control channel (invoke)
- packet.HeaderType=HeaderType.Large;
- packet.PacketType= PacketType.SharedObject;
- packet.AllocPacket(4096);
- List<byte>enc=new List<byte>();
- short length = IPAddress.HostToNetworkOrder((short)name.Length);
- enc.AddRange(BitConverter.GetBytes(length));
- enc.AddRange(Encoding.ASCII.GetBytes(name));
- Coding.EncodeInt32(enc,0,0);
- if(IsPersistant)
- Coding.EncodeInt32(enc,2,0);
- else
- Coding.EncodeInt32(enc,0,0);
- Coding.EncodeInt32(enc,0,0);
- enc.Add(0x01);
- Coding.EncodeInt32(enc,0,0);
- Array.Copy(enc.ToArray(), packet.m_body, enc.Count);
- packet.m_nBodySize = (uint)enc.Count;
- if(con.SendPacket(packet))
- logger.Log("SO connect request sent");
- else
- logger.Log("SO connect request failed to send");
- }
- public void Close()
- {
- if(!con.SOList.ContainsKey(name))
- con.SOList.Add(name,this);
-
- RTMPPacket packet=new RTMPPacket();
- packet.m_nChannel = 0x03; // control channel (invoke)
- packet.HeaderType=HeaderType.Large;
- packet.PacketType= PacketType.SharedObject;
- packet.AllocPacket(4096);
- List<byte>enc=new List<byte>();
- short length = IPAddress.HostToNetworkOrder((short)name.Length);
- enc.AddRange(BitConverter.GetBytes(length));
- enc.AddRange(Encoding.ASCII.GetBytes(name));
- Coding.EncodeInt32(enc,0,0);
- if(IsPersistant)
- Coding.EncodeInt32(enc,2,0);
- else
- Coding.EncodeInt32(enc,0,0);
- Coding.EncodeInt32(enc,0,0);
- enc.Add(0x02);
- Coding.EncodeInt32(enc,0,0);
- Array.Copy(enc.ToArray(), packet.m_body, enc.Count);
- packet.m_nBodySize = (uint)enc.Count;
- if(con.SendPacket(packet))
- logger.Log("SO close request sent");
- else
- logger.Log("SO close request failed to send");
- }
- public bool send(string message, object param)
- {
- try
- {
- List<byte>enc=new List<byte>();
- List<byte>temp=new List<byte>();
- encodeName(enc,name);
- Coding.EncodeInt32(enc,0x2);
- Coding.EncodeInt32(enc,0x0);
- Coding.EncodeInt32(enc,0x0);
- enc.Add(0x6); // client sends message event
- encodeString(temp,message);
- if(param.GetType()==typeof(bool))
- encodeBoolean(temp,(bool)param);
- else if(param.GetType()==typeof(double))
- encodeNumber(temp,(double)param);
- else if(param.GetType()==typeof(string))
- encodeString(temp,(string)param);
- else if(param.GetType()==typeof(List<object>) || param.GetType()==typeof(Dictionary<object,object>))
- encodeObject(ref temp,param);
- else
- return false;
- byte[] bl=BitConverter.GetBytes(temp.Count);
- enc.AddRange(new byte[]{bl[3],bl[2],bl[1],bl[0]});
- enc.AddRange(temp);
- RTMPPacket packet=new RTMPPacket();
- packet.m_nChannel = 0x03; // control channel (invoke)
- packet.HeaderType=HeaderType.Large;
- packet.PacketType= PacketType.SharedObject;
- packet.AllocPacket(4096);
- Array.Copy(enc.ToArray(), packet.m_body, enc.Count);
- packet.m_nBodySize = (uint)enc.Count;
- con.SendPacket(packet,true);
- }
- catch{return false;}
- return true;
- }
- public bool setDirty(string property)
- {
- if(data==null)
- return false;
- if(data.GetType()!=typeof(Dictionary<object, object>))
- return false;
- try
- {
- List<byte>enc=new List<byte>();
- List<byte>temp=new List<byte>();
- encodeName(enc,name);
- Coding.EncodeInt32(enc,0x2);
- Coding.EncodeInt32(enc,0x0);
- Coding.EncodeInt32(enc,0x0);
- enc.Add(0x3); // client side named parameter changed event
- Dictionary<object, object>dic=(Dictionary<object, object>)this.data;
- object obj=null;
- if(!dic.TryGetValue((object)property,out obj))
- return false;
- if(obj==null)
- return false;
- encodeName(temp,property);
- if(obj.GetType()==typeof(bool))
- encodeBoolean(temp,(bool)obj);
- else if(obj.GetType()==typeof(double))
- encodeNumber(temp,(double)obj);
- else if(obj.GetType()==typeof(string))
- encodeString(temp,(string)obj);
- else if(obj.GetType()==typeof(List<object>) || obj.GetType()==typeof(Dictionary<object,object>))
- encodeObject(ref temp,obj);
- else
- return false;
- byte[] bl=BitConverter.GetBytes(temp.Count);
- enc.AddRange(new byte[]{bl[3],bl[2],bl[1],bl[0]});
- enc.AddRange(temp);
- RTMPPacket packet=new RTMPPacket();
- packet.m_nChannel = 0x03; // control channel (invoke)
- packet.HeaderType=HeaderType.Large;
- packet.PacketType= PacketType.SharedObject;
- packet.AllocPacket(4096);
- Array.Copy(enc.ToArray(), packet.m_body, enc.Count);
- packet.m_nBodySize = (uint)enc.Count;
- con.SendPacket(packet,true);
- }
- catch{return false;}
- return true;
- }
- private int handleStatus(byte[] data,int offset,int size)
- {
- string message=Coding.ReadString(data,offset);
- int msgsize=Coding.ReadInt16(data,offset);
- string status=Coding.ReadString(data,offset+msgsize+2);
- int statussize=Coding.ReadInt16(data,offset+msgsize+2);
- onStatus(status,message);
- logger.Log("SO: "+name+"--->Status message arrived: "+status+": "+message);
- return msgsize+statussize+4;
- }
- private object insertAMFObject(AMFObject prop)
- {
- object pdata=null;
- foreach(AMFObjectProperty p in prop.m_properties)
- {
- object obj=null;
- if(p.m_type==AMFDataType.AMF_NUMBER)
- obj=p.m_dNumVal;
- else if(p.m_type==AMFDataType.AMF_BOOLEAN)
- {
- if(p.m_dNumVal==0) obj=false;
- else obj=true;
- }
- else if(p.m_type== AMFDataType.AMF_STRING)
- obj=p.m_strVal;
- else if(p.m_type==AMFDataType.AMF_STRICT_ARRAY || p.m_type==AMFDataType.AMF_OBJECT ||
- p.m_type==AMFDataType.AMF_TYPED_OBJECT)
- obj=insertAMFObject(p.m_objVal);
- else
- {
- logger.Log("Unsupported shared object type");
- continue;
- }
- if(pdata==null)
- {
- if(p.m_strName.Length>0)
- pdata=new Dictionary<object, object>();
- else
- pdata=new List<object>();
- }
- if(pdata.GetType()==typeof(List<object>))
- ((List<object>)pdata).Add(obj);
- else
- ((Dictionary<object, object>)pdata).Add(p.m_strName,obj);
- }
- return pdata;
- }
- private void encodeObject(ref List<byte>data,object amfdata)
- {
- List<byte>temp=new List<byte>();
- byte[] bcount=null;
- if(amfdata.GetType()==typeof(List<object>))
- {
- byte[] btemp=BitConverter.GetBytes(((List<object>)amfdata).Count);
- bcount=new Byte[]{btemp[3],btemp[2],btemp[1],btemp[0]};
- foreach(object obj in (List<object>)amfdata)
- {
- try
- {
- if(obj.GetType()==typeof(bool))
- encodeBoolean(temp,(bool)obj);
- else if(obj.GetType()==typeof(double))
- encodeNumber(temp,(double)obj);
- else if(obj.GetType()==typeof(string))
- encodeString(temp,(string)obj);
- else if(obj.GetType()==typeof(List<object>) || obj.GetType()==typeof(Dictionary<object,object>))
- encodeObject(ref data,obj);
- else
- continue;
- }
- catch{continue;}
- }
- data.Add((byte)AMFDataType.AMF_STRICT_ARRAY);
- }
- else if(amfdata.GetType()==typeof(Dictionary<object, object>))
- {
- byte[] btemp=BitConverter.GetBytes(((Dictionary<object, object>)amfdata).Keys.Count);
- bcount=new Byte[]{10,btemp[3],btemp[2],btemp[1],btemp[0]};
- foreach(object nameobj in ((Dictionary<object, object>)amfdata).Keys)
- {
- try
- {
- object obj=null;
- encodeName(temp,(string)nameobj);
- if(!((Dictionary<object, object>)amfdata).TryGetValue(nameobj,out obj))
- continue;
- if(obj.GetType()==typeof(bool))
- encodeBoolean(temp,(bool)obj);
- else if(obj.GetType()==typeof(double))
- encodeNumber(temp,(double)obj);
- else if(obj.GetType()==typeof(string))
- encodeString(temp,(string)obj);
- else if(obj.GetType()==typeof(List<object>) || obj.GetType()==typeof(Dictionary<object,object>))
- encodeObject(ref data,obj);
- else
- continue;
-
- }
- catch{continue;}
- }
- data.Add((byte)AMFDataType.AMF_ECMA_ARRAY);
- }
- data.AddRange(bcount);
- data.AddRange(temp);
- }
- private bool deleteData(string name)
- {
- if(data==null)
- return false;
- if(data.GetType()!=typeof(Dictionary<object, object>))
- return false;
- Dictionary<object, object>dic=(Dictionary<object, object>)data;
- if(dic.Remove((object)name))
- return true;
- return false;
- }
- private int insertData(byte[] data,int offset,int size)
- {
- int pos=0;
- AMFObjectProperty prop=new AMFObjectProperty();
- pos+=prop.Decode(data,offset,size,true);
- object obj=null;
- if(pos==-1)
- return size;
- if(prop.m_type==AMFDataType.AMF_NUMBER)
- obj=prop.m_dNumVal;
- else if(prop.m_type==AMFDataType.AMF_BOOLEAN)
- {
- if(prop.m_dNumVal==0)
- obj=false;
- else
- obj=true;
- }
- else if(prop.m_type== AMFDataType.AMF_STRING)
- obj=prop.m_strVal;
- else if(prop.m_type==AMFDataType.AMF_STRICT_ARRAY || prop.m_type==AMFDataType.AMF_OBJECT ||
- prop.m_type==AMFDataType.AMF_TYPED_OBJECT)
- obj=insertAMFObject(prop.m_objVal);
- else
- {
- logger.Log("Unsupported shared object type");
- return size;
- }
- if(this.data==null)
- {
- if(prop.m_strName.Length==0)
- this.data=new List<object>();
- else
- this.data=new Dictionary<object, object>();
- }
- if(this.data.GetType()==typeof(List<object>))
- ((List<object>)this.data).Add(obj);
- else
- {
- Dictionary<object, object>sodata=(Dictionary<object, object>)this.data;
- if(!initrunning)
- {
- if(sodata.ContainsKey(prop.m_strName))
- onSync(prop.m_strName,sodata[prop.m_strName],obj);
- else
- onSync(prop.m_strName,null,obj);
- }
- if(sodata.ContainsKey(prop.m_strName))
- deleteData(prop.m_strName);
- sodata.Add(prop.m_strName,obj);
- }
- return pos;
- }
- private int handleUpdateData(byte[] data,int offset,int size)
- {
- int pos=0;
- while(pos<size)
- {
- pos+=insertData(data,offset,size);
- }
- return pos;
- }
- private int handleAcceptRequest(byte[] data, int offset,int size)
- {
- int pos=0;
- while(pos<size)
- {
- string name=Coding.ReadString(data,offset+pos);
- object newData=null;
- if(PendingData.TryGetValue((object)name,out newData))
- {
- object oldData=null;
- ((Dictionary<object, object>)this.data).TryGetValue((object)name,out oldData);
- onSync(name,oldData,newData);
- Dictionary<object, object>dic=(Dictionary<object, object>)this.data;
- if(dic.ContainsKey((object)name))
- dic[(object)name]=newData;
- else
- dic.Add((object)name,newData);
- PendingData.Remove((object)name);
- }
- pos+=name.Length+2;
- logger.Log("SO "+name+": ---> Update data accepted on property: "+name);
- }
- return pos;
- }
-
- private int handleDeleteData(byte[] data,int offset,int size)
- {
- int pos=0;
- while(pos<size)
- {
- AMFObjectProperty prop=new AMFObjectProperty();
- prop.Decode(data,offset,size,true);
- pos+=prop.m_strName.Length+2;
- if(prop.m_strName.Length>0)
- {
- Dictionary<object, object>sodata=(Dictionary<object, object>)this.data;
- if(!sodata.ContainsKey(prop.m_strName))
- continue;
- onSync(prop.m_strName,sodata[prop.m_strName],null);
- if(deleteData(prop.m_strName))
- {}
- //logger.Log("SO "+name+": ---> Property: "+prop.m_strName+" deleted");
- }
- }
- return pos;
- }
- private int handleInitData(byte[] data, int offset,int size)
- {
- int pos=0;
- logger.Log("SO: "+name+"---> Connect success message arrived!");
- while(pos<size)
- {
- AMFObjectProperty prop=new AMFObjectProperty();
- pos+=prop.Decode(data,offset,size,true);
- }
- return pos;
- }
- private int handleClear(byte[] data,int offset,int size)
- {
- this.data=null;
- logger.Log("SO: "+name+"---> Clear request arrived!");
- return 0;
- }
- private int handleSendMessage(byte[] data,int offset,int size)
- {
- if(client==null)
- return size;
- int pos=0;
- AMFObject obj=new AMFObject();
- pos+=obj.Decode(data,offset,size,false);
- try
- {
- string methodname=obj.GetProperty(0).GetString();
- Type t=client.GetType();
- if(t==null)
- throw new Exception();
- MethodInfo method=t.GetMethod(methodname);
- if(method==null)
- return size;
- if(obj.m_properties.Count>1)
- {
- List<object>param=new List<object>();
- for(int i=1;i<obj.m_properties.Count;i++)
- {
- AMFObjectProperty prop=obj.m_properties[i];
- if(prop.m_type==AMFDataType.AMF_BOOLEAN || prop.m_type== AMFDataType.AMF_NUMBER)
- param.Add((object)prop.m_dNumVal);
- else if(prop.m_type==AMFDataType.AMF_STRING)
- param.Add((object)prop.m_strVal);
- else if(prop.m_objVal!=null)
- param.Add((object)prop.m_objVal);
- }
- method.Invoke(client,param.ToArray());
- }
- else
- method.Invoke(client,null);
-
- }
- catch{}
- return size;
- }
- private int handleEvent(byte[] data,int offset)
- {
- int type=(int)data[offset];
- int size=(int)Coding.ReadInt32(data,offset+1);
- int dataoffset=offset+5;
- int pos=size;
- switch(type)
- {
- case (int)SOEvents.Change:
- pos=handleUpdateData(data,dataoffset,size);
- //logger.Log("-------------Shared object: "+name+"----------------");
- //dump(this.data);
- break;
- case (int)SOEvents.Success:
- pos=handleAcceptRequest(data,dataoffset,size);
- //logger.Log("-------------Shared object: "+name+"----------------");
- //dump(this.data);
- break;
- case (int)SOEvents.SendMessage:
- pos=handleSendMessage(data,dataoffset,size);
- break;
- case (int)SOEvents.Status:
- pos=handleStatus(data,dataoffset,size);
- break;
- case (int)SOEvents.Clear:
- pos=handleClear(data,dataoffset,size);
- onCleared();
- break;
- case (int)SOEvents.Remove:
- pos=handleDeleteData(data,dataoffset,size);
- //logger.Log("-------------Shared object: "+name+"----------------");
- //dump(this.data);
- break;
- case (int)SOEvents.UseSuccess:
- IsConnected=true;
- initrunning=true;
- pos=handleInitData(data,dataoffset,size);
- break;
- default:
- logger.Log("Unknown shared object event arrived: "+type.ToString());
- break;
- }
- return 5+pos;
- }
- internal void handleEvents(byte[] data)
- {
- int offset=0;
- int count=0;
- while(offset<data.Length && count<5000)
- {
- offset+=handleEvent(data,offset);
- count++;
- }
- if(initrunning)
- {
- initrunning=false;
- //dump(this.data);
- onConnected();
- }
- if(count==4999 && offset<data.Length)
- logger.Log("SharedObject<"+name+ "> error: event overflow");
- }
- private void encodeBoolean(List<byte> output, bool bVal)
- {
- output.Add(0x1); // type: Boolean
- output.Add(bVal ? (byte)0x1 : (byte)0x0);
- }
- private void encodeName(List<byte>output,string strValue)
- {
- short length = IPAddress.HostToNetworkOrder((short)strValue.Length);
- output.AddRange(BitConverter.GetBytes(length));
- output.AddRange(Encoding.ASCII.GetBytes(strValue));
- }
- private void encodeString(List<byte>output,string strValue)
- {
- output.Add(0x2); // type: Number
- short length = IPAddress.HostToNetworkOrder((short)strValue.Length);
- output.AddRange(BitConverter.GetBytes(length));
- output.AddRange(Encoding.ASCII.GetBytes(strValue));
- }
- private void encodeNumber(List<byte> output, double dVal)
- {
- output.Add(0x0); // type: Number
- byte[] bytes = BitConverter.GetBytes(dVal);
- for (int i = bytes.Length - 1; i >= 0; i--) output.Add(bytes[i]); // add in reversed byte order
- }
- internal void dump(object data)
- {
- if(data==null)
- return;
- if(data.GetType()==typeof(List<object>))
- {
- foreach(object obj in ((List<object>)data))
- {
- try
- {
- if(obj.GetType()!=typeof(List<object>) && obj.GetType()!=typeof(Dictionary<object, object>))
- logger.Log(obj.ToString());
- else
- {
- logger.Log("-------------");
- dump(obj);
- logger.Log("-------------");
- }
- }
- catch(Exception e)
- {
- logger.Log(e.Message);
- }
- }
- }
- else
- {
- foreach(object obj in ((Dictionary<object,object>)data).Keys)
- {
- try
- {
- object d=((Dictionary<object, object>)data)[obj];
- if(d.GetType()!=typeof(List<object>) && d.GetType()!=typeof(Dictionary<object, object>))
- logger.Log(obj.ToString()+": "+d.ToString());
- else
- {
- logger.Log("-------------");
- logger.Log(obj.ToString());
- logger.Log("-------------");
- dump(d);
- logger.Log("-------------");
- logger.Log(" ");
- }
- }
- catch(Exception e)
- {
- logger.Log(e.Message);
- }
- }
- }
- }
- private void onSync(string name,object oldData,object newData)
- {
- if(Sync!=null)
- Sync(name,oldData,newData);
- }
- private void onConnected()
- {
- if(Connected!=null)
- Connected();
- }
- private void onStatus(string status,string message)
- {
- if(Status!=null)
- Status(status,message);
- }
- private void onCleared()
- {
- if(Cleared!=null)
- Cleared();
- }
- }
- }