# HG changeset patch # User Ivo Smits # Date 1347373733 -7200 # Node ID 3ab940a0c7a01d245e9e58322ff699fd30c03ee7 Initial commit diff -r 000000000000 -r 3ab940a0c7a0 Cache.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Cache.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; + +namespace UCIS { + public class Cache { + private Dictionary _items; + + public Cache() { + _items = new Dictionary(); + } + + public int Count { get { return _items.Count; } } + public int getCount(bool checkAlive) { + Purge(); + return _items.Count; + } + + private void getItem(TKey key, out TValue value, out bool exists, out bool collected) { + WeakReference w; + lock (_items) { + if (!_items.TryGetValue(key, out w)) { + value = default(TValue); + exists = false; + collected = false; + return; + } + Object r = w.Target; + if (r == null) { + _items.Remove(key); + value = default(TValue); + exists = false; + collected = true; + return; + } + value = (TValue)r; + exists = true; + collected = false; + return; + } + } + + public bool TryGetValue(TKey key, out TValue value) { + bool exists, collected; + getItem(key, out value, out exists, out collected); + return exists; + } + + public void Purge() { + lock (_items) { + List remove = new List(); + foreach (KeyValuePair kvp in _items) { + if (!kvp.Value.IsAlive) remove.Add(kvp.Key); + } + foreach (TKey key in remove) { + _items.Remove(key); + } + } + } + + public void Add(TKey key, TValue value) { + lock(_items) _items.Add(key, new WeakReference(value)); + } + + public bool Remove(TKey key) { + lock(_items) return _items.Remove(key); + } + + public void Clear() { + _items.Clear(); + } + } +} \ No newline at end of file diff -r 000000000000 -r 3ab940a0c7a0 Cci/CciCommand.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Cci/CciCommand.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,195 @@ +using System; +using System.Collections.Generic; +using System.Text; +using UCIS.Pml; + +namespace UCIS.Cci { + public enum CciResultType { + Success, + Error, + Value, + Message, + List, + Pml, + Object, + Binary + } + + public class CciResult { + private CciResultType _type; + private Object _value; + + public CciResult(CciResultType type, Object value) { + _type = type; + _value = value; + } + public CciResult(CciResultType type) : this(type, null) { } + public CciResult(Exception ex) : this(CciResultType.Error, ex) { } + public CciResult(Pml.PmlElement pml) : this(CciResultType.Pml, pml) { } + public CciResult(byte[] binary) : this(CciResultType.Binary, binary) { } + public CciResult(string[] stringList) : this(CciResultType.List, stringList) { } + public CciResult(string message) : this(CciResultType.Message, message) { } + + public override string ToString() { + if (_value == null) { + return _type.ToString(); + } else { + return _type.ToString() + ": " + ValueToString(); + } + } + public string ValueToString() { + if (_value == null) { + return ""; + } else if (_value is string) { + return (string)_value; + } else if (_value is byte[]) { + return Encoding.UTF8.GetString((byte[])_value); + } else if (_value is PmlElement) { + return Pml.PmlTextWriter.GetMessageString((PmlElement)_value); + } else if (_value is IEnumerable) { + StringBuilder sb = new StringBuilder(); + foreach (Object i in (Array)_value) sb.AppendLine(i.ToString()); + return sb.ToString(); + } else { + return _value.ToString(); + } + } + public PmlElement ValueToPml() { + if (_value == null) return new PmlNull(); + switch (_type) { + case CciResultType.Binary: return new PmlBinary((byte[])_value); + case CciResultType.Message: + case CciResultType.Object: + case CciResultType.Value: + case CciResultType.Error: return new PmlString(_value.ToString()); + case CciResultType.Success: return new PmlInteger(1); + case CciResultType.List: { + PmlCollection c = new PmlCollection(); + foreach (Object i in (Array)_value) c.Add(i.ToString()); + return c; + } + case CciResultType.Pml: return (PmlElement)_value; + default: return new PmlString("Unknown type: " + _type.ToString()); + } + } + public PmlElement ToPml() { + PmlDictionary d = new PmlDictionary(); + //d.Add("Type", (int)_type); + d.Add("Type", (int)CciResultType.Message); + //d.Add("TypeName", _type.ToString()); + d.Add("TypeName", "Message"); + //d.Add("Value", ValueToPml()); + d.Add("Value", ToString()); + d.Add("String", ToString()); + return d; + } + + public CciResultType Type { get { return _type; } } + public Object Value { get { return _value; } } + } + + public class CciCommand { + private string[] _command; + private int _offset; + private CciResult _result; + + public CciCommand(string[] command) { + _command = command; + _offset = 0; + _result = null; + } + + public int Offset { get { return _offset; } set { _offset = value; } } + + public static CciCommand Parse(string command, bool urlEncode, bool cEscape, bool quotes) { + List l = new List(); + + StringBuilder part = new StringBuilder(); + bool inQuotes = false; + int len = command.Length; + for (int i = 0; i < len; i++) { + char c = command[i]; + if (quotes && !inQuotes && c == '"') { + inQuotes = true; + } else if (quotes && inQuotes && c == '"') { + inQuotes = false; + } else if (urlEncode && c == '%') { + part.Append(Uri.HexUnescape(command, ref i)); + i--; + } else if (cEscape && c == '\\' && i + 1 < len) { + i++; + switch (command[i]) { + case 't': part.Append('\t'); break; + case 'n': part.Append('\n'); break; + case 'r': part.Append('\r'); break; + default: part.Append(command[i]); break; + } + } else if (!inQuotes && (c == ' ' || c == '\t')) { + if (part.Length > 0) l.Add(part.ToString()); + part.Length = 0; + } else { + part.Append(c); + } + } + if (part.Length > 0) l.Add(part.ToString()); + + return new CciCommand(l.ToArray()); + } + + public PmlCollection ToPml() { return ToPml(0); } + public PmlCollection ToPml(int offset) { + PmlCollection c = new PmlCollection(); + for (int i = _offset + offset; i < _command.Length; i++) c.Add(_command[i]); + return c; + } + public static CciCommand FromPml(PmlCollection pml) { + List l = new List(); + foreach (PmlElement e in pml) l.Add(e.ToString()); + return new CciCommand(l.ToArray()); + } + + public string Command { + get { + return _command[_offset]; + } + } + + public string GetArgument(int index) { + return _command[_offset + index + 1]; + } + + public CciCommand Jump(int offset) { + _offset += offset; + return this; + } + + public int Count { + get { + return _command.Length - _offset - 1; + } + } + + public CciResult Result { + get { + return _result; + } + set { + _result = value; + } + } + + public CciCommand Return(CciResult result) { + _result = result; + return this; + } + public CciCommand Return(CciResultType type, Object value) { return Return(new CciResult(type, value)); } + public CciCommand Return() { return Return(CciResultType.Success); } + public CciCommand Return(int value) { return Return(CciResultType.Value, value); } + public CciCommand Return(CciResultType type) { return Return(type, null); } + public CciCommand Return(Exception ex) { return Return(CciResultType.Error, ex); } + public CciCommand Return(PmlElement pml) { return Return(CciResultType.Pml, pml); } + public CciCommand Return(byte[] binary) { return Return(CciResultType.Binary, binary); } + public CciCommand Return(string[] stringList) { return Return(CciResultType.List, stringList); } + public CciCommand Return(string message) { return Return(CciResultType.Message, message); } + } +} diff -r 000000000000 -r 3ab940a0c7a0 DBReader.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DBReader.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,103 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Data; +using System.Data.Common; + +namespace UCIS { + public class DBReader : IEnumerable, IEnumerator { + private IDbCommand _Command; + private IDataReader _Reader; + private object[] _CurrentRow; + + internal DBReader(IDbCommand Command) { + _Command = Command; + } + + public bool Read() { + if (_Reader == null) { + if (_Command == null) return false; + _Reader = _Command.ExecuteReader(); + } + if (_Reader.Read()) { + return true; + } else { + Close(); + return false; + } + } + + public void Close() { + if (_Reader != null) _Reader.Close(); + if (_Command != null) { + _Command.Connection.Close(); + _Command.Dispose(); + } + _Command = null; + _CurrentRow = null; + _Reader = null; + } + + public object GetField() { + if (_Reader == null) { + return _Command.ExecuteScalar(); + } else { + return _Reader.GetValue(0); + } + } + + public object GetField(int Offset) { + if (_Reader == null) Read(); + return _Reader.GetValue(Offset); + } + public object[] GetRow(bool GoNextRow) { + object[] Result = null; + if (_Reader == null) { + if (!Read()) return null; + } + Result = new object[_Reader.FieldCount]; + + _Reader.GetValues(Result); + if (GoNextRow) Read(); + return Result; + } + public object[] GetRow() { + return GetRow(true); + } + public object[][] GetAllRows() { + List Result = new List(); + object[] ResultArray = null; + if (_Reader == null) { + if (!Read()) return null; + } + do { + ResultArray = new object[_Reader.FieldCount]; + + _Reader.GetValues(ResultArray); + Result.Add(ResultArray); + } + while (_Reader.Read()); + Close(); + return Result.ToArray(); + } + + IEnumerator IEnumerable.GetEnumerator() { + return this; + } + object IEnumerator.Current { + get { return _CurrentRow; } + } + bool IEnumerator.MoveNext() { + if (!Read()) return false; + _CurrentRow = GetRow(false); + return true; + } + void IEnumerator.Reset() { + throw new NotImplementedException(); + } + + public void Dispose() { + Close(); + } + } +} diff -r 000000000000 -r 3ab940a0c7a0 Database.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Database.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,127 @@ +using System; +using System.Reflection; +using System.Data; +using System.Data.Common; +using System.Collections.Generic; + +namespace UCIS { + public class Database { + private delegate object ConstructorDelegate(); + private ConstructorInfo _ConnectionConstructor; + + public Database(Type DBConnectionType, string connectionString) { + this.ConnectionString = connectionString; + _ConnectionConstructor = DBConnectionType.GetConstructor(new Type[] { }); + } + + public string ConnectionString { get; set; } + + public virtual IDbConnection GetConnection() { + lock (_ConnectionConstructor) { + IDbConnection conn = (IDbConnection)_ConnectionConstructor.Invoke(null); + conn.ConnectionString = ConnectionString; + conn.Open(); + return conn; + } + } + + public IDbCommand PrepareQuery(string Query, params object[] Parameters) { + int ParameterI = 0; + IDbConnection Connection = GetConnection(); + try { + IDbCommand Command = Connection.CreateCommand(); + Command.CommandType = CommandType.Text; + Command.CommandText = Query; + Command.Parameters.Clear(); + foreach (object Parameter in Parameters) { + IDbDataParameter DBParameter = Command.CreateParameter(); + DBParameter.Direction = ParameterDirection.Input; + DBParameter.ParameterName = "?" + ParameterI.ToString(); + DBParameter.Value = Parameter; + Command.Parameters.Add(DBParameter); + ParameterI++; + } + if (ParameterI > 0) Command.Prepare(); + return Command; + } catch (Exception ex) { + Connection.Close(); + throw ex; + } + } + + public int NonQuery(string QueryString, params object[] Parameters) { + IDbCommand Command = PrepareQuery(QueryString, Parameters); + try { + return Command.ExecuteNonQuery(); + } finally { + Command.Connection.Close(); + } + } + + public object FetchField(string QueryString, params object[] Parameters) { + IDbCommand Command = PrepareQuery(QueryString, Parameters); + try { + return Command.ExecuteScalar(); + } finally { + Command.Connection.Close(); + } + } + public object[] FetchRow(string QueryString, params object[] Parameters) { + IDbCommand Command = PrepareQuery(QueryString, Parameters); + try { + IDataReader Reader = Command.ExecuteReader(); + try { + if (!Reader.Read()) return null; + object[] Result = new object[Reader.FieldCount]; + Reader.GetValues(Result); + return Result; + } finally { + Reader.Close(); + } + } finally { + Command.Connection.Close(); + } + } + public object[][] FetchRows(string QueryString, params object[] Parameters) { + IDbCommand Command = PrepareQuery(QueryString, Parameters); + try { + IDataReader Reader = Command.ExecuteReader(); + try { + List Result = new List(); + while (Reader.Read()) { + object[] ResultArray = new object[Reader.FieldCount]; + Reader.GetValues(ResultArray); + Result.Add(ResultArray); + } + return Result.ToArray(); + } finally { + Reader.Close(); + } + } finally { + Command.Connection.Close(); + } + } + public void ForEachRow(Action f, string QueryString, params object[] Parameters) { + IDbCommand Command = PrepareQuery(QueryString, Parameters); + try { + IDataReader Reader = Command.ExecuteReader(); + try { + while (Reader.Read()) { + object[] ResultArray = new object[Reader.FieldCount]; + Reader.GetValues(ResultArray); + f(ResultArray); + } + } finally { + Reader.Close(); + } + } finally { + Command.Connection.Close(); + } + + } + + /*public DBReader GetReader(string QueryString, params object[] Parameters) { + return new DBReader(PrepareQuery(QueryString, Parameters)); + }*/ + } +} \ No newline at end of file diff -r 000000000000 -r 3ab940a0c7a0 Net/ConnectionList.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Net/ConnectionList.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,133 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace UCIS.Net { + public class NetworkConnectionList : ICollection { + List _list = new List(); + + public ulong BytesWritten { + get { + ulong sum = 0; + lock (_list) foreach (INetworkConnection c in _list) sum += c.BytesWritten; + return sum; + } + } + public ulong BytesRead { + get { + ulong sum = 0; + lock (_list) foreach (INetworkConnection c in _list) sum += c.BytesRead; + return sum; + } + } + public NetworkConnectionList FindByHandler(Object Handler) { + NetworkConnectionList l = new NetworkConnectionList(); + lock (_list) foreach (INetworkConnection c in _list) if (c.Handler == Handler) l.Add(c); + return l; + } + public NetworkConnectionList FindByHandlerType(Type HandlerType) { + NetworkConnectionList l = new NetworkConnectionList(); + lock (_list) foreach (INetworkConnection c in _list) if (c.Handler.GetType() == HandlerType) l.Add(c); + return l; + } + public void CloseAll() { + foreach (INetworkConnection c in ToArray()) c.Close(); + } + + public void Add(INetworkConnection item) { + if (item == null) throw new ArgumentNullException("item"); + lock (_list) _list.Add(item); + item.Closed += _ConnectionClosed; + if (!item.Connected) Remove(item); + } + public void Insert(int index, INetworkConnection item) { + throw new NotSupportedException(); + } + public bool Remove(INetworkConnection item) { + if (item == null) throw new ArgumentNullException("item"); + item.Closed -= _ConnectionClosed; + lock (_list) return _list.Remove(item); + } + public void RemoveAt(int index) { + lock (_list) { + INetworkConnection item = _list[index]; + item.Closed -= _ConnectionClosed; + _list.Remove(item); + } + } + public int Count { get { lock (_list) return _list.Count; } } + public bool IsReadOnly { get { return false; } } + public bool Contains(INetworkConnection item) { + lock (_list) return _list.Contains(item); + } + public void Clear() { + lock (_list) { + foreach (INetworkConnection c in _list) c.Closed -= _ConnectionClosed; + _list.Clear(); + } + } + public INetworkConnection this[int index] { + get { return _list[index]; } + set { throw new NotSupportedException(); } + } + public int IndexOf(INetworkConnection item) { + lock (_list) return _list.IndexOf(item); + } + + IEnumerator IEnumerable.GetEnumerator() { + return new Enumerator(_list); + } + public IEnumerator GetEnumerator() { + return new Enumerator(_list); + } + + public void CopyTo(INetworkConnection[] array, int offset) { + lock (_list) _list.CopyTo(array, offset); + } + + public INetworkConnection[] ToArray() { + lock (_list) return _list.ToArray(); + } + + private void _ConnectionClosed(Object sender, EventArgs e) { + if (sender == null || !(sender is INetworkConnection)) return; + Remove((INetworkConnection)sender); + } + + private class Enumerator : IEnumerator { + int index = 0; + INetworkConnection current = null; + IList list; + + public Enumerator(IList list) { + this.list = list; + } + + public void Reset() { + index = 0; + } + public bool MoveNext() { + lock (list) { + if (index < list.Count) { + current = list[index]; + index++; + return true; + } else { + current = null; + return false; + } + } + } + public INetworkConnection Current { + get { return current; } + } + object IEnumerator.Current { + get { return current; } + } + public void Dispose() { + current = null; + list = null; + } + } + } +} diff -r 000000000000 -r 3ab940a0c7a0 Net/HTTP.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Net/HTTP.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,158 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Threading; + +namespace UCIS.Net.HTTP { + public class HTTPServer : TCPServer.IModule { + public Dictionary Content = new Dictionary(StringComparer.InvariantCultureIgnoreCase); + public HTTPContent DefaultContent = null; + + public bool Accept(TCPStream Stream) { + StreamReader StreamReader = new StreamReader(Stream, Encoding.ASCII); + String Line = StreamReader.ReadLine(); + String[] Request = Line.Split(' '); + + //Console.WriteLine("HTTP.Server.Accept Request: " + Line); + + if (Request == null || Request.Length < 2 || Request[0] != "GET" || Request[1][0] != '/') { + //Console.WriteLine("HTTP.Server.Start Bad request"); + SendError(Stream, 400); + return true; + } + + Request = Request[1].Split(new Char[] { '?' }, 2); + HTTPContent content; + if (Content.TryGetValue(Request[0], out content)) { + } else if (DefaultContent != null) { + content = DefaultContent; + } else { + SendError(Stream, 404); + return true; + } + HTTPContext Context = new HTTPContext(); + Context.Stream = Stream; + Context.Request = new HTTPRequest(); + Context.Request.Method = Method.GET; + Context.Request.Path = Request[0]; + if (Request.Length == 2) { + Context.Request.Query = Request[1]; + } else { + Context.Request.Query = null; + } + HTTPContent.Result ServeResult = content.Serve(Context); + + if (ServeResult == HTTPContent.Result.OK_KEEPALIVE) { + return false; + } else if (!(ServeResult == HTTPContent.Result.OK_CLOSE)) { + SendError(Stream, (int)ServeResult); + } + return true; + } + + public static void SendError(Stream Stream, int ErrorCode) { + string ErrorText = null; + switch (ErrorCode) { + case 400: + ErrorText = "The request could not be understood by the server due to malformed syntax."; + break; + case 404: + ErrorText = "The requested file can not be found."; + break; + default: + ErrorText = "Unknown error code: " + ErrorCode.ToString() + "."; + break; + } + SendHeader(Stream, ErrorCode, "text/plain", ErrorText.Length); + WriteLine(Stream, ErrorText); + Thread.Sleep(100); + return; + } + + public static void SendHeader(Stream Stream, int ResultCode, string ContentType) { + SendHeader(Stream, ResultCode, ContentType, -1); + } + public static void SendHeader(Stream Stream, int ResultCode, string ContentType, int ContentLength) { + //ResultCode = 200, ContentType = null, ContentLength = -1 + string ResultString; + switch (ResultCode) { + case 200: ResultString = "OK"; break; + case 400: ResultString = "Bad Request"; break; + case 404: ResultString = "Not found"; break; + default: ResultString = "Unknown"; break; + } + WriteLine(Stream, "HTTP/1.1 " + ResultCode.ToString() + " " + ResultString); + WriteLine(Stream, "Expires: Mon, 26 Jul 1990 05:00:00 GMT"); + WriteLine(Stream, "Cache-Control: no-store, no-cache, must-revalidate"); + WriteLine(Stream, "Cache-Control: post-check=0, pre-check=0"); + WriteLine(Stream, "Pragma: no-cache"); + WriteLine(Stream, "Server: UCIS Simple Webserver"); + WriteLine(Stream, "Connection: Close"); + if ((ContentType != null)) WriteLine(Stream, "Content-Type: " + ContentType); + if (ContentLength != -1) WriteLine(Stream, "Content-Length: " + ContentLength.ToString()); + WriteLine(Stream, ""); + } + + public static void WriteLine(Stream Stream, string Line) { + byte[] Buffer = null; + Buffer = Encoding.ASCII.GetBytes(Line); + Stream.Write(Buffer, 0, Buffer.Length); + Stream.WriteByte(13); + Stream.WriteByte(10); + } + } + + public abstract class HTTPContent { + public abstract Result Serve(HTTPContext Context); + public enum Result : int { + OK_CLOSE = -2, + OK_KEEPALIVE = -1, + ERR_NOTFOUND = 404 + } + } + + public class HTTPFileContent : HTTPContent { + public string Filename { get; private set; } + public string ContentType { get; private set; } + + public HTTPFileContent(string Filename) : this(Filename, "application/octet-stream") { } + public HTTPFileContent(string Filename, string ContentType) { + this.Filename = Filename; + this.ContentType = ContentType; + } + + public override Result Serve(HTTPContext Context) { + if (!File.Exists(Filename)) return Result.ERR_NOTFOUND; + + using (FileStream FileStream = File.OpenRead(Filename)) { + HTTPServer.SendHeader(Context.Stream, 200, ContentType, (int)FileStream.Length); + byte[] Buffer = new byte[1025]; + while (FileStream.CanRead) { + int Length = FileStream.Read(Buffer, 0, Buffer.Length); + if (Length <= 0) break; + Context.Stream.Write(Buffer, 0, Length); + } + } + return Result.OK_CLOSE; + } + } + + public class HTTPContext { + public HTTPRequest Request { get; internal set; } + public TCPStream Stream { get; internal set; } + } + + public enum Method { + GET = 0, + HEAD = 1, + POST = 2, + PUT = 3 + } + + public class HTTPRequest { + public HTTP.Method Method { get; internal set; } + public string Path { get; internal set; } + public string Query { get; internal set; } + } +} diff -r 000000000000 -r 3ab940a0c7a0 Net/INetworkConnection.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Net/INetworkConnection.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,16 @@ +using System; +using System.Net; + +namespace UCIS.Net { + public interface INetworkConnection { + event EventHandler Closed; + void Close(); + bool Connected { get; } + ulong BytesWritten { get; } + ulong BytesRead { get; } + TimeSpan Age { get; } + EndPoint RemoteEndPoint { get; } + //Object Proxy { get; } + Object Handler { get; } + } +} diff -r 000000000000 -r 3ab940a0c7a0 Net/TCPServer.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Net/TCPServer.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,235 @@ +using System; +using System.Net; +using System.Net.Sockets; +using System.Threading; +using System.Collections.Generic; + +namespace UCIS.Net { + public class TCPServer { + public class ModuleCollection : Dictionary { + public void Add(char Key, IModule Value) { + base.Add((byte)Key, Value); + } + public void Remove(char Key) { + base.Remove((byte)Key); + } + } + + public class ClientAcceptedEventArgs : EventArgs { + private TCPStream _client; + internal ClientAcceptedEventArgs(TCPStream client) { + _client = client; + } + public TCPStream Client { get { return _client; } } + } + + public event EventHandler ClientAccepted; + + private Socket _Listener; + private UCIS.ThreadPool _ThreadPool; + private NetworkConnectionList _Clients = new NetworkConnectionList(); + private ModuleCollection _Modules = new ModuleCollection(); + private IModule _CatchAllModule = null; + private Int32 _ThrottleCounter; + private Int32 _ThrottleBurst = 10; + private Int32 _ThrottleRate = 0; + private Timer _ThrottleTimer = null; + + public TCPServer() { + _ThreadPool = UCIS.ThreadPool.DefaultPool; + } + + public NetworkConnectionList Clients { + get { return _Clients; } + } + + public ModuleCollection Modules { + get { return _Modules; } + } + + public IModule CatchAllModule { + get { + return _CatchAllModule; + } + set { + _CatchAllModule = value; + } + } + + public Int32 ThrottleRate { + get { return _ThrottleRate; } + set { + if (value < 0) throw new ArgumentOutOfRangeException("value"); + _ThrottleRate = value; + if (_Listener == null) return; + if (value == 0 && _ThrottleTimer != null) { + _ThrottleTimer.Dispose(); + _ThrottleTimer = null; + } else if (value > 0 && _ThrottleTimer == null) { + _ThrottleTimer = new Timer(ThrottleCallback, null, 1000, 1000); + } + } + } + public Int32 ThrottleBurst { + get { return _ThrottleBurst; } + set { + if (value < 1) throw new ArgumentOutOfRangeException("value"); + _ThrottleBurst = value; + } + } + + public EndPoint LocalEndPoint { get { return _Listener.LocalEndPoint; } } + + public void Listen(int Port) { + Listen(AddressFamily.InterNetwork, Port); + } + public void Listen(AddressFamily af, int Port) { + Stop(); + + _Listener = new Socket(af, SocketType.Stream, ProtocolType.Tcp); + + _Listener.Blocking = false; + _Listener.Bind(new IPEndPoint(af == AddressFamily.InterNetworkV6 ? IPAddress.IPv6Any : IPAddress.Any, Port)); + _Listener.Listen(25); + _ThrottleCounter = _ThrottleBurst; + _Listener.BeginAccept(AcceptCallback, null); + + if (_ThrottleRate > 0) { + _ThrottleTimer = new Timer(ThrottleCallback, null, 1000, 1000); + } + } + + public void Stop() { + if (_ThrottleTimer != null) _ThrottleTimer.Dispose(); + if (_Listener != null && _Listener.IsBound) _Listener.Close(); + _Listener = null; + } + + public void Close() { + Close(true); + } + public void Close(bool CloseClients) { + Stop(); + if (CloseClients) { + _Clients.CloseAll(); + if (_Clients.Count > 0) Console.WriteLine("TCPServer.Close: Warning: " + _Clients.Count.ToString() + " connections were not properly terminated."); + } else { + _Clients.Clear(); + } + } + + private void AcceptCallback(System.IAsyncResult ar) { + Client Client = null; + Socket Socket = null; + if (_Listener == null) return; + try { + Socket = _Listener.EndAccept(ar); + } catch (ObjectDisposedException) { + Console.WriteLine("TCPServer.AcceptCallback Listener object has been disposed. Aborting."); + return; + } catch (SocketException ex) { + Console.WriteLine("TCPServer.AcceptCallback SocketException: " + ex.Message); + Socket = null; + } + if (Socket != null) { + try { + Client = new Client(Socket, this); + _Clients.Add(Client); + if (ClientAccepted != null) ClientAccepted(this, new ClientAcceptedEventArgs(Client)); + Client.Start(_ThreadPool); + } catch (Exception ex) { + Console.WriteLine(ex.ToString()); + } + } + if (_ThrottleCounter > 0 || _ThrottleRate == 0) { + _ThrottleCounter--; + _Listener.BeginAccept(AcceptCallback, null); + } + } + + private void ThrottleCallback(Object state) { + if (_Listener == null) return; + if (_ThrottleRate == 0) return; + if (_ThrottleCounter >= _ThrottleBurst) return; + if (_ThrottleCounter <= 0) { + _Listener.BeginAccept(AcceptCallback, null); + } + _ThrottleRate += _ThrottleRate; + } + + public interface IModule { + // Return value: True = Close connection, False = keep alive + bool Accept(TCPStream Stream); + } + + private class Client : TCPStream { + private TCPServer _Server; + private UCIS.ThreadPool.WorkItem _WorkItem; + private IModule _Module; + private byte _MagicNumber; + + public TCPServer Server { + get { return _Server; } + } + public IModule Module { + get { return _Module; } + } + + private void _Stream_Closed(object sender, EventArgs e) { + _WorkItem = null; + _Module = null; + _Server = null; + base.Closed -= _Stream_Closed; + } + + internal Client(Socket Socket, TCPServer Server) : base(Socket) { + _Server = Server; + Socket.Blocking = true; + base.Closed += _Stream_Closed; + this.Tag = Server; + } + + internal void Start(UCIS.ThreadPool Pool) { + _WorkItem = Pool.QueueWorkItem(WorkerProc, null); + } + + private void WorkerProc(object state) { + bool CloseSocket = true; + try { + try { + base.Blocking = true; + //base.NoDelay = true; + base.ReadTimeout = 5000; + base.WriteBufferSize = 1024 * 10; + base.ReadBufferSize = 1024 * 10; + //Console.WriteLine("TCPServer: Accepted connection from " + base.Socket.RemoteEndPoint.ToString()); + _MagicNumber = (byte)base.PeekByte(); + } catch (TimeoutException ex) { + Console.WriteLine("TCPServer: Caught TimeoutException while reading magic number: " + ex.Message); + return; + } + if (_Server._Modules.TryGetValue(_MagicNumber, out _Module)) { + this.Tag = _Module; + CloseSocket = _Module.Accept(this); + } else if (_Server._CatchAllModule != null) { + this.Tag = _Server._CatchAllModule; + CloseSocket = _Server._CatchAllModule.Accept(this); + } else { + this.Tag = this; + Console.WriteLine("TCPServer: Unknown magic number: " + _MagicNumber.ToString()); + } + } catch (ThreadAbortException) { + Console.WriteLine("TCPServer: Caught ThreadAbortException"); + } catch (SocketException ex) { + Console.WriteLine("TCPServer: Caught SocketException: " + ex.Message); + } catch (Exception ex) { + Console.WriteLine("TCPServer: Caught Exception: " + ex.ToString()); + } finally { + try { + if (CloseSocket) base.Close(); + } catch { } + } + } + } + } +} diff -r 000000000000 -r 3ab940a0c7a0 Net/TCPStream.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Net/TCPStream.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,254 @@ +using System; +using System.IO; +using System.Net; +using System.Net.Sockets; +using System.Threading; + +namespace UCIS.Net { + public class TCPStream : Stream, INetworkConnection { + private static long _totalBytesRead = 0; + private static long _totalBytesWritten = 0; + public static ulong TotalBytesWritten { get { return (ulong)_totalBytesWritten; } set { _totalBytesWritten = (long)value; } } + public static ulong TotalBytesRead { get { return (ulong)_totalBytesRead; } set { _totalBytesRead = (long)value; } } + + private Socket _Socket; + private byte _PeekByte; + private bool _HasPeekByte; + private ulong _BytesWritten; + private ulong _BytesRead; + private DateTime _StartTime; + private bool _Blocking; + + public event EventHandler Closed; + + public TCPStream(Socket Socket) { + _Socket = Socket; + _HasPeekByte = false; + _StartTime = DateTime.Now; + _Blocking = _Socket.Blocking; + } + + public Socket Socket { + get { return _Socket; } + } + + public DateTime CreationTime { + get { return _StartTime; } + } + + public bool Blocking { + get { return _Blocking; } + set { + Socket.Blocking = value; + _Blocking = value; + } + } + + public bool NoDelay { + get { return Socket.NoDelay; } + set { Socket.NoDelay = value; } + } + + public override bool CanTimeout { + get { return true; } + } + + public override int ReadTimeout { + get { return Socket.ReceiveTimeout; } + set { Socket.ReceiveTimeout = value; } + } + + public override int WriteTimeout { + get { return Socket.SendTimeout; } + set { Socket.SendTimeout = value; } + } + + public override int ReadByte() { + if (_HasPeekByte) { + _HasPeekByte = false; + return _PeekByte; + } else { + byte[] Buffer = new byte[1]; + if (Read(Buffer, 0, 1) != 1) return -1; + return Buffer[0]; + } + } + + public override int Read(byte[] buffer, int offset, int size) { + int Count = 0; + + if (size < 1) return 0; + if (_HasPeekByte) { + buffer[offset] = _PeekByte; + _HasPeekByte = false; + Count = 1; + offset += 1; + size -= 1; + } + + try { + if (size > 0) Count += Socket.Receive(buffer, offset, size, SocketFlags.None); + } catch (SocketException ex) { + switch (ex.SocketErrorCode) { + case SocketError.WouldBlock: + _Socket.Blocking = _Blocking; + throw new TimeoutException("The receive operation would block", ex); + case SocketError.TimedOut: + throw new TimeoutException("The receive operation timed out", ex); + case SocketError.ConnectionReset: + case SocketError.Disconnecting: + case SocketError.NetworkDown: + case SocketError.NetworkReset: + case SocketError.NetworkUnreachable: + case SocketError.NotConnected: + Close(); + throw new SocketException((int)ex.SocketErrorCode); + default: + throw new SocketException((int)ex.SocketErrorCode); + } + } + + _BytesRead += (ulong)Count; + Interlocked.Add(ref _totalBytesRead, (long)Count); + return Count; + } + + public int PeekByte() { + if (_HasPeekByte) { + return _PeekByte; + } else { + int Result = 0; + Result = ReadByte(); + if (Result >= 0 && Result <= 255) { + _PeekByte = (byte)Result; + _HasPeekByte = true; + } + return Result; + } + } + + public int WriteBufferSize { + get { return Socket.SendBufferSize; } + set { Socket.SendBufferSize = value; } + } + + public int ReadBufferSize { + get { return Socket.ReceiveBufferSize; } + set { Socket.ReceiveBufferSize = value; } + } + + public override bool CanRead { + get { return Socket.Connected && (Blocking || (Socket.Available > 0)); } + } + + public override bool CanSeek { + get { return false; } + } + + public override bool CanWrite { + get { return Socket.Connected; } + } + + public override void Flush() { + //Do nothing + //_Socket.NoDelay = true; + } + + public override long Length { + get { + throw new NotSupportedException(); + } + } + + public override long Position { + get { + throw new NotSupportedException(); + } + set { + throw new NotSupportedException(); + } + } + + public override long Seek(long offset, SeekOrigin origin) { + throw new NotSupportedException(); + } + + public override void SetLength(long value) { + throw new NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int size) { + int left = size; + if (_Socket == null) throw new ObjectDisposedException("socket"); + try { + while (left > 0) { + int sent = _Socket.Send(buffer, offset, left, 0); + left -= sent; + offset += sent; + } + } catch (SocketException ex) { + switch (ex.SocketErrorCode) { + case SocketError.WouldBlock: + _Socket.Blocking = _Blocking; + throw new TimeoutException("The send operation would block", ex); + case SocketError.TimedOut: + throw new TimeoutException("The send operation timed out", ex); + case SocketError.ConnectionReset: + case SocketError.Disconnecting: + case SocketError.NetworkDown: + case SocketError.NetworkReset: + case SocketError.NetworkUnreachable: + case SocketError.NotConnected: + Close(); + throw new SocketException((int)ex.SocketErrorCode); + default: + throw new SocketException((int)ex.SocketErrorCode); + } + } + _BytesWritten += (ulong)size; + Interlocked.Add(ref _totalBytesWritten, (long)size); + } + + public override void Close() { + System.Net.Sockets.Socket s = Interlocked.Exchange(ref _Socket, null); + try { + if (s != null) { + try { + if (s.Connected) s.Shutdown(SocketShutdown.Both); + } catch { } + s.Close(); + } + } finally { + base.Close(); + if (Closed != null) Closed(this, new EventArgs()); + } + } + + public bool Connected { + get { + if (Socket == null) return false; + if (Socket.Connected) return true; + Close(); + return false; + } + } + + public object Tag { get; set; } + + public ulong BytesWritten { get { return _BytesWritten; } } + public ulong BytesRead { get { return _BytesRead; } } + public TimeSpan Age { get { return DateTime.Now.Subtract(_StartTime); } } + public EndPoint RemoteEndPoint { + get { + if (_Socket == null || !_Socket.Connected) return null; + try { + return _Socket.RemoteEndPoint; + } catch (SocketException) { + return null; + } + } + } + //public Object Proxy { get { return null; } } + Object INetworkConnection.Handler { get { return Tag; } } + } +} diff -r 000000000000 -r 3ab940a0c7a0 Pml/Channels/ActivePmlChannel.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Pml/Channels/ActivePmlChannel.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,107 @@ +using System; +using UCIS.Pml; +using System.Collections.Generic; +using System.Threading; + +namespace UCIS.Pml { + public abstract class ActivePmlChannel : IPmlChannel { + private AutoResetEvent _receiveEvent = new AutoResetEvent(false); + private ReadMessageAsyncResult _asyncWait = null; + private Queue _queue = new Queue(); + private bool _isOpen = true; + + public virtual bool IsOpen { get { return _isOpen; } } + public abstract void WriteMessage(PmlElement message); + + public PmlElement ReadMessage() { + if (!IsOpen) throw new InvalidOperationException("The channel is not open"); + if (_queue.Count == 0) { + _receiveEvent.WaitOne(); + if (_queue.Count == 0) throw new OperationCanceledException("The operation did not complete"); + } else if (_queue.Count == 1) { + _receiveEvent.Reset(); + } + return _queue.Dequeue(); + } + + public IAsyncResult BeginReadMessage(AsyncCallback callback, object state) { + ReadMessageAsyncResult ar = new ReadMessageAsyncResult(state, callback); + if (!IsOpen) throw new InvalidOperationException("The channel is not open"); + if (_asyncWait != null) throw new InvalidOperationException("Another asynchronous operation is in progress"); + if (_queue.Count == 0) { + _asyncWait = ar; + } else { + if (_queue.Count == 1) _receiveEvent.Reset(); + ar.Complete(true, _queue.Dequeue(), true); + } + return ar; + } + + public PmlElement EndReadMessage(IAsyncResult asyncResult) { + ReadMessageAsyncResult ar = (ReadMessageAsyncResult)asyncResult; + if (ar.Error) new OperationCanceledException("The operation did not complete"); + return ar.Message; + } + + public virtual void Close() { + _isOpen = false; + ReadMessageAsyncResult asyncWait = Interlocked.Exchange(ref _asyncWait, null); + if (asyncWait != null) asyncWait.Complete(false, null, false); + _receiveEvent.Set(); + _receiveEvent.Close(); + } + + public void Dispose() { + Close(); + } + + protected void PushReceivedMessage(PmlElement message) { + ReadMessageAsyncResult asyncWait = Interlocked.Exchange(ref _asyncWait, null); + if (asyncWait != null) { + asyncWait.Complete(true, message, false); + } else { + _queue.Enqueue(message); + _receiveEvent.Set(); + } + } + + private class ReadMessageAsyncResult : IAsyncResult { + private object state; + private AsyncCallback callback; + private bool completed; + private bool synchronously; + private ManualResetEvent waitHandle; + + internal PmlElement Message; + internal bool Error; + + public bool CompletedSynchronously { get { return synchronously; } } + public object AsyncState { get { return state; } } + public WaitHandle AsyncWaitHandle { + get { + if (waitHandle == null) waitHandle = new ManualResetEvent(completed); + return waitHandle; + } + } + public bool IsCompleted { get { return completed; } } + + internal ReadMessageAsyncResult(object state, AsyncCallback callback) { + this.state = state; + this.callback = callback; + this.completed = false; + this.synchronously = false; + this.Message = null; + this.Error = false; + this.waitHandle = null; + } + internal void Complete(bool success, PmlElement message, bool synchronously) { + this.Message = message; + this.Error = !success; + this.synchronously = synchronously; + this.completed = true; + if (waitHandle != null) waitHandle.Set(); + if (this.callback != null) this.callback.Invoke(this); + } + } + } +} diff -r 000000000000 -r 3ab940a0c7a0 Pml/Channels/IPmlChannel.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Pml/Channels/IPmlChannel.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,22 @@ +using System; + +namespace UCIS.Pml { + /*public class PmlMessageReceivedEventArgs : EventArgs { + private PmlElement _message; + public PmlMessageReceivedEventArgs(PmlElement message) { + _message = message; + } + public PmlElement Message { get { return _message; } } + }*/ + public interface IPmlChannel : IDisposable { + //event EventHandler MessageReceived; + //event EventHandler Closed; + bool IsOpen { get; } + void WriteMessage(PmlElement message); + void Close(); + + PmlElement ReadMessage(); + IAsyncResult BeginReadMessage(AsyncCallback callback, object state); + PmlElement EndReadMessage(IAsyncResult asyncResult); + } +} diff -r 000000000000 -r 3ab940a0c7a0 Pml/Channels/PassivePmlChannel.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Pml/Channels/PassivePmlChannel.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,59 @@ +using System; +using UCIS.Pml; +using System.Collections.Generic; +using System.Threading; + +namespace UCIS.Pml { + public abstract class PassivePmlChannel : IPmlChannel { + private bool _isOpen = true; + + public virtual bool IsOpen { get { return _isOpen; } } + public abstract void WriteMessage(PmlElement message); + + public void Dispose() { + Close(); + } + public virtual void Close() { + _isOpen = false; + } + + public abstract PmlElement ReadMessage(); + + public IAsyncResult BeginReadMessage(AsyncCallback callback, object state) { + ReadMessageAsyncResult ar = new ReadMessageAsyncResult(); + ar.Callback = callback; + ar.State = state; + UCIS.ThreadPool.RunCall(AsyncReadMessage, ar); + return ar; + } + public PmlElement EndReadMessage(IAsyncResult asyncResult) { + ReadMessageAsyncResult ar = (ReadMessageAsyncResult)asyncResult; + if (ar.Error != null) throw new Exception("The asynchronous operation could not be completed", ar.Error); + return ar.Message; + } + + private struct ReadMessageAsyncResult : IAsyncResult { + internal object State; + internal PmlElement Message; + internal AsyncCallback Callback; + internal Exception Error; + internal bool Completed; + + public bool CompletedSynchronously { get { return false; } } + public object AsyncState { get { return State; } } + public WaitHandle AsyncWaitHandle { get { return null; } } + public bool IsCompleted { get { return Completed; } } + } + private void AsyncReadMessage(object state) { + ReadMessageAsyncResult ar = (ReadMessageAsyncResult)state; + try { + ar.Message = ReadMessage(); + ar.Error = null; + } catch (Exception ex) { + ar.Error = ex; + } + ar.Completed = true; + ar.Callback.Invoke(ar); + } + } +} diff -r 000000000000 -r 3ab940a0c7a0 Pml/Channels/PmlChannel.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Pml/Channels/PmlChannel.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace UCIS.Pml { + public class PmlChannel : ActivePmlChannel { + private IPmlRW _rw; + private bool _open; + + public PmlChannel(IPmlRW rw) { + if (rw == null) throw new ArgumentNullException("rw"); + _rw = rw; + _open = true; + ThreadPool.RunTask(worker, null); + } + + public IPmlReader Reader { get { return _rw; } } + public IPmlWriter Writer { get { return _rw; } } + + public new bool IsOpen { get { return _open; } } + + public override void WriteMessage(PmlElement message) { + if (!_open) throw new InvalidOperationException("The channel is not open"); + lock (_rw) _rw.WriteMessage(message); + } + + public override void Close() { + if (!_open) return; + _open = false; + if (_rw != null) _rw = null; + base.Close(); + } + + private void worker(Object state) { + try { + while (_open) { + base.PushReceivedMessage(_rw.ReadMessage()); + } + } catch (System.Net.Sockets.SocketException ex) { + Console.WriteLine("SocketException in PmlChannel.worker: " + ex.Message); + } catch (System.IO.EndOfStreamException ex) { + Console.WriteLine("EndOfStreamException in PmlChannel.worker: " + ex.Message); + } catch (Exception ex) { + Console.WriteLine(ex.ToString()); + } finally { + Close(); + } + } + } +} diff -r 000000000000 -r 3ab940a0c7a0 Pml/Channels/TCPPmlChannel.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Pml/Channels/TCPPmlChannel.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,49 @@ +using System; +using System.IO; +using System.Net.Sockets; +using UCIS.Net; + +namespace UCIS.Pml { + public class TCPPmlChannel : PassivePmlChannel { + private TCPStream _socket; + private IPmlRW _rw; + private bool _open = false; + + public TCPPmlChannel(Socket socket) : this(new TCPStream(socket)) { } + public TCPPmlChannel(TCPStream socket) { + if (socket == null) throw new ArgumentNullException("socket"); + _socket = socket; + _rw = new PmlBinaryRW(_socket); + _open = true; + //ThreadPool.RunTask(worker, null); + } + + public override void WriteMessage(PmlElement message) { + if (!_open) throw new InvalidOperationException("The channel is not open"); + lock (_rw) _rw.WriteMessage(message); + } + + public override void Close() { + if (!_open) return; + _open = false; + if (_socket != null) try { _socket.Close(); } catch { } + base.Close(); + } + + public override PmlElement ReadMessage() { + return _rw.ReadMessage(); + } + + /*private void worker(Object state) { + try { + while (_open) { + base.PushReceivedMessage(_rw.ReadMessage()); + } + } catch (Exception ex) { + Console.WriteLine(ex.ToString()); + } finally { + Close(); + } + }*/ + } +} diff -r 000000000000 -r 3ab940a0c7a0 Pml/Elements/Array.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Pml/Elements/Array.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,281 @@ +using System; +using System.Collections; +using System.Collections.Generic; +//using KvpType = System.Collections.Generic.KeyValuePair; +using KvpType = UCIS.Pml.PmlArray.KeyValuePair; + +namespace UCIS.Pml { + public class PmlArray : PmlElement, IDictionary, IList, IList, ICollection { + /* Internal variables */ + private List _items = new List(); + private int _indexed = 0; + + /* Internal key-value pair structure */ + public class KeyValuePair { + internal KeyValuePair(string key, PmlElement value) { this.Key = key; this.Value = value; } + public string Key { get; set; } + public PmlElement Value { get; set; } + } + + /* Constructors */ + public PmlArray() { + } + public PmlArray(params KeyValuePair[] elements) { + foreach (KeyValuePair item in elements) Add(item); + } + public PmlArray(IEnumerable> elements) { + foreach (KeyValuePair item in elements) Add(item); + } + public PmlArray(params PmlElement[] elements) { + foreach (PmlElement item in elements) Add(item); + } + public PmlArray(IEnumerable elements) { + foreach (PmlElement item in elements) Add(item); + } + public PmlArray(String key1, PmlElement val1) { + Add(key1, val1); + } + public PmlArray(String key1, PmlElement val1, String key2, PmlElement val2) { + Add(key1, val1); + Add(key2, val2); + } + public PmlArray(String key1, PmlElement val1, String key2, PmlElement val2, String key3, PmlElement val3) { + Add(key1, val1); + Add(key2, val2); + Add(key3, val3); + } + public PmlArray(params Object[] interleavedKeyValue) { + for (int i = 0; i < interleavedKeyValue.Length; ) { + Add(interleavedKeyValue[i++] as String, interleavedKeyValue[i++]); + } + } + public PmlArray(String[] keys, params PmlElement[] values) { + if (keys.Length != values.Length) throw new ArgumentException("Length of keys array does not match length of values array"); + for (int i = 0; i < keys.Length; i++) { Add(keys[i] as String, values[i]); } + } + + public bool IsIndexed { + get { + if (_indexed == -1) { + _indexed = 0; + foreach (KvpType kvp in _items) { + if (kvp.Key != null && kvp.Key.Length > 0) { + _indexed = 1; + break; + } + } + } + return _indexed != 0; + } + } + + /* PmlElement implementation */ + protected override object GetValue() { return _items; } + public override PmlElement GetChild(string Name) { return GetItem(Name); } + public override PmlElement GetChild(int index) { return GetItem(index); } + public override object ToNumeric() { return _items.Count; } + public override PmlElementType Type { get { return PmlElementType.Dictionary; } } + + /* Internal KVP lookup */ + private KvpType GetKVP(string name) { + return _items.Find(delegate(KvpType kvp) { return (kvp.Key == name); }); + } + private KvpType GetKVP(PmlElement value) { + return _items.Find(delegate(KvpType kvp) { return (kvp.Value == value); }); + } + private KvpType GetKVP(int index) { + if (index < 0 || index >= _items.Count) return null; + return _items[index]; + } + + /* Item retrieval */ + public PmlElement GetItem(string name) { + KvpType kvp = GetKVP(name); + return kvp == null ? null : kvp.Value; + } + public PmlElement GetItem(int index) { + if (index < 0 || index >= _items.Count) return null; + return _items[index].Value; + } + public bool TryGetValue(string key, out PmlElement value) { + value = GetItem(key); + return (value != null); + } + + /* Array implementation */ + public PmlElement this[string key] { + get { return GetItem(key); } + set { + Remove(key); + Add(key, value); + } + } + public KvpType this[int id] { + get { return GetKVP(id); } + set { _items[id] = value; } + } + PmlElement IList.this[int id] { + get { return GetItem(id); } + set { + KvpType item = GetKVP(id); + item = new KvpType(item == null ? null : item.Key, value); + _items[id] = item; + } + } + + /* Add implementations */ + public void Add(KvpType kvp) { //Final Add method, handles all additions (except insertions!) + if (_indexed == 0 && kvp.Key != null && kvp.Key.Length > 0) _indexed = 1; + _items.Add(kvp); + } + + public PmlElement Add(string Key, PmlElement Element) { + if (Element == null) Element = new PmlNull(); + Add(new KvpType(Key, Element)); + return Element; + } + + public PmlElement Add(string key, Object value) { + PmlElement el; + if (value == null) { + el = new PmlNull(); + } else if (value is PmlElement) { + el = value as PmlElement; + } else if (value is String) { + el = new PmlString(value as string); + } else if (value is Int32 || value is Int64) { + el = new PmlNumber((Int64)value); + } else if (value is UInt32 || value is UInt32) { + el = new PmlNumber((UInt64)value); + } else { + el = new PmlString(value.ToString()); + } + return Add(key, el); + } + public PmlElement Add(string Key, string Element) { return Add(Key, new PmlString(Element)); } + public PmlElement Add(string Key, long Element) { return Add(Key, new PmlInteger(Element)); } + public PmlElement Add(string Key, ulong Element) { return Add(Key, new PmlInteger(Element)); } + + public PmlElement Add(PmlElement Element) { return Add(null, Element); } + public PmlElement Add(object Element) { return Add(null, Element); } + public PmlElement Add(string Element) { return Add(new PmlString(Element)); } + public PmlElement Add(long Element) { return Add(new PmlInteger(Element)); } + public PmlElement Add(ulong Element) { return Add(new PmlInteger(Element)); } + + public void Add(KeyValuePair item) { Add(item.Key, item.Value); } + + void ICollection.Add(PmlElement item) { Add(item); } + void IDictionary.Add(string key, PmlElement value) { Add(key, value); } + + /* Insert implementations */ + private void Insert(int index, KvpType kvp) { + if (kvp.Key != null && kvp.Key.Length > 0 && _indexed == 0) _indexed = 1; + _items.Insert(index, kvp); + } + void IList.Insert(int index, KvpType value) { Insert(index, value); } + void IList.Insert(int index, PmlElement value) { Insert(index, new KvpType(null, value)); } + + /* Remove */ + public bool Remove(KvpType item) { + _indexed = -1; + return _items.Remove(item); + } + public void RemoveAt(int index) { + _indexed = -1; + _items.RemoveAt(index); + } + public bool Remove(PmlElement item) { + KvpType kvp = GetKVP(item); + if (kvp == null) return false; + return Remove(kvp); + } + public bool Remove(string Key) { + KvpType kvp = GetKVP(Key); + if (kvp == null) return false; + return Remove(kvp); + } + bool ICollection>.Remove(KeyValuePair kvp) { return Remove(kvp.Key); } + + public void Clear() { + _indexed = 0; + _items.Clear(); + } + + /* Contains */ + public bool Contains(PmlElement item) { return GetKVP(item) != null; } + public bool Contains(string key) { return GetKVP(key) != null; } + bool IDictionary.ContainsKey(string key) { return Contains(key); } + bool ICollection.Contains(KvpType kvp) { return _items.Contains(kvp); } + bool ICollection>.Contains(KeyValuePair kvp) { return Contains(kvp.Key); } + + /* Index lookup */ + public int IndexOf(PmlElement value) { return _items.FindIndex(delegate(KvpType kvp) { return (kvp.Value == value); }); } + int IList.IndexOf(KvpType value) { return _items.IndexOf(value); } + + /* Copy operations */ + public void CopyTo(KvpType[] array, int offset) { + _items.CopyTo(array, offset); + } + public void CopyTo(PmlElement[] array, int offset) { + foreach (KvpType kvp in _items) array[offset++] = kvp.Value; + } + void ICollection.CopyTo(string[] array, int offset) { + foreach (KvpType kvp in _items) array[offset++] = kvp.Key; + } + void ICollection>.CopyTo(KeyValuePair[] array, int offset) { + foreach (KvpType kvp in _items) array[offset++] = new KeyValuePair(kvp.Key, kvp.Value); + } + + /* Dictionary props */ + public ICollection Values { get { return this as ICollection; } } + public ICollection Keys { get { return this as ICollection; } } + + /* Stuf... */ + public int Count { get { return _items.Count; } } + public bool IsReadOnly { get { return false; } } + void ICollection.Add(string value) { throw new NotImplementedException(); } + + /* Enumerators */ + IEnumerator IEnumerable.GetEnumerator() { return _items.GetEnumerator(); } + IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } + public IEnumerator GetEnumerator() { return new ValueEnumerator(this); } + IEnumerator IEnumerable.GetEnumerator() { return new KeyEnumerator(this); } + IEnumerator> IEnumerable>.GetEnumerator() { return new KvpEnumerator(this); } + + private class KeyEnumerator : IEnumerator { + protected IEnumerator _enum; + internal KeyEnumerator(PmlArray array) { _enum = array._items.GetEnumerator(); } + private KvpType KVP { get { return _enum.Current; } } + public bool MoveNext() { return _enum.MoveNext(); } + public void Reset() { _enum.Reset(); } + public void Dispose() { _enum.Dispose(); } + Object IEnumerator.Current { get { return Current; } } + + public String Current { get { return KVP == null ? null : KVP.Key; } } + } + private class ValueEnumerator : IEnumerator { + protected IEnumerator _enum; + internal ValueEnumerator(PmlArray array) { _enum = array._items.GetEnumerator(); } + private KvpType KVP { get { return _enum.Current; } } + public bool MoveNext() { return _enum.MoveNext(); } + public void Reset() { _enum.Reset(); } + public void Dispose() { _enum.Dispose(); } + Object IEnumerator.Current { get { return Current; } } + + public PmlElement Current { get { return KVP == null ? null : KVP.Value; } } + } + private class KvpEnumerator : IEnumerator> { + protected IEnumerator _enum; + internal KvpEnumerator(PmlArray array) { _enum = array._items.GetEnumerator(); } + private KvpType KVP { get { return _enum.Current; } } + public bool MoveNext() { return _enum.MoveNext(); } + public void Reset() { _enum.Reset(); } + public void Dispose() { _enum.Dispose(); } + Object IEnumerator.Current { get { return Current; } } + + public KeyValuePair Current { get { + return KVP == null ? default(KeyValuePair) : new KeyValuePair(KVP.Key, KVP.Value); + } } + } + } +} \ No newline at end of file diff -r 000000000000 -r 3ab940a0c7a0 Pml/Elements/Binary.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Pml/Elements/Binary.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,31 @@ +using System; +using System.Text; + +namespace UCIS.Pml { + public class PmlBinary : PmlElement { + private byte[] _Value; + + public PmlBinary(byte[] Value) { + _Value = Value; + } + + public override PmlType Type { get { return PmlType.Binary; } } + + public override object ToObject() { return _Value; } + public override string ToString() { return Encoding.UTF8.GetString(_Value); } + public override bool ToBoolean() { return BitConverter.ToBoolean(_Value, 0); } + public override byte ToByte() { return _Value[0]; } + public override decimal ToDecimal() { return _Value.Length == 4 ? (Decimal)BitConverter.ToSingle(_Value, 0) : (Decimal)BitConverter.ToDouble(_Value, 0); } + public override double ToDouble() { return BitConverter.ToDouble(_Value, 0); } + public override short ToInt16() { return BitConverter.ToInt16(_Value, 0); } + public override int ToInt32() { return BitConverter.ToInt32(_Value, 0); } + public override long ToInt64() { return BitConverter.ToInt64(_Value, 0); } + public override sbyte ToSByte() { return (SByte)_Value[0]; } + public override float ToSingle() { return BitConverter.ToSingle(_Value, 0); } + public override ushort ToUInt16() { return BitConverter.ToUInt16(_Value, 0); } + public override uint ToUInt32() { return BitConverter.ToUInt32(_Value, 0); } + public override ulong ToUInt64() { return BitConverter.ToUInt64(_Value, 0); } + public override char ToChar() { return BitConverter.ToChar(_Value, 0); } + public override byte[] ToByteArray() { return _Value; } + } +} \ No newline at end of file diff -r 000000000000 -r 3ab940a0c7a0 Pml/Elements/Collection.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Pml/Elements/Collection.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,74 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace UCIS.Pml { + public class PmlCollection : PmlElement, ICollection { + private List pItems = new List(); + + public PmlCollection() { } + public PmlCollection(params PmlElement[] Elements) { + pItems.AddRange(Elements); + } + public PmlCollection(IEnumerable Elements) { + pItems.AddRange(Elements); + } + + public PmlElement Add(PmlElement Element) { + pItems.Add(Element); + return Element; + } + public void Remove(PmlElement Element) { + pItems.Remove(Element); + } + public void RemoveAt(int Index) { + pItems.RemoveAt(Index); + } + public void Clear() { + pItems.Clear(); + } + public bool Contains(PmlElement item) { + return pItems.Contains(item); + } + public void CopyTo(PmlElement[] array, int arrayIndex) { + pItems.CopyTo(array, arrayIndex); + } + public int Count { get { return pItems.Count; } } + public bool IsReadOnly { get { return false; } } + public IEnumerator GetEnumerator() { return pItems.GetEnumerator(); } + IEnumerator IEnumerable.GetEnumerator() { return pItems.GetEnumerator(); } + bool ICollection.Remove(PmlElement item) { return pItems.Remove(item); } + void ICollection.Add(PmlElement item) { Add(item); } + + public override PmlType Type { get { return PmlType.Collection; } } + + public override object ToObject() { return pItems; } + public override string ToString() { return null; } + public override bool ToBoolean() { return pItems.Count > 0; } + public override byte ToByte() { return (Byte)pItems.Count; } + public override decimal ToDecimal() { return pItems.Count; } + public override double ToDouble() { return pItems.Count; } + public override short ToInt16() { return (Int16)pItems.Count; } + public override int ToInt32() { return pItems.Count; } + public override long ToInt64() { return pItems.Count; } + public override sbyte ToSByte() { return (SByte)pItems.Count; } + public override float ToSingle() { return pItems.Count; } + public override ushort ToUInt16() { return (UInt16)pItems.Count; } + public override uint ToUInt32() { return (UInt32)pItems.Count; } + public override ulong ToUInt64() { return (UInt64)pItems.Count; } + public override char ToChar() { return '\0'; } + public override byte[] ToByteArray() { return null; } + + //public override PmlElement GetChild(string name) { return GetChild(name); } + public override PmlElement GetChild(int index) { return pItems[index]; } + public override IEnumerable GetChildren() { return pItems; } + public override IEnumerable> GetNamedChildren() { + KeyValuePair[] kvps = new KeyValuePair[pItems.Count]; + for (int i = 0; i < kvps.Length; i++) kvps[i] = new KeyValuePair(null, pItems[i]); + return kvps; + } + public override int GetChildCount() { return pItems.Count; } + public override void AddChild(string name, PmlElement value) { Add(value); } + public override void AddChild(PmlElement value) { Add(value); } + } +} diff -r 000000000000 -r 3ab940a0c7a0 Pml/Elements/Dictionary.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Pml/Elements/Dictionary.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,165 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace UCIS.Pml { + public class PmlDictionary : PmlElement, IDictionary, ICollection { + private List> pItems = new List>(); + + public PmlDictionary() { } + public PmlDictionary(String[] keys, params PmlElement[] values) { + if (keys.Length != values.Length) throw new ArgumentException("keys.Length != values.Length", "values"); + for (int i = 0; i < keys.Length; i++) Add(keys[i], values[i]); + } + public PmlDictionary(params KeyValuePair[] Elements) { + foreach (KeyValuePair Item in Elements) pItems.Add(Item); + } + public PmlDictionary(IEnumerable> Elements) { + foreach (KeyValuePair Item in Elements) pItems.Add(Item); + } + + public override PmlElement GetChild(string Name) { + foreach (KeyValuePair KVP in pItems) { + if (KVP.Key.Equals(Name, StringComparison.InvariantCultureIgnoreCase)) return KVP.Value; + } + return null; + } + public override PmlElement GetChild(int index) { + return pItems[index].Value; + } + public bool TryGetValue(string key, out PmlElement value) { + value = GetChild(key); + return (value != null); + } + public PmlElement this[string key] { + get { return GetChild(key); } + set { + Remove(key); + Add(key, value); + } + } + + public PmlElement Add(string Key, PmlElement Element) { + if (Element == null) Element = new PmlNull(); + pItems.Add(new KeyValuePair(Key, Element)); + return Element; + } + private void Add(KeyValuePair item) { + pItems.Add(item); + } + public void Add(PmlElement item) { + Add("", item); + } + + void IDictionary.Add(string key, PmlElement value) { + Add(key, value); + } + void ICollection>.Add(KeyValuePair item) { + Add(item); + } + + public bool Remove(PmlElement item) { + foreach (KeyValuePair KVP in pItems) { + if (KVP.Value == item) { + pItems.Remove(KVP); + return true; + } + } + return false; + } + public bool Remove(string Key) { + foreach (KeyValuePair KVP in pItems) { + if (KVP.Key.Equals(Key, StringComparison.InvariantCultureIgnoreCase)) { + pItems.Remove(KVP); + return true; + } + } + return false; + } + public bool Remove(KeyValuePair item) { + return ((ICollection>)pItems).Remove(item); + } + + public int Count { + get { return pItems.Count; } + } + + public void Clear() { + pItems.Clear(); + } + + public bool Contains(PmlElement item) { + foreach (KeyValuePair KVP in pItems) { + if (KVP.Value == item) return true; + } + return false; + } + bool ICollection>.Contains(KeyValuePair item) { + return ((ICollection>)pItems).Contains(item); + } + public bool ContainsKey(string key) { + foreach (KeyValuePair KVP in pItems) { + if (KVP.Key.Equals(key, StringComparison.InvariantCultureIgnoreCase)) return true; + } + return false; + } + + void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) { + ((ICollection>)pItems).CopyTo(array, arrayIndex); + } + void ICollection.CopyTo(PmlElement[] array, int arrayIndex) { + foreach (KeyValuePair KVP in pItems) { + array[arrayIndex] = KVP.Value; + arrayIndex += 1; + } + } + + public ICollection Keys { + get { + List Ret = new List(); + foreach (KeyValuePair KVP in pItems) Ret.Add(KVP.Key); + return Ret; + } + } + public ICollection Values { + get { + List Ret = new List(); + foreach (KeyValuePair KVP in pItems) Ret.Add(KVP.Value); + return Ret; + } + } + public IEnumerator> GetEnumerator() { return pItems.GetEnumerator(); } + IEnumerator IEnumerable.GetEnumerator() { return pItems.GetEnumerator(); } + IEnumerator IEnumerable.GetEnumerator() { return Values.GetEnumerator(); } + + public bool IsReadOnly { get { return false; } } + + + public override PmlType Type { get { return PmlType.Dictionary; } } + + public override object ToObject() { return pItems; } + public override string ToString() { return null; } + public override bool ToBoolean() { return pItems.Count > 0; } + public override byte ToByte() { return (Byte)pItems.Count; } + public override decimal ToDecimal() { return pItems.Count; } + public override double ToDouble() { return pItems.Count; } + public override short ToInt16() { return (Int16)pItems.Count; } + public override int ToInt32() { return pItems.Count; } + public override long ToInt64() { return pItems.Count; } + public override sbyte ToSByte() { return (SByte)pItems.Count; } + public override float ToSingle() { return pItems.Count; } + public override ushort ToUInt16() { return (UInt16)pItems.Count; } + public override uint ToUInt32() { return (UInt32)pItems.Count; } + public override ulong ToUInt64() { return (UInt64)pItems.Count; } + public override char ToChar() { return '\0'; } + public override byte[] ToByteArray() { return null; } + + //public override PmlElement GetChild(string name) { return GetChild(name); } + //public override PmlElement GetChild(int index) { return GetChild(index); } + public override IEnumerable GetChildren() { return Values; } + public override IEnumerable> GetNamedChildren() { return pItems; } + public override int GetChildCount() { return pItems.Count; } + public override void AddChild(string name, PmlElement value) { Add(name, value); } + public override void AddChild(PmlElement value) { Add(value); } + } +} \ No newline at end of file diff -r 000000000000 -r 3ab940a0c7a0 Pml/Elements/Element.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Pml/Elements/Element.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace UCIS.Pml { + /*public enum PmlElementType : byte { + Null = 0, + + Dictionary = 1, + Collection = 2, + + Binary = 10, + String = 11, + + Integer = 20 + }*/ + public enum PmlType { + Null, + Dictionary, + Collection, + Binary, + String, + Integer, + //Number, + } + public abstract class PmlElement { + public abstract PmlType Type { get; } + + public virtual PmlElement GetChild(string name) { return null; } + public virtual PmlElement GetChild(int index) { return null; } + public virtual IEnumerable GetChildren() { return null; } + public virtual IEnumerable> GetNamedChildren() { return null; } + public virtual int GetChildCount() { return 0; } + public virtual void AddChild(string name, PmlElement value) { throw new NotSupportedException(); } + public virtual void AddChild(PmlElement value) { throw new NotSupportedException(); } + + public abstract object ToObject(); + public abstract override string ToString(); + public abstract bool ToBoolean(); + public abstract byte ToByte(); + public abstract decimal ToDecimal(); + public abstract double ToDouble(); + public abstract short ToInt16(); + public abstract int ToInt32(); + public abstract long ToInt64(); + public abstract sbyte ToSByte(); + public abstract float ToSingle(); + public abstract ushort ToUInt16(); + public abstract uint ToUInt32(); + public abstract ulong ToUInt64(); + public abstract char ToChar(); + public abstract byte[] ToByteArray(); + + public static explicit operator string(PmlElement e) { return e == null ? null : e.ToString(); } + public static explicit operator bool(PmlElement e) { return e == null ? false : e.ToBoolean(); } + public static explicit operator byte(PmlElement e) { return e == null ? (byte)0 : e.ToByte(); } + public static explicit operator decimal(PmlElement e) { return e == null ? (decimal)0 : e.ToDecimal(); } + public static explicit operator double(PmlElement e) { return e == null ? (double)0 : e.ToDouble(); } + public static explicit operator short(PmlElement e) { return e == null ? (short)0 : e.ToInt16(); } + public static explicit operator int(PmlElement e) { return e == null ? (int)0 : e.ToInt32(); } + public static explicit operator long(PmlElement e) { return e == null ? (long)0 : e.ToInt64(); } + public static explicit operator sbyte(PmlElement e) { return e == null ? (sbyte)0 : e.ToSByte(); } + public static explicit operator float(PmlElement e) { return e == null ? (float)0 : e.ToSingle(); } + public static explicit operator ushort(PmlElement e) { return e == null ? (ushort)0 : e.ToUInt16(); } + public static explicit operator uint(PmlElement e) { return e == null ? (uint)0 : e.ToUInt32(); } + public static explicit operator ulong(PmlElement e) { return e == null ? (ulong)0 : e.ToUInt64(); } + public static explicit operator char(PmlElement e) { return e == null ? '\0' : e.ToChar(); } + public static explicit operator byte[](PmlElement e) { return e == null ? null : e.ToByteArray(); } + + public static implicit operator PmlElement(String str) { return new PmlString(str); } + public static implicit operator PmlElement(UInt64 number) { return new PmlInteger(number); } + public static implicit operator PmlElement(UInt32 number) { return new PmlInteger(number); } + public static implicit operator PmlElement(Int64 number) { return new PmlInteger(number); } + public static implicit operator PmlElement(Int32 number) { return new PmlInteger(number); } + public static implicit operator PmlElement(Int16 number) { return new PmlInteger(number); } + public static implicit operator PmlElement(UInt16 number) { return new PmlInteger(number); } + public static implicit operator PmlElement(Byte number) { return new PmlInteger(number); } + //public static implicit operator PmlElement(Double number) { return new PmlNumber(number); } + } +} diff -r 000000000000 -r 3ab940a0c7a0 Pml/Elements/Integer.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Pml/Elements/Integer.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,52 @@ +using System; + +namespace UCIS.Pml { + public class PmlInteger : PmlElement { + private UInt64 pUValue; + private Int64 pSValue; + private bool pSigned; + + public PmlInteger() { + pSValue = 0; + pSigned = true; + } + public PmlInteger(UInt64 Value) { + pUValue = Value; + pSigned = false; + } + public PmlInteger(Int64 Value) { + pSValue = Value; + pSigned = true; + } + public PmlInteger(string Value) { + if (Int64.TryParse(Value, out pSValue)) { + pSigned = true; + } else if (UInt64.TryParse(Value, out pUValue)) { + pSigned = false; + } else { + throw new FormatException(); + } + } + + public Boolean IsSigned { get { return pSigned; } } + + public override PmlType Type { get { return PmlType.Integer; } } + + public override object ToObject() { return pSigned ? (Object)pSValue : (Object)pUValue; } + public override string ToString() { return pSigned ? pSValue.ToString() : pUValue.ToString(); } + public override bool ToBoolean() { return pSigned ? (pSValue != 0) : (pUValue != 0); } + public override byte ToByte() { return pSigned ? (Byte)pSValue : (Byte)pUValue; } + public override decimal ToDecimal() { return pSigned ? (Decimal)pSValue : (Decimal)pUValue; } + public override double ToDouble() { return pSigned ? (Double)pSValue : (Double)pUValue; } + public override short ToInt16() { return pSigned ? (Int16)pSValue : (Int16)pUValue; } + public override int ToInt32() { return pSigned ? (Int32)pSValue : (Int32)pUValue; } + public override long ToInt64() { return pSigned ? pSValue : (Int64)pUValue; } + public override sbyte ToSByte() { return pSigned ? (SByte)pSValue : (SByte)pUValue; } + public override float ToSingle() { return pSigned ? (Single)pSValue : (Single)pUValue; } + public override ushort ToUInt16() { return pSigned ? (UInt16)pSValue : (UInt16)pUValue; } + public override uint ToUInt32() { return pSigned ? (UInt32)pSValue : (UInt32)pUValue; } + public override ulong ToUInt64() { return pSigned ? (UInt64)pSValue : pUValue; } + public override char ToChar() { return pSigned ? (Char)pSValue : (Char)pUValue; } + public override byte[] ToByteArray() { return pSigned ? BitConverter.GetBytes(pSValue) : BitConverter.GetBytes(pUValue); } + } +} \ No newline at end of file diff -r 000000000000 -r 3ab940a0c7a0 Pml/Elements/Number.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Pml/Elements/Number.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,37 @@ +using System; +using System.Globalization; + +namespace UCIS.Pml { + public class PmlNumber : PmlElement { + private double _Value; + + public PmlNumber() { + _Value = 0; + } + public PmlNumber(double Value) { + _Value = Value; + } + public PmlNumber(string Value) { + _Value = double.Parse(Value); + } + + public override PmlType Type { get { return PmlType.Number; } } + + public override object ToObject() { return _Value; } + public override string ToString() { return _Value.ToString("#,#", CultureInfo.InvariantCulture); } + public override bool ToBoolean() { return _Value != 0; } + public override byte ToByte() { return (Byte)_Value; } + public override decimal ToDecimal() { return (Decimal)_Value; } + public override double ToDouble() { return (Double)_Value; } + public override short ToInt16() { return (Int16)_Value; } + public override int ToInt32() { return (Int32)_Value; } + public override long ToInt64() { return (Int64)_Value; } + public override sbyte ToSByte() { return (SByte)_Value; } + public override float ToSingle() { return (Single)_Value; } + public override ushort ToUInt16() { return (UInt16)_Value; } + public override uint ToUInt32() { return (UInt32)_Value; } + public override ulong ToUInt64() { return (UInt64)_Value; } + public override char ToChar() { return (Char)_Value; } + public override byte[] ToByteArray() { return BitConverter.GetBytes(_Value); } + } +} diff -r 000000000000 -r 3ab940a0c7a0 Pml/Elements/PmlNull.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Pml/Elements/PmlNull.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,22 @@ +namespace UCIS.Pml { + public class PmlNull : PmlElement { + public override PmlType Type { get { return PmlType.Null; } } + + public override object ToObject() { return null; } + public override string ToString() { return null; } + public override bool ToBoolean() { return false; } + public override byte ToByte() { return 0; } + public override decimal ToDecimal() { return 0; } + public override double ToDouble() { return 0; } + public override short ToInt16() { return 0; } + public override int ToInt32() { return 0; } + public override long ToInt64() { return 0; } + public override sbyte ToSByte() { return 0; } + public override float ToSingle() { return 0; } + public override ushort ToUInt16() { return 0; } + public override uint ToUInt32() { return 0; } + public override ulong ToUInt64() { return 0; } + public override char ToChar() { return '\0'; } + public override byte[] ToByteArray() { return null; } + } +} \ No newline at end of file diff -r 000000000000 -r 3ab940a0c7a0 Pml/Elements/PmlString.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Pml/Elements/PmlString.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,32 @@ +using System; +using System.Text; +using System.Globalization; + +namespace UCIS.Pml { + public class PmlString : PmlElement { + private string _Value; + + public PmlString(string Value) { + _Value = Value; + } + + public override PmlType Type { get { return PmlType.String; } } + + public override object ToObject() { return _Value; } + public override string ToString() { return _Value; } + public override bool ToBoolean() { return Boolean.Parse(_Value); } + public override byte ToByte() { return Byte.Parse(_Value, CultureInfo.InvariantCulture); } + public override decimal ToDecimal() { return Decimal.Parse(_Value, CultureInfo.InvariantCulture); } + public override double ToDouble() { return Double.Parse(_Value, CultureInfo.InvariantCulture); } + public override short ToInt16() { return Int16.Parse(_Value, CultureInfo.InvariantCulture); } + public override int ToInt32() { return Int32.Parse(_Value, CultureInfo.InvariantCulture); } + public override long ToInt64() { return Int64.Parse(_Value, CultureInfo.InvariantCulture); } + public override sbyte ToSByte() { return SByte.Parse(_Value, CultureInfo.InvariantCulture); } + public override float ToSingle() { return Single.Parse(_Value, CultureInfo.InvariantCulture); } + public override ushort ToUInt16() { return UInt16.Parse(_Value, CultureInfo.InvariantCulture); } + public override uint ToUInt32() { return UInt32.Parse(_Value, CultureInfo.InvariantCulture); } + public override ulong ToUInt64() { return UInt64.Parse(_Value, CultureInfo.InvariantCulture); } + public override char ToChar() { return _Value[0]; } + public override byte[] ToByteArray() { return Encoding.UTF8.GetBytes(_Value); } + } +} diff -r 000000000000 -r 3ab940a0c7a0 Pml/IPmlCommunicator.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Pml/IPmlCommunicator.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace UCIS.Pml { + public class PmlCallReceivedEventArgs : EventArgs { + private PmlElement _request; + private PmlElement _reply; + private UInt32 _sid; + private bool _wantReply; + + internal PmlCallReceivedEventArgs(PmlElement request, bool wantReply, UInt32 sid) { + _request = request; + _wantReply = wantReply; + _sid = sid; + _reply = null; + } + public bool WantReply { + get { return _wantReply; } + } + internal UInt32 SID { + get { return _sid; } + } + public PmlElement Reply { + get { return _reply; } + set { _reply = value; } + } + public PmlElement Request { + get { return _request; } + } + } + public abstract class PmlChannelRequestReceivedEventArgs : EventArgs { + public abstract IPmlChannel Accept(); + public abstract void Reject(); + public abstract PmlElement Data { get; } + } + public interface IPmlCommunicator { + event EventHandler CallReceived; + event EventHandler ChannelRequestReceived; + + void Call(PmlElement message); + PmlElement Invoke(PmlElement message); + + IAsyncResult BeginInvoke(PmlElement message, AsyncCallback callback, Object state); + PmlElement EndInvoke(IAsyncResult result); + + IPmlChannel CreateChannel(PmlElement data); + IAsyncResult BeginCreateChannel(PmlElement data, AsyncCallback callback, Object state); + IPmlChannel EndCreateChannel(IAsyncResult result); + } +} diff -r 000000000000 -r 3ab940a0c7a0 Pml/IPmlRpc.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Pml/IPmlRpc.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; + +namespace UCIS.Pml { + interface IPmlRpcServer { + IDictionary ExportedMethods { get; } + IDictionary ExportedObjects { get; } + } + interface IPmlRpcClient { + void Call(String method, params Object[] args); + void Invoke(String method, params Object[] args); + void BeginInvoke(String method, Object[] args, AsyncCallback callback, Object state); + Object EndInvoke(IAsyncResult result); + } +} diff -r 000000000000 -r 3ab940a0c7a0 Pml/LegacyPmlCommunicator.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Pml/LegacyPmlCommunicator.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,403 @@ +using System; +using System.Threading; +using System.Collections.Generic; +using UCIS.Pml; + +namespace UCIS.Pml { + public class LegacyPmlCommunicator { + private class CSyncRequest { + internal PmlElement Reply; + internal ManualResetEvent ResetEvent = new ManualResetEvent(false); + } + public abstract class SessionBase { + private bool pActive; + private LegacyPmlCommunicator pConnection; + private UInt32 pSID; + + public uint SID { get { return pSID; } } + public bool Active { get { return pActive; } } + public LegacyPmlCommunicator Communicator { get { return pConnection; } } + + protected SessionBase(LegacyPmlCommunicator Connection) { + pConnection = Connection; + } + + protected void Accept(UInt32 SID) { + if (pActive) throw new InvalidOperationException("Session is active"); + pSID = SID; + lock (pConnection.pSessions) pConnection.pSessions.Add(pSID, this); + pActive = true; + } + protected void Request() { + Request(null); + } + protected void Request(PmlElement Message) { + if (pActive) throw new InvalidOperationException("Session is active"); + pSID = pConnection.GetNextSessionId(true); + lock (pConnection.pSessions) pConnection.pSessions.Add(pSID, this); + pConnection.WriteSessionMessage(pSID, 0, Message); + pActive = true; + } + + protected internal abstract void MessageIn(PmlElement Message); + + protected void SendMessage(PmlElement Message) { + if (!pActive) throw new InvalidOperationException("Session is not active"); + pConnection.WriteSessionMessage(pSID, 1, Message); + } + + public void Close() { + Close(null); + } + public void Close(PmlElement Message) { + if (!pActive) return; // throw new InvalidOperationException("Session is not active"); + pConnection.WriteSessionMessage(pSID, 2, Message); + ClosedA(); + } + + internal void ClosedA() { + pActive = false; + lock (pConnection.pSessions) pConnection.pSessions.Remove(pSID); + } + + internal void ClosedB(PmlElement Message) { + pActive = false; + Closed(Message); + } + + protected virtual void Closed(PmlElement Message) { + } + } + public class Session : SessionBase { + public event MessageReceivedEventHandler MessageReceived; + public delegate void MessageReceivedEventHandler(PmlElement Message); + public event SessionClosedEventHandler SessionClosed; + public delegate void SessionClosedEventHandler(PmlElement Message); + + public Session(LegacyPmlCommunicator Connection) : base(Connection) { } + + public new void Accept(UInt32 SID) { + base.Accept(SID); + } + public new void Request() { + Request(null); + } + public new void Request(PmlElement Message) { + base.Request(Message); + } + + protected internal override void MessageIn(PmlElement Message) { + if (MessageReceived != null) MessageReceived(Message); + } + + public new void SendMessage(PmlElement Message) { + base.SendMessage(Message); + } + + protected override void Closed(PmlElement Message) { + if (SessionClosed != null) SessionClosed(Message); + } + } + + private Dictionary pSessions = new Dictionary(); + private UInt32 pNextSession; + private Dictionary pSyncRequests = new Dictionary(); + private UInt32 pNextSyncRequest; + + private IPmlChannel _channel; + + public event MessageReceivedEventHandler MessageReceived; + public delegate void MessageReceivedEventHandler(PmlElement Message); + public event RequestReceivedEventHandler RequestReceived; + public delegate void RequestReceivedEventHandler(PmlElement Request, ref PmlElement Reply); + public event SessionRequestReceivedEventHandler SessionRequestReceived; + public delegate void SessionRequestReceivedEventHandler(PmlElement Request, uint SID); + public event EventHandler Closed; + + public ICollection Sessions { get { return (ICollection)pSessions.Values; } } + public int SyncRequests { get { return pSyncRequests.Count; } } + + public LegacyPmlCommunicator(IPmlChannel channel, bool autoStart) { + _channel = channel; + if (autoStart) Start(); + //_channel.BeginReadMessage(messageReceived, null); + //_channel.MessageReceived += messageReceived; + //_channel.Closed += closed; + } + public void Start() { + _channel.BeginReadMessage(messageReceived, null); + } + + public IPmlChannel Channel { get { return _channel; } } + + public void Close() { + //_channel.MessageReceived -= messageReceived; + //_channel.Closed -= closed; + _channel.Close(); + } + + private void _WriteMessage(PmlElement Message) { + lock (_channel) { + if (_channel.IsOpen) { + _channel.WriteMessage(Message); + } else { + throw new InvalidOperationException("Could not write message: the channel is not open"); + } + } + } + + private UInt32 GetNextSessionId(bool IsSession) { + if (IsSession) { + lock (pSessions) { + do { + if (pNextSession == UInt32.MaxValue) { + pNextSession = 0; + } else { + pNextSession += (uint)1; + } + } + while (pSessions.ContainsKey(pNextSession)); + return pNextSession; + } + } else { + lock (pSyncRequests) { + do { + if (pNextSyncRequest == UInt32.MaxValue) { + pNextSyncRequest = 0; + } else { + pNextSyncRequest += (uint)1; + } + } + while (pSyncRequests.ContainsKey(pNextSyncRequest)); + return pNextSyncRequest; + } + } + } + + protected void WriteSessionMessage(UInt32 SID, byte CMD, PmlElement MSG) { + PmlDictionary Msg2 = new PmlDictionary(); + Msg2.Add("CMD", new PmlString("SES")); + Msg2.Add("SID", new PmlInteger(SID)); + Msg2.Add("SCMD", new PmlInteger(CMD)); + Msg2.Add("MSG", MSG); + _WriteMessage(Msg2); + } + + protected void WriteSyncMessage(UInt32 SID, bool RPL, PmlElement MSG) { + PmlDictionary Msg2 = new PmlDictionary(); + if (RPL) { + Msg2.Add("CMD", new PmlString("RPL")); + } else { + Msg2.Add("CMD", new PmlString("REQ")); + } + Msg2.Add("SID", new PmlInteger(SID)); + Msg2.Add("MSG", MSG); + _WriteMessage(Msg2); + } + + private void messageReceived(IAsyncResult ar) { + PmlElement Message; + try { + Message = _channel.EndReadMessage(ar); + _channel.BeginReadMessage(messageReceived, null); + } catch (InvalidOperationException ex) { + Console.WriteLine("InvalidOperationException in LegacyPmlCommunicator.messageReceived: " + ex.Message); + closed(); + _channel.Close(); + return; + } catch (Exception ex) { + Console.WriteLine(ex.ToString()); + closed(); + _channel.Close(); + return; + } + int Ping = 0; + if (Message == null) { + if (Ping > 2) { + _channel.Close(); + return; + } else { + _WriteMessage(new PmlString("PING")); + } + Ping += 1; + } else if (Message is PmlString) { + string Cmd = Message.ToString(); + if (Cmd.Equals("PING")) { + _WriteMessage(new PmlString("PONG")); + } else if (Cmd.Equals("PONG")) { + Ping = 0; + } + } else if (Message is PmlDictionary) { + string Cmd = null; + Cmd = Message.GetChild("CMD").ToString(); + if (Cmd.Equals("SES")) { + UInt32 SID = default(UInt32); + byte SCMD = 0; + SessionBase Session = default(SessionBase); + PmlElement InnerMsg = default(PmlElement); + SID = Message.GetChild("SID").ToUInt32(); + SCMD = Message.GetChild("SCMD").ToByte(); + InnerMsg = Message.GetChild("MSG"); + lock (pSessions) { + if (pSessions.ContainsKey(SID)) { + Session = pSessions[SID]; + } else { + Session = null; + } + } + if (SCMD == 0) { + if (Session == null) { + if (SessionRequestReceived != null) { + try { + SessionRequestReceived(InnerMsg, SID); + } catch (Exception ex) { + Console.WriteLine("Exception in LegacyPmlCommnuicator.messageReceived->SessionRequestReceived: " + ex.ToString()); + WriteSessionMessage(SID, 2, null); + } + } + } else { + try { + Session.ClosedA(); + Session.ClosedB(null); + } catch (Exception ex) { + Console.WriteLine("Exception in LegacyPmlCommnuicator.messageReceived->Session.ClosedA/B: " + ex.ToString()); + } + WriteSessionMessage(SID, 2, null); + } + } else if (SCMD == 1) { + if (Session == null) { + WriteSessionMessage(SID, 2, null); + } else { + try { + Session.MessageIn(InnerMsg); + } catch (Exception ex) { + Console.WriteLine("Exception in LegacyPmlCommnuicator.messageReceived->Session.MessageIn: " + ex.ToString()); + WriteSessionMessage(SID, 2, null); + } + } + } else if (SCMD == 2) { + if (Session != null) { + try { + Session.ClosedA(); + Session.ClosedB(InnerMsg); + } catch (Exception ex) { + Console.WriteLine("Exception in LegacyPmlCommnuicator.messageReceived->Session.ClosedA/B: " + ex.ToString()); + } + } + } + } else if (Cmd.Equals("RPL")) { + UInt32 SID = default(UInt32); + CSyncRequest SRequest = null; + SID = Message.GetChild("SID").ToUInt32(); + lock (pSyncRequests) { + if (pSyncRequests.TryGetValue(SID, out SRequest)) { + pSyncRequests.Remove(SID); + } else { + Console.WriteLine("UCIS.PML.Connection.Worker Invalid request ID in reply: " + SID.ToString()); + } + } + if (SRequest != null) { + SRequest.Reply = Message.GetChild("MSG"); + SRequest.ResetEvent.Set(); + } + } else if (Cmd.Equals("REQ")) { + UCIS.ThreadPool.RunCall(SyncRequestHandler, Message); + //System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(SyncRequestHandler), Message); + } else if (Cmd.Equals("MSG")) { + PmlElement InnerMsg = Message.GetChild("MSG"); + if (MessageReceived != null) MessageReceived(InnerMsg); + } else { + throw new InvalidOperationException("Invalid operation"); + } + } + } + private void closed() { + //_channel.MessageReceived -= messageReceived; + //_channel.Closed -= closed; + Console.WriteLine("UCIS.PML.Connection: Connection closed"); + try { + SessionBase[] sessions; + lock (pSessions) { + sessions = new SessionBase[pSessions.Count]; + pSessions.Values.CopyTo(sessions, 0); + } + foreach (SessionBase S in sessions) { + try { + S.ClosedB(null); + } catch (Exception ex) { + Console.WriteLine(ex.ToString()); + } + } + } catch (Exception ex) { + Console.WriteLine(ex.ToString()); + } + lock (pSessions) pSessions.Clear(); + try { + CSyncRequest[] reqs; + lock (pSyncRequests) { + reqs = new CSyncRequest[pSyncRequests.Count]; + pSyncRequests.Values.CopyTo(reqs, 0); + } + foreach (CSyncRequest T in reqs) { + T.ResetEvent.Set(); + } + } catch (Exception ex) { + Console.WriteLine(ex.ToString()); + } + lock (pSyncRequests) pSyncRequests.Clear(); + if (Closed != null) Closed(this, new EventArgs()); + } + + private void SyncRequestHandler(object state) { + PmlDictionary Message = (PmlDictionary)state; + PmlElement Reply = null; + UInt32 SID = 0; + try { + SID = Message.GetChild("SID").ToUInt32(); + PmlElement InnerMsg = Message.GetChild("MSG"); + if (RequestReceived != null) { + RequestReceived(InnerMsg, ref Reply); + } + } catch (Exception ex) { + Reply = new PmlDictionary(); + ((PmlDictionary)Reply).Add("EXCEPTION", new PmlString(ex.ToString())); + Console.WriteLine(ex.ToString()); + } + try { + WriteSyncMessage(SID, true, Reply); + } catch (Exception ex) { + Console.WriteLine("Exception: " + ex.ToString()); + } + } + + public PmlElement SyncRequest(PmlElement Request) { + return SyncRequest(Request, 30000); + } + public PmlElement SyncRequest(PmlElement Request, int Timeout) { + CSyncRequest SyncEvent = new CSyncRequest(); + UInt32 SID = GetNextSessionId(false); + lock (pSyncRequests) pSyncRequests.Add(SID, SyncEvent); + try { + WriteSyncMessage(SID, false, Request); + if (!SyncEvent.ResetEvent.WaitOne(Timeout, false)) { + lock (pSyncRequests) pSyncRequests.Remove(SID); + throw new TimeoutException("The SyncRequest timed out (SID=" + SID.ToString() + ")"); + } + } finally { + lock (pSyncRequests) pSyncRequests.Remove(SID); + } + return SyncEvent.Reply; + } + + public void SendMessage(PmlElement Message) { + PmlDictionary Msg = new PmlDictionary(); + Msg.Add("CMD", new PmlString("MSG")); + Msg.Add("MSG", Message); + _WriteMessage(Msg); + } + + public void SendRawMessage(PmlElement Message) { + _WriteMessage(Message); + } + } +} diff -r 000000000000 -r 3ab940a0c7a0 Pml/PmlBuilder.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Pml/PmlBuilder.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,129 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace UCIS.Pml { + public class PmlBuilder { + private IPmlWriter pWriter; + private Stack pStack = new Stack(); + + public PmlBuilder(IPmlWriter Writer) { + pWriter = Writer; + } + public PmlBuilder() { + pWriter = null; + } + + public IPmlWriter BaseWriter { + get { return pWriter; } + set { pWriter = value; } + } + + private PmlElement AddChildElement(PmlElement Element, bool AddToStack) { + return AddChildElement(Element, AddToStack, null); + } + private PmlElement AddChildElement(PmlElement Element, bool AddToStack, string ChildName) { + PmlElement Parent; + if (pStack.Count > 0) { + Parent = pStack.Peek(); + if (Parent is PmlDictionary) { + if (ChildName == null) throw new ArgumentNullException("ChildName", "Dictionary items need a Name"); + ((PmlDictionary)Parent).Add(ChildName, Element); + } else if (Parent is PmlCollection) { + if (ChildName != null) throw new ArgumentOutOfRangeException("ChildName", "Can not add named element to a Collection"); + ((PmlCollection)Parent).Add(Element); + } else { + throw new InvalidOperationException("Invalid Element type in stack: " + Parent.Type.ToString()); + } + } else { + if (ChildName != null) { + throw new ArgumentOutOfRangeException("ChildName", "Can not create named element without container (Dictionary)"); + } else if (!AddToStack) { + pWriter.WriteMessage(Element); + } + } + if (AddToStack) pStack.Push(Element); + return Element; + } + + public PmlElement EndElement() { + if (pStack.Count > 0) { + PmlElement Element = pStack.Pop(); + if (pStack.Count == 0) { + if (pWriter != null) pWriter.WriteMessage(Element); + } + return Element; + } else { + return null; + } + } + public PmlElement GetMessage() { + if (pStack.Count == 1) { + PmlElement Element = pStack.Pop(); + return Element; + } else if (pStack.Count == 0) { + throw new InvalidOperationException("No stacked element. The top most element should not be ended. All elements, except Dictionary and Collection, are sent automatically."); + } else { + throw new InvalidOperationException("All elements, except for the top most element, should be ended."); + } + } + + public PmlElement SendMessage() { + PmlElement Element; + if (pWriter == null) throw new NullReferenceException("Writer is not set"); + Element = GetMessage(); + pWriter.WriteMessage(Element); + return Element; + } + + public PmlDictionary Dictionary() { + return (PmlDictionary)AddChildElement(new PmlDictionary(), true); + } + public PmlCollection Collection() { + return (PmlCollection)AddChildElement(new PmlCollection(), true); + } + public PmlString String(string Value) { + return (PmlString)AddChildElement(new PmlString(Value), false); + } + public PmlBinary Binary(byte[] Value) { + return (PmlBinary)AddChildElement(new PmlBinary(Value), false); + } + public PmlInteger Integer(UInt64 Value) { + return (PmlInteger)AddChildElement(new PmlInteger(Value), false); + } + public PmlInteger Integer(Int64 Value) { + return (PmlInteger)AddChildElement(new PmlInteger(Value), false); + } + public PmlNull Null() { + return (PmlNull)AddChildElement(new PmlNull(), false); + } + public PmlElement Element(PmlElement Child) { + return AddChildElement(Child, false); + } + + public PmlDictionary Dictionary(string Name) { + return (PmlDictionary)AddChildElement(new PmlDictionary(), true, Name); + } + public PmlCollection Collection(string Name) { + return (PmlCollection)AddChildElement(new PmlCollection(), true, Name); + } + public PmlString String(string Name, string Value) { + return (PmlString)AddChildElement(new PmlString(Value), false, Name); + } + public PmlBinary Binary(string Name, byte[] Value) { + return (PmlBinary)AddChildElement(new PmlBinary(Value), false, Name); + } + public PmlInteger Integer(string Name, UInt64 Value) { + return (PmlInteger)AddChildElement(new PmlInteger(Value), false, Name); + } + public PmlInteger Integer(string Name, Int64 Value) { + return (PmlInteger)AddChildElement(new PmlInteger(Value), false, Name); + } + public PmlNull Null(string Name) { + return (PmlNull)AddChildElement(new PmlNull(), false, Name); + } + public PmlElement Element(string Name, PmlElement Child) { + return AddChildElement(Child, false, Name); + } + } +} \ No newline at end of file diff -r 000000000000 -r 3ab940a0c7a0 Pml/PmlCommunicator.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Pml/PmlCommunicator.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,342 @@ +using System; +using System.Threading; +using System.Collections.Generic; + +namespace UCIS.Pml { +/* class PmlCommunicator : IPmlCommunicator, IDisposable { + private IPmlChannel _channel; + private Dictionary _subchannels = new Dictionary(); + private Random _random = new Random(); + + private enum CommandCode : int { + CallWithoutReply = 0, + CallWithReply = 1, + Message = 2, + ChannelRequest = 3, + ChannelAcknowledge = 4, + ChannelClose = 5, + Error = 6 + } + + private interface IPmlSubChannel { + void CloseIn(); + void ErrorIn(PmlElement message); + void MessageIn(PmlElement message); + } + + private class ChannelRequestWaitHandler : IAsyncResult { + internal AsyncCallback Callback = null; + internal Object CallbackState = null; + internal ManualResetEvent Event = null; + internal PmlSubChannel Channel = null; + internal bool Completed = false; + + internal ChannelRequestWaitHandler(PmlSubChannel channel) { + Channel = channel; + } + + internal void Complete() { + Completed = true; + if (Event != null) Event.Set(); + if (Callback != null) Callback.Invoke(this); + } + + public object AsyncState { get { return CallbackState; } } + public WaitHandle AsyncWaitHandle { get { return null; } } + public bool CompletedSynchronously { get { return false; } } + public bool IsCompleted { get { return Completed; } } + } + private class PmlSubChannel : ActivePmlChannel, IPmlSubChannel { + private enum ChannelState { Requesting, Acknowledged, Closed } + + private PmlCommunicator _communicator; + private UInt32 _id; + private ChannelState _state; + + internal PmlSubChannel(PmlCommunicator communicator, UInt32 sid) { + _communicator = communicator; + _id = sid; + _state = ChannelState.Requesting; + } + + public override bool IsOpen { get { return _state == ChannelState.Acknowledged; } } + + internal void AcknowledgeIn() { + if (_state != 0) throw new InvalidOperationException("The subchannel is not awaiting an acknowledgement"); + _state = ChannelState.Acknowledged; + } + void IPmlSubChannel.CloseIn() { + _state = ChannelState.Closed; + _communicator._subchannels.Remove(_id); + base.Close(); + } + void IPmlSubChannel.ErrorIn(PmlElement message) { + (this as IPmlSubChannel).CloseIn(); + } + void IPmlSubChannel.MessageIn(PmlElement message) { + base.PushReceivedMessage(message); + } + + internal void AcknowledgeOut() { + if (_state != 0) throw new InvalidOperationException("The subchannel is not awaiting an acknowledgement"); + _state = ChannelState.Acknowledged; + _communicator.sendMessage(CommandCode.ChannelAcknowledge, _id, null); + } + internal void RejectOut() { + if (_state != 0) throw new InvalidOperationException("The subchannel is not awaiting an acknowledgement"); + _state = ChannelState.Closed; + _communicator.sendMessage(CommandCode.ChannelClose, _id, null); + } + + public override void SendMessage(PmlElement message) { + if (_state != ChannelState.Acknowledged) throw new InvalidOperationException("The subchannel is not open"); + _communicator.sendMessage(CommandCode.Message, _id, message); + } + public override void Close() { + if (_state != ChannelState.Acknowledged) return; + _state = ChannelState.Closed; + _communicator.sendMessage(CommandCode.ChannelClose, _id, null); + _communicator._subchannels.Remove(_id); + base.Close(); + } + } + private class PmlChannelRequestReceivedEventArgsA : PmlChannelRequestReceivedEventArgs { + private PmlCommunicator _communicator; + private PmlElement _data; + private PmlSubChannel _channel; + private bool _accepted; + private bool _rejected; + internal PmlChannelRequestReceivedEventArgsA(PmlCommunicator communicator, UInt32 sid, PmlElement message) { + _communicator = communicator; + _channel = new PmlSubChannel(communicator, sid); + _data = message; + } + public override IPmlChannel Accept() { + if (_accepted || _rejected) throw new InvalidOperationException("The channel has already been accepted or rejected"); + _accepted = true; + _channel.AcknowledgeOut(); + return _channel; + } + public override void Reject() { + if (_accepted) throw new InvalidOperationException("The channel has already been accepted"); + if (_rejected) return; + _rejected = true; + _channel.RejectOut(); + } + internal void RejectIfNotAccepted() { + if (!_accepted) Reject(); + } + public override PmlElement Data { + get { + return _data; + } + } + } + + private class PmlInvocation : IAsyncResult, IPmlSubChannel { + internal PmlCommunicator Communicator = null; + internal AsyncCallback Callback = null; + internal Object CallbackState = null; + internal bool Error = false; + internal bool Completed = false; + internal PmlElement Message = null; + internal ManualResetEvent Event = null; + internal UInt32 ID; + + internal PmlInvocation(PmlCommunicator communicator, UInt32 id) { + Communicator = communicator; + ID = id; + } + + void IPmlSubChannel.CloseIn() { + (this as IPmlSubChannel).ErrorIn(null); + } + void IPmlSubChannel.ErrorIn(PmlElement message) { + Error = true; + Communicator._subchannels.Remove(ID); + (this as IPmlSubChannel).MessageIn(message); + } + void IPmlSubChannel.MessageIn(PmlElement message) { + Message = message; + Completed = true; + if (Event != null) Event.Set(); + if (Callback != null) Callback.Invoke(this); + } + + public object AsyncState { get { return CallbackState; } } + public WaitHandle AsyncWaitHandle { get { return null; } } + public bool CompletedSynchronously { get { return false; } } + public bool IsCompleted { get { return Completed; } } + } + + public event EventHandler CallReceived; + public event EventHandler ChannelRequestReceived; + + public PmlCommunicator(IPmlChannel channel) { + _channel = channel; + _channel.Closed += channelClosed; + } + + public void Dispose() { + _channel.Close(); + _channel = null; + IPmlSubChannel[] A = new IPmlSubChannel[_subchannels.Count]; + _subchannels.Values.CopyTo(A, 0); + foreach (IPmlSubChannel S in A) S.CloseIn(); + _subchannels.Clear(); + _subchannels = null; + _random = null; + } + + private void channelClosed(Object sender, EventArgs e) { + Dispose(); + } + + public IPmlChannel Channel { get { return _channel; } } + + public void Call(PmlElement message) { + sendMessage(0, 0, message); //Call without reply + } + public PmlElement Invoke(PmlElement message) { + return Invoke(message, 60000); + } + public PmlElement Invoke(PmlElement message, int timeout) { + UInt32 sid = getSessionID(); + PmlInvocation inv = new PmlInvocation(this, sid); + inv.Event = new ManualResetEvent(false); + _subchannels.Add(sid, inv); + sendMessage(CommandCode.CallWithReply, sid, message); + inv.Event.WaitOne(timeout); + if (inv.Error) throw new Exception(message.ToString()); + return inv.Message; + } + + public IAsyncResult BeginInvoke(PmlElement message, AsyncCallback callback, Object state) { + UInt32 sid = getSessionID(); + PmlInvocation inv = new PmlInvocation(this, sid); + inv.Callback = callback; + inv.CallbackState = state; + _subchannels.Add(sid, inv); + sendMessage(CommandCode.CallWithReply, sid, message); + return inv; + } + public PmlElement EndInvoke(IAsyncResult result) { + PmlInvocation ar = (PmlInvocation)result; + if (!ar.Completed) { + (_subchannels as IList).Remove(ar); + throw new InvalidOperationException("The asynchronous operation has not completed"); + } else if (ar.Error) { + throw new Exception(ar.Message.ToString()); + } else { + return ar.Message; + } + } + + public IPmlChannel CreateChannel(PmlElement data) { + UInt32 sid = getSessionID(); + PmlSubChannel ch = new PmlSubChannel(this, sid); + ChannelRequestWaitHandler wh = new ChannelRequestWaitHandler(ch); + wh.Event = new ManualResetEvent(false); + _subchannels.Add(sid, ch); + sendMessage(CommandCode.ChannelRequest, sid, data); + wh.Event.WaitOne(); + if (!ch.IsOpen) return null; + return ch; + } + public IAsyncResult BeginCreateChannel(PmlElement data, AsyncCallback callback, Object state) { + UInt32 sid = getSessionID(); + PmlSubChannel ch = new PmlSubChannel(this, sid); + ChannelRequestWaitHandler wh = new ChannelRequestWaitHandler(ch); + wh.Callback = callback; + wh.CallbackState = state; + _subchannels.Add(sid, ch); + sendMessage(CommandCode.ChannelRequest, sid, data); + if (!ch.IsOpen) return null; + return wh; + } + public IPmlChannel EndCreateChannel(IAsyncResult result) { + ChannelRequestWaitHandler ar = (ChannelRequestWaitHandler)result; + if (!ar.Channel.IsOpen) return null; + return ar.Channel; + } + + private UInt32 getSessionID() { + return (uint)_random.Next(); + } + + private void sendMessage(CommandCode cmd, uint sid, PmlElement message) { + PmlDictionary msg = new PmlDictionary(); + msg.Add("c", (int)cmd); + if (cmd > 0) msg.Add("s", sid); + if (message != null) msg.Add("m", message); + _channel.SendMessage(msg); + } + + private void invokeCallReceived(Object state) { + PmlCallReceivedEventArgs e = (PmlCallReceivedEventArgs)state; + try { + if (CallReceived != null) CallReceived(this, e); + if (e.WantReply) sendMessage(CommandCode.Message, e.SID, e.Reply); + } catch (Exception ex) { + if (e.WantReply) sendMessage(CommandCode.Error, e.SID, new PmlString(ex.ToString())); + } + } + private void invokeChannelRequestReceived(Object state) { + PmlChannelRequestReceivedEventArgsA e = (PmlChannelRequestReceivedEventArgsA)state; + if (ChannelRequestReceived != null) ChannelRequestReceived(this, e); + e.RejectIfNotAccepted(); + } + + private void messageReceived(Object sender, EventArgs e) { + IPmlSubChannel subChannel = null; + UInt32 sid = 0; + bool subChannelExists = false; + if (!(e.Message is PmlDictionary)) return; + PmlDictionary msg = (PmlDictionary)e.Message; + PmlElement cmdElement = msg.GetChild("c"); + PmlElement sidElement = msg.GetChild("i"); + PmlElement msgElement = msg.GetChild("m"); + if (cmdElement == null) return; + if (sidElement != null) sid = sidElement.ToUInt32(); + if (sidElement != null) subChannelExists = _subchannels.TryGetValue(sid, out subChannel); + if (!subChannelExists) subChannel = null; + switch ((CommandCode)cmdElement.ToInt32()) { + case CommandCode.CallWithoutReply: + if (CallReceived != null) ThreadPool.RunCall(invokeCallReceived, new PmlCallReceivedEventArgs(msgElement, false, 0)); + break; + case CommandCode.CallWithReply: + if (CallReceived != null) ThreadPool.RunCall(invokeCallReceived, new PmlCallReceivedEventArgs(msgElement, true, sid)); + else sendMessage(CommandCode.Error, sid, null); + break; + case CommandCode.Message: //Reply to call | subchannel message + if (subChannelExists) subChannel.MessageIn(msgElement); + else sendMessage(CommandCode.Error, sid, null); + break; + case CommandCode.ChannelRequest: + if (subChannelExists) { + sendMessage(CommandCode.Error, sid, null); + subChannel.CloseIn(); + } else { + if (ChannelRequestReceived == null) sendMessage(CommandCode.ChannelClose, sid, null); + else ThreadPool.RunCall(invokeChannelRequestReceived, new PmlChannelRequestReceivedEventArgsA(this, sid, msgElement)); + } + break; + case CommandCode.ChannelAcknowledge: + if (subChannelExists) { + if (subChannel is PmlSubChannel) (subChannel as PmlSubChannel).AcknowledgeIn(); + else { + sendMessage(CommandCode.Error, sid, null); //Error + subChannel.CloseIn(); + } + } else sendMessage(CommandCode.Error, sid, null); //Error + break; + case CommandCode.ChannelClose: + if (subChannelExists) subChannel.CloseIn(); + break; + case CommandCode.Error: + if (subChannelExists) subChannel.ErrorIn(msgElement); + break; + } + } + }*/ +} diff -r 000000000000 -r 3ab940a0c7a0 Pml/PmlCommunicator2.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Pml/PmlCommunicator2.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,479 @@ +using System; +using System.Threading; +using System.Collections.Generic; +using UCIS.Pml; + +namespace UCIS.Pml { + public class PmlCommunicator { + private class CSyncRequest { + internal PmlElement Reply; + internal ManualResetEvent ResetEvent = new ManualResetEvent(false); + } + private interface ISession { + void MessageIn(PmlElement message); + void CloseIn(); + UInt32 ID { get; } + } + /*public abstract class SessionBase : ISession { + private bool pActive; + private PmlCommunicator _communicator; + private UInt32 _id; + + public uint SID { get { return _id; } } + public bool Active { get { return pActive; } } + public PmlCommunicator Communicator { get { return _communicator; } } + + protected SessionBase(PmlCommunicator Connection) { + _communicator = Connection; + } + + protected void Accept(UInt32 sid) { + if (pActive) throw new InvalidOperationException("Session is active"); + _id = sid; + lock (_communicator._sessions) _communicator._sessions.Add(_id, this); + pActive = true; + } + protected void Request() { + Request(null); + } + protected void Request(PmlElement Message) { + if (pActive) throw new InvalidOperationException("Session is active"); + _id = _communicator.GetNextSessionId(true); + lock (_communicator._sessions) _communicator._sessions.Add(_id, this); + _communicator.WriteSessionMessage(_id, 0, Message); + pActive = true; + } + + uint ISession.ID { get { return _id; } } + void ISession.MessageIn(PmlElement message) { this.MessageIn(message); } + void ISession.CloseIn() { + pActive = false; + _communicator.RemoveSession(this); + Closed(null); + } + + protected internal abstract void MessageIn(PmlElement Message); + + protected void SendMessage(PmlElement Message) { + if (!pActive) throw new InvalidOperationException("Session is not active"); + _communicator.WriteSessionMessage(_id, 1, Message); + } + + public void Close() { + if (!pActive) return; + pActive = false; + _communicator.WriteSessionMessage(_id, 2, null); + _communicator.RemoveSession(this); + } + + protected virtual void Closed(PmlElement Message) { } + } + public class Session : SessionBase { + public event MessageReceivedEventHandler MessageReceived; + public delegate void MessageReceivedEventHandler(PmlElement Message); + public event SessionClosedEventHandler SessionClosed; + public delegate void SessionClosedEventHandler(PmlElement Message); + + public Session(PmlCommunicator Connection) : base(Connection) { } + + public new void Accept(UInt32 SID) { + base.Accept(SID); + } + public new void Request() { + Request(null); + } + public new void Request(PmlElement Message) { + base.Request(Message); + } + + protected internal override void MessageIn(PmlElement Message) { + if (MessageReceived != null) MessageReceived(Message); + } + + public new void SendMessage(PmlElement Message) { + base.SendMessage(Message); + } + + protected override void Closed(PmlElement Message) { + if (SessionClosed != null) SessionClosed(Message); + } + }*/ + + private class PmlSubChannel : ActivePmlChannel, ISession { + private enum ChannelState { Requesting, Acknowledged, Closed } + + private PmlCommunicator _communicator; + private UInt32 _id; + private ChannelState _state; + + internal PmlSubChannel(PmlCommunicator communicator, UInt32 sid, bool accepted) { + _communicator = communicator; + _id = sid; + _state = accepted ? ChannelState.Acknowledged : ChannelState.Requesting; + if (accepted) _communicator.AddSession(this); + } + + public override bool IsOpen { get { return _state == ChannelState.Acknowledged; } } + + uint ISession.ID { get { return _id; } } + void ISession.CloseIn() { + _state = ChannelState.Closed; + _communicator.RemoveSession(this); + base.Close(); + } + void ISession.MessageIn(PmlElement message) { + base.PushReceivedMessage(message); + } + + public override void WriteMessage(PmlElement message) { + if (_state != ChannelState.Acknowledged) throw new InvalidOperationException("The subchannel is not open"); + _communicator.WriteSessionMessage(_id, 1, message); + } + public override void Close() { + if (_state != ChannelState.Acknowledged) return; + _state = ChannelState.Closed; + _communicator.WriteSessionMessage(_id, 2, null); + _communicator.RemoveSession(this); + base.Close(); + } + } + private class PmlChannelRequestReceivedEventArgsA : PmlChannelRequestReceivedEventArgs { + private PmlCommunicator _communicator; + private PmlElement _data; + private bool _accepted, _rejected; + private UInt32 _sid; + internal PmlChannelRequestReceivedEventArgsA(PmlCommunicator communicator, UInt32 sid, PmlElement message) { + _communicator = communicator; + _data = message; + _sid = sid; + _accepted = _rejected = false; + } + public UInt32 AcceptSession() { + if (_accepted || _rejected) throw new InvalidOperationException("The channel has already been accepted or rejected"); + _accepted = true; + return _sid; + } + public override IPmlChannel Accept() { + if (_accepted || _rejected) throw new InvalidOperationException("The channel has already been accepted or rejected"); + _accepted = true; + return new PmlSubChannel(_communicator, _sid, true); + } + public override void Reject() { + if (_accepted) throw new InvalidOperationException("The channel has already been accepted"); + if (_rejected) return; + _rejected = true; + _communicator.WriteSessionMessage(_sid, 2, null); + //_channel.RejectOut(); + } + internal void RejectIfNotAccepted() { + if (!_accepted) Reject(); + } + public override PmlElement Data { + get { + return _data; + } + } + } + + public event EventHandler CallReceived; + public event EventHandler ChannelRequestReceived; + public event EventHandler Closed; + + private Dictionary _sessions = new Dictionary(); + private Dictionary _invocations = new Dictionary(); + private UInt32 pNextSession; + private UInt32 pNextSyncRequest; + + private bool _closed; + private IPmlChannel _channel; + + public IPmlChannel Channel { get { return _channel; } } + + public PmlCommunicator(IPmlChannel channel, bool autoStart) { + _channel = channel; + if (autoStart) Start(); + } + public void Start() { + _channel.BeginReadMessage(messageReceived, null); + } + public void StartSync() { + while (true) { + try { + processMessage(_channel.ReadMessage()); + } catch (InvalidOperationException ex) { + Console.WriteLine("InvalidOperationException in LegacyPmlCommunicator.messageReceived: " + ex.Message); + closed(); + _channel.Close(); + return; + } catch (Exception ex) { + Console.WriteLine(ex.ToString()); + closed(); + _channel.Close(); + return; + } + } + } + public void Close() { + _channel.Close(); + } + public void WriteRawMessage(PmlElement Message) { + _WriteMessage(Message); + } + + private void _WriteMessage(PmlElement Message) { + lock (_channel) { + if (!_channel.IsOpen) throw new InvalidOperationException("Could not write message: the channel is not open"); + _channel.WriteMessage(Message); + } + } + private void closed() { + _closed = true; + lock (_sessions) { + foreach (ISession S in _sessions.Values) { + try { + S.CloseIn(); + } catch (Exception ex) { + Console.WriteLine(ex.ToString()); + } + } + _sessions.Clear(); + } + lock (_invocations) { + foreach (CSyncRequest T in _invocations.Values) { + T.ResetEvent.Set(); + } + _invocations.Clear(); + } + if (Closed != null) Closed(this, new EventArgs()); + } + + private void messageReceived(IAsyncResult ar) { + try { + PmlElement Message = _channel.EndReadMessage(ar); + processMessage(Message); + _channel.BeginReadMessage(messageReceived, null); + } catch (InvalidOperationException ex) { + Console.WriteLine("InvalidOperationException in LegacyPmlCommunicator.messageReceived: " + ex.Message); + closed(); + _channel.Close(); + return; + } catch (Exception ex) { + Console.WriteLine(ex.ToString()); + closed(); + _channel.Close(); + return; + } + } + private void processMessage(PmlElement Message) { + if (Message is PmlString) { + string Cmd = Message.ToString(); + if (Cmd.Equals("PING")) { + _WriteMessage(new PmlString("PONG")); + /*} else if (Cmd.Equals("PONG")) { + Ping = 0;*/ + } + } else if (Message is PmlDictionary) { + string Cmd = Message.GetChild("CMD").ToString(); + if (Cmd.Equals("SES")) { + processSessionMessage(Message); + } else if (Cmd.Equals("RPL")) { + UInt32 SID = Message.GetChild("SID").ToUInt32(); + CSyncRequest SRequest = null; + lock (_invocations) { + if (_invocations.TryGetValue(SID, out SRequest)) { + _invocations.Remove(SID); + } else { + Console.WriteLine("UCIS.PML.Connection.Worker Invalid request ID in reply: " + SID.ToString()); + } + } + if (SRequest != null) { + SRequest.Reply = Message.GetChild("MSG"); + SRequest.ResetEvent.Set(); + } + } else if (Cmd.Equals("REQ") || Cmd.Equals("MSG")) { + UCIS.ThreadPool.RunCall(processCall, Message); + } else { + Console.WriteLine("UCIS.PML.Connection.Worker Invalid command received"); + } + } + } + private void processSessionMessage(PmlElement Message) { + UInt32 SID = Message.GetChild("SID").ToUInt32(); + byte SCMD = Message.GetChild("SCMD").ToByte(); + PmlElement InnerMsg = Message.GetChild("MSG"); + ISession Session = null; + lock (_sessions) if (!_sessions.TryGetValue(SID, out Session)) Session = null; + switch (SCMD) { + case 0: //Request + if (Session != null) { + try { + Session.CloseIn(); + } catch (Exception ex) { + Console.WriteLine("UCIS.Pml.PmlCommunicator.processSessionMessage-Request: exception in session.CloseIn: " + ex.ToString()); + } + WriteSessionMessage(SID, 2, null); + } else if (ChannelRequestReceived != null) { + try { + PmlChannelRequestReceivedEventArgsA ea = new PmlChannelRequestReceivedEventArgsA(this, SID, InnerMsg); + ChannelRequestReceived(this, ea); + ea.RejectIfNotAccepted(); + } catch (Exception ex) { + Console.WriteLine("UCIS.Pml.PmlCommunicator.processSessionMessage: exception in ChannelRequestReceived: " + ex.ToString()); + WriteSessionMessage(SID, 2, null); + } + } else { + WriteSessionMessage(SID, 2, null); + } + break; + case 1: //Message + if (Session != null) { + try { + Session.MessageIn(InnerMsg); + } catch (Exception ex) { + Console.WriteLine("UCIS.Pml.PmlCommunicator.processSessionMessage: exception in session.MessageIn: " + ex.ToString()); + WriteSessionMessage(SID, 2, null); + } + } else { + WriteSessionMessage(SID, 2, null); + } + break; + case 2: //Close + if (Session != null) { + try { + if (InnerMsg != null && !(InnerMsg is PmlNull)) Session.MessageIn(InnerMsg); + } catch (Exception ex) { + Console.WriteLine("UCIS.Pml.PmlCommunicator.processSessionMessage-Close: exception in session.MessageIn: " + ex.ToString()); + } finally { + try { + Session.CloseIn(); + } catch (Exception ex) { + Console.WriteLine("UCIS.Pml.PmlCommunicator.processSessionMessage: exception in session.CloseIn: " + ex.ToString()); + } + } + } + break; + } + } + private void processCall(object state) { + PmlDictionary Message = (PmlDictionary)state; + bool wantReply = Message.ContainsKey("SID"); + UInt32 SID = 0; + if (wantReply) SID = Message.GetChild("SID").ToUInt32(); + PmlElement Reply = null; + try { + if (CallReceived != null) { + PmlCallReceivedEventArgs ea = new PmlCallReceivedEventArgs(Message.GetChild("MSG"), wantReply, SID); + CallReceived(this, ea); + Reply = ea.Reply; + } + } catch (Exception ex) { + Reply = new PmlDictionary(); + ((PmlDictionary)Reply).Add("EXCEPTION", new PmlString(ex.ToString())); + Console.WriteLine(ex.ToString()); + } finally { + if (wantReply && Channel.IsOpen) { + try { + WriteSyncMessage(SID, true, Reply); + } catch (Exception ex) { + Console.WriteLine("UCIS.Pml.PmlCommunicator.processCall: exception: " + ex.ToString()); + closed(); + Channel.Close(); + } + } + } + } + + public void Call(PmlElement message) { + PmlDictionary Msg = new PmlDictionary(); + Msg.Add("CMD", new PmlString("MSG")); + Msg.Add("MSG", message); + _WriteMessage(Msg); + } + public PmlElement Invoke(PmlElement message) { + return Invoke(message, 60000); + } + public PmlElement Invoke(PmlElement message, int timeout) { + if (_closed) throw new InvalidOperationException("Sorry, we're closed."); + CSyncRequest SyncEvent = new CSyncRequest(); + UInt32 SID = GetNextSessionId(false); + lock (_invocations) _invocations.Add(SID, SyncEvent); + try { + WriteSyncMessage(SID, false, message); + if (!SyncEvent.ResetEvent.WaitOne(timeout, false)) { + if (!_closed) lock (_invocations) _invocations.Remove(SID); + throw new TimeoutException("The SyncRequest timed out (SID=" + SID.ToString() + ")"); + } + } finally { + lock (_invocations) _invocations.Remove(SID); + } + return SyncEvent.Reply; + } + + public IPmlChannel CreateChannel(PmlElement data) { + UInt32 sid = GetNextSessionId(true); + PmlSubChannel ch = new PmlSubChannel(this, sid, true); + WriteSessionMessage(sid, 0, data); + if (!ch.IsOpen) return null; + return ch; + } + + private void AddSession(ISession session) { + if (_closed) return; + lock (_sessions) _sessions.Add(session.ID, session); + } + private void RemoveSession(UInt32 session) { + if (_closed) return; + lock (_sessions) _sessions.Remove(session); + } + private void RemoveSession(ISession session) { + RemoveSession(session.ID); + } + + private UInt32 GetNextSessionId(bool IsSession) { + if (IsSession) { + lock (_sessions) { + do { + unchecked { pNextSession++; } + } while (_sessions.ContainsKey(pNextSession)); + return pNextSession; + } + } else { + lock (_invocations) { + do { + unchecked { pNextSyncRequest++; } + } while (_invocations.ContainsKey(pNextSyncRequest)); + return pNextSyncRequest; + } + } + } + + protected void WriteSyncMessage(UInt32 SID, bool RPL, PmlElement MSG) { + PmlDictionary Msg2 = new PmlDictionary(); + Msg2.Add("CMD", new PmlString(RPL ? "RPL" : "REQ")); + Msg2.Add("SID", new PmlInteger(SID)); + Msg2.Add("MSG", MSG); + _WriteMessage(Msg2); + } + protected void WriteSessionMessage(UInt32 SID, byte CMD, PmlElement MSG) { + PmlDictionary Msg2 = new PmlDictionary(); + Msg2.Add("CMD", new PmlString("SES")); + Msg2.Add("SID", new PmlInteger(SID)); + Msg2.Add("SCMD", new PmlInteger(CMD)); + if (MSG != null) Msg2.Add("MSG", MSG); + _WriteMessage(Msg2); + } + + + + /* LegacyPmlCommunicator compatibility */ + public PmlElement SyncRequest(PmlElement Request) { + return Invoke(Request); + } + public PmlElement SyncRequest(PmlElement Request, int Timeout) { + return Invoke(Request, Timeout); + } + public void SendMessage(PmlElement Message) { + Call(Message); + } + } +} diff -r 000000000000 -r 3ab940a0c7a0 Pml/PmlConnection.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Pml/PmlConnection.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,384 @@ +using System; +using System.Collections.Generic; +using System.Text; +using UCIS.Net; +using System.Net.Sockets; +using System.Threading; +using System.IO; + +namespace UCIS.Pml { + /*public class PmlConnection : LegacyPmlCommunicator { + public PmlConnection(Socket Socket) : this(new TCPPmlChannel(Socket)) { } + public PmlConnection(TCPStream Stream) : this(new TCPPmlChannel(Stream)) { } + public PmlConnection(Stream Stream) : this(new PmlBinaryRW(Stream)) {} + public PmlConnection(IPmlRW RW) : this(new PmlChannel(RW)) { } + public PmlConnection(IPmlChannel CH) : base(CH) { } + }*/ + public class PmlConnection { + private class CSyncRequest { + internal PmlElement Reply; + internal ManualResetEvent ResetEvent = new ManualResetEvent(false); + } + public abstract class SessionBase { + private bool pActive; + private PmlConnection pConnection; + private UInt32 pSID; + + protected SessionBase(PmlConnection Connection) { + pConnection = Connection; + } + + protected void Accept(UInt32 SID) { + if (pActive) throw new InvalidOperationException("Session is active"); + pSID = SID; + lock (pConnection.pSessions) pConnection.pSessions.Add(pSID, this); + pActive = true; + } + protected void Request() { + Request(null); + } + protected void Request(PmlElement Message) { + if (pActive) throw new InvalidOperationException("Session is active"); + pSID = pConnection.GetNextSessionId(true); + lock (pConnection.pSessions) pConnection.pSessions.Add(pSID, this); + pConnection.WriteSessionMessage(pSID, 0, Message); + pActive = true; + } + + protected internal abstract void MessageIn(PmlElement Message); + + protected void SendMessage(PmlElement Message) { + if (!pActive) throw new InvalidOperationException("Session is not active"); + pConnection.WriteSessionMessage(pSID, 1, Message); + } + + public void Close() { + Close(null); + } + public void Close(PmlElement Message) { + if (!pActive) throw new InvalidOperationException("Session is not active"); + pConnection.WriteSessionMessage(pSID, 2, Message); + ClosedA(); + } + + internal void ClosedA() { + pActive = false; + lock (pConnection.pSessions) pConnection.pSessions.Remove(pSID); + } + + internal void ClosedB(PmlElement Message) { + pActive = false; + Closed(Message); + } + + protected virtual void Closed(PmlElement Message) { + } + } + public class Session : SessionBase { + public event MessageReceivedEventHandler MessageReceived; + public delegate void MessageReceivedEventHandler(PmlElement Message); + public event SessionClosedEventHandler SessionClosed; + public delegate void SessionClosedEventHandler(PmlElement Message); + + public Session(PmlConnection Connection) : base(Connection) { } + + public new void Accept(UInt32 SID) { + base.Accept(SID); + } + public new void Request() { + Request(null); + } + public new void Request(PmlElement Message) { + base.Request(Message); + } + + protected internal override void MessageIn(PmlElement Message) { + if (MessageReceived != null) MessageReceived(Message); + } + + public new void SendMessage(PmlElement Message) { + base.SendMessage(Message); + } + + protected override void Closed(PmlElement Message) { + if (SessionClosed != null) SessionClosed(Message); + } + } + + private Dictionary pSessions = new Dictionary(); + private UInt32 pNextSession; + private Dictionary pSyncRequests = new Dictionary(); + private UInt32 pNextSyncRequest; + + private Stream pStream; + + public event MessageReceivedEventHandler MessageReceived; + public delegate void MessageReceivedEventHandler(PmlElement Message); + public event RequestReceivedEventHandler RequestReceived; + public delegate void RequestReceivedEventHandler(PmlElement Request, ref PmlElement Reply); + public event SessionRequestReceivedEventHandler SessionRequestReceived; + public delegate void SessionRequestReceivedEventHandler(PmlElement Request, uint SID); + + private IPmlWriter _writer; + private IPmlReader _reader; + + public PmlConnection(Socket Socket) : this(new TCPStream(Socket)) { } + public PmlConnection(Stream Stream) : this(new PmlBinaryRW(Stream)) { + pStream = Stream; + } + public PmlConnection(IPmlRW RMRW) : this(RMRW, RMRW) { } + public PmlConnection(IPmlReader Reader, IPmlWriter Writer) { + _reader = Reader; + _writer = Writer; + } + + public void Close() { + if (pStream != null) pStream.Close(); + } + + public IPmlReader Reader { + get { return _reader; } + } + public IPmlWriter Writer { + get { return _writer; } + } + private PmlElement _ReadMessage() { + PmlElement Message = _reader.ReadMessage(); + return Message; //Warning: Can't lock reader because it can be the same as the Writer (possible deadlock) + } + private void _WriteMessage(PmlElement Message) { + lock (_writer) _writer.WriteMessage(Message); + } + + private UInt32 GetNextSessionId(bool IsSession) { + if (IsSession) { + lock (pSessions) { + do { + if (pNextSession == UInt32.MaxValue) { + pNextSession = 0; + } else { + pNextSession += (uint)1; + } + } + while (pSessions.ContainsKey(pNextSession)); + return pNextSession; + } + } else { + lock (pSyncRequests) { + do { + if (pNextSyncRequest == UInt32.MaxValue) { + pNextSyncRequest = 0; + } else { + pNextSyncRequest += (uint)1; + } + } + while (pSyncRequests.ContainsKey(pNextSyncRequest)); + return pNextSyncRequest; + } + } + } + + protected void WriteSessionMessage(UInt32 SID, byte CMD, PmlElement MSG) { + PmlDictionary Msg2 = new PmlDictionary(); + Msg2.Add("CMD", new PmlString("SES")); + Msg2.Add("SID", new PmlInteger(SID)); + Msg2.Add("SCMD", new PmlInteger(CMD)); + Msg2.Add("MSG", MSG); + _WriteMessage(Msg2); + } + + protected void WriteSyncMessage(UInt32 SID, bool RPL, PmlElement MSG) { + PmlDictionary Msg2 = new PmlDictionary(); + if (RPL) { + Msg2.Add("CMD", new PmlString("RPL")); + } else { + Msg2.Add("CMD", new PmlString("REQ")); + } + Msg2.Add("SID", new PmlInteger(SID)); + Msg2.Add("MSG", MSG); + _WriteMessage(Msg2); + } + + public void Worker() { + try { + PmlElement Message = null; + int Ping = 0; + while (true) { + try { + Message = _ReadMessage(); + if (Message == null) Console.WriteLine("UCIS.PML.Connection: Message is just null?"); + } catch (EndOfStreamException) { + Console.WriteLine("UCIS.PML.Connection: End of stream"); + return; + } catch (SocketException ex) { + if (ex.ErrorCode == (int)SocketError.TimedOut) { + Console.WriteLine("UCIS.PML.Connection: SocketException/TimedOut"); + Message = null; + } else if (ex.ErrorCode == (int)SocketError.ConnectionReset) { + Console.WriteLine("UCIS.PML.Connection: Connection reset by peer"); + return; + } else { + throw new Exception("Exception while reading message", ex); + } + } catch (IOException ex) { + Console.WriteLine("UCIS.PML.Connection: IOException: " + ex.Message); + Message = null; + } catch (TimeoutException) { + Message = null; + } + if (Message == null) { + if (Ping > 2) { + Console.WriteLine("UCIS.PML.Connection: Connection timed out"); + break; + } else { + _WriteMessage(new PmlString("PING")); + } + Ping += 1; + } else if (Message is PmlString) { + string Cmd = Message.ToString(); + if (Cmd.Equals("PING")) { + _WriteMessage(new PmlString("PONG")); + } else if (Cmd.Equals("PONG")) { + Ping = 0; + } + } else if (Message is PmlDictionary) { + string Cmd = null; + Cmd = Message.GetChild("CMD").ToString(); + if (Cmd.Equals("SES")) { + UInt32 SID = default(UInt32); + byte SCMD = 0; + SessionBase Session = default(SessionBase); + PmlElement InnerMsg = default(PmlElement); + SID = Message.GetChild("SID").ToUInt32(); + SCMD = Message.GetChild("SCMD").ToByte(); + InnerMsg = Message.GetChild("MSG"); + lock (pSessions) { + if (pSessions.ContainsKey(SID)) { + Session = pSessions[SID]; + } else { + Session = null; + } + } + if (SCMD == 0) { + if (Session == null) { + if (SessionRequestReceived != null) { + SessionRequestReceived(InnerMsg, SID); + } + } else { + Session.ClosedA(); + Session.ClosedB(null); + WriteSessionMessage(SID, 2, null); + } + } else if (SCMD == 1) { + if (Session == null) { + WriteSessionMessage(SID, 2, null); + } else { + Session.MessageIn(InnerMsg); + } + } else if (SCMD == 2) { + if (Session != null) { + Session.ClosedA(); + Session.ClosedB(InnerMsg); + } + } + } else if (Cmd.Equals("RPL")) { + UInt32 SID = default(UInt32); + CSyncRequest SRequest = null; + SID = Message.GetChild("SID").ToUInt32(); + lock (pSyncRequests) { + if (pSyncRequests.TryGetValue(SID, out SRequest)) { + pSyncRequests.Remove(SID); + } else { + Console.WriteLine("UCIS.PML.Connection.Worker Invalid request ID in reply: " + SID.ToString()); + } + } + if (SRequest != null) { + SRequest.Reply = Message.GetChild("MSG"); + SRequest.ResetEvent.Set(); + } + } else if (Cmd.Equals("REQ")) { + System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(SyncRequestHandler), Message); + } else if (Cmd.Equals("MSG")) { + PmlElement InnerMsg = Message.GetChild("MSG"); + if (MessageReceived != null) MessageReceived(InnerMsg); + } else { + throw new InvalidOperationException("Invalid operation"); + } + } + } + } catch (System.Threading.ThreadAbortException ex) { + throw ex; + } catch (Exception ex) { + Console.WriteLine(ex.ToString()); + } finally { + Console.WriteLine("UCIS.PML.Connection: Connection closed"); + try { + foreach (SessionBase S in pSessions.Values) { + try { + S.ClosedB(null); + } catch (Exception ex) { + Console.WriteLine(ex.ToString()); + } + } + pSessions.Clear(); + foreach (CSyncRequest T in pSyncRequests.Values) { + T.ResetEvent.Set(); + } + } catch (Exception ex) { + Console.WriteLine(ex.ToString()); + } + } + } + + private void SyncRequestHandler(object state) { + PmlDictionary Message = (PmlDictionary)state; + UInt32 SID = default(UInt32); + PmlElement InnerMsg = default(PmlElement); + PmlElement Reply = default(PmlElement); + Reply = null; + SID = Message.GetChild("SID").ToUInt32(); + InnerMsg = Message.GetChild("MSG"); + try { + if (RequestReceived != null) { + RequestReceived(InnerMsg, ref Reply); + } + } catch (Exception ex) { + Reply = new PmlDictionary(); + ((PmlDictionary)Reply).Add("EXCEPTION", new PmlString(ex.ToString())); + Console.WriteLine(ex.ToString()); + } + WriteSyncMessage(SID, true, Reply); + } + + public PmlElement SyncRequest(PmlElement Request) { + return SyncRequest(Request, 30000); + } + public PmlElement SyncRequest(PmlElement Request, int Timeout) { + UInt32 SID = default(UInt32); + CSyncRequest SyncEvent = new CSyncRequest(); + SID = GetNextSessionId(false); + lock (pSyncRequests) pSyncRequests.Add(SID, SyncEvent); + WriteSyncMessage(SID, false, Request); + if (!SyncEvent.ResetEvent.WaitOne(Timeout, false)) { + Console.WriteLine("UCIS.PML.Connection.SyncRequest Timeout: " + SID.ToString()); + lock (pSyncRequests) pSyncRequests.Remove(SID); + throw new TimeoutException(); + } + return SyncEvent.Reply; + } + + public void SendMessage(PmlElement Message) { + PmlDictionary Msg = new PmlDictionary(); + Msg.Add("CMD", new PmlString("MSG")); + Msg.Add("MSG", Message); + _WriteMessage(Msg); + } + + public PmlElement ReadMessage() { + return _ReadMessage(); + } + public void SendRawMessage(PmlElement Message) { + _WriteMessage(Message); + } + } +} diff -r 000000000000 -r 3ab940a0c7a0 Pml/RW/IPmlRW.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Pml/RW/IPmlRW.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,10 @@ +namespace UCIS.Pml { + public interface IPmlReader { + PmlElement ReadMessage(); + } + public interface IPmlWriter { + void WriteMessage(PmlElement Message); + } + public interface IPmlRW : IPmlReader, IPmlWriter { + } +} \ No newline at end of file diff -r 000000000000 -r 3ab940a0c7a0 Pml/RW/PmlAmfRW.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Pml/RW/PmlAmfRW.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,282 @@ +using System; +using System.IO; +using System.Text; +using System.Collections.Generic; +using UCIS.Pml; + +namespace UCIS.Pml { + internal enum AmfDataType : byte { + Number = 0, + Boolean = 1, + String = 2, + UntypedObject = 3, + MovieClip = 4, + Null = 5, + Undefined = 6, + ReferencedObject = 7, + MixedArray = 8, + End = 9, + Array = 10, + Date = 11, + LongString = 12, + TypeAsObject = 13, + Recordset = 14, + Xml = 15, + TypedObject = 16 + } + public class PmlAmfWriter : IPmlWriter { + private BinaryWriter pWriter; + + public PmlAmfWriter(BinaryWriter Writer) { + pWriter = Writer; + } + public PmlAmfWriter(Stream Stream) { + pWriter = new BinaryWriter(Stream, Encoding.UTF8); + } + + public BinaryWriter BaseWriter { + get { return pWriter; } + set { pWriter = value; } + } + + public void WriteMessage(PmlElement Message) { + WriteMessageTo(Message, pWriter); + } + + public static void WriteMessageTo(PmlElement Message, BinaryWriter Writer) { + lock (Writer) { + WriteElementTo(Message, Writer); + Writer.Flush(); + } + } + + private static void WriteElementTo(PmlElement Element, BinaryWriter Writer) { + if (Element == null) { + Writer.Write((byte)AmfDataType.Null); + return; + } + switch (Element.Type) { + case PmlType.Null: + Writer.Write((byte)AmfDataType.Null); + break; + case PmlType.Dictionary: + Writer.Write((byte)AmfDataType.UntypedObject); + //WriteDictionary(Writer, (PmlDictionary)Element); + WriteUntypedObject(Writer, (PmlDictionary)Element); + break; + case PmlType.Collection: + Writer.Write((byte)AmfDataType.Array); + WriteCollection(Writer, (PmlCollection)Element); + break; + case PmlType.Binary: + Writer.Write((byte)AmfDataType.String); + byte[] bytes = Element.ToByteArray(); + if (bytes.Length > UInt16.MaxValue) { + Writer.Write((byte)AmfDataType.String); + WriteString(Writer, bytes); + } else { + Writer.Write((byte)AmfDataType.LongString); + WriteLongString(Writer, bytes); + } + break; + case PmlType.String: + string str = Element.ToString(); + if (str.Length < UInt16.MaxValue) { + Writer.Write((byte)AmfDataType.String); + WriteString(Writer, str); + } else { + Writer.Write((byte)AmfDataType.LongString); + WriteLongString(Writer, str); + } + break; + case PmlType.Integer: + Writer.Write((byte)AmfDataType.Number); + WriteDouble(Writer, (Element as PmlInteger).ToDouble()); + break; + } + } + private static void WriteEnd(BinaryWriter w) { + WriteUInt16(w, 0); + w.Write((byte)AmfDataType.End); + } + private static void WriteUntypedObject(BinaryWriter w, PmlDictionary value) { + foreach (KeyValuePair kvp in value) { + WriteString(w, kvp.Key); + WriteElementTo(kvp.Value, w); + } + WriteEnd(w); + } + private static void WriteDictionary(BinaryWriter w, PmlDictionary value) { + WriteUInt32(w, (UInt32)value.Count); + foreach (KeyValuePair kvp in value) { + WriteString(w, kvp.Key); + WriteElementTo(kvp.Value, w); + } + } + private static void WriteCollection(BinaryWriter w, PmlCollection value) { + WriteUInt32(w,(UInt32)value.Count); + foreach (PmlElement o in value) { + WriteElementTo(o, w); + } + } + private static void WriteDouble(BinaryWriter w, double value) { + WriteReverse(w, BitConverter.GetBytes(value)); + } + private static void WriteUInt32(BinaryWriter w, UInt32 value) { + WriteReverse(w, BitConverter.GetBytes(value)); + } + private static void WriteUInt16(BinaryWriter w, UInt16 value) { + WriteReverse(w, BitConverter.GetBytes(value)); + } + private static void WriteString(BinaryWriter w, string value) { + WriteString(w, Encoding.UTF8.GetBytes(value)); + } + private static void WriteLongString(BinaryWriter w, string value) { + WriteLongString(w, Encoding.UTF8.GetBytes(value)); + } + private static void WriteString(BinaryWriter w, byte[] buffer) { + WriteUInt16(w, (UInt16)buffer.Length); + w.Write(buffer, 0, buffer.Length); + } + private static void WriteLongString(BinaryWriter w, byte[] buffer) { + WriteUInt32(w, (UInt32)buffer.Length); + w.Write(buffer, 0, buffer.Length); + } + private static void WriteReverse(BinaryWriter w, byte[] value) { + Array.Reverse(value); + w.Write(value); + } + } + + public class PmlAmfReader : IPmlReader { + private BinaryReader pReader; + + public PmlAmfReader(BinaryReader Reader) { + pReader = Reader; + } + public PmlAmfReader(Stream Stream) { + pReader = new BinaryReader(Stream, Encoding.UTF8); + } + + public BinaryReader BaseReader { + get { return pReader; } + set { pReader = value; } + } + + public PmlElement ReadMessage() { + return ReadMessageFrom(pReader); + } + + public static PmlElement ReadMessageFrom(BinaryReader Reader) { + PmlElement Element = null; + lock (Reader) { + Element = ReadElementFrom(Reader); + } + return Element; + } + + + private static PmlElement ReadElementFrom(BinaryReader Reader) { + AmfDataType EType = (AmfDataType)Reader.ReadByte(); + return ReadData(Reader, EType); + } + private static PmlElement ReadData(BinaryReader Reader, AmfDataType EType) { + switch (EType) { + case AmfDataType.Number: + Double d = ReadDouble(Reader); + if (d == (double)(Int64)d) { + return new PmlInteger((Int64)d); + } else if (d == (double)(UInt64)d) { + return new PmlInteger((UInt64)d); + } else { + return new PmlString(d.ToString()); + } + case AmfDataType.Boolean: + return new PmlInteger(Reader.ReadByte()); + case AmfDataType.String: + return new PmlString(ReadShortString(Reader)); + case AmfDataType.Array: + PmlCollection ElementC = new PmlCollection(); + int size = ReadInt32(Reader); + for (int i = 0; i < size; ++i) { + ElementC.Add(ReadElementFrom(Reader)); + } + return ElementC; + case AmfDataType.Date: + return new PmlString(ReadDate(Reader).ToString()); + case AmfDataType.LongString: + return new PmlString(ReadLongString(Reader)); + case AmfDataType.TypedObject: + ReadShortString(Reader); + return ReadUntypedObject(Reader); + case AmfDataType.MixedArray: + return ReadDictionary(Reader); + case AmfDataType.Null: + case AmfDataType.Undefined: + case AmfDataType.End: + return new PmlNull(); + case AmfDataType.UntypedObject: + return ReadUntypedObject(Reader); + case AmfDataType.Xml: + return new PmlString(ReadLongString(Reader)); + case AmfDataType.MovieClip: + case AmfDataType.ReferencedObject: + case AmfDataType.TypeAsObject: + case AmfDataType.Recordset: + default: + throw new NotSupportedException("The AMF type is not supported: " + EType.ToString()); + } + } + + private static PmlDictionary ReadUntypedObject(BinaryReader Reader) { + PmlDictionary ElementD = new PmlDictionary(); + string key = ReadShortString(Reader); + for (byte type = Reader.ReadByte(); type != 9; type = Reader.ReadByte()) { + ElementD.Add(key, ReadData(Reader, (AmfDataType)type)); + key = ReadShortString(Reader); + } + return ElementD; + } + private static PmlDictionary ReadDictionary(BinaryReader Reader) { + PmlDictionary ElementD = new PmlDictionary(); + int size = ReadInt32(Reader); + return ReadUntypedObject(Reader); + } + + private static DateTime ReadDate(BinaryReader r) { + double ms = ReadDouble(r); + DateTime date = (new DateTime(1970, 1, 1)).AddMilliseconds(ms); + ReadUInt16(r); //gets the timezone + return date; + } + private static double ReadDouble(BinaryReader r) { + return BitConverter.ToDouble(ReadReverse(r, 8), 0); + } + + private static int ReadInt32(BinaryReader r) { + return BitConverter.ToInt32(ReadReverse(r, 4), 0); + } + + private static ushort ReadUInt16(BinaryReader r) { + return BitConverter.ToUInt16(ReadReverse(r, 2), 0); + } + + private static byte[] ReadReverse(BinaryReader r, int size) { + byte[] buffer = r.ReadBytes(size); + Array.Reverse(buffer); + return buffer; + } + private static string ReadLongString(BinaryReader r) { + int length = ReadInt32(r); + return ReadString(r, length); + } + private static string ReadShortString(BinaryReader r) { + int length = ReadUInt16(r); + return ReadString(r, length); + } + private static string ReadString(BinaryReader r, int length) { + byte[] buffer = r.ReadBytes(length); + return Encoding.UTF8.GetString(buffer); + } + } +} \ No newline at end of file diff -r 000000000000 -r 3ab940a0c7a0 Pml/RW/PmlBinaryRW.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Pml/RW/PmlBinaryRW.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,223 @@ +using System; +using System.IO; +using System.Text; +using System.Collections.Generic; + +namespace UCIS.Pml { + public class PmlBinaryRW : IPmlRW { + private PmlBinaryReader pReader; + private PmlBinaryWriter pWriter; + + public PmlBinaryRW(Stream Stream) { + pReader = new PmlBinaryReader(Stream); + pWriter = new PmlBinaryWriter(Stream); + } + public PmlBinaryRW(Stream Stream, Encoding Encoding) { + pReader = new PmlBinaryReader(Stream, Encoding); + pWriter = new PmlBinaryWriter(Stream, Encoding); + } + + public PmlElement ReadMessage() { + return pReader.ReadMessage(); + } + + public void WriteMessage(PmlElement Message) { + pWriter.WriteMessage(Message); + } + + public PmlBinaryReader Reader { + get { return pReader; } + } + public PmlBinaryWriter Writer { + get { return pWriter; } + } + } + + public class PmlBinaryWriter : IPmlWriter { + //private BinaryWriter pWriter; + private Stream pStream; + private Encoding pEncoding; + + /*public PmlBinaryWriter(BinaryWriter Writer) { + pWriter = Writer; + }*/ + public PmlBinaryWriter(Stream Stream) { + //pWriter = new BinaryWriter(Stream); + pStream = Stream; + pEncoding = Encoding.UTF8; + } + public PmlBinaryWriter(Stream Stream, Encoding Encoding) { + //pWriter = new BinaryWriter(Stream, Encoding); + pStream = Stream; + pEncoding = Encoding; + } + + /*public BinaryWriter BaseWriter { + get { return pWriter; } + set { pWriter = value; } + }*/ + + public void WriteMessage(PmlElement Message) { + MemoryStream stream = new MemoryStream(); + BinaryWriter writer = new BinaryWriter(stream, pEncoding); + WriteMessageTo(Message, writer); + lock (pStream) { + stream.WriteTo(pStream); + pStream.Flush(); + } + } + + public static void WriteMessageTo(PmlElement Message, BinaryWriter Writer) { + lock (Writer) { + Writer.Write((byte)255); + WriteElementTo(Message, Writer); + Writer.Write((byte)255); + Writer.Flush(); + } + } + + private static void WriteElementTo(PmlElement Element, BinaryWriter Writer) { + //byte[] Buffer = null; + if (Element == null) { + //Writer.Write((byte)PmlElementType.Null); + Writer.Write((byte)0); + return; + } + //Writer.Write((byte)Element.Type); + switch (Element.Type) { + case PmlType.Null: + Writer.Write((byte)0); + break; + case PmlType.Dictionary: + Writer.Write((byte)1); + foreach (KeyValuePair Item in (PmlDictionary)Element) { + Writer.Write((byte)1); + Writer.Write(Item.Key); + WriteElementTo(Item.Value, Writer); + } + Writer.Write((byte)0); + break; + case PmlType.Collection: + Writer.Write((byte)2); + foreach (PmlElement Item in (PmlCollection)Element) { + Writer.Write((byte)1); + WriteElementTo(Item, Writer); + } + Writer.Write((byte)0); + break; + case PmlType.Binary: { + Writer.Write((byte)10); + Byte[] Buffer = Element.ToByteArray(); + if (Buffer == null) { + Writer.Write((int)0); + } else { + Writer.Write((int)Buffer.Length); + Writer.Write(Buffer); + } + } break; + case PmlType.String: + Writer.Write((byte)11); + string Str = Element.ToString(); + if (Str == null) { + Writer.Write(""); + } else { + Writer.Write(Str); + } + + break; + case PmlType.Integer: + Writer.Write((byte)20); + PmlInteger RMInt = (PmlInteger)Element; + if (RMInt.IsSigned) { + Writer.Write((byte)1); + Writer.Write((long)RMInt); + } else { + Writer.Write((byte)0); + Writer.Write((ulong)RMInt); + } + break; + default: + Writer.Write((byte)0); + Console.WriteLine("PmlBinaryRW: Can not encode PML type {0}", Element.Type); + break; + } + } + } + + public class PmlBinaryReader : IPmlReader { + private BinaryReader pReader; + + public PmlBinaryReader(BinaryReader Reader) { + pReader = Reader; + } + public PmlBinaryReader(Stream Stream) { + pReader = new BinaryReader(Stream); + } + public PmlBinaryReader(Stream Stream, Encoding Encoding) { + pReader = new BinaryReader(Stream, Encoding); + } + + public BinaryReader BaseReader { + get { return pReader; } + set { pReader = value; } + } + + public PmlElement ReadMessage() { + return ReadMessageFrom(pReader); + } + + public static PmlElement ReadMessageFrom(BinaryReader Reader) { + PmlElement Element = null; + lock (Reader) { + if (Reader.ReadByte() != 255) { + return null; + } + Element = ReadElementFrom(Reader); + if (Reader.ReadByte() != 255) { + return null; + } + } + return Element; + } + + private static PmlElement ReadElementFrom(BinaryReader Reader) { + Byte EType = Reader.ReadByte(); + switch (EType) { + case 0: return new PmlNull(); + case 1: + PmlDictionary ElementD = new PmlDictionary(); + do { + byte B = Reader.ReadByte(); + if (B == 0) return ElementD; + else if (B == 1) ElementD.Add(Reader.ReadString(), ReadElementFrom(Reader)); + else return null; + } + while (true); + case 2: + PmlCollection ElementC = new PmlCollection(); + do { + byte B = Reader.ReadByte(); + if (B == 0) return ElementC; + else if (B == 1) ElementC.Add(ReadElementFrom(Reader)); + else return null; + } + while (true); + case 10: + int Len = 0; + Len = Reader.ReadInt32(); + return new PmlBinary(Reader.ReadBytes(Len)); + case 11: + return new PmlString(Reader.ReadString()); + case 20: { + byte B = Reader.ReadByte(); + if (B == 0) return new PmlInteger(Reader.ReadUInt64()); + else if (B == 1) return new PmlInteger(Reader.ReadInt64()); + else return null; + + } + default: + throw new Exception("Unknown PML type code " + EType.ToString()); + } + } + } +} diff -r 000000000000 -r 3ab940a0c7a0 Pml/RW/PmlPHPRW.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Pml/RW/PmlPHPRW.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,238 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.IO; + +namespace UCIS.Pml { + public class PmlPHPWriter : IPmlWriter { + private TextWriter pWriter; + + public static string GetMessageString(PmlElement Message) { + StringWriter Buffer = new StringWriter(); + WriteMessageTo(Message, Buffer); + return Buffer.ToString(); + } + + public PmlPHPWriter(TextWriter Writer) { + pWriter = Writer; + } + public PmlPHPWriter(Stream Writer, Encoding Encoding) { + pWriter = new StreamWriter(Writer, Encoding); + } + public PmlPHPWriter(StringBuilder StringBuilder) { + pWriter = new StringWriter(StringBuilder); + } + + public TextWriter BaseWriter { + get { return pWriter; } + set { pWriter = value; } + } + + public void WriteMessage(PmlElement Message) { + WriteMessageTo(Message, pWriter); + } + + public static void WriteMessageTo(PmlElement Message, TextWriter Writer) { + lock (Writer) { + WriteElementTo(Message, Writer); + Writer.Flush(); + } + } + + private static void WriteElementTo(PmlElement Element, TextWriter Writer) { + string Str; + if (Element == null) { + Writer.Write("N;"); + return; + } + switch (Element.Type) { + case PmlType.Null: + Writer.Write("N;"); + break; + case PmlType.String: + case PmlType.Binary: + Str = Element.ToString(); + Writer.Write("s:"); + Writer.Write(Encoding.UTF8.GetByteCount(Str).ToString()); + Writer.Write(":\""); + Writer.Write(Str); + Writer.Write("\";"); + break; + case PmlType.Integer: + Writer.Write("i:"); + Writer.Write(Element.ToString()); + Writer.Write(";"); + break; + case PmlType.Dictionary: + Writer.Write("a:"); + Writer.Write(((IDictionary)Element).Count.ToString()); + Writer.Write(":{"); + foreach (KeyValuePair Child in (IDictionary)Element) { + Str = Child.Key; + Writer.Write("s:"); + Writer.Write(Encoding.UTF8.GetByteCount(Str).ToString()); + Writer.Write(":\""); + Writer.Write(Str); + Writer.Write("\";"); + WriteElementTo(Child.Value, Writer); + } + + Writer.Write("}"); + break; + case PmlType.Collection: + int I = 0; + Writer.Write("a:"); + Writer.Write(((ICollection)Element).Count.ToString()); + Writer.Write(":{"); + foreach (PmlElement Child in (ICollection)Element) { + Writer.Write("i:"); + Writer.Write(I.ToString()); + Writer.Write(";"); + WriteElementTo(Child, Writer); + I += 1; + } + + Writer.Write("}"); + break; + default: + Writer.Write("N;"); + break; + } + } + } + public class PmlPHPReader : IPmlReader { + private TextReader pReader; + + public static PmlElement GetMessageFromString(string Data) { + StringReader Buffer = new StringReader(Data); + return ReadMessageFrom(Buffer); + } + + public PmlPHPReader(TextReader Reader) { + pReader = Reader; + } + public PmlPHPReader(Stream Reader, Encoding Encoding) { + pReader = new StreamReader(Reader, Encoding); + } + public PmlPHPReader(string Data) { + pReader = new StringReader(Data); + } + + public TextReader BaseReader { + get { return pReader; } + set { pReader = value; } + } + + public PmlElement ReadMessage() { + return ReadMessageFrom(pReader); + } + + public static PmlElement ReadMessageFrom(TextReader Reader) { + lock (Reader) { + return ReadElementFrom(Reader); + } + } + + public class PhpSerializerException : Exception { + + public PhpSerializerException(int Position, char Read, char Expected) + : base("At position " + Position.ToString() + " expected " + Expected + " but got " + Read) { + } + } + + private static char ReadChar(TextReader Reader) { + char[] Buffer = new char[1]; + if (Reader.Read(Buffer, 0, 1) != 1) throw new EndOfStreamException(); + return Buffer[0]; + } + + private static string ReadNumber(TextReader Reader, char TerminatedBy) { + char Buffer = '\0'; + string S = ""; + do { + Buffer = ReadChar(Reader); + if (Buffer == TerminatedBy) break; + if (Buffer < '0' && Buffer > '9' && Buffer != '.' && Buffer != ',' && Buffer != '-' && Buffer != 'e') + throw new PhpSerializerException(0, Buffer, TerminatedBy); + S += Buffer; + } + while (true); + return S; + } + + private static void ReadExpect(TextReader Reader, char Expect) { + char Read = '\0'; + Read = ReadChar(Reader); + if (Read != Expect) throw new PhpSerializerException(0, Read, Expect); + } + + private static PmlElement ReadElementFrom(TextReader Reader) { + char Type = '\0'; + char Read = '\0'; + int KL; + Type = ReadChar(Reader); + switch (Type) { + case 'N': + ReadExpect(Reader, ';'); + return new PmlNull(); + case 'i': + ReadExpect(Reader, ':'); + return new PmlInteger(ReadNumber(Reader, ';')); + case 'd': + ReadExpect(Reader, ':'); + return new PmlString(ReadNumber(Reader, ';')); + //Return New PML.PMLNumber(ReadNumber(Reader, ";"c)) + case 's': + KL = 0; + char[] Buffer = null; + ReadExpect(Reader, ':'); + KL = int.Parse(ReadNumber(Reader, ':')); + Buffer = new Char[KL]; + ReadExpect(Reader, '"'); + Reader.ReadBlock(Buffer, 0, KL); + ReadExpect(Reader, '"'); + ReadExpect(Reader, ';'); + return new PmlString(new String(Buffer)); + case 'a': + PmlDictionary D = new PmlDictionary(); + int I = 0; + int L = 0; + KL = 0; + char[] K = null; + ReadExpect(Reader, ':'); + L = int.Parse(ReadNumber(Reader, ':')); + ReadExpect(Reader, '{'); + for (I = 1; I <= L; I++) { + Read = ReadChar(Reader); + switch (Read) { + case 'i': + ReadExpect(Reader, ':'); + K = ReadNumber(Reader, ';').ToCharArray(); + break; + case 's': + ReadExpect(Reader, ':'); + KL = int.Parse(ReadNumber(Reader, ':')); + K = new char[KL]; + ReadExpect(Reader, '"'); + Reader.ReadBlock(K, 0, KL); + ReadExpect(Reader, '"'); + ReadExpect(Reader, ';'); + break; + case 'd': + ReadExpect(Reader, ':'); + K = ReadNumber(Reader, ';').ToCharArray(); + break; + default: + throw new NotSupportedException("Only integer and string keys are supported, got: " + Read); + } + D.Add(new String(K), ReadElementFrom(Reader)); + } + + ReadExpect(Reader, '}'); + return D; + default: + throw new NotSupportedException("Unknown type: " + Type); + } + } + } +} \ No newline at end of file diff -r 000000000000 -r 3ab940a0c7a0 Pml/RW/PmlTextRW.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Pml/RW/PmlTextRW.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.IO; + +namespace UCIS.Pml { + public class PmlTextWriter : IPmlWriter { + private TextWriter pWriter; + + public static string GetMessageString(PmlElement Message) { + StringWriter Buffer = new StringWriter(); + WriteMessageTo(Message, Buffer); + return Buffer.ToString(); + } + + public PmlTextWriter(TextWriter Writer) { + pWriter = Writer; + } + public PmlTextWriter(Stream Writer, Encoding Encoding) { + pWriter = new StreamWriter(Writer, Encoding); + } + public PmlTextWriter(StringBuilder StringBuilder) { + pWriter = new StringWriter(StringBuilder); + } + + public TextWriter BaseWriter { + get { return pWriter; } + set { pWriter = value; } + } + + public void WriteMessage(PmlElement Message) { + WriteElementTo(Message, "", pWriter); + } + + public static void WriteMessageTo(PmlElement Message, TextWriter Writer) { + lock (Writer) { + WriteElementTo(Message, "", Writer); + Writer.Flush(); + } + } + + private static void WriteElementTo(PmlElement Element, string Indent, TextWriter Writer) { + if (Element == null) { + Console.WriteLine("NULL"); + return; + } + switch (Element.Type) { + case PmlType.Null: + Writer.WriteLine("NULL"); + break; + case PmlType.Collection: + Writer.WriteLine("COLLECTION {"); + foreach (PmlElement Child in (PmlCollection)Element) { + Writer.Write(Indent + " "); + WriteElementTo(Child, Indent + " ", Writer); + } + + Writer.WriteLine(Indent + "}"); + break; + case PmlType.Dictionary: + Writer.WriteLine("DICTIONARY {"); + foreach (KeyValuePair Child in (PmlDictionary)Element) { + Writer.Write(Indent + " " + Uri.EscapeDataString(Child.Key) + " "); + WriteElementTo(Child.Value, Indent + " ", Writer); + } + + Writer.WriteLine(Indent + "}"); + break; + case PmlType.Binary: + Writer.WriteLine("BINARY " + Convert.ToBase64String(Element.ToByteArray())); + break; + case PmlType.Integer: + Writer.WriteLine("INT " + Element.ToString()); + break; + case PmlType.String: + Writer.WriteLine("STRING " + Uri.EscapeDataString(Element.ToString())); + break; + } + } + } +} diff -r 000000000000 -r 3ab940a0c7a0 Pml/RW/PmlXmlRW.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Pml/RW/PmlXmlRW.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,269 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Xml; +using System.IO; +using UCIS.Pml; + +namespace UCIS.Pml { + public class PmlXmlRW : IPmlRW { + private PmlXmlReader pReader; + private PmlXmlWriter pWriter; + + public PmlXmlRW(Stream Stream) { + pReader = new PmlXmlReader(Stream); + pWriter = new PmlXmlWriter(Stream); + } + public PmlXmlRW(Stream Stream, Encoding Encoding) { + pReader = new PmlXmlReader(Stream); + pWriter = new PmlXmlWriter(Stream, Encoding); + } + + public PmlElement ReadMessage() { + return pReader.ReadMessage(); + } + + public void WriteMessage(PmlElement Message) { + pWriter.WriteMessage(Message); + } + } + + public class PmlXmlWriter : IPmlWriter { + private Stream pStream; + private XmlWriterSettings pXMLConfig; + + public PmlXmlWriter(Stream Stream, Encoding Encoding) { + pXMLConfig = CreateXMLSettings(Encoding); + + pStream = Stream; + } + public PmlXmlWriter(Stream Stream) + : this(Stream, Encoding.UTF8) { + } + + private static XmlWriterSettings CreateXMLSettings() { + return CreateXMLSettings(null); + } + private static XmlWriterSettings CreateXMLSettings(Encoding Encoding) { + XmlWriterSettings XMLConfig = new XmlWriterSettings(); + if (Encoding == null) Encoding = Encoding.UTF8; + XMLConfig.ConformanceLevel = ConformanceLevel.Document; + XMLConfig.NewLineHandling = NewLineHandling.Entitize; + XMLConfig.OmitXmlDeclaration = true; + XMLConfig.CheckCharacters = true; + XMLConfig.Encoding = Encoding; + XMLConfig.CloseOutput = false; + return XMLConfig; + } + + public void WriteMessage(PmlElement Message) { + WriteMessageToStream(Message, pStream); + pStream.WriteByte(0); + pStream.Flush(); + } + + public static void WriteMessageToFile(PmlElement Message, string Filename) { + FileStream F = File.Create(Filename); + WriteMessageToStream(Message, F); + F.Close(); + } + + public static void WriteMessageToStream(PmlElement Message, Stream Stream) { + WriteMessageToStream(Message, Stream, CreateXMLSettings()); + } + + public static void WriteMessageToStream(PmlElement Message, Stream Stream, XmlWriterSettings Settings) { + XmlWriter Writer = System.Xml.XmlWriter.Create(Stream, Settings); + Writer.WriteStartDocument(); + Writer.WriteStartElement("msg"); + WriteElementTo(Message, Writer); + Writer.WriteEndElement(); + Writer.WriteEndDocument(); + Writer.Flush(); + Writer.Close(); + } + + private static void WriteElementTo(PmlElement Element, System.Xml.XmlWriter Writer) { + switch (Element.Type) { + case PmlType.Binary: + Writer.WriteAttributeString("type", "binary"); + byte[] Bytes = Element.ToByteArray(); + Writer.WriteBase64(Bytes, 0, Bytes.Length); + break; + case PmlType.Collection: + Writer.WriteAttributeString("type", "collection"); + foreach (PmlElement Child in (PmlCollection)Element) { + Writer.WriteStartElement("item"); + WriteElementTo(Child, Writer); + Writer.WriteEndElement(); + } + + break; + case PmlType.Dictionary: + Writer.WriteAttributeString("type", "dictionary"); + foreach (KeyValuePair Child in (PmlDictionary)Element) { + Writer.WriteStartElement(Child.Key); + WriteElementTo(Child.Value, Writer); + Writer.WriteEndElement(); + } + + break; + case PmlType.Integer: + Writer.WriteAttributeString("type", "integer"); + Writer.WriteString(Element.ToString()); + break; + case PmlType.Null: + Writer.WriteAttributeString("type", "null"); + break; + case PmlType.String: + Writer.WriteAttributeString("type", "string"); + Writer.WriteString(Element.ToString()); + break; + } + } + } + + public class PmlXmlReader : IPmlReader { + private BinaryReader pReader; + private System.Xml.XmlReaderSettings pXMLSettings; + + public PmlXmlReader(Stream Stream) + : this(new BinaryReader(Stream)) { + } + + public PmlXmlReader(BinaryReader Reader) { + pReader = Reader; + pXMLSettings = new System.Xml.XmlReaderSettings(); + pXMLSettings.ConformanceLevel = System.Xml.ConformanceLevel.Document; + pXMLSettings.CloseInput = true; + pXMLSettings.IgnoreComments = true; + pXMLSettings.IgnoreProcessingInstructions = true; + pXMLSettings.IgnoreWhitespace = true; + pXMLSettings.ValidationType = System.Xml.ValidationType.None; + pXMLSettings.ValidationFlags = System.Xml.Schema.XmlSchemaValidationFlags.None; + pXMLSettings.CheckCharacters = true; + } + + public BinaryReader BaseReader { + get { return pReader; } + set { pReader = value; } + } + + private XmlDocument ReadXMLDocument() { + System.Xml.XmlDocument Doc = new System.Xml.XmlDocument(); + MemoryStream Buffer = default(MemoryStream); + System.Xml.XmlReader XMLReader = default(System.Xml.XmlReader); + byte B = 0; + Buffer = new MemoryStream(); + do { + B = pReader.ReadByte(); + if (B == 0) break; + Buffer.WriteByte(B); + } + while (true); + Buffer.Flush(); + Buffer.Seek(0, SeekOrigin.Begin); + + XMLReader = System.Xml.XmlReader.Create(Buffer, pXMLSettings); + Doc.Load(XMLReader); + XMLReader.Close(); + return Doc; + } + + public PmlElement ReadMessage() { + System.Xml.XmlDocument Doc = default(System.Xml.XmlDocument); + Doc = ReadXMLDocument(); + if (Doc == null) return null; + return ReadElement(Doc.FirstChild); + } + + public static PmlElement ReadElement(System.Xml.XmlNode X) { + PmlType pType; + bool pTypeFound = false; + pType = PmlType.Null; + pTypeFound = true; + if (X.Attributes != null && X.Attributes.Count > 0 && X.Attributes["type"] != null) { + switch (X.Attributes["type"].Value.ToLowerInvariant()) { + case "binary": + pType = PmlType.Binary; + break; + case "collection": + pType = PmlType.Collection; + break; + case "dictionary": + pType = PmlType.Dictionary; + break; + case "string": + pType = PmlType.String; + break; + case "null": + pType = PmlType.Null; + break; + case "integer": + pType = PmlType.Integer; + break; + default: + pTypeFound = false; + break; + } + } else { + pTypeFound = false; + } + + if (!pTypeFound) { + if (X.HasChildNodes) { + if (X.ChildNodes.Count == 1 && X.FirstChild.NodeType == System.Xml.XmlNodeType.Text) { + Int64 dummy; + UInt64 dummyu; + if (Int64.TryParse(X.FirstChild.Value, out dummy) || UInt64.TryParse(X.FirstChild.Value, out dummyu)) { + pType = PmlType.Integer; + } else { + pType = PmlType.String; + } + } else if (X.FirstChild.Name == "item") { + pType = PmlType.Collection; + } else { + pType = PmlType.Dictionary; + } + } else { + pType = PmlType.Null; + } + } + + switch (pType) { + case PmlType.Null: + return new PmlNull(); + case PmlType.Binary: + if (X.FirstChild == null) { + return new PmlBinary(new byte[0]); + } else { + return new PmlBinary(Convert.FromBase64String(X.FirstChild.Value)); + } + case PmlType.Integer: + return new PmlInteger(X.FirstChild.Value); + case PmlType.String: + if (X.FirstChild == null) { + return new PmlString(""); + } else { + return new PmlString(X.FirstChild.Value); + } + case PmlType.Collection: + PmlCollection C = new PmlCollection(); + foreach (XmlNode N in X.ChildNodes) { + C.Add(ReadElement(N)); + } + + return C; + case PmlType.Dictionary: + PmlDictionary D = new PmlDictionary(); + foreach (XmlNode N in X.ChildNodes) { + D.Add(N.Name, ReadElement(N)); + } + + return D; + default: + return null; + } + } + } +} \ No newline at end of file diff -r 000000000000 -r 3ab940a0c7a0 Properties/AssemblyInfo.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Properties/AssemblyInfo.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("UCIS")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("UCIS")] +[assembly: AssemblyCopyright("Copyright © 2009")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("5ed5657c-523a-4e07-a993-662200f08b42")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff -r 000000000000 -r 3ab940a0c7a0 Radio/Tuner.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Radio/Tuner.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,262 @@ +using System; +using System.Collections.Generic; + +namespace UCIS.Radio { + public struct TunerFrequencyRange { + public TunerFrequencyRange(ulong Begin, ulong End) { + this.Begin = Begin; + this.End = End; + } + + public ulong Begin; + public ulong End; + } + public struct TunerMode { + public TunerMode(int Index, string Name) { + this.Index = Index; + this.Name = Name; + } + + public int Index; + public string Name; + } + public struct TunerFilter { + public TunerFilter(int Index, string Name) { + this.Index = Index; + this.Name = Name; + } + + public int Index; + public string Name; + } + + public class TunerCapabilities { + public TunerFrequencyRange[] Bands = new TunerFrequencyRange[0]; + public IDictionary Modes = new Dictionary(); + public IDictionary Filters = new Dictionary(); + public IList Options = new List(); + public byte[] AvailableModes; + public byte[] AvailableFilters; + } + + public enum TunerOption : byte { + //R/W 0-255 value + Volume = 1, + Squelch = 2, + IfShift = 3, + + //Not accessible (feature indication only) + Frequency = 50, + Mode = 51, + Filter = 52, + + //Read only + Signal = 70, + Online = 71, + + //R/W On/Off + Attenuator = 100, + AGC = 101, + NoiseBlanker = 102, + VSC = 103, + StereoMono = 104, + + //W Execute + Poll = 151, + RadioText = 200, + + //200+: reserved for personal use + } + + public class TunerOptionChangedEventArgs : EventArgs { + public TunerOptionChangedEventArgs(TunerOption option) { Option = option; } + public TunerOption Option; + } + + public interface ITuner { + event EventHandler TuningChanged; + event EventHandler OptionChanged; + void Open(); + void Close(); + void Poll(); + TunerCapabilities Capabilities { get; } + ulong Frequency { get; set; } + byte Mode { get; set; } + byte Filter { get; set; } + bool SetTuning(ulong frequency, byte mode, byte filter); + bool SetOption(TunerOption Option, byte Value); + byte GetOption(TunerOption Option); + } + + public abstract class Tuner : ITuner { + private ulong _frequency; + private byte _mode, _filter; + private TunerCapabilities _capabilities = new TunerCapabilities(); + private byte[] _options = new byte[256]; + + public event EventHandler TuningChanged; + public event EventHandler AvailableModesChanged; + public event EventHandler OptionChanged; + + protected Tuner() { + //AcceptOption(ReceiverOptions.IfShift, 127); + //AcceptOption(ReceiverOptions.Online, 1); + } + + public virtual void Open() { } + public virtual void Close() { } + public virtual void Poll() { } + + public TunerCapabilities Capabilities { get { return _capabilities; } } + + public ulong Frequency { + get { return _frequency; } + set {SetTuning(value, 0, 0); } + } + public byte Mode { + get { return _mode; } + set { SetTuning(0, value, 0); } + } + public byte Filter { + get { return _mode; } + set { SetTuning(0, 0, value); } + } + public virtual bool SetTuning(ulong frequency, byte mode, byte filter) { + return SetTuning(ref frequency, ref mode, ref filter); + } + public virtual bool SetTuning(ref ulong frequency, ref byte mode, ref byte filter) { + bool notexact = false; + CheckFrequency(ref frequency, ref notexact); + CheckMode(ref mode, ref notexact); + CheckFilter(ref filter, ref notexact); + AcceptTuning(frequency, mode, filter); + return !notexact; + } + + public virtual bool SetOption(TunerOption Option, byte Value) { + return SetOption(Option, ref Value); + } + public virtual bool SetOption(TunerOption Option, ref byte Value) { + bool notexact = false; + CheckOption(Option, ref Value, ref notexact); + AcceptOption(Option, Value); + return !notexact; + } + public virtual byte GetOption(TunerOption Option) { + return _options[(int)Option]; + } + protected bool CheckOption(TunerOption Option, ref byte Value, ref bool notexact) { + switch (Option) { + case TunerOption.Filter: + case TunerOption.Frequency: + case TunerOption.Mode: + case TunerOption.Signal: + Value = 0; + notexact = true; + return false; + case TunerOption.AGC: + case TunerOption.Attenuator: + case TunerOption.NoiseBlanker: + case TunerOption.StereoMono: + case TunerOption.VSC: + if (Value > 1) Value = 1; + return (Value != _options[(int)Option]); + case TunerOption.IfShift: + case TunerOption.Squelch: + case TunerOption.Volume: + return (Value != _options[(int)Option]); + case TunerOption.RadioText: + Value = 1; + return true; + default: + return true; + } + } + protected void AcceptOption(TunerOption Option, byte Value) { + if (_options[(int)Option] != Value) { + _options[(int)Option] = Value; + if (OptionChanged != null) OptionChanged(this, new TunerOptionChangedEventArgs(Option)); + } + } + + protected bool CheckFrequency(ref ulong frequency, ref bool notexact) { + ulong closest = 0; + ulong diff = ulong.MaxValue; + if (frequency == 0 || frequency == _frequency) { //Frequency was not changed, return current mode + frequency = _mode; + return false; + } + foreach (TunerFrequencyRange f in _capabilities.Bands) { + if (frequency >= f.Begin && frequency <= f.End) return true; + if (frequency < f.Begin && diff > f.Begin - frequency) { + closest = f.Begin; + diff = closest - frequency; + } else if (frequency > f.End && diff > frequency - f.End) { + closest = f.End; + diff = frequency - closest; + } + } + if (closest != 0 && closest != _frequency) { + notexact = true; + frequency = closest; + return true; + } else { + return false; + } + } + protected bool CheckMode(ref byte mode, ref bool notexact) { + if (mode == 0 || mode == _mode) { //Mode was not changed, return current mode + mode = _mode; + return false; + } + foreach (byte b in _capabilities.AvailableModes) { //Mode was changed, accept if allowed + if (mode == b) return true; + } + mode = _mode; //Mode was changed but not allowed, keep current mode + return false; + } + protected bool CheckFilter(ref byte filter, ref bool notexact) { + byte closest = 0; + int diff = int.MaxValue; + //Filter has to be checked against AvailableFilters, in case AvailableFilters was changed + /*if (filter == 0 || filter == _filter) { //Filter was not changed, return current filter + filter = _filter; + return false; + }*/ + foreach (byte b in _capabilities.AvailableFilters) { //Filter was changed, find closest one + if (filter == b) return true; + if (filter < b && diff > b - filter) { + closest = b; + diff = closest - filter; + } else if (filter > b && diff > filter - b) { + closest = b; + diff = filter - closest; + } + } + if (closest != 0 && closest != _filter) { + notexact = true; + filter = closest; + return true; + } else { + return false; + } + } + + protected void AcceptTuning(ulong frequency, byte mode, byte filter) { + bool changed = false; + if (frequency != 0 && frequency != _frequency) { changed = true; _frequency = frequency; } + if (mode != 0 && mode != _mode) { changed = true; _mode = mode; } + if (filter != 0 && filter != _filter) { changed = true; _filter = filter; } + if (changed && TuningChanged != null) TuningChanged(this, new EventArgs()); + } + + protected void AcceptAvailableFilters(byte[] Filters) { + AcceptAvailableModes(null, Filters); + } + protected void AcceptAvailableModes(byte[] Modes, byte[] Filters) { + if (Modes != null) _capabilities.AvailableModes = Modes; + if (Filters != null) _capabilities.AvailableFilters = Filters; + if (AvailableModesChanged != null) AvailableModesChanged(this, new EventArgs()); + } + } +} diff -r 000000000000 -r 3ab940a0c7a0 ThreadPool.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ThreadPool.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,281 @@ +using System; +using System.Threading; +using System.Collections.Generic; + +namespace UCIS { + public class ThreadPool { + private static ThreadPool pManager = null; + + public static ThreadPool DefaultPool { + get { + if (pManager == null) pManager = new ThreadPool(); + return pManager; + } + } + + //Starts a long-term background task + public static WorkItem RunTask(WaitCallback Callback, object State) { + return DefaultPool.QueueWorkItem(Callback, State); + } + //Starts a short-term background task + public static WorkItem RunCall(WaitCallback Callback, object State) { + return DefaultPool.QueueWorkItem(Callback, State); + } + + + public class WorkItem { + public WaitCallback Callback { get; internal set; } + public object State { get; internal set; } + public ThreadInfo Thread { get; internal set; } + } + public class ThreadInfo { + public Thread Thread { get; internal set; } + internal AutoResetEvent WaitHandle = new AutoResetEvent(false); + public WorkItem WorkItem { get; internal set; } + public bool Busy { get; internal set; } + public bool Abort { get; internal set; } + public DateTime LastActive { get; internal set; } + } + + public class ExceptionEventArgs : EventArgs { + public ExceptionEventArgs(WorkItem Item, Exception Exception, bool ThrowError) { + this.Item = Item; + this.Exception = Exception; + this.ThrowError = ThrowError; + } + public WorkItem Item; + public Exception Exception; + public bool ThrowError; + } + + private List pThreads = new List(); + private List pBusyThreads = new List(); + private Queue pIdleThreads = new Queue(); + private int pThreadsMax; + private int pThreadsMinIdle; + private int pThreadsMaxIdle; + + public event OnExceptionEventHandler OnException; + public delegate void OnExceptionEventHandler(ThreadPool sender, ExceptionEventArgs e); + + public System.Collections.ObjectModel.ReadOnlyCollection Threads { + get { + return new System.Collections.ObjectModel.ReadOnlyCollection(pThreads); + } + } + + public ThreadPool() : this(250, 1, 5) { } + + public ThreadPool(int MaxThreads, int MinIdle, int MaxIdle) { + int I = 0; + if (MaxThreads < 0) { + throw new ArgumentOutOfRangeException("ThreadsMaxIdle", "ThreadsMaxIdle must greater than 0"); + } else if (MaxThreads < MaxIdle) { + throw new ArgumentOutOfRangeException("ThreadsMax", "ThreadsMax must be greater than or equal to ThreadsMaxIdle"); + } else if (MaxIdle < 0) { + throw new ArgumentOutOfRangeException("ThreadsMaxIdle", "ThreadsMaxIdle must greater than or equal to 0"); + } else if (MinIdle < 0) { + throw new ArgumentOutOfRangeException("ThreadsMinIdle", "ThreadsMinIdle must greater than or equal to 0"); + } else if (MinIdle > MaxIdle) { + throw new ArgumentOutOfRangeException("ThreadsMaxIdle", "ThreadsMaxIdle must be greater than or equal to ThreadsMinIdle"); + } + pThreadsMax = MaxThreads; + pThreadsMinIdle = MinIdle; + pThreadsMaxIdle = MaxIdle; + for (I = 1; I <= pThreadsMinIdle; I++) { + StartThread(false); + } + } + + public int ThreadsIdle { + get { return pIdleThreads.Count; } + } + public int ThreadsBusy { + get { return pBusyThreads.Count; } + } + public int ThreadsAlive { + get { return pThreads.Count; } + } + public int ThreadsMinIdle { + get { return pThreadsMinIdle; } + set { + if (value > pThreadsMaxIdle) { + throw new ArgumentOutOfRangeException("ThreadsMinIdle", "ThreadsMinIdle must be smaller than ThreadsMaxIdle"); + } else if (value < 0) { + throw new ArgumentOutOfRangeException("ThreadsMinIdle", "ThreadsMinIdle must greater than or equal to 0"); + } else { + int I = 0; + int C = 0; + C = pIdleThreads.Count; + if (value > C) { + for (I = C; I <= value - 1; I++) { + StartThread(false); + } + } + pThreadsMinIdle = value; + } + } + } + public int ThreadsMaxIdle { + get { return pThreadsMaxIdle; } + set { + if (pThreadsMinIdle > value) { + throw new ArgumentOutOfRangeException("ThreadsMaxIdle", "ThreadsMaxIdle must be greater than or equal to ThreadsMinIdle"); + } else if (value < 0) { + throw new ArgumentOutOfRangeException("ThreadsMaxIdle", "ThreadsMaxIdle must greater than or equal to 0"); + } else { + int I = 0; + int C = 0; + ThreadInfo T = default(ThreadInfo); + lock (pIdleThreads) { + C = pIdleThreads.Count; + if (value < C) { + for (I = value; I <= C - 1; I++) { + T = pIdleThreads.Dequeue(); + T.Abort = true; + T.WaitHandle.Set(); + } + } + } + pThreadsMaxIdle = value; + } + } + } + public int ThreadsMax { + get { return pThreadsMax; } + set { + if (pThreadsMaxIdle > value) { + throw new ArgumentOutOfRangeException("ThreadsMax", "ThreadsMax must be greater than or equal to ThreadsMaxIdle"); + } else if (value <= 0) { + throw new ArgumentOutOfRangeException("ThreadsMax", "ThreadsMax must greater than 0"); + } else { + pThreadsMax = value; + } + } + } + + public WorkItem QueueWorkItem(WaitCallback Callback, object State) { + WorkItem WorkItem = new WorkItem(); + ThreadInfo Thread = null; + WorkItem.Callback = Callback; + WorkItem.State = State; + lock (pIdleThreads) { + while (pIdleThreads.Count > 0) { + Thread = pIdleThreads.Dequeue(); + if (!Thread.Abort) { + break; + } else { + Thread = null; + } + } + } + if (Thread == null) { + if (pThreads.Count < pThreadsMax) { + Thread = StartThread(true); + } else { + throw new ThreadStateException("Thread limit exceeded"); + } + } + Thread.LastActive = DateTime.Now; + WorkItem.Thread = Thread; + Thread.WorkItem = WorkItem; + Thread.WaitHandle.Set(); + return WorkItem; + } + + private ThreadInfo StartThread(bool Reserved) { + ThreadInfo Thread = new ThreadInfo(); + Thread.Thread = new Thread(pWorker); + lock (pThreads) { + pThreads.Add(Thread); + if (!Reserved) pIdleThreads.Enqueue(Thread); + } + Thread.LastActive = DateTime.Now; + Thread.Thread.Start(Thread); + return Thread; + } + + public void AbortAllThreads() { + lock (pIdleThreads) { + while (pIdleThreads.Count > 0) { + ThreadInfo Thread = pIdleThreads.Dequeue(); + Thread.Abort = true; + Thread.WaitHandle.Set(); + } + } + foreach (ThreadInfo Thread in pThreads.ToArray()) { + if (Thread != null && !Thread.Abort) { + Thread.Thread.Abort(); + Thread.Abort = true; + Thread.WaitHandle.Set(); + } + } + pIdleThreads.Clear(); + } + + //ToDo: add timer to kill old threads periodically + public void KillOldThreads() { + ThreadInfo Thread; + lock (pIdleThreads) { + if (pIdleThreads.Count == 0) return; + Thread = pIdleThreads.Dequeue(); + } + if (DateTime.Now.Subtract(Thread.LastActive).TotalMinutes > 1) { + Thread.Abort = true; + Thread.WaitHandle.Set(); + } else { + lock (pIdleThreads) pIdleThreads.Enqueue(Thread); + } + } + + private void pWorker(object state) { + ThreadInfo Thread = (ThreadInfo)state; + if (Thread == null) throw new ArgumentNullException("state"); + try { + while (true) { + if (Thread.WaitHandle == null) throw new ArgumentNullException("WaitHandle"); + if (!Thread.WaitHandle.WaitOne(1000, false)) { + if (pBusyThreads.Count == 0) { + return; + } else { + continue; + } + } + if (Thread.Abort) break; + + Thread.Busy = true; + lock (pBusyThreads) pBusyThreads.Add(Thread); + try { + if (Thread.WorkItem == null) throw new ArgumentNullException("WorkItem"); + if (Thread.WorkItem.Callback == null) throw new ArgumentNullException("WorkItem.Callback"); + Thread.WorkItem.Callback.Invoke(Thread.WorkItem.State); + } catch (ThreadAbortException ex) { + ExceptionEventArgs e = new ExceptionEventArgs(Thread.WorkItem, ex, false); + if (OnException != null) OnException(this, e); + if (e.ThrowError) Console.WriteLine("ThreadAbortException in ThreadPool thread: " + e.Exception.ToString()); + return; + } catch (Exception ex) { + ExceptionEventArgs e = new ExceptionEventArgs(Thread.WorkItem, ex, true); + if (OnException != null) OnException(this, e); + if (e.ThrowError) { + Console.WriteLine("Exception in ThreadPool thread: " + e.Exception.ToString()); + throw new Exception("Unhandled exception in work item", e.Exception); + } + } finally { + lock (pBusyThreads) pBusyThreads.Remove(Thread); + } + Thread.WorkItem.Thread = null; + Thread.WorkItem = null; + Thread.Busy = false; + lock (pIdleThreads) { + if (pIdleThreads.Count >= pThreadsMaxIdle) break; + pIdleThreads.Enqueue(Thread); + } + } + } finally { + Thread.Abort = true; + lock (pThreads) pThreads.Remove(Thread); + } + } + } +} diff -r 000000000000 -r 3ab940a0c7a0 UCIS.csproj --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UCIS.csproj Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,98 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {3200885C-E36B-400B-BE21-6209B47832E6} + Library + Properties + UCIS + UCIS + v2.0 + 512 + + + true + full + false + ..\lib\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + ..\lib\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff -r 000000000000 -r 3ab940a0c7a0 UTF8NoPreamble.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UTF8NoPreamble.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,7 @@ +namespace UCIS { + public class UTF8NoPreamble : System.Text.UTF8Encoding { + public override byte[] GetPreamble() { + return new byte[] { }; + } + } +} diff -r 000000000000 -r 3ab940a0c7a0 Util/ArrayUtil.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Util/ArrayUtil.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; + +namespace UCIS.Util { + public class ArrayUtil { + public static T[] Slice(T[] input, int offset) { + if (offset < 0) offset = input.Length + offset; + return Slice(input, offset, input.Length - offset); + } + public static T[] Slice(T[] input, int offset, int count) { + if (offset < 0) offset = input.Length + offset; + if (count < 0) count = input.Length + count - offset; + T[] output = new T[count]; + Array.Copy(input, offset, output, 0, count); + return output; + } + public static T[] ToArray(ICollection input) { + T[] output = new T[input.Count]; + input.CopyTo(output, 0); + return output; + } + public static IList ToList(IEnumerable input) { + return new List(input); + } + public static void GnomeSort(IList a, Comparison comparer) { + int pos = 1; + while (pos < a.Count) { + if (comparer(a[pos], a[pos - 1]) >= 0) { + pos++; + } else { + T tmp = a[pos]; + a[pos] = a[pos - 1]; + a[pos - 1] = tmp; + if (pos > 1) pos--; else pos++; + } + } + } + //Array shuffle + //Array unique + public static T[] Merge(params ArraySegment[] parts) { + int count = 0; + foreach (ArraySegment segment in parts) count += segment.Count; + T[] ret = new T[count]; + int offset = 0; + foreach (ArraySegment segment in parts) { + Array.Copy(segment.Array, segment.Offset, ret, offset, segment.Count); + offset += segment.Count; + } + return ret; + } + public static T[] Merge(params T[][] parts) { + int count = 0; + foreach (T[] segment in parts) count += segment.Length; + T[] ret = new T[count]; + int offset = 0; + foreach (T[] segment in parts) { + segment.CopyTo(ret, offset); + offset += segment.Length; + } + return ret; + } + public static Boolean Equal(T[] a, T[] b, IEqualityComparer comparer) { + if (ReferenceEquals(a, b)) return true; + if (a == null || b == null) return false; + if (a.Length != b.Length) return false; + for (int i = 0; i < a.Length; i++) if (!comparer.Equals(a[i], b[i])) return false; + return true; + } + public static Boolean Equal(T[] a, T[] b) where T : IEquatable { + if (ReferenceEquals(a, b)) return true; + if (a == null || b == null) return false; + if (a.Length != b.Length) return false; + for (int i = 0; i < a.Length; i++) { + if (ReferenceEquals(a[i], b[i])) continue; + if (ReferenceEquals(a[i], null) || ReferenceEquals(b[i], null)) continue; + if (!a[i].Equals(b[i])) return false; + } + return true; + } + public static Boolean Equal(Byte[] a, Byte[] b) { + if (ReferenceEquals(a, b)) return true; + if (a == null || b == null) return false; + if (a.Length != b.Length) return false; + for (int i = 0; i < a.Length; i++) if (a[i] != b[i]) return false; + return true; + } + } +} diff -r 000000000000 -r 3ab940a0c7a0 Util/AsyncStream.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Util/AsyncStream.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,88 @@ +using System; +using System.IO; + +namespace UCIS.Util { + public class AsyncStreamWrapper : Stream { + ReadDelegate readDelegate; + WriteDelegate writeDelegate; + + public Stream BaseStream { get; private set; } + + public AsyncStreamWrapper(Stream stream) { + BaseStream = stream; + readDelegate = (ReadDelegate)Read; + writeDelegate = (WriteDelegate)Write; + } + + public override int Read(byte[] buffer, int offset, int count) { return BaseStream.Read(buffer, offset, count); } + public override void Write(byte[] buffer, int offset, int count) { BaseStream.Write(buffer, offset, count); } + public override void Close() { BaseStream.Close(); } + + public override bool CanRead { get { return BaseStream.CanRead; } } + public override bool CanSeek { get { return BaseStream.CanSeek; } } + public override bool CanTimeout { get { return BaseStream.CanTimeout ; } } + public override bool CanWrite { get { return BaseStream.CanWrite ; } } + + public override int ReadTimeout { + get { return BaseStream.ReadTimeout; } + set { BaseStream.ReadTimeout = value; } + } + public override int WriteTimeout { + get { return BaseStream.WriteTimeout; } + set { BaseStream.WriteTimeout = value; } + } + + public override void Flush() { BaseStream.Flush(); } + public override long Length { get { return BaseStream.Length; } } + public override long Position { + get { return BaseStream.Position; } + set { BaseStream.Position = value; } + } + public override long Seek(long offset, SeekOrigin origin) { return BaseStream.Seek(offset, origin); } + public override void SetLength(long value) { BaseStream.SetLength(value); } + + public override int ReadByte() { return base.ReadByte(); } + public override void WriteByte(byte value) { BaseStream.WriteByte(value); } + + private delegate int ReadDelegate(byte[] buffer, int offset, int count); + private delegate void WriteDelegate(byte[] buffer, int offset, int count); + + public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { + return readDelegate.BeginInvoke(buffer, offset, count, callback, state); + } + public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { + return writeDelegate.BeginInvoke(buffer, offset, count, callback, state); + } + public override int EndRead(IAsyncResult asyncResult) { + return readDelegate.EndInvoke(asyncResult); + } + public override void EndWrite(IAsyncResult asyncResult) { + writeDelegate.EndInvoke(asyncResult); + } + } + public abstract class AsyncStream : Stream { + ReadDelegate readDelegate; + WriteDelegate writeDelegate; + + public AsyncStream() { + readDelegate = (ReadDelegate)Read; + writeDelegate = (WriteDelegate)Write; + } + + private delegate int ReadDelegate(byte[] buffer, int offset, int count); + private delegate void WriteDelegate(byte[] buffer, int offset, int count); + + public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { + return readDelegate.BeginInvoke(buffer, offset, count, callback, state); + } + public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { + return writeDelegate.BeginInvoke(buffer, offset, count, callback, state); + } + public override int EndRead(IAsyncResult asyncResult) { + return readDelegate.EndInvoke(asyncResult); + } + public override void EndWrite(IAsyncResult asyncResult) { + writeDelegate.EndInvoke(asyncResult); + } + } +} diff -r 000000000000 -r 3ab940a0c7a0 Util/CrossStream.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Util/CrossStream.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; + +namespace UCIS.Util { + public class CrossStream : Stream { + private Queue queue = new Queue(); + private byte[] currentBuffer = null; + private int currentBufferIndex; + private CrossStream otherPart; + private AutoResetEvent resetEvent = new AutoResetEvent(false); + + public static CrossStream CreatePair(out CrossStream stream1, out CrossStream stream2) { + stream1 = new CrossStream(); + stream2 = new CrossStream(stream1); + stream1.otherPart = stream2; + return stream1; + } + public static CrossStream CreatePair(out CrossStream stream2) { + CrossStream stream1 = new CrossStream(); + stream2 = new CrossStream(stream1); + stream1.otherPart = stream2; + return stream1; + } + + private CrossStream() { } + public CrossStream(CrossStream other) { + this.otherPart = other; + } + + public override bool CanRead { get { return true; } } + public override bool CanWrite { get { return true; } } + public override bool CanSeek { get { return false; } } + public override bool CanTimeout { get { return true; } } + public override long Length { get { throw new NotSupportedException(); } } + public override long Position { get { throw new NotSupportedException(); } set { throw new NotSupportedException(); } } + public override void Flush() { } + public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } + public override void SetLength(long value) { throw new NotSupportedException(); } + public override int Read(byte[] buffer, int offset, int count) { + if (currentBuffer == null) { + //if (queue.Count == 0) if (!resetEvent.WaitOne(this.ReadTimeout)) throw new TimeoutException(); + if (queue.Count == 0 && !resetEvent.WaitOne()) throw new TimeoutException(); + //while (queue.Count == 0) Thread.Sleep(100); + resetEvent.Reset(); + currentBuffer = queue.Dequeue(); + currentBufferIndex = 0; + } + if (count > currentBuffer.Length - currentBufferIndex) count = currentBuffer.Length - currentBufferIndex; + Buffer.BlockCopy(currentBuffer, currentBufferIndex, buffer, offset, count); + currentBufferIndex += count; + if (currentBufferIndex == currentBuffer.Length) currentBuffer = null; + return count; + } + public override void Write(byte[] buffer, int offset, int count) { + byte[] tostore; + if (count == 0) return; + tostore = new byte[count]; + Buffer.BlockCopy(buffer, offset, tostore, 0, count); + otherPart.queue.Enqueue(tostore); + otherPart.resetEvent.Set(); + } + } +} diff -r 000000000000 -r 3ab940a0c7a0 Util/HoldStream.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Util/HoldStream.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,64 @@ +using System; +using System.IO; + +namespace UCIS.Util { + public class HoldStream : Stream { + private Stream baseStream; + private MemoryStream buffer; + + public HoldStream(Stream baseStream) { + this.baseStream = baseStream; + this.buffer = new MemoryStream(4096); + } + + public override bool CanRead { + get { return baseStream.CanRead; } + } + public override bool CanSeek { + get { return buffer.CanSeek; } + } + public override bool CanTimeout { + get { return baseStream.CanTimeout; } + } + public override bool CanWrite { + get { return buffer.CanWrite; } + } + public override void Close() { + buffer.Close(); + baseStream.Close(); + } + public override void Flush() { + buffer.WriteTo(baseStream); + buffer.SetLength(0); + buffer.Seek(0, SeekOrigin.Begin); + } + public override void Write(byte[] buffer, int offset, int count) { + this.buffer.Write(buffer, offset, count); + } + public override int Read(byte[] buffer, int offset, int count) { + return baseStream.Read(buffer, offset, count); + } + public override void SetLength(long value) { + buffer.SetLength(value); + } + public override long Seek(long offset, SeekOrigin origin) { + return buffer.Seek(offset, origin); + } + public override long Position { + get { return buffer.Position; } + set { buffer.Position = value; } + } + public override long Length { + get { return buffer.Length; } + } + public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { + return baseStream.BeginRead(buffer, offset, count, callback, state); + } + public override int EndRead(IAsyncResult asyncResult) { + return baseStream.EndRead(asyncResult); + } + public override void WriteByte(byte value) { + buffer.WriteByte(value); + } + } +} diff -r 000000000000 -r 3ab940a0c7a0 Util/PipeStream.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Util/PipeStream.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; + +namespace UCIS.Util { + public class PipeStream : Stream { + private Queue queue = new Queue(); + private byte[] currentBuffer = null; + private int currentBufferIndex; + private AutoResetEvent resetEvent = new AutoResetEvent(false); + private Boolean closed = false; + + public PipeStream() { + ReadTimeout = Timeout.Infinite; + } + + public override int ReadTimeout { get; set; } + public override bool CanRead { get { return !closed; } } + public override bool CanWrite { get { return !closed; } } + public override bool CanSeek { get { return false; } } + public override bool CanTimeout { get { return !closed; } } + public override long Length { get { throw new NotSupportedException(); } } + public override long Position { get { throw new NotSupportedException(); } set { throw new NotSupportedException(); } } + public override void Flush() { } + public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } + public override void SetLength(long value) { throw new NotSupportedException(); } + public override int Read(byte[] buffer, int offset, int count) { + if (closed) throw new ObjectDisposedException("PipeStream"); + if (currentBuffer == null) { + //if (queue.Count == 0) if (!resetEvent.WaitOne(this.ReadTimeout)) throw new TimeoutException(); + if (queue.Count == 0 && (ReadTimeout == 0 || !resetEvent.WaitOne(ReadTimeout))) throw new TimeoutException(); + //while (queue.Count == 0) Thread.Sleep(100); + resetEvent.Reset(); + currentBuffer = queue.Dequeue(); + currentBufferIndex = 0; + } + if (count > currentBuffer.Length - currentBufferIndex) count = currentBuffer.Length - currentBufferIndex; + Buffer.BlockCopy(currentBuffer, currentBufferIndex, buffer, offset, count); + currentBufferIndex += count; + if (currentBufferIndex == currentBuffer.Length) currentBuffer = null; + return count; + } + public override void Write(byte[] buffer, int offset, int count) { + byte[] tostore; + if (closed) throw new ObjectDisposedException("PipeStream"); + if (count == 0) return; + tostore = new byte[count]; + Buffer.BlockCopy(buffer, offset, tostore, 0, count); + queue.Enqueue(tostore); + resetEvent.Set(); + } + public override void Close() { + closed = true; + resetEvent.Set(); + base.Close(); + } + } +} diff -r 000000000000 -r 3ab940a0c7a0 Windows/ServiceManager.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Windows/ServiceManager.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,116 @@ +using System; +using System.Management; +using System.IO; + +namespace UCIS.Windows { + public class ServiceManager { + private ManagementObject _serviceObject; + + public const string StartMode_Automatic = "Automatic"; + public const string StartMode_Manual = "Manual"; + public const string StartMode_Disabled = "Disabled"; + + private ServiceManager(ManagementObject ob) { + _serviceObject = ob; + } + + public static ServiceManager GetServiceByPath(string FileName) { + ManagementClass mc = new ManagementClass("Win32_Service"); + foreach (ManagementObject ob in mc.GetInstances()) { + string Value = (string)ob.GetPropertyValue("PathName"); + if (Value == null) continue; + int Position = Value.IndexOf(FileName); + if (Position == 0 || Position == 1) { //Either or <"filepath"> + return new ServiceManager(ob); + } + } + return null; + } + public static ServiceManager GetServiceByName(string Name) { + ManagementClass mc = new ManagementClass("Win32_Service"); + foreach (ManagementObject ob in mc.GetInstances()) { + string Value = (string)ob.GetPropertyValue("Name"); + if (Value == null) continue; + if (Value.Equals(Name, StringComparison.InvariantCultureIgnoreCase)) return new ServiceManager(ob); + } + return null; + } + public static ServiceManager Create(string Name, string DisplayName, string PathName, string StartMode, bool DesktopInteract, string StartName, string StartPassword) { + ManagementClass mc = new ManagementClass("Win32_Service"); + UInt32 ret; + ret = (UInt32)mc.InvokeMethod("Create", new Object[] { + Name, //Name + DisplayName, //DisplayName + PathName, //PathName + 16, //ServiceType (16 = own process) + 1, //ErrorControl (1 = user is notified) + StartMode, //StartMode + DesktopInteract, //DesktopInteract + StartName, //StartName (null = LocalSystem) + StartPassword, //StartPassword + null, //LoadOrderGroup + null, //LoadOrderGroupDependencies + null //ServiceDependencies + }); + if (ret != 0) throw new ManagementException("Could not create service (code " + ret.ToString() + ")"); + return GetServiceByName(Name); + } + + public string Name { get { return (string)_serviceObject.GetPropertyValue("Name"); } } + public string DisplayName { get { return (string)_serviceObject.GetPropertyValue("DisplayName"); } } + public string PathName { get { return (string)_serviceObject.GetPropertyValue("PathName"); } } + public string StartMode { + get { return (string)_serviceObject.GetPropertyValue("StartMode"); } + set { _serviceObject.InvokeMethod("ChangeStartMode", new Object[] { value }); Refresh(); } + } + public bool DesktopInteract { get { return (bool)_serviceObject.GetPropertyValue("DesktopInteract"); } } + public string StartName { get { return (string)_serviceObject.GetPropertyValue("StartName"); } } + public string StartPassword { get { return (string)_serviceObject.GetPropertyValue("StartPassword"); } } + + public void Change(string DisplayName, string PathName, string StartMode, bool DesktopInteract, string StartName, string StartPassword) { + UInt32 ret; + ret = (UInt32)_serviceObject.InvokeMethod("Change", new Object[] { + DisplayName, //DisplayName + PathName, //PathName + 16, //ServiceType (16 = own process) + 1, //ErrorControl (1 = user is notified) + StartMode, //StartMode + DesktopInteract, //DesktopInteract + StartName, //StartName (null = LocalSystem) + StartPassword, //StartPassword + null, //LoadOrderGroup + null, //LoadOrderGroupDependencies + null //ServiceDependencies + }); + if (ret != 0) throw new ManagementException("Could not change service (code " + ret.ToString() + ")"); + Refresh(); + } + + public void Refresh() { + _serviceObject.Get(); + } + + public void Start() { + _serviceObject.InvokeMethod("StartService", null); + Refresh(); + } + public void Stop() { + _serviceObject.InvokeMethod("StopService", null); + Refresh(); + } + + public bool Running { + get { + Refresh(); + return (bool)_serviceObject.GetPropertyValue("Started"); + } + } + + public String State { + get { + Refresh(); + return (String)_serviceObject.GetPropertyValue("State"); + } + } + } +} \ No newline at end of file diff -r 000000000000 -r 3ab940a0c7a0 Xml/PolicyFile.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Xml/PolicyFile.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Text; +using UCIS.Net; + +namespace UCIS.Xml { + public class XmlPolicyFile : XmlServer.IModule { + private string[] pHosts; + private string pPorts; + + public XmlPolicyFile(string[] Hosts) : this(Hosts, null) { } + public XmlPolicyFile(string[] Hosts, int[] Ports) { + pHosts = Hosts; + if (Ports != null) { + pPorts = ""; + foreach (int Port in Ports) { + pPorts += "," + Port.ToString(); + } + pPorts = pPorts.Substring(1); + } else { + pPorts = null; + } + } + + public void Accept(XmlSocket Socket, System.Xml.XmlDocument FirstMessage) { + Socket.WriterSettings.OmitXmlDeclaration = false; + + Socket.WriteStartDocument(); + Socket.WriteDocType("cross-domain-policy", null, "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd", null); + Socket.WriteStartElement("cross-domain-policy"); + + foreach (string Host in pHosts) { + Socket.WriteStartElement("allow-access-from"); + Socket.WriteAttributeString("domain", Host); + if (pPorts != null) Socket.WriteAttributeString("to-ports", pPorts); + Socket.WriteEndElement(); + } + + Socket.WriteEndElement(); + Socket.WriteEndDocument(); + } + } +} diff -r 000000000000 -r 3ab940a0c7a0 Xml/Server.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Xml/Server.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Xml; +using UCIS.Net; + +namespace UCIS.Xml { + public class XmlServer : TCPServer.IModule { + public Dictionary Modules = new Dictionary(StringComparer.OrdinalIgnoreCase); + + public bool Accept(TCPStream Stream) { + XmlSocket XSocket = new XmlSocket(Stream); + Stream.ReadTimeout = 5000; + XmlDocument FirstMessage = XSocket.ReadDocument(); + if (FirstMessage == null) return true; + IModule module; + if (Modules.TryGetValue(FirstMessage.FirstChild.Name, out module)) { + module.Accept(XSocket, FirstMessage); + } else { + Console.WriteLine("XMLServer.Accept: Module not found: " + FirstMessage.FirstChild.Name); + } + return true; + } + + public interface IModule { + void Accept(XmlSocket Socket, XmlDocument FirstMessage); + } + } +} diff -r 000000000000 -r 3ab940a0c7a0 Xml/Socket.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Xml/Socket.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,197 @@ +using System; +using System.Text; +using System.IO; +using System.Xml; + +namespace UCIS.Xml { + public class XmlSocket : XmlWriter { + protected Stream pStream; + protected XmlWriter pWriter; + protected XmlReaderSettings pXMLReaderSettings;// = new XmlReaderSettings(); + + public Stream BaseStream { get { return pStream; } } + + public override XmlWriterSettings Settings { get { return WriterSettings; } } + public XmlWriterSettings WriterSettings { get; private set; } + public XmlReaderSettings ReaderSettings { get { return pXMLReaderSettings; } } + + public XmlSocket(Stream Stream, Encoding Encoding) { + WriterSettings = new XmlWriterSettings(); + WriterSettings.ConformanceLevel = ConformanceLevel.Document; + WriterSettings.NewLineHandling = NewLineHandling.Entitize; + WriterSettings.OmitXmlDeclaration = true; + WriterSettings.CheckCharacters = false; + WriterSettings.Encoding = Encoding; + WriterSettings.CloseOutput = false; + + pXMLReaderSettings = new XmlReaderSettings(); + pXMLReaderSettings.ConformanceLevel = ConformanceLevel.Document; + pXMLReaderSettings.CloseInput = true; + pXMLReaderSettings.IgnoreComments = true; + pXMLReaderSettings.IgnoreProcessingInstructions = true; + pXMLReaderSettings.IgnoreWhitespace = true; + pXMLReaderSettings.ValidationType = ValidationType.None; + pXMLReaderSettings.ValidationFlags = System.Xml.Schema.XmlSchemaValidationFlags.None; + pXMLReaderSettings.CheckCharacters = false; + + pStream = Stream; + } + public XmlSocket(Stream Stream) : this(Stream, new UTF8NoPreamble()) { } + + public virtual MemoryStream ReadRawDocument() { + MemoryStream Buffer = new MemoryStream(); + byte[] ByteBuffer = new byte[1]; + int ByteCount = 0; + while (true) { + ByteCount = pStream.Read(ByteBuffer, 0, 1); + if (ByteCount == 0) { + throw new EndOfStreamException(); + } else if (ByteBuffer[0] == 0) { + if (Buffer.Length > 0) break; + } else { + Buffer.WriteByte(ByteBuffer[0]); + } + } + Buffer.Flush(); + Buffer.Seek(0, SeekOrigin.Begin); + + return Buffer; + } + public virtual XmlDocument ReadDocument() { + MemoryStream Buffer = ReadRawDocument(); + try { + XmlDocument Doc = new XmlDocument(); + XmlReader XMLReader = XmlReader.Create(Buffer, pXMLReaderSettings); + Doc.Load(XMLReader); + XMLReader.Close(); + return Doc; + } catch (Exception ex) { + Buffer.Seek(0, SeekOrigin.Begin); + throw new IOException("Could not parse XML document: \"" + Encoding.UTF8.GetString(Buffer.ToArray()) + "\"", ex); + } + } + + protected virtual void CreateWriter() { + pWriter = XmlWriter.Create(pStream, WriterSettings); + } + protected virtual void CloseWriter() { + pWriter.Flush(); + pWriter.Close(); + pStream.WriteByte(0); + pStream.Flush(); + } + public override void Flush() { + if (pWriter != null) { + pWriter.Flush(); + } else { + pStream.Flush(); + } + } + public override void Close() { + if (pWriter != null) { + pWriter.Close(); + pWriter = null; + } + pStream.Close(); + } + + public void WriteDocument(XmlDocument Document) { + CreateWriter(); + Document.WriteTo(pWriter); + CloseWriter(); + } + + public virtual void WriteRawDocument(string data) { + byte[] Buffer = WriterSettings.Encoding.GetBytes(data); + pStream.Write(Buffer, 0, Buffer.Length); + pStream.WriteByte(0); + pStream.Flush(); + } + + public override void WriteStartDocument() { + CreateWriter(); + pWriter.WriteStartDocument(); + } + public override void WriteStartDocument(bool standalone) { + CreateWriter(); + pWriter.WriteStartDocument(standalone); + } + public override void WriteEndDocument() { + pWriter.WriteEndDocument(); + CloseWriter(); + } + public void WriteDocumentString(string localName, string value) { + WriteStartDocument(); + WriteElementString(localName, value); + WriteEndDocument(); + } + + public override System.Xml.WriteState WriteState { + get { + if (pWriter != null) { + return pWriter.WriteState; + } else { + return WriteState.Start; + } + } + } + + public override string LookupPrefix(string ns) { + return pWriter.LookupPrefix(ns); + } + public override void WriteBase64(byte[] buffer, int index, int count) { + pWriter.WriteBase64(buffer, index, count); + } + public override void WriteCData(string text) { + pWriter.WriteCData(text); + } + public override void WriteCharEntity(char ch) { + pWriter.WriteCharEntity(ch); + } + public override void WriteChars(char[] buffer, int index, int count) { + pWriter.WriteChars(buffer, index, count); + } + public override void WriteComment(string text) { + pWriter.WriteComment(text); + } + public override void WriteDocType(string name, string pubid, string sysid, string subset) { + pWriter.WriteDocType(name, pubid, sysid, subset); + } + public override void WriteEndAttribute() { + pWriter.WriteEndAttribute(); + } + public override void WriteEndElement() { + pWriter.WriteEndElement(); + } + public override void WriteEntityRef(string name) { + pWriter.WriteEntityRef(name); + } + public override void WriteFullEndElement() { + pWriter.WriteFullEndElement(); + } + public override void WriteProcessingInstruction(string name, string text) { + pWriter.WriteProcessingInstruction(name, text); + } + public override void WriteRaw(char[] buffer, int index, int count) { + pWriter.WriteRaw(buffer, index, count); + } + public override void WriteRaw(string data) { + pWriter.WriteRaw(data); + } + public override void WriteStartAttribute(string prefix, string localName, string ns) { + pWriter.WriteStartAttribute(prefix, localName, ns); + } + public override void WriteStartElement(string prefix, string localName, string ns) { + pWriter.WriteStartElement(prefix, localName, ns); + } + public override void WriteString(string text) { + pWriter.WriteString(text); + } + public override void WriteSurrogateCharEntity(char lowChar, char highChar) { + pWriter.WriteSurrogateCharEntity(lowChar, highChar); + } + public override void WriteWhitespace(string ws) { + pWriter.WriteWhitespace(ws); + } + } +}