Refactored EndPointListener.cs

This commit is contained in:
sta 2014-10-16 14:44:09 +09:00
parent 3dee61f5f8
commit 292a904ad7

View File

@ -51,41 +51,52 @@ namespace WebSocketSharp.Net
{
internal sealed class EndPointListener
{
#region Private Static Fields
private static readonly string _defaultCertFolderPath =
Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData);
#endregion
#region Private Fields
private List<ListenerPrefix> _all; // host = '+'
private List<ListenerPrefix> _all; // host == '+'
private X509Certificate2 _cert;
private static readonly string _defaultCertFolderPath;
private IPEndPoint _endpoint;
private Dictionary<ListenerPrefix, HttpListener> _prefixes;
private bool _secure;
private Socket _socket;
private List<ListenerPrefix> _unhandled; // host = '*'
private List<ListenerPrefix> _unhandled; // host == '*'
private Dictionary<HttpConnection, HttpConnection> _unregistered;
private object _unregisteredSync;
#endregion
#region Static Constructor
static EndPointListener ()
{
_defaultCertFolderPath =
Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData);
}
#endregion
#region Public Constructors
public EndPointListener (
IPAddress address, int port, bool secure, string certFolderPath, X509Certificate2 defaultCert)
IPAddress address,
int port,
bool secure,
string certificateFolderPath,
X509Certificate2 defaultCertificate)
{
if (secure) {
_secure = secure;
_cert = getCertificate (port, certFolderPath, defaultCert);
_cert = getCertificate (port, certificateFolderPath, defaultCertificate);
if (_cert == null)
throw new ArgumentException ("No server certificate found.");
throw new ArgumentException ("No server certificate could be found.");
}
_endpoint = new IPEndPoint (address, port);
_prefixes = new Dictionary<ListenerPrefix, HttpListener> ();
_unregistered = new Dictionary<HttpConnection, HttpConnection> ();
_unregisteredSync = ((ICollection) _unregistered).SyncRoot;
_socket = new Socket (address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
_socket.Bind (_endpoint);
@ -124,8 +135,8 @@ namespace WebSocketSharp.Net
var path = prefix.Path;
foreach (var pref in prefixes)
if (pref.Path == path) // TODO: Code?
throw new HttpListenerException (400, "Prefix already in use.");
if (pref.Path == path)
throw new HttpListenerException (400, "The prefix is already in use."); // TODO: Code?
prefixes.Add (prefix);
}
@ -146,9 +157,9 @@ namespace WebSocketSharp.Net
private static RSACryptoServiceProvider createRSAFromFile (string filename)
{
byte [] pvk = null;
byte[] pvk = null;
using (var fs = File.Open (filename, FileMode.Open, FileAccess.Read, FileShare.Read)) {
pvk = new byte [fs.Length];
pvk = new byte[fs.Length];
fs.Read (pvk, 0, pvk.Length);
}
@ -159,14 +170,14 @@ namespace WebSocketSharp.Net
}
private static X509Certificate2 getCertificate (
int port, string certFolderPath, X509Certificate2 defaultCert)
int port, string certificateFolderPath, X509Certificate2 defaultCertificate)
{
if (certFolderPath == null || certFolderPath.Length == 0)
certFolderPath = _defaultCertFolderPath;
if (certificateFolderPath == null || certificateFolderPath.Length == 0)
certificateFolderPath = _defaultCertFolderPath;
try {
var cer = Path.Combine (certFolderPath, String.Format ("{0}.cer", port));
var key = Path.Combine (certFolderPath, String.Format ("{0}.key", port));
var cer = Path.Combine (certificateFolderPath, String.Format ("{0}.cer", port));
var key = Path.Combine (certificateFolderPath, String.Format ("{0}.key", port));
if (File.Exists (cer) && File.Exists (key)) {
var cert = new X509Certificate2 (cer);
cert.PrivateKey = createRSAFromFile (key);
@ -177,7 +188,7 @@ namespace WebSocketSharp.Net
catch {
}
return defaultCert;
return defaultCertificate;
}
private static HttpListener matchFromList (
@ -188,14 +199,14 @@ namespace WebSocketSharp.Net
return null;
HttpListener bestMatch = null;
var bestLength = -1;
var bestLen = -1;
foreach (var pref in list) {
var ppath = pref.Path;
if (ppath.Length < bestLength)
if (ppath.Length < bestLen)
continue;
if (path.StartsWith (ppath)) {
bestLength = ppath.Length;
bestLen = ppath.Length;
bestMatch = pref.Listener;
prefix = pref;
}
@ -207,7 +218,7 @@ namespace WebSocketSharp.Net
private static void onAccept (object sender, EventArgs e)
{
var args = (SocketAsyncEventArgs) e;
var listener = (EndPointListener) args.UserToken;
var epl = (EndPointListener) args.UserToken;
Socket accepted = null;
if (args.SocketError == SocketError.Success) {
accepted = args.AcceptSocket;
@ -215,7 +226,7 @@ namespace WebSocketSharp.Net
}
try {
listener._socket.AcceptAsync (args);
epl._socket.AcceptAsync (args);
}
catch {
if (accepted != null)
@ -229,9 +240,9 @@ namespace WebSocketSharp.Net
HttpConnection conn = null;
try {
conn = new HttpConnection (accepted, listener);
lock (((ICollection) listener._unregistered).SyncRoot)
listener._unregistered [conn] = conn;
conn = new HttpConnection (accepted, epl);
lock (epl._unregisteredSync)
epl._unregistered[conn] = conn;
conn.BeginReadRequest ();
}
@ -251,9 +262,9 @@ namespace WebSocketSharp.Net
return false;
var path = prefix.Path;
var count = prefixes.Count;
for (int i = 0; i < count; i++) {
if (prefixes [i].Path == path) {
var cnt = prefixes.Count;
for (var i = 0; i < cnt; i++) {
if (prefixes[i].Path == path) {
prefixes.RemoveAt (i);
return true;
}
@ -271,27 +282,27 @@ namespace WebSocketSharp.Net
var host = uri.Host;
var port = uri.Port;
var path = HttpUtility.UrlDecode (uri.AbsolutePath);
var pathSlash = path [path.Length - 1] == '/' ? path : path + "/";
var pathSlash = path[path.Length - 1] == '/' ? path : path + "/";
HttpListener bestMatch = null;
var bestLength = -1;
var bestLen = -1;
if (host != null && host.Length > 0) {
foreach (var pref in _prefixes.Keys) {
var ppath = pref.Path;
if (ppath.Length < bestLength)
if (ppath.Length < bestLen)
continue;
if (pref.Host != host || pref.Port != port)
continue;
if (path.StartsWith (ppath) || pathSlash.StartsWith (ppath)) {
bestLength = ppath.Length;
bestMatch = _prefixes [pref];
bestLen = ppath.Length;
bestMatch = _prefixes[pref];
prefix = pref;
}
}
if (bestLength != -1)
if (bestLen != -1)
return bestMatch;
}
@ -318,20 +329,20 @@ namespace WebSocketSharp.Net
#region Internal Methods
internal static bool CertificateExists (int port, string certFolderPath)
internal static bool CertificateExists (int port, string certificateFolderPath)
{
if (certFolderPath == null || certFolderPath.Length == 0)
certFolderPath = _defaultCertFolderPath;
if (certificateFolderPath == null || certificateFolderPath.Length == 0)
certificateFolderPath = _defaultCertFolderPath;
var cer = Path.Combine (certFolderPath, String.Format ("{0}.cer", port));
var key = Path.Combine (certFolderPath, String.Format ("{0}.key", port));
var cer = Path.Combine (certificateFolderPath, String.Format ("{0}.cer", port));
var key = Path.Combine (certificateFolderPath, String.Format ("{0}.key", port));
return File.Exists (cer) && File.Exists (key);
}
internal void RemoveConnection (HttpConnection connection)
{
lock (((ICollection) _unregistered).SyncRoot)
lock (_unregisteredSync)
_unregistered.Remove (connection);
}
@ -339,7 +350,7 @@ namespace WebSocketSharp.Net
#region Public Methods
public void AddPrefix (ListenerPrefix prefix, HttpListener listener)
public void AddPrefix (ListenerPrefix prefix, HttpListener httpListener)
{
List<ListenerPrefix> current, future;
if (prefix.Host == "*") {
@ -349,7 +360,7 @@ namespace WebSocketSharp.Net
? new List<ListenerPrefix> (current)
: new List<ListenerPrefix> ();
prefix.Listener = listener;
prefix.Listener = httpListener;
addSpecial (future, prefix);
}
while (Interlocked.CompareExchange (ref _unhandled, future, current) != current);
@ -364,7 +375,7 @@ namespace WebSocketSharp.Net
? new List<ListenerPrefix> (current)
: new List<ListenerPrefix> ();
prefix.Listener = listener;
prefix.Listener = httpListener;
addSpecial (future, prefix);
}
while (Interlocked.CompareExchange (ref _all, future, current) != current);
@ -376,28 +387,29 @@ namespace WebSocketSharp.Net
do {
prefs = _prefixes;
if (prefs.ContainsKey (prefix)) {
var other = prefs [prefix];
if (other != listener) // TODO: Code?
throw new HttpListenerException (400, "There's another listener for " + prefix);
var other = prefs[prefix];
if (other != httpListener)
throw new HttpListenerException (
400, String.Format ("There's another listener for {0}.", prefix)); // TODO: Code?
return;
}
prefs2 = new Dictionary<ListenerPrefix, HttpListener> (prefs);
prefs2 [prefix] = listener;
prefs2[prefix] = httpListener;
}
while (Interlocked.CompareExchange (ref _prefixes, prefs2, prefs) != prefs);
}
public bool BindContext (HttpListenerContext context)
{
ListenerPrefix prefix;
var listener = searchListener (context.Request.Url, out prefix);
if (listener == null)
ListenerPrefix pref;
var httpl = searchListener (context.Request.Url, out pref);
if (httpl == null)
return false;
context.Listener = listener;
context.Connection.Prefix = prefix;
context.Listener = httpl;
context.Connection.Prefix = pref;
return true;
}
@ -406,7 +418,7 @@ namespace WebSocketSharp.Net
{
_socket.Close ();
lock (((ICollection) _unregistered).SyncRoot) {
lock (_unregisteredSync) {
var conns = new List<HttpConnection> (_unregistered.Keys);
_unregistered.Clear ();
foreach (var conn in conns)
@ -416,7 +428,7 @@ namespace WebSocketSharp.Net
}
}
public void RemovePrefix (ListenerPrefix prefix, HttpListener listener)
public void RemovePrefix (ListenerPrefix prefix, HttpListener httpListener)
{
List<ListenerPrefix> current, future;
if (prefix.Host == "*") {