WIP
parent
3cc4f92e40
commit
c4f456f8c5
|
@ -3,10 +3,11 @@ using System.Collections.Generic;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using ln.http.threads;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using ln.http.resources.session;
|
using ln.http.resources.session;
|
||||||
|
using ln.logging;
|
||||||
|
using ln.types.threads;
|
||||||
|
|
||||||
|
|
||||||
namespace ln.http
|
namespace ln.http
|
||||||
|
@ -19,17 +20,21 @@ namespace ln.http
|
||||||
|
|
||||||
public HttpApplication DefaultApplication { get; set; }
|
public HttpApplication DefaultApplication { get; set; }
|
||||||
|
|
||||||
|
public SessionCache SessionCache { get; set; }
|
||||||
|
|
||||||
|
public bool IsRunning => (currentListenerThreads.Count > 0) || (threadPool.NumThreads > 0);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool shutdown = false;
|
bool shutdown = false;
|
||||||
|
|
||||||
Dictionary<IPEndPoint, TcpListener> tcpListeners = new Dictionary<IPEndPoint, TcpListener>();
|
Dictionary<IPEndPoint, TcpListener> tcpListeners = new Dictionary<IPEndPoint, TcpListener>();
|
||||||
Dictionary<Uri, HttpApplication> applications = new Dictionary<Uri, HttpApplication>();
|
Dictionary<Uri, HttpApplication> applications = new Dictionary<Uri, HttpApplication>();
|
||||||
|
|
||||||
|
Dictionary<TcpListener, Thread> currentListenerThreads = new Dictionary<TcpListener, Thread>();
|
||||||
|
|
||||||
Pool threadPool = new Pool();
|
Pool threadPool = new Pool();
|
||||||
|
|
||||||
public SessionCache SessionCache { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public HTTPServer()
|
public HTTPServer()
|
||||||
{
|
{
|
||||||
SessionCache = new SessionCache();
|
SessionCache = new SessionCache();
|
||||||
|
@ -64,7 +69,9 @@ namespace ln.http
|
||||||
foreach (TcpListener tcpListener in this.tcpListeners.Values)
|
foreach (TcpListener tcpListener in this.tcpListeners.Values)
|
||||||
{
|
{
|
||||||
tcpListener.Start(backlog);
|
tcpListener.Start(backlog);
|
||||||
this.threadPool.Enqueue(() => AcceptConnections(tcpListener));
|
|
||||||
|
Thread listenerThread = new Thread(() => AcceptConnections(tcpListener));
|
||||||
|
listenerThread.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -74,20 +81,49 @@ namespace ln.http
|
||||||
lock (this)
|
lock (this)
|
||||||
{
|
{
|
||||||
this.shutdown = true;
|
this.shutdown = true;
|
||||||
|
|
||||||
|
foreach (TcpListener tcpListener in tcpListeners.Values)
|
||||||
|
{
|
||||||
|
tcpListener.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
threadPool.NumThreads = 0;
|
||||||
|
|
||||||
|
while (IsRunning)
|
||||||
|
{
|
||||||
|
Thread.Sleep(50);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AcceptConnections(TcpListener tcpListener)
|
private void AcceptConnections(TcpListener tcpListener)
|
||||||
{
|
{
|
||||||
while (true)
|
lock (this)
|
||||||
{
|
{
|
||||||
lock(this)
|
if (currentListenerThreads.ContainsKey(tcpListener))
|
||||||
{
|
{
|
||||||
if (this.shutdown) {
|
throw new Exception("HTTP listener thread already running");
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
AcceptConnection(tcpListener);
|
currentListenerThreads.Add(tcpListener, Thread.CurrentThread);
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
|
||||||
|
while (!this.shutdown)
|
||||||
|
{
|
||||||
|
AcceptConnection(tcpListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e)
|
||||||
|
{
|
||||||
|
Logging.Log(LogLevel.ERROR, "HTTPServer: Listener thread caught exception {0}",e);
|
||||||
|
Logging.Log(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
lock (this)
|
||||||
|
{
|
||||||
|
currentListenerThreads.Remove(tcpListener);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,6 @@
|
||||||
<Compile Include="exceptions\HttpException.cs" />
|
<Compile Include="exceptions\HttpException.cs" />
|
||||||
<Compile Include="exceptions\IllegalRequestException.cs" />
|
<Compile Include="exceptions\IllegalRequestException.cs" />
|
||||||
<Compile Include="exceptions\ResourceNotFoundException.cs" />
|
<Compile Include="exceptions\ResourceNotFoundException.cs" />
|
||||||
<Compile Include="threads\Pool.cs" />
|
|
||||||
<Compile Include="HTTPServer.cs" />
|
<Compile Include="HTTPServer.cs" />
|
||||||
<Compile Include="HttpReader.cs" />
|
<Compile Include="HttpReader.cs" />
|
||||||
<Compile Include="HttpRequest.cs" />
|
<Compile Include="HttpRequest.cs" />
|
||||||
|
@ -50,8 +49,17 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="exceptions\" />
|
<Folder Include="exceptions\" />
|
||||||
<Folder Include="threads\" />
|
|
||||||
<Folder Include="session\" />
|
<Folder Include="session\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\ln.logging\ln.logging.csproj">
|
||||||
|
<Project>{D471A566-9FB6-41B2-A777-3C32874ECD0E}</Project>
|
||||||
|
<Name>ln.logging</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\ln.types\ln.types.csproj">
|
||||||
|
<Project>{8D9AB9A5-E513-4BA7-A450-534F6456BF28}</Project>
|
||||||
|
<Name>ln.types</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||||
</Project>
|
</Project>
|
|
@ -1,82 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
namespace ln.http.threads
|
|
||||||
{
|
|
||||||
public delegate void JobDelegate();
|
|
||||||
|
|
||||||
public class Pool
|
|
||||||
{
|
|
||||||
public int Timeout { get; set; } = 15000;
|
|
||||||
|
|
||||||
ISet<Thread> threads = new HashSet<Thread>();
|
|
||||||
Queue<JobDelegate> queuedJobs = new Queue<JobDelegate>();
|
|
||||||
HashSet<Thread> idleThreads = new HashSet<Thread>();
|
|
||||||
|
|
||||||
public Pool()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AllocateThread()
|
|
||||||
{
|
|
||||||
Thread thread = new Thread(pool_thread);
|
|
||||||
thread.Start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Enqueue(JobDelegate job)
|
|
||||||
{
|
|
||||||
lock (this)
|
|
||||||
{
|
|
||||||
queuedJobs.Enqueue(job);
|
|
||||||
|
|
||||||
if (idleThreads.Count == 0)
|
|
||||||
{
|
|
||||||
AllocateThread();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Monitor.Pulse(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void pool_thread()
|
|
||||||
{
|
|
||||||
Thread me = Thread.CurrentThread;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
JobDelegate job = null;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
lock (this)
|
|
||||||
{
|
|
||||||
if (queuedJobs.Count == 0)
|
|
||||||
{
|
|
||||||
idleThreads.Add(me);
|
|
||||||
bool s = Monitor.Wait(this, Timeout);
|
|
||||||
idleThreads.Remove(me);
|
|
||||||
if (!s)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
job = queuedJobs.Dequeue();
|
|
||||||
}
|
|
||||||
|
|
||||||
job();
|
|
||||||
|
|
||||||
} while (true);
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Console.WriteLine("Exception in worker thread: {0}", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
lock (this)
|
|
||||||
{
|
|
||||||
threads.Remove(me);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue