# HG changeset patch # User Ivo Smits # Date 1358099057 -3600 # Node ID 4b78cc5f116b048955baea612008e2192ce6c023 # Parent 5ce7a138fdba96c7f4163218e44855851b8dd1fb Fixes and improvements (some untested) diff -r 5ce7a138fdba -r 4b78cc5f116b Database.cs --- a/Database.cs Tue Jan 08 16:38:37 2013 +0100 +++ b/Database.cs Sun Jan 13 18:44:17 2013 +0100 @@ -1,8 +1,7 @@ using System; -using System.Reflection; +using System.Collections.Generic; using System.Data; -using System.Data.Common; -using System.Collections.Generic; +using System.Reflection; namespace UCIS { public class Database { @@ -17,107 +16,103 @@ public string ConnectionString { get; set; } public virtual IDbConnection GetConnection() { - lock (_ConnectionConstructor) { - IDbConnection conn = (IDbConnection)_ConnectionConstructor.Invoke(null); - conn.ConnectionString = ConnectionString; - conn.Open(); - return conn; + IDbConnection conn = (IDbConnection)_ConnectionConstructor.Invoke(null); + conn.ConnectionString = ConnectionString; + conn.Open(); + return conn; + } + + private IDbCommand PrepareQuery(IDbConnection Connection, string Query, params object[] Parameters) { + IDbCommand Command = Connection.CreateCommand(); + Command.CommandType = CommandType.Text; + Command.CommandText = Query; + Command.Parameters.Clear(); + int ParameterI = 0; + 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; } 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) { + return PrepareQuery(Connection, Query, Parameters); + } catch (Exception) { Connection.Close(); - throw ex; + throw; } } public int NonQuery(string QueryString, params object[] Parameters) { - IDbCommand Command = PrepareQuery(QueryString, Parameters); - try { - return Command.ExecuteNonQuery(); - } finally { - Command.Connection.Close(); + using (IDbConnection connection = GetConnection()) { + using (IDbCommand command = PrepareQuery(connection, QueryString, Parameters)) { + return command.ExecuteNonQuery(); + } } } public object FetchField(string QueryString, params object[] Parameters) { - IDbCommand Command = PrepareQuery(QueryString, Parameters); - try { - return Command.ExecuteScalar(); - } finally { - Command.Connection.Close(); + using (IDbConnection connection = GetConnection()) { + using (IDbCommand command = PrepareQuery(connection, QueryString, Parameters)) { + return command.ExecuteScalar(); + } } } 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(); + using (IDbConnection connection = GetConnection()) { + using (IDbCommand command = PrepareQuery(connection, QueryString, Parameters)) { + using (IDataReader Reader = command.ExecuteReader()) { + if (!Reader.Read()) return null; + object[] Result = new object[Reader.FieldCount]; + Reader.GetValues(Result); + return Result; + } } - } 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); + using (IDbConnection connection = GetConnection()) { + using (IDbCommand command = PrepareQuery(connection, QueryString, Parameters)) { + using (IDataReader Reader = command.ExecuteReader()) { + List Result = new List(); + while (Reader.Read()) { + object[] ResultArray = new object[Reader.FieldCount]; + Reader.GetValues(ResultArray); + Result.Add(ResultArray); + } + return Result.ToArray(); } - 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); + using (IDbConnection connection = GetConnection()) { + using (IDbCommand command = PrepareQuery(connection, QueryString, Parameters)) { + using (IDataReader Reader = command.ExecuteReader()) { + while (Reader.Read()) { + object[] ResultArray = new object[Reader.FieldCount]; + Reader.GetValues(ResultArray); + f(ResultArray); + } } - } finally { - Reader.Close(); } - } finally { - Command.Connection.Close(); } - + } + public void ForEachRow(Action callback, string query, params object[] parameters) { + using (IDbConnection connection = GetConnection()) { + using (IDbCommand command = PrepareQuery(connection, query, parameters)) { + using (IDataReader Reader = command.ExecuteReader()) { + while (Reader.Read()) callback(Reader); + } + } + } } /*public DBReader GetReader(string QueryString, params object[] Parameters) { diff -r 5ce7a138fdba -r 4b78cc5f116b Net/HTTP.cs --- a/Net/HTTP.cs Tue Jan 08 16:38:37 2013 +0100 +++ b/Net/HTTP.cs Sun Jan 13 18:44:17 2013 +0100 @@ -171,9 +171,11 @@ return; SendError400AndClose: + State = HTTPConnectionState.ProcessingRequest; SendErrorAndClose(400); return; SendError500AndClose: + State = HTTPConnectionState.ProcessingRequest; SendErrorAndClose(500); return; } @@ -288,6 +290,37 @@ } } } + public class HTTPStaticContent : IHTTPContentProvider { + public ArraySegment ContentBuffer { get; set; } + public String ContentType { get; set; } + public HTTPStaticContent() : this(new ArraySegment()) { } + public HTTPStaticContent(ArraySegment content) : this(content, "application/octet-stream") { } + public HTTPStaticContent(String content, String contentType) : this(Encoding.UTF8.GetBytes(content), contentType) { } + public HTTPStaticContent(String contentType) : this(new ArraySegment(), contentType) { } + public HTTPStaticContent(Byte[] content, String contentType) : this(new ArraySegment(content), contentType) { } + public HTTPStaticContent(ArraySegment content, String contentType) { + this.ContentBuffer = content; + this.ContentType = contentType; + } + public void SetContent(Byte[] bytes) { ContentBuffer = new ArraySegment(bytes); } + public void SetContent(Byte[] bytes, int offset, int count) { ContentBuffer = new ArraySegment(bytes, offset, count); } + public void SetContent(String content, Encoding encoding) { SetContent(encoding.GetBytes(content)); } + public void SetContent(String content) { SetContent(content, Encoding.UTF8); } + public void ServeRequest(HTTPContext context) { + ArraySegment content = ContentBuffer; + if (content.Array == null) { + context.SendErrorAndClose(404); + return; + } + String contentType = ContentType; + context.SendStatus(200); + if (contentType != null) context.SendHeader("Content-Type", contentType); + context.SendHeader("Content-Length", content.Count.ToString()); + Stream response = context.GetResponseStream(); + response.Write(content.Array, content.Offset, content.Count); + response.Close(); + } + } public class HTTPFileProvider : IHTTPContentProvider { public String FileName { get; private set; } public String ContentType { get; private set; } @@ -347,7 +380,7 @@ context.SendStatus(200); context.SendHeader("Content-Length", fsizei.ToString()); String ctype = null; - switch (Path.GetExtension(fname).ToUpperInvariant()) { + switch (Path.GetExtension(fname).ToLowerInvariant()) { case ".txt": ctype = "text/plain"; break; case ".htm": case ".html": ctype = "text/html"; break; diff -r 5ce7a138fdba -r 4b78cc5f116b Net/TCPStream.cs --- a/Net/TCPStream.cs Tue Jan 08 16:38:37 2013 +0100 +++ b/Net/TCPStream.cs Sun Jan 13 18:44:17 2013 +0100 @@ -3,6 +3,7 @@ using System.Net; using System.Net.Sockets; using System.Threading; +using UCIS.Util; using SysThreadPool = System.Threading.ThreadPool; namespace UCIS.Net { @@ -76,17 +77,15 @@ } public override int Read(byte[] buffer, int offset, int size) { + if (size < 1) return 0; int Count = 0; - - if (size < 1) return 0; if (_HasPeekByte) { buffer[offset] = _PeekByte; _HasPeekByte = false; Count = 1; offset += 1; - size -= 1; + size = 0; } - try { if (size > 0) Count += Socket.Receive(buffer, offset, size, SocketFlags.None); } catch (SocketException ex) { @@ -114,34 +113,12 @@ return Count; } - class AsyncResult : IAsyncResult { - public Object AsyncState { get; private set; } - public WaitHandle AsyncWaitHandle { get { return WaitHandle; } } - public Boolean CompletedSynchronously { get; private set; } - public Boolean IsCompleted { get; private set; } + class AsyncResult : AsyncResultBase { public int Count { get; private set; } - - private ManualResetEvent WaitHandle = new ManualResetEvent(false); - private AsyncCallback Callback = null; - private void CallCallback(Object state) { - if (Callback != null) Callback(this); - } + public AsyncResult(AsyncCallback callback, Object state) : base(callback, state) { } public void SetCompleted(Boolean synchronously, int cnt) { - CompletedSynchronously = synchronously; Count = cnt; - IsCompleted = true; - WaitHandle.Set(); - if (synchronously) { - CallCallback(null); - } else { - if (Callback != null) SysThreadPool.QueueUserWorkItem(CallCallback); - } - } - public AsyncResult(AsyncCallback callback, Object state) { - this.Callback = callback; - this.AsyncState = state; - CompletedSynchronously = false; - IsCompleted = false; + base.SetCompleted(synchronously, null); } } public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { @@ -152,8 +129,6 @@ } else if (_HasPeekByte) { buffer[offset] = _PeekByte; _HasPeekByte = false; - offset += 1; - count -= 1; AsyncResult ar = new AsyncResult(callback, state); ar.SetCompleted(true, 1); return ar; @@ -173,8 +148,7 @@ if (_HasPeekByte) { return _PeekByte; } else { - int Result = 0; - Result = ReadByte(); + int Result = ReadByte(); if (Result >= 0 && Result <= 255) { _PeekByte = (byte)Result; _HasPeekByte = true; @@ -211,18 +185,11 @@ } public override long Length { - get { - throw new NotSupportedException(); - } + get { throw new NotSupportedException(); } } - public override long Position { - get { - throw new NotSupportedException(); - } - set { - throw new NotSupportedException(); - } + get { throw new NotSupportedException(); } + set { throw new NotSupportedException(); } } public override long Seek(long offset, SeekOrigin origin) { @@ -266,7 +233,7 @@ } public override void Close() { - System.Net.Sockets.Socket s = Interlocked.Exchange(ref _Socket, null); + Socket s = Interlocked.Exchange(ref _Socket, null); try { if (s != null) { try { diff -r 5ce7a138fdba -r 4b78cc5f116b ThreadPool.cs --- a/ThreadPool.cs Tue Jan 08 16:38:37 2013 +0100 +++ b/ThreadPool.cs Sun Jan 13 18:44:17 2013 +0100 @@ -1,6 +1,7 @@ using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Threading; -using System.Collections.Generic; namespace UCIS { public class ThreadPool { @@ -49,7 +50,7 @@ } private List pThreads = new List(); - private List pBusyThreads = new List(); + private int pBusyThreads = 0; private Queue pIdleThreads = new Queue(); private int pThreadsMax; private int pThreadsMinIdle; @@ -58,16 +59,11 @@ 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 ReadOnlyCollection Threads { get { return pThreads.AsReadOnly(); } } - public ThreadPool() : this(250, 1, 5) { } + public ThreadPool() : this(250, 0, 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) { @@ -82,20 +78,14 @@ pThreadsMax = MaxThreads; pThreadsMinIdle = MinIdle; pThreadsMaxIdle = MaxIdle; - for (I = 1; I <= pThreadsMinIdle; I++) { + for (int 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 ThreadsIdle { get { return pIdleThreads.Count; } } + public int ThreadsBusy { get { return pBusyThreads; } } + public int ThreadsAlive { get { return pThreads.Count; } } public int ThreadsMinIdle { get { return pThreadsMinIdle; } set { @@ -119,62 +109,39 @@ 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(); - } - } + if (pThreadsMinIdle > value) throw new ArgumentOutOfRangeException("ThreadsMaxIdle", "ThreadsMaxIdle must be greater than or equal to ThreadsMinIdle"); + if (value < 0) throw new ArgumentOutOfRangeException("ThreadsMaxIdle", "ThreadsMaxIdle must greater than or equal to 0"); + lock (pIdleThreads) { + while (value > pIdleThreads.Count) { + ThreadInfo T = pIdleThreads.Dequeue(); + T.Abort = true; + T.WaitHandle.Set(); } - pThreadsMaxIdle = value; } + 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; - } + if (pThreadsMaxIdle > value) throw new ArgumentOutOfRangeException("ThreadsMax", "ThreadsMax must be greater than or equal to ThreadsMaxIdle"); + if (value <= 0) throw new ArgumentOutOfRangeException("ThreadsMax", "ThreadsMax must greater than 0"); + pThreadsMax = value; } } public WorkItem QueueWorkItem(WaitCallback Callback, object State) { - WorkItem WorkItem = new WorkItem(); + WorkItem WorkItem = new WorkItem() { Callback = Callback, State = State }; ThreadInfo Thread = null; - WorkItem.Callback = Callback; - WorkItem.State = State; lock (pIdleThreads) { - while (pIdleThreads.Count > 0) { + while (Thread == null && pIdleThreads.Count > 0) { Thread = pIdleThreads.Dequeue(); - if (!Thread.Abort) { - break; - } else { - Thread = null; - } + if (Thread.Abort) Thread = null; } } if (Thread == null) { - if (pThreads.Count < pThreadsMax) { - Thread = StartThread(true); - } else { - throw new ThreadStateException("Thread limit exceeded"); - } + if (pThreads.Count >= pThreadsMax) throw new ThreadStateException("Thread limit exceeded"); + Thread = StartThread(true); } Thread.LastActive = DateTime.Now; WorkItem.Thread = Thread; @@ -235,16 +202,13 @@ while (true) { if (Thread.WaitHandle == null) throw new ArgumentNullException("WaitHandle"); if (!Thread.WaitHandle.WaitOne(1000, false)) { - if (pBusyThreads.Count == 0) { - return; - } else { - continue; - } - } + if (pBusyThreads <= 0) return; + continue; + } if (Thread.Abort) break; Thread.Busy = true; - lock (pBusyThreads) pBusyThreads.Add(Thread); + Interlocked.Increment(ref pBusyThreads); try { if (Thread.WorkItem == null) throw new ArgumentNullException("WorkItem"); if (Thread.WorkItem.Callback == null) throw new ArgumentNullException("WorkItem.Callback"); @@ -262,7 +226,7 @@ throw new Exception("Unhandled exception in work item", e.Exception); } } finally { - lock (pBusyThreads) pBusyThreads.Remove(Thread); + Interlocked.Decrement(ref pBusyThreads); } Thread.WorkItem.Thread = null; Thread.WorkItem = null; diff -r 5ce7a138fdba -r 4b78cc5f116b UTF8NoPreamble.cs --- a/UTF8NoPreamble.cs Tue Jan 08 16:38:37 2013 +0100 +++ b/UTF8NoPreamble.cs Sun Jan 13 18:44:17 2013 +0100 @@ -1,5 +1,6 @@ -namespace UCIS { - public class UTF8NoPreamble : System.Text.UTF8Encoding { +using System.Text; +namespace UCIS { + public class UTF8NoPreamble : UTF8Encoding { public UTF8NoPreamble() : base(false) { } } } diff -r 5ce7a138fdba -r 4b78cc5f116b Util/AsyncResultBase.cs --- a/Util/AsyncResultBase.cs Tue Jan 08 16:38:37 2013 +0100 +++ b/Util/AsyncResultBase.cs Sun Jan 13 18:44:17 2013 +0100 @@ -35,7 +35,13 @@ IsCompleted = true; if (WaitEvent != null) WaitEvent.Set(); } - if (Callback != null) SysThreadPool.QueueUserWorkItem(CallCallback); + if (Callback != null) { + if (synchronously) { + Callback(this); + } else { + SysThreadPool.QueueUserWorkItem(CallCallback); + } + } } protected void ThrowError() { diff -r 5ce7a138fdba -r 4b78cc5f116b Util/QueuedPacketStream.cs --- a/Util/QueuedPacketStream.cs Tue Jan 08 16:38:37 2013 +0100 +++ b/Util/QueuedPacketStream.cs Sun Jan 13 18:44:17 2013 +0100 @@ -104,43 +104,26 @@ return ret; } - class AsyncResult : IAsyncResult { - public Object AsyncState { get; private set; } - public WaitHandle AsyncWaitHandle { get { return WaitHandle; } } - public Boolean CompletedSynchronously { get; private set; } - public Boolean IsCompleted { get; private set; } + class AsyncResult : AsyncResultBase { public Boolean IsReadPacket { get; private set; } - public Byte[] Buffer = null; public int BufferOffset = 0; public int BufferLength = 0; - private ManualResetEvent WaitHandle = new ManualResetEvent(false); - private AsyncCallback Callback = null; - private void CallCallback(Object state) { - if (Callback != null) Callback(this); + public void SetCompleted(Boolean synchronously) { + base.SetCompleted(synchronously, null); } - public void SetCompleted(Boolean synchronously) { - CompletedSynchronously = synchronously; - IsCompleted = true; - WaitHandle.Set(); - if (Callback != null) SysThreadPool.QueueUserWorkItem(CallCallback); - } - public AsyncResult(AsyncCallback callback, Object state) { - this.Callback = callback; - this.AsyncState = state; - CompletedSynchronously = false; - IsCompleted = false; + public AsyncResult(AsyncCallback callback, Object state) : base(callback, state) { IsReadPacket = true; } - public AsyncResult(AsyncCallback callback, Object state, Byte[] buffer, int bufferOffset, int bufferLength) - : this(callback, state) { + public AsyncResult(AsyncCallback callback, Object state, Byte[] buffer, int bufferOffset, int bufferLength) : base(callback, state) { this.Buffer = buffer; this.BufferOffset = bufferOffset; this.BufferLength = bufferLength; IsReadPacket = false; } } + private IAsyncResult BeginAsyncReadOperation(AsyncResult ar) { lock (ReceiveQueue) { if (AsyncReceiveOperation != null) throw new InvalidOperationException("Another asynchronous operation is in progress"); diff -r 5ce7a138fdba -r 4b78cc5f116b Windows/ServiceManager.cs --- a/Windows/ServiceManager.cs Tue Jan 08 16:38:37 2013 +0100 +++ b/Windows/ServiceManager.cs Sun Jan 13 18:44:17 2013 +0100 @@ -68,8 +68,7 @@ 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[] { + UInt32 ret = (UInt32)_serviceObject.InvokeMethod("Change", new Object[] { DisplayName, //DisplayName PathName, //PathName 16, //ServiceType (16 = own process)