X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2FSystem%2FSystem.Net%2FEndPointListener.cs;h=09f3197a7a4e844d7302d9a418d4801124bd21f8;hb=4df4b7a47a07d924d7bfcfc53f43bd2319b54266;hp=034ad4076c2164fd0d221755b4e04f3b2f50e26b;hpb=37a947e74ed65d58d14ab37a52ba9ec04465ee79;p=mono.git diff --git a/mcs/class/System/System.Net/EndPointListener.cs b/mcs/class/System/System.Net/EndPointListener.cs index 034ad4076c2..09f3197a7a4 100644 --- a/mcs/class/System/System.Net/EndPointListener.cs +++ b/mcs/class/System/System.Net/EndPointListener.cs @@ -2,9 +2,10 @@ // System.Net.EndPointListener // // Author: -// Gonzalo Paniagua Javier (gonzalo@novell.com) +// Gonzalo Paniagua Javier (gonzalo.mono@gmail.com) // // Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// Copyright (c) 2012 Xamarin, Inc. (http://xamarin.com) // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -26,28 +27,31 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -#if NET_2_0 && SECURITY_DEP +#if SECURITY_DEP + +extern alias MonoSecurity; using System.IO; using System.Net.Sockets; using System.Collections; +using System.Collections.Generic; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Threading; -using Mono.Security.Authenticode; +using MonoSecurity::Mono.Security.Authenticode; namespace System.Net { sealed class EndPointListener { IPEndPoint endpoint; Socket sock; - ReaderWriterLock plock; Hashtable prefixes; // Dictionary ArrayList unhandled; // List unhandled; host = '*' ArrayList all; // List all; host = '+' X509Certificate2 cert; AsymmetricAlgorithm key; bool secure; + Dictionary unregistered; public EndPointListener (IPAddress addr, int port, bool secure) { @@ -65,7 +69,7 @@ namespace System.Net { args.Completed += OnAccept; sock.AcceptAsync (args); prefixes = new Hashtable (); - plock = new ReaderWriterLock (); + unregistered = new Dictionary (); } void LoadCertificateAndKey (IPAddress addr, int port) @@ -76,7 +80,11 @@ namespace System.Net { string path = Path.Combine (dirname, ".mono"); path = Path.Combine (path, "httplistener"); string cert_file = Path.Combine (path, String.Format ("{0}.cer", port)); + if (!File.Exists (cert_file)) + return; string pvk_file = Path.Combine (path, String.Format ("{0}.pvk", port)); + if (!File.Exists (pvk_file)) + return; cert = new X509Certificate2 (cert_file); key = PrivateKey.CreateFromFile (pvk_file).RSA; } catch { @@ -114,20 +122,29 @@ namespace System.Net { return; } HttpConnection conn = new HttpConnection (accepted, epl, epl.secure, epl.cert, epl.key); + lock (epl.unregistered) { + epl.unregistered [conn] = conn; + } conn.BeginReadRequest (); } + internal void RemoveConnection (HttpConnection conn) + { + lock (unregistered) { + unregistered.Remove (conn); + } + } + public bool BindContext (HttpListenerContext context) { HttpListenerRequest req = context.Request; ListenerPrefix prefix; - HttpListener listener = SearchListener (req.UserHostName, req.Url, out prefix); + HttpListener listener = SearchListener (req.Url, out prefix); if (listener == null) return false; context.Listener = listener; context.Connection.Prefix = prefix; - listener.RegisterContext (context); return true; } @@ -136,62 +153,57 @@ namespace System.Net { if (context == null || context.Request == null) return; - HttpListenerRequest req = context.Request; - ListenerPrefix prefix; - HttpListener listener = SearchListener (req.UserHostName, req.Url, out prefix); - if (listener != null) - listener.UnregisterContext (context); + context.Listener.UnregisterContext (context); } - HttpListener SearchListener (string host, Uri uri, out ListenerPrefix prefix) + HttpListener SearchListener (Uri uri, out ListenerPrefix prefix) { prefix = null; if (uri == null) return null; - //TODO: We should use a ReaderWriterLock between this and the add/remove operations. - if (host != null) { - int colon = host.IndexOf (':'); - if (colon >= 0) - host = host.Substring (0, colon); - } - + string host = uri.Host; + int port = uri.Port; string path = HttpUtility.UrlDecode (uri.AbsolutePath); string path_slash = path [path.Length - 1] == '/' ? path : path + "/"; HttpListener best_match = null; int best_length = -1; - try { - plock.AcquireReaderLock (-1); - if (host != null && host != "") { - foreach (ListenerPrefix p in prefixes.Keys) { - string ppath = p.Path; - if (ppath.Length < best_length) - continue; - - if (p.Host == host && (path.StartsWith (ppath) || path_slash.StartsWith (ppath))) { - best_length = ppath.Length; - best_match = (HttpListener) prefixes [p]; - prefix = p; - } - } - if (best_length != -1) - return best_match; - } + if (host != null && host != "") { + Hashtable p_ro = prefixes; + foreach (ListenerPrefix p in p_ro.Keys) { + string ppath = p.Path; + if (ppath.Length < best_length) + continue; - best_match = MatchFromList (host, path, unhandled, out prefix); - if (best_match != null) - return best_match; + if (p.Host != host || p.Port != port) + continue; - best_match = MatchFromList (host, path, all, out prefix); - if (best_match != null) + if (path.StartsWith (ppath) || path_slash.StartsWith (ppath)) { + best_length = ppath.Length; + best_match = (HttpListener) p_ro [p]; + prefix = p; + } + } + if (best_length != -1) return best_match; - } finally { - try { - plock.ReleaseReaderLock (); - } catch {} } + + ArrayList list = unhandled; + best_match = MatchFromList (host, path, list, out prefix); + if (path != path_slash && best_match == null) + best_match = MatchFromList (host, path_slash, list, out prefix); + if (best_match != null) + return best_match; + + list = all; + best_match = MatchFromList (host, path, list, out prefix); + if (path != path_slash && best_match == null) + best_match = MatchFromList (host, path_slash, list, out prefix); + if (best_match != null) + return best_match; + return null; } @@ -224,55 +236,40 @@ namespace System.Net { if (coll == null) return; - try { - plock.AcquireReaderLock (-1); - foreach (ListenerPrefix p in coll) { - if (p.Path == prefix.Path) //TODO: code - throw new HttpListenerException (400, "Prefix already in use."); - } - plock.UpgradeToWriterLock (-1); - coll.Add (prefix); - } finally { - try { - plock.ReleaseReaderLock (); // This releases the writer lock if held. - } catch { } + foreach (ListenerPrefix p in coll) { + if (p.Path == prefix.Path) //TODO: code + throw new HttpListenerException (400, "Prefix already in use."); } + coll.Add (prefix); } - void RemoveSpecial (ArrayList coll, ListenerPrefix prefix) + bool RemoveSpecial (ArrayList coll, ListenerPrefix prefix) { if (coll == null) - return; + return false; - try { - plock.AcquireReaderLock (-1); - int c = coll.Count; - for (int i = 0; i < c; i++) { - ListenerPrefix p = (ListenerPrefix) coll [i]; - if (p.Path == prefix.Path) { - plock.UpgradeToWriterLock (-1); - coll.RemoveAt (i); - CheckIfRemove (); - return; - } + int c = coll.Count; + for (int i = 0; i < c; i++) { + ListenerPrefix p = (ListenerPrefix) coll [i]; + if (p.Path == prefix.Path) { + coll.RemoveAt (i); + return true; } - } finally { - try { - plock.ReleaseReaderLock (); // Releases the writer lock if held - } catch {} } + return false; } - // Writer lock held when calling (could use just reader) void CheckIfRemove () { if (prefixes.Count > 0) return; - if (unhandled != null && unhandled.Count > 0) + ArrayList list = unhandled; + if (list != null && list.Count > 0) return; - if (all != null && all.Count > 0) + list = all; + if (list != null && list.Count > 0) return; EndPointManager.RemoveEndPoint (this, endpoint); @@ -281,68 +278,92 @@ namespace System.Net { public void Close () { sock.Close (); + lock (unregistered) { + // + // Clone the list because RemoveConnection can be called from Close + // + var connections = new List (unregistered.Keys); + + foreach (HttpConnection c in connections) + c.Close (true); + unregistered.Clear (); + } } public void AddPrefix (ListenerPrefix prefix, HttpListener listener) { + ArrayList current; + ArrayList future; if (prefix.Host == "*") { - if (unhandled == null) - unhandled = new ArrayList (); - - prefix.Listener = listener; - AddSpecial (unhandled, prefix); + do { + current = unhandled; + future = (current != null) ? (ArrayList) current.Clone () : new ArrayList (); + prefix.Listener = listener; + AddSpecial (future, prefix); + } while (Interlocked.CompareExchange (ref unhandled, future, current) != current); return; } if (prefix.Host == "+") { - if (all == null) - all = new ArrayList (); - prefix.Listener = listener; - AddSpecial (all, prefix); + do { + current = all; + future = (current != null) ? (ArrayList) current.Clone () : new ArrayList (); + prefix.Listener = listener; + AddSpecial (future, prefix); + } while (Interlocked.CompareExchange (ref all, future, current) != current); return; } - try { - plock.AcquireReaderLock (-1); - if (prefixes.ContainsKey (prefix)) { - HttpListener other = (HttpListener) prefixes [prefix]; + Hashtable prefs, p2; + do { + prefs = prefixes; + if (prefs.ContainsKey (prefix)) { + HttpListener other = (HttpListener) prefs [prefix]; if (other != listener) // TODO: code. throw new HttpListenerException (400, "There's another listener for " + prefix); return; } - plock.AcquireWriterLock (-1); - prefixes [prefix] = listener; - } finally { - try { - plock.ReleaseReaderLock (); - } catch {} - } + p2 = (Hashtable) prefs.Clone (); + p2 [prefix] = listener; + } while (Interlocked.CompareExchange (ref prefixes, p2, prefs) != prefs); } public void RemovePrefix (ListenerPrefix prefix, HttpListener listener) { + ArrayList current; + ArrayList future; if (prefix.Host == "*") { - RemoveSpecial (unhandled, prefix); + do { + current = unhandled; + future = (current != null) ? (ArrayList) current.Clone () : new ArrayList (); + if (!RemoveSpecial (future, prefix)) + break; // Prefix not found + } while (Interlocked.CompareExchange (ref unhandled, future, current) != current); + CheckIfRemove (); return; } if (prefix.Host == "+") { - RemoveSpecial (all, prefix); + do { + current = all; + future = (current != null) ? (ArrayList) current.Clone () : new ArrayList (); + if (!RemoveSpecial (future, prefix)) + break; // Prefix not found + } while (Interlocked.CompareExchange (ref all, future, current) != current); + CheckIfRemove (); return; } - try { - plock.AcquireReaderLock (-1); - if (prefixes.ContainsKey (prefix)) { - plock.UpgradeToWriterLock (-1); - prefixes.Remove (prefix); - CheckIfRemove (); - } - } finally { - try { - plock.ReleaseReaderLock (); - } catch {} - } + Hashtable prefs, p2; + do { + prefs = prefixes; + if (!prefs.ContainsKey (prefix)) + break; + + p2 = (Hashtable) prefs.Clone (); + p2.Remove (prefix); + } while (Interlocked.CompareExchange (ref prefixes, p2, prefs) != prefs); + CheckIfRemove (); } } }