/Network/HTTP/HTTPServer.cs |
@@ -0,0 +1,125 @@ |
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3 // |
// Please see: http://www.gnu.org/licenses/gpl.html for legal details, // |
// rights of fair usage, the disclaimer and warranty conditions. // |
/////////////////////////////////////////////////////////////////////////// |
|
using System; |
using System.Collections.Generic; |
using System.Net; |
using System.Threading; |
|
namespace wasSharpNET.Network.HTTP |
{ |
public abstract class HTTPServer |
{ |
private int activeRequests; |
private readonly HttpListener HTTPListener = new HttpListener(); |
private int processedRequests; |
|
private readonly ManualResetEvent stopEvent = new ManualResetEvent(false); |
|
public HashSet<string> Prefixes { get; set; } = new HashSet<string>(); |
|
public AuthenticationSchemes AuthenticationSchemes { get; set; } = AuthenticationSchemes.None; |
|
public bool IsRunning => HTTPListener.IsListening; |
|
public bool Start() |
{ |
foreach (var prefix in Prefixes) |
{ |
if (!HTTPListener.Prefixes.Contains(prefix)) |
HTTPListener.Prefixes.Add(prefix); |
} |
|
// Set up HTTP listener. |
HTTPListener.AuthenticationSchemes = AuthenticationSchemes; |
|
// Do not start the HTTP server if it is already running. |
if (HTTPListener.IsListening) |
return false; |
|
// Do not bomb if the client disconnects. |
HTTPListener.IgnoreWriteExceptions = true; |
HTTPListener.Start(); |
var state = new HTTPServerCallbackState(HTTPListener); |
ThreadPool.QueueUserWorkItem(Listen, state); |
return true; |
} |
|
public bool Stop() |
{ |
return stopEvent.Set(); |
} |
|
private void Listen(object state) |
{ |
var callbackState = (HTTPServerCallbackState) state; |
|
while (callbackState.Listener.IsListening) |
{ |
callbackState.Listener.BeginGetContext(ContextCallback, callbackState); |
var n = WaitHandle.WaitAny(new WaitHandle[] {callbackState.ContextRetrieved, stopEvent}); |
|
if (n.Equals(1)) |
{ |
callbackState.Listener.Stop(); |
break; |
} |
} |
} |
|
public abstract void ProcessHTTPContext(HttpListenerContext context); |
|
private void ContextCallback(IAsyncResult ar) |
{ |
var callbackState = (HTTPServerCallbackState) ar.AsyncState; |
HttpListenerContext httpContext = null; |
|
Interlocked.Increment(ref processedRequests); |
Interlocked.Increment(ref activeRequests); |
|
try |
{ |
httpContext = callbackState.Listener.EndGetContext(ar); |
} |
catch (Exception) |
{ |
Interlocked.Decrement(ref activeRequests); |
return; |
} |
finally |
{ |
callbackState.ContextRetrieved.Set(); |
} |
|
if (httpContext == null) |
return; |
|
try |
{ |
ProcessHTTPContext(httpContext); |
} |
finally |
{ |
Interlocked.Decrement(ref activeRequests); |
} |
} |
|
private class HTTPServerCallbackState |
{ |
public HTTPServerCallbackState(HttpListener listener) |
{ |
if (listener == null) |
throw new ArgumentNullException("listener"); |
Listener = listener; |
ContextRetrieved = new AutoResetEvent(false); |
} |
|
public HttpListener Listener { get; } |
|
public AutoResetEvent ContextRetrieved { get; } |
} |
} |
} |
/Network/TCP/Utilities.cs |
@@ -0,0 +1,40 @@ |
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3 // |
// Please see: http://www.gnu.org/licenses/gpl.html for legal details, // |
// rights of fair usage, the disclaimer and warranty conditions. // |
/////////////////////////////////////////////////////////////////////////// |
|
using System.Net; |
using System.Net.Sockets; |
|
namespace wasSharpNET.Network.TCP |
{ |
public static class Utilities |
{ |
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2016 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Try to find an unused port. |
/// </summary> |
/// <param name="address">the address associated with the port</param> |
/// <param name="port">an integer to hold the port if found</param> |
/// <returns>true if an unused port could be found</returns> |
public static bool TryGetUnusedPort(IPAddress address, out int port) |
{ |
try |
{ |
var l = new TcpListener(address, 0); |
l.Start(); |
port = ((IPEndPoint) l.LocalEndpoint).Port; |
l.Stop(); |
return true; |
} |
catch |
{ |
port = default(int); |
return false; |
} |
} |
} |
} |