// 
 | 
// ListenerAsyncResult.cs 
 | 
//    Copied from System.Net.ListenerAsyncResult 
 | 
// 
 | 
// Authors: 
 | 
//    Gonzalo Paniagua Javier (gonzalo@ximian.com) 
 | 
// 
 | 
// Copyright (c) 2005 Ximian, Inc (http://www.ximian.com) 
 | 
// 
 | 
// Permission is hereby granted, free of charge, to any person obtaining 
 | 
// a copy of this software and associated documentation files (the 
 | 
// "Software"), to deal in the Software without restriction, including 
 | 
// without limitation the rights to use, copy, modify, merge, publish, 
 | 
// distribute, sublicense, and/or sell copies of the Software, and to 
 | 
// permit persons to whom the Software is furnished to do so, subject to 
 | 
// the following conditions: 
 | 
//  
 | 
// The above copyright notice and this permission notice shall be 
 | 
// included in all copies or substantial portions of the Software. 
 | 
//  
 | 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
 | 
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
 | 
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
 | 
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 
 | 
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 
 | 
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
 | 
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
 | 
// 
 | 
  
 | 
using System; 
 | 
using System.Net; 
 | 
using System.Threading; 
 | 
  
 | 
namespace WebSocketSharp.Net { 
 | 
  
 | 
    class ListenerAsyncResult : IAsyncResult 
 | 
    { 
 | 
        static WaitCallback InvokeCB = new WaitCallback (InvokeCallback); 
 | 
  
 | 
        AsyncCallback       cb; 
 | 
        bool                completed; 
 | 
        HttpListenerContext context; 
 | 
        Exception           exception; 
 | 
        ListenerAsyncResult forward; 
 | 
        ManualResetEvent    handle; 
 | 
        object              locker; 
 | 
        object              state; 
 | 
        bool                synch; 
 | 
  
 | 
        internal bool EndCalled; 
 | 
        internal bool InGet; 
 | 
  
 | 
        public ListenerAsyncResult (AsyncCallback cb, object state) 
 | 
        { 
 | 
            this.cb     = cb; 
 | 
            this.state  = state; 
 | 
            this.locker = new object(); 
 | 
        } 
 | 
  
 | 
        public object AsyncState { 
 | 
            get { 
 | 
                if (forward != null) 
 | 
                    return forward.AsyncState; 
 | 
                return state; 
 | 
            } 
 | 
        } 
 | 
  
 | 
        public WaitHandle AsyncWaitHandle { 
 | 
            get { 
 | 
                if (forward != null) 
 | 
                    return forward.AsyncWaitHandle; 
 | 
  
 | 
                lock (locker) { 
 | 
                    if (handle == null) 
 | 
                        handle = new ManualResetEvent (completed); 
 | 
                } 
 | 
                 
 | 
                return handle; 
 | 
            } 
 | 
        } 
 | 
  
 | 
        public bool CompletedSynchronously { 
 | 
            get { 
 | 
                if (forward != null) 
 | 
                    return forward.CompletedSynchronously; 
 | 
                return synch; 
 | 
            } 
 | 
  
 | 
        } 
 | 
  
 | 
        public bool IsCompleted { 
 | 
            get { 
 | 
                if (forward != null) 
 | 
                    return forward.IsCompleted; 
 | 
  
 | 
                lock (locker) { 
 | 
                    return completed; 
 | 
                } 
 | 
            } 
 | 
        } 
 | 
  
 | 
        static void InvokeCallback (object o) 
 | 
        { 
 | 
            ListenerAsyncResult ares = (ListenerAsyncResult) o; 
 | 
            if (ares.forward != null) { 
 | 
                InvokeCallback (ares.forward); 
 | 
                return; 
 | 
            } 
 | 
            try { 
 | 
                ares.cb (ares); 
 | 
            } catch { 
 | 
            } 
 | 
        } 
 | 
  
 | 
        internal void Complete (Exception exc) 
 | 
        { 
 | 
            if (forward != null) { 
 | 
                forward.Complete (exc); 
 | 
                return; 
 | 
            } 
 | 
            exception = exc; 
 | 
            if (InGet && (exc is ObjectDisposedException)) 
 | 
                exception = new HttpListenerException (500, "Listener closed"); 
 | 
            lock (locker) { 
 | 
                completed = true; 
 | 
                if (handle != null) 
 | 
                    handle.Set (); 
 | 
  
 | 
                if (cb != null) 
 | 
                    ThreadPool.UnsafeQueueUserWorkItem (InvokeCB, this); 
 | 
            } 
 | 
        } 
 | 
  
 | 
        internal void Complete (HttpListenerContext context) 
 | 
        { 
 | 
            Complete (context, false); 
 | 
        } 
 | 
  
 | 
        internal void Complete (HttpListenerContext context, bool synch) 
 | 
        { 
 | 
            if (forward != null) { 
 | 
                forward.Complete (context, synch); 
 | 
                return; 
 | 
            } 
 | 
            this.synch = synch; 
 | 
            this.context = context; 
 | 
            lock (locker) { 
 | 
                AuthenticationSchemes schemes = context.Listener.SelectAuthenticationScheme (context); 
 | 
                if ((schemes == AuthenticationSchemes.Basic || context.Listener.AuthenticationSchemes == AuthenticationSchemes.Negotiate) && context.Request.Headers ["Authorization"] == null) { 
 | 
                    context.Response.StatusCode = 401; 
 | 
                    context.Response.Headers ["WWW-Authenticate"] = schemes + " realm=\"" + context.Listener.Realm + "\""; 
 | 
                    context.Response.OutputStream.Close (); 
 | 
                    IAsyncResult ares = context.Listener.BeginGetContext (cb, state); 
 | 
                    this.forward = (ListenerAsyncResult) ares; 
 | 
                    lock (forward.locker) { 
 | 
                        if (handle != null) 
 | 
                            forward.handle = handle; 
 | 
                    } 
 | 
                    ListenerAsyncResult next = forward; 
 | 
                    for (int i = 0; next.forward != null; i++) { 
 | 
                        if (i > 20) 
 | 
                            Complete (new HttpListenerException (400, "Too many authentication errors")); 
 | 
                        next = next.forward; 
 | 
                    } 
 | 
                } else { 
 | 
                    completed = true; 
 | 
                    if (handle != null) 
 | 
                        handle.Set (); 
 | 
  
 | 
                    if (cb != null) 
 | 
                        ThreadPool.UnsafeQueueUserWorkItem (InvokeCB, this); 
 | 
                } 
 | 
            } 
 | 
        } 
 | 
  
 | 
        internal HttpListenerContext GetContext () 
 | 
        { 
 | 
            if (forward != null) 
 | 
                return forward.GetContext (); 
 | 
            if (exception != null) 
 | 
                throw exception; 
 | 
  
 | 
            return context; 
 | 
        } 
 | 
    } 
 | 
} 
 |