Peer.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / ndp / fx / src / SystemNet / Net / PeerToPeer / Collaboration / Peer.cs / 2 / Peer.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

namespace System.Net.PeerToPeer.Collaboration 
{ 
    using System;
    using System.Collections; 
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Text;
    using System.Runtime.InteropServices; 
    using System.Net.Sockets;
    using System.Net.Mail; 
    using System.ComponentModel; 
    using System.Threading;
    using System.Diagnostics; 
    using System.Runtime.Serialization;
    using System.Security.Permissions;
    using System.IO;
 
    /// 
    /// This is the object changed event args class we give back when 
    /// we have have an object changed event fired by native 
    /// 
    public class ObjectChangedEventArgs : EventArgs 
    {
        private PeerEndPoint m_peerEndPoint;
        private PeerContact m_peerContact;
        private PeerChangeType m_peerChangeType; 
        private PeerObject m_peerObject;
 
        internal ObjectChangedEventArgs(PeerEndPoint peerEndPoint, PeerContact peerContact, 
                                        PeerChangeType peerChangeType, PeerObject peerObject)
        { 
            m_peerEndPoint = peerEndPoint;
            m_peerContact = peerContact;
            m_peerChangeType = peerChangeType;
            m_peerObject = peerObject; 
        }
 
        public PeerEndPoint PeerEndPoint 
        {
            get 
            {
                return m_peerEndPoint;
            }
        } 

        public PeerContact PeerContact 
        { 
            get
            { 
                return m_peerContact;
            }
        }
 
        public PeerChangeType PeerChangeType
        { 
            get 
            {
                return m_peerChangeType; 
            }
        }

        public PeerObject PeerObject 
        {
            get 
            { 
                return m_peerObject;
            } 
        }
    }

    ///  
    /// This is the presence changed event args class we give back when
    /// we have have presence changed event fired by native 
    ///  
    public class PresenceChangedEventArgs : EventArgs
    { 
        private PeerEndPoint m_peerEndPoint;
        private PeerContact m_peerContact;
        private PeerChangeType m_peerChangeType;
        private PeerPresenceInfo m_peerPresenceInfo; 

        internal PresenceChangedEventArgs(PeerEndPoint peerEndPoint, PeerContact peerContact, 
                                        PeerChangeType peerChangeType, PeerPresenceInfo peerPresenceInfo) 
        {
            m_peerEndPoint = peerEndPoint; 
            m_peerContact = peerContact;
            m_peerChangeType = peerChangeType;
            m_peerPresenceInfo = peerPresenceInfo;
        } 

        public PeerEndPoint PeerEndPoint 
        { 
            get
            { 
                return m_peerEndPoint;
            }
        }
 
        public PeerContact PeerContact
        { 
            get 
            {
                return m_peerContact; 
            }
        }

        public PeerChangeType PeerChangeType 
        {
            get 
            { 
                return m_peerChangeType;
            } 
        }

        public PeerPresenceInfo PeerPresenceInfo
        { 
            get
            { 
                return m_peerPresenceInfo; 
            }
        } 
    }

    /// 
    /// This is the event args class we give back when 
    /// we have completed the subscribeasync call
    ///  
    public class SubscribeCompletedEventArgs : AsyncCompletedEventArgs 
    {
        private PeerNearMe m_peerNearMe; 
        private PeerContact m_peerContact;

        internal SubscribeCompletedEventArgs(PeerNearMe peerNearMe,
                                        PeerContact peerContact, 
                                        Exception error,
                                        bool cancelled, 
                                        object userToken) 
            : base(error, cancelled, userToken)
        { 
            m_peerNearMe = peerNearMe;
            m_peerContact = peerContact;
        }
 
        public PeerNearMe PeerNearMe
        { 
            get 
            {
                return m_peerNearMe; 
            }
        }

        public PeerContact PeerContact 
        {
            get 
            { 
                return m_peerContact;
            } 
        }
    }

    ///  
    /// This is the event args class we give back when
    /// we have completed the refreshendpoint async call 
    ///  
    public class RefreshDataCompletedEventArgs : AsyncCompletedEventArgs
    { 
        private PeerEndPoint m_peerEndPoint;
        internal RefreshDataCompletedEventArgs(PeerEndPoint peerEndPoint,
                                                        Exception error,
                                                        bool cancelled, 
                                                        object userToken)
            : base(error, cancelled, userToken) 
        { 
            m_peerEndPoint = peerEndPoint;
        } 

        public PeerEndPoint PeerEndPoint
        {
            get 
            {
                return m_peerEndPoint; 
            } 
        }
    } 

    /// 
    /// This is the event args class we give back when
    /// we have completed the inviteasync call 
    /// 
    public class InviteCompletedEventArgs : AsyncCompletedEventArgs 
    { 
        private PeerInvitationResponse m_peerInvResponse;
        internal InviteCompletedEventArgs(PeerInvitationResponse peerInvResponse, 
                                                        Exception error,
                                                        bool cancelled,
                                                        object userToken)
            : base(error, cancelled, userToken) 
        {
            m_peerInvResponse = peerInvResponse; 
        } 

        public PeerInvitationResponse InviteResponse 
        {
            get
            {
                return m_peerInvResponse; 
            }
        } 
    } 

    ///  
    /// Has the common interface for PeerNearMe and PeerContact which derive from it
    /// 
    [Serializable]
    public abstract class Peer : IDisposable, IEquatable, ISerializable 
    {
        private PeerEndPointCollection m_peerEndPoints = new PeerEndPointCollection(); 
        private ISynchronizeInvoke m_synchronizingObject; 

        public virtual PeerEndPointCollection PeerEndPoints 
        {
            get {
                if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
 
                return m_peerEndPoints;
            } 
        } 

        public bool IsOnline 
        {
            get{
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Get Isonline called.");
                if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName); 

                bool isOnline = false; 
                PeerPresenceInfo presenceInfo; 

                foreach (PeerEndPoint peerEndPoint in PeerEndPoints){ 
                    presenceInfo = null;

                    try{
                        presenceInfo = GetPresenceInfo(peerEndPoint); 
                    }
                    catch (Exception e){ 
                        Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "Exception thrown {0}", e.Message); 
                    }
                    if ((presenceInfo != null) && (presenceInfo.PresenceStatus == PeerPresenceStatus.Online)){ 
                        isOnline = true;
                        break;
                    }
                } 
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Leaving Isonline called with {0}.", isOnline);
                return isOnline; 
            } 
        }
 
        /// 
        /// Gets and set the object used to marshall event handlers calls for stand alone
        /// events
        ///  
        [Browsable(false), DefaultValue(null), Description(SR.SynchronizingObject)]
        public ISynchronizeInvoke SynchronizingObject 
        { 
            get
            { 
                if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
                return m_synchronizingObject;
            }
            set 
            {
                if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName); 
                m_synchronizingObject = value; 
            }
        } 

        static internal Guid CurrentApplicationGuid
        {
            //  
            // 
            //  
            //  
            [System.Security.SecurityCritical]
            get{ 
                Guid guid = Guid.Empty;

                //
                // Get path and args of app 
                //
                string path = Path.Combine( Environment.CurrentDirectory, Process.GetCurrentProcess().ProcessName + ".exe"); 
                string arguments = null; 
                string[] argsArray = Environment.GetCommandLineArgs();
                int length = argsArray.Length; 
                if (length > 1){
                    StringBuilder argsBuilder = new StringBuilder();
                    for (int i = 1; i < length; ++i){
                        argsBuilder.Append(argsArray[i]); 
                        if (i != (length - 1)) argsBuilder.Append(' ');
                    } 
 
                    arguments = argsBuilder.ToString();
                } 

                //
                // Find a matching registered application and return its guid
                // 
                PeerApplicationCollection peerApplications = PeerCollaboration.GetLocalRegisteredApplications();
 
                foreach (PeerApplication peerApplication in peerApplications){ 
                    if ((peerApplication.CommandLineArgs == arguments) &&
                        (peerApplication.Path == path)) 
                        return peerApplication.Id;
                }
                return guid;
            } 
        }
 
        internal Peer(){ 
            OnInviteCompletedDelegate = new SendOrPostCallback(InviteCompletedWaitCallback);
        } 

        /// 
        /// Constructor to enable serialization
        ///  
        protected Peer(SerializationInfo serializationInfo, StreamingContext streamingContext):this()
        { 
            m_peerEndPoints = (PeerEndPointCollection)serializationInfo.GetValue("_PeerEndPoints", typeof(PeerEndPointCollection)); 
        }
 
        //
        // Gets the presence info from collab for a specific endpoint
        //
        //  
        // 
        //  
        //  
        // 
        //  
        // 
        // 
        // 
        //  
        // 
        [System.Security.SecurityCritical] 
        public PeerPresenceInfo GetPresenceInfo(PeerEndPoint peerEndPoint) 
        {
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "GetPresenceInfo()called."); 
            if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
            PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();

            if (peerEndPoint == null) 
                throw new ArgumentNullException("peerEndPoint");
 
            if (peerEndPoint.EndPoint == null) 
                throw new ArgumentException(SR.GetString(SR.Collab_NoEndPointInPeerEndPoint));
 
            if (Logging.P2PTraceSource.Switch.ShouldTrace(TraceEventType.Information)){
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Getting presence for the following endpoint.");
                peerEndPoint.TracePeerEndPoint();
            } 

            SafeCollabData presenceInfo = null; 
            PeerPresenceInfo peerPresenceInfo = null; 
            int errorCode;
 
            PEER_ENDPOINT pep = new PEER_ENDPOINT();
            pep.peerAddress = CollaborationHelperFunctions.ConvertIPEndpointToPEER_ADDRESS(peerEndPoint.EndPoint);

            // 
            // Pin all the data to pass to native
            // 
            GCHandle pepName = new GCHandle(); 

            if (peerEndPoint.Name != null){ 
                pepName = GCHandle.Alloc(peerEndPoint.Name, GCHandleType.Pinned);
                pep.pwzEndpointName = pepName.AddrOfPinnedObject();
            }
 
            GCHandle peerEP = GCHandle.Alloc(pep, GCHandleType.Pinned);
            IntPtr ptrPeerEP = peerEP.AddrOfPinnedObject(); 
 
            //
            // Refresh data for getting presence info 
            //
            RefreshIfNeeded();

            try{ 
                errorCode = UnsafeCollabNativeMethods.PeerCollabGetPresenceInfo(ptrPeerEP, out presenceInfo);
                if (errorCode != 0){ 
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabGetPresenceInfo returned with errorcode {0}", errorCode); 
                    throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_GetPresenceFailed), errorCode);
                } 

                IntPtr ptrPeerPresenceInfo = presenceInfo.DangerousGetHandle();
                PEER_PRESENCE_INFO ppi = (PEER_PRESENCE_INFO)Marshal.PtrToStructure(ptrPeerPresenceInfo, typeof(PEER_PRESENCE_INFO));
                peerPresenceInfo = new PeerPresenceInfo(); 
                peerPresenceInfo.PresenceStatus = ppi.status;
                peerPresenceInfo.DescriptiveText = ppi.descText; 
            } 
            finally{
                if (pepName.IsAllocated) pepName.Free(); 
                if (peerEP.IsAllocated) peerEP.Free();
                if (presenceInfo != null) presenceInfo.Dispose();
            }
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Leaving GetPresenceInfo()."); 

            return peerPresenceInfo; 
        } 

        // 
        // Gets all the objects for all the endpoints
        //
        // 
        //  
        // 
        [System.Security.SecurityCritical] 
        public PeerObjectCollection GetObjects() 
        {
            PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand(); 

            return InternalGetAllObjects(Guid.Empty, false);
        }
 
        //
        // Gets specific object for all the endpoints 
        // 
        // 
        //  
        // 
        [System.Security.SecurityCritical]
        public PeerObjectCollection GetObjects(Guid objectId)
        { 
            PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
 
            return InternalGetAllObjects(objectId, true); 
        }
 
        internal abstract void RefreshIfNeeded();

        // 
        //  
        // 
        [System.Security.SecurityCritical] 
        private PeerObjectCollection InternalGetAllObjects(Guid objectId, bool guidSupplied) 
        {
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Entering InternalGetAllObjects() with ObjectId {0}.", objectId);

            Dictionary mergedObjects = new Dictionary();
            PeerObjectCollection peerObjectCollection; 

            // 
            // Refresh the data at the endpoint before calling get objs 
            //
            RefreshIfNeeded(); 

            foreach (PeerEndPoint peerEndPoint in PeerEndPoints)
            {
                peerObjectCollection = InternalGetObjects(objectId, guidSupplied, peerEndPoint); 

                // 
                // Special case. If we have already found an endpoint with the user guid then 
                // we just return it
                // 
                if (guidSupplied && peerObjectCollection.Count != 0)
                    return peerObjectCollection;

                foreach (PeerObject peerObject in peerObjectCollection) 
                {
                    mergedObjects[peerObject.Id] = peerObject; 
                } 
            }
 
            //
            // Return the object collection from the dictionary
            //
 
            Dictionary.ValueCollection objects = mergedObjects.Values;
            peerObjectCollection = new PeerObjectCollection(); 
            foreach (PeerObject peerObject in objects) 
            {
                peerObjectCollection.Add(peerObject); 
            }

            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Leaving InternalGetAllObjects(). " +
            "Returning collection with {0} objects.", peerObjectCollection.Count); 

            return peerObjectCollection; 
        } 

        // 
        // Gets specific objects for an endpoint
        //
        // 
        //  
        // 
        //  
        //  
        // 
        //  
        // 
        // 
        // 
        //  
        // 
        //  
        //  
        // 
        //  
        // 
        [System.Security.SecurityCritical]
        internal static PeerObjectCollection InternalGetObjects(Guid objectId, bool guidSupplied, PeerEndPoint peerEndPoint)
        { 
            if (Logging.P2PTraceSource.Switch.ShouldTrace(TraceEventType.Information)){
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Entering InternalGetObjects() with the following PeerEndPoint"); 
                peerEndPoint.TracePeerEndPoint(); 
            }
 
            PeerObjectCollection peerObjectColl = new PeerObjectCollection();
            SafeCollabEnum handlePeerEnum = null;
            UInt32 objectCount = 0;
            int errorCode = 0; 

 
            GCHandle guidHandle = new GCHandle(); 
            IntPtr guidPtr = IntPtr.Zero;
 
            if (guidSupplied){
                GUID guid = CollaborationHelperFunctions.ConvertGuidToGUID(objectId);
                guidHandle = GCHandle.Alloc(guid, GCHandleType.Pinned);
                guidPtr = guidHandle.AddrOfPinnedObject(); 
            }
 
            PEER_ENDPOINT pep = new PEER_ENDPOINT(); 
            pep.peerAddress = CollaborationHelperFunctions.ConvertIPEndpointToPEER_ADDRESS(peerEndPoint.EndPoint);
 
            //
            // Pin data to pass to native
            //
 
            GCHandle pepName = new GCHandle();
 
            if (peerEndPoint.Name != null){ 
                pepName = GCHandle.Alloc(peerEndPoint.Name, GCHandleType.Pinned);
                pep.pwzEndpointName = pepName.AddrOfPinnedObject(); 
            }
            GCHandle peerEP = GCHandle.Alloc(pep, GCHandleType.Pinned);
            IntPtr ptrPeerEP = peerEP.AddrOfPinnedObject();
 
            try{
                // 
                // Enumerate through the objects for the endpoint 
                //
 
                errorCode = UnsafeCollabNativeMethods.PeerCollabEnumObjects(ptrPeerEP, guidPtr, out handlePeerEnum);

                if (errorCode != 0){
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabEnumObjects returned with errorcode {0}", errorCode); 
                    throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_GetObjectsFailed), errorCode);
                } 
 
                errorCode = UnsafeCollabNativeMethods.PeerGetItemCount(handlePeerEnum, ref objectCount);
                if (errorCode != 0){ 
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerGetItemCount returned with errorcode {0}", errorCode);
                    throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_GetObjectsFailed), errorCode);
                }
 
                if (objectCount == 0){
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "No PeerObjects found."); 
                    return peerObjectColl; 
                }
                unsafe 
                {
                    SafeCollabData objectArray;
                    errorCode = UnsafeCollabNativeMethods.PeerGetNextItem(handlePeerEnum, ref objectCount, out objectArray);
                    if (errorCode != 0){ 
                        Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerGetNextItem returned with errorcode {0}", errorCode);
                        throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_GetObjectsFailed), errorCode); 
                    } 

                    IntPtr pPEER_OBJECT = objectArray.DangerousGetHandle(); 
                    IntPtr* pObjects = (IntPtr*)pPEER_OBJECT;

                    //
                    // Loop through the applications array from native 
                    //
                    for (ulong i = 0; i < objectCount; i++){ 
                        PEER_OBJECT* pPeerObject = (PEER_OBJECT*)pObjects[i]; 
                        byte[] data = null;
 
                        if (pPeerObject->data.cbData != 0){
                            data = new byte[pPeerObject->data.cbData];
                            Marshal.Copy(pPeerObject->data.pbData, data, 0, (int)pPeerObject->data.cbData);
                        } 

                        PeerObject peerObject = new PeerObject(CollaborationHelperFunctions.ConvertGUIDToGuid(pPeerObject->guid), data, (PeerScope)pPeerObject->dwPublicationScope); 
 
                        if (Logging.P2PTraceSource.Switch.ShouldTrace(TraceEventType.Information)){
                            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Retrieved following Object"); 
                            peerObject.TracePeerObject();
                        }

                        peerObjectColl.Add(peerObject); 
                    }
                } 
            } 
            finally{
                if (guidHandle.IsAllocated) guidHandle.Free(); 
                if (pepName.IsAllocated) pepName.Free();
                if (peerEP.IsAllocated) peerEP.Free();
                if (handlePeerEnum != null) handlePeerEnum.Dispose();
            } 

            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Leaving InternalGetApplications(). " + 
            "Returning collection with {0} objects.", peerObjectColl.Count); 

            return peerObjectColl; 
        }

        public abstract PeerInvitationResponse Invite();
 
        public abstract PeerInvitationResponse Invite(PeerApplication applicationToInvite, string message, byte[] invitationData);
 
        // 
        // Invites an endpoint with passed data. Includes a contact if it was passed in.
        // 
        // 
        // 
        // 
        //  
        // 
        //  
        //  
        // 
        //  
        // 
        // 
        // 
        //  
        // 
        //  
        //  
        // 
        //  
        [System.Security.SecurityCritical]
        internal static PeerInvitationResponse InternalInviteEndPoint(Guid applicationToInviteGuid,
                                                                string message, byte[] invitationData,
                                                                PeerEndPoint peerEndPoint, PeerContact peerContact) 
        {
 
            if (Logging.P2PTraceSource.Switch.ShouldTrace(TraceEventType.Information)){ 
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Entering InternalInviteEndPoint() with the following information.");
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Invitation Message: ", message); 
                if (Logging.P2PTraceSource.Switch.ShouldTrace(TraceEventType.Verbose) && (invitationData != null)){
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "\tInvitation data:");
                    Logging.DumpData(Logging.P2PTraceSource, TraceEventType.Verbose, Logging.P2PTraceSource.MaxDataSize, invitationData, 0, invitationData.Length);
                } 
                else
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Invitation Data length: ", (invitationData != null ? invitationData.Length : 0)); 
 
                if (peerEndPoint != null) peerEndPoint.TracePeerEndPoint();
            } 

            PEER_INVITATION pi = new PEER_INVITATION();
            pi.applicationId = CollaborationHelperFunctions.ConvertGuidToGUID(applicationToInviteGuid);
            pi.pwzMessage = message; 

            SafeCollabMemory data = null; 
            pi.applicationData.cbData = (invitationData != null) ? (UInt32)invitationData.Length : 0; 

            // 
            // Marshal Invitation Data
            //
            if ((invitationData != null) && (invitationData.Length > 0))
            { 
                data = new SafeCollabMemory(invitationData.Length);
                pi.applicationData.pbData = data.DangerousGetHandle(); 
                Marshal.Copy(invitationData, 0, pi.applicationData.pbData, invitationData.Length); 
            }
            else 
                pi.applicationData.pbData = IntPtr.Zero;


            PEER_ENDPOINT pep = new PEER_ENDPOINT(); 
            pep.peerAddress = CollaborationHelperFunctions.ConvertIPEndpointToPEER_ADDRESS(peerEndPoint.EndPoint);
 
            // 
            // Pin data to pass to native
            // 
            GCHandle pepName = new GCHandle();

            if (peerEndPoint.Name != null){
                pepName = GCHandle.Alloc(peerEndPoint.Name, GCHandleType.Pinned); 
                pep.pwzEndpointName = pepName.AddrOfPinnedObject();
            } 
            GCHandle peerEP = GCHandle.Alloc(pep, GCHandleType.Pinned); 
            IntPtr ptrPeerEP = peerEP.AddrOfPinnedObject();
 
            SafeCollabData safeResponse = null;
            PeerInvitationResponse peerInvResponse = null;
            int errorCode;
 
            try{
                // 
                // Make native call with endpoint with/without contact 
                //
                if (peerContact != null){ 

                    //
                    // Generate native contact
                    // 
                    SafeCollabMemory safeCredentials = null;
                    PEER_CONTACT pc = CollaborationHelperFunctions.ConvertPeerContactToPEER_CONTACT(peerContact, ref safeCredentials); 
 
                    try{
                        errorCode = UnsafeCollabNativeMethods.PeerCollabInviteContact(ref pc, 
                                                                                        ptrPeerEP,
                                                                                        ref pi,
                                                                                        out safeResponse);
                    } 
                    finally{
                        if (safeCredentials != null) safeCredentials.Dispose(); 
                    } 
                }
                else 
                    errorCode = UnsafeCollabNativeMethods.PeerCollabInviteEndpoint(ptrPeerEP, ref pi, out safeResponse);

                if (errorCode != 0){
                    if ((errorCode == UnsafeCollabReturnCodes.PEER_E_TIMEOUT) || (errorCode == UnsafeCollabReturnCodes.ERROR_TIMEOUT)){ 
                        Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0,
                            "Timed out. Leaving InternalInviteEndPoint() with InvitationResponseType expired."); 
 
                        return new PeerInvitationResponse(PeerInvitationResponseType.Expired);
                    } 

                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, ((peerContact != null) ? "PeerCollabInviteContact" : "PeerCollabInviteEndpoint")
                        + " returned with errorcode {0}", errorCode);
                    throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_InviteFailed), errorCode); 
                }
 
                if (!safeResponse.IsInvalid){ 
                    PEER_INVITATION_RESPONSE pir = (PEER_INVITATION_RESPONSE)Marshal.PtrToStructure(safeResponse.DangerousGetHandle(),
                                                                                                    typeof(PEER_INVITATION_RESPONSE)); 
                    peerInvResponse = new PeerInvitationResponse(pir.action);
                }
            }
            finally{ 
                if (safeResponse != null) safeResponse.Dispose();
                if (pepName.IsAllocated) pepName.Free(); 
                if (peerEP.IsAllocated) peerEP.Free(); 
            }
 

            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0,
                "Leaving InternalInviteEndPoint() with InvitationResponse {0}.", peerInvResponse);
 
            return peerInvResponse;
        } 
 

        private event EventHandler m_inviteCompleted; 
        public event EventHandler InviteCompleted
        {
            add{
                if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName); 
                PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
 
                m_inviteCompleted += value; 
            }
            remove{ 
                if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
                PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();

                m_inviteCompleted -= value; 
            }
        } 
 
        public abstract void InviteAsync(Object userToken);
 
        public abstract void InviteAsync(   PeerApplication applicationToInvite, string message,
                                            byte[] invitationData, Object userToken);

 
        #region Invite Async variables
        SendOrPostCallback OnInviteCompletedDelegate; 
 
        internal Dictionary m_inviteAsyncHelperList = new Dictionary();
        #endregion 

        // 
        // 
        //  
        [System.Security.SecurityCritical]
        internal void InternalInviteAsync(Guid applicationToInviteGuid, 
                                        string message, byte[] invitationData, 
                                        PeerEndPointCollection peerEndPoints, PeerContact peerContact,
                                        Object userToken) 
        {
            InviteAsyncHelper inviteAsyncHelper = null;

            // 
            //The userToken can't be duplicate of what is in the
            //current list. These are the requriments for the new Async model 
            //that supports multiple outstanding async calls 
            //
            int newTraceEventId = NewTraceEventId; 

            lock (m_inviteAsyncHelperList){
                if (m_inviteAsyncHelperList.ContainsKey(userToken)){
                    throw new ArgumentException(SR.GetString(SR.DuplicateUserToken)); 
                }
 
                inviteAsyncHelper = new InviteAsyncHelper(  peerContact, this, peerEndPoints, 
                                                            applicationToInviteGuid, message,
                                                            invitationData, userToken, newTraceEventId); 
                m_inviteAsyncHelperList[userToken] = inviteAsyncHelper;
            }

            try{ 
                //
                //Start resolution on that resolver 
                // 
                inviteAsyncHelper.InviteAsync();
            } 
            catch{
                //
                //If an exception happens clear the userState from the
                //list so that that token can be reused 
                //
                lock (m_inviteAsyncHelperList){ 
                    m_inviteAsyncHelperList.Remove(userToken); 
                }
                throw; 
            }

        }
 
        protected virtual void OnInviteCompleted(InviteCompletedEventArgs e)
        { 
            EventHandler handlerCopy = m_inviteCompleted; 

            if (handlerCopy != null){ 
                handlerCopy(this, e);
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Fired the invite completed event callback.");
            }
        } 

        void InviteCompletedWaitCallback(object operationState) 
        { 
            OnInviteCompleted((InviteCompletedEventArgs)operationState);
        } 

        internal void PrepareToRaiseInviteCompletedEvent(AsyncOperation asyncOP, InviteCompletedEventArgs args)
        {
            lock (m_inviteAsyncHelperList){ 
                InviteAsyncHelper helper = m_inviteAsyncHelperList[args.UserState];
                if (helper == null){ 
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Critical, 0, "userState for which we are about to call Completed event does not exist in the pending async list"); 
                }else{
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Critical, helper.TraceEventId, 
                         "userState {0} is being removed from the pending async list", args.UserState.GetHashCode());
                    m_inviteAsyncHelperList.Remove(args.UserState);
                }
            } 
            asyncOP.PostOperationCompleted(OnInviteCompletedDelegate, args);
        } 
 
        // 
        //  
        // 
        [System.Security.SecurityCritical]
        public void InviteAsyncCancel(Object userToken)
        { 
            if (userToken == null)
                throw new ArgumentNullException("userToken"); 
 
            InviteAsyncHelper helper;
            lock (m_inviteAsyncHelperList){ 
                if (!m_inviteAsyncHelperList.TryGetValue(userToken, out helper)){
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Warning, 0, "InviteAsyncCancel called with a userState token that is not in the pending async list - returning");
                    return;
                } 
            }
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, helper.TraceEventId, 
                    "Proceeding to cancel the pending async"); 
            helper.CancelAsync(userToken);
        } 

        //
        // Used to track inviteasynchelpers
        // 
        private static int s_TraceEventId = 1;
        internal static int NewTraceEventId 
        { 
            get{
                Interlocked.CompareExchange(ref s_TraceEventId, 0, int.MaxValue); 
                Interlocked.Increment(ref s_TraceEventId);
                return s_TraceEventId;
            }
        } 

        public bool Equals(Peer other) 
        { 
            if (other != null){
                if (other.PeerEndPoints != null){ 
                    return other.PeerEndPoints.Equals(PeerEndPoints);
                }
            }
            return false; 
        }
 
        public override string ToString() 
        {
            return PeerEndPoints.ToString(); 
        }

        private bool m_Disposed;
 
        public void Dispose()
        { 
 
            Dispose(true);
            GC.SuppressFinalize(this); 
        }

        // 
        //  
        // 
        [System.Security.SecurityCritical] 
        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter, SerializationFormatter = true)] 
        void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
        { 
            GetObjectData(info, context);
        }

        ///  
        /// This is made virtual so that derived types can be implemented correctly
        ///  
        ///  
        /// 
        [SecurityPermission(SecurityAction.LinkDemand, SerializationFormatter = true)] 
        protected virtual void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("_PeerEndPoints", PeerEndPoints);
        } 

        protected virtual void Dispose(bool disposing) 
        { 
            if (!m_Disposed){
                m_Disposed = true; 
            }
        }
    }
 
    /// 
    /// Helps in all the async invites sent from Peer, PeerContact and PeerNearMe 
    ///  
    internal class InviteAsyncHelper : IDisposable
    { 
        internal object m_userState;
        internal SafeCollabInvite m_SafeCollabInvite;
        internal AutoResetEvent m_InviteEvent = new AutoResetEvent(false);
 
        //
        //The WaitHandle that hooks up a callback to the 
        //event 
        //
        internal RegisteredWaitHandle m_RegisteredWaitHandle; 

        //
        //Disposed or not
        // 
        internal bool m_Disposed;
 
        internal bool m_Cancelled; 

        // 
        //Async operation to ensure synchornization
        //context
        //
        AsyncOperation m_AsyncOp; 

        // 
        //A link to the resolver to avoid 
        //circular dependencies and enable GC
        // 
        WeakReference m_peerWeakReference;

        //
        //Lock to make sure things don't mess up stuff 
        //
        object m_Lock = new Object(); 
 
        //
        //EventID or Just a tracking id 
        //
        int m_TraceEventId;

        // 
        // Store the latest exception
        // 
        Exception m_latestException; 

        // 
        // Stores reponses from all endpoints
        //
        Collection m_responses = new Collection();
 
        //
        // Callback called 
        // 
        bool m_Completed;
 
        //
        // Used to ensure only on thread calls the callback
        //
        bool m_aboutToFireCallback; 
        object m_aboutToFireCallbackLock = new object();
 
        // 
        // Number of reponses received
        // 
        int m_numberOfResponses;

        PeerContact m_peerContact;
        PeerEndPointCollection m_peerEndPoints; 
        Guid m_applicationId;
        string m_message; 
        byte[] m_inviteData; 

        internal InviteAsyncHelper( PeerContact peerContact, Peer parentPeer, PeerEndPointCollection peerEndPoints, 
                                    Guid applicationId, string message, byte[] inviteData,
                                    object userState, int NewTraceEventId)
        {
            m_userState = userState; 
            m_peerContact = peerContact;
            m_applicationId = applicationId; 
            m_message = message; 
            m_inviteData = inviteData;
            m_peerEndPoints = peerEndPoints; 
            m_TraceEventId = NewTraceEventId;
            m_peerWeakReference = new WeakReference(parentPeer);

            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId, "New InviteAsyncHelper created with TraceEventID {0}", m_TraceEventId); 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId,
                "\tPeerContact: {0}, App Guid: {1}, userState {2}, ParentReference {3}", 
                (m_peerContact != null ? m_peerContact.ToString() : "null"), 
                applicationId.ToString(),
                userState.GetHashCode(), 
                m_peerWeakReference.Target.GetHashCode()
                );

        } 

        //  
        //  
        // 
        //  
        // 
        // 
        // 
        //  
        // 
        //  
        //  
        // 
        [System.Security.SecurityCritical] 
        internal void InviteAsync()
        {
            if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId,
            "InviteAsync called"); 
            // 
            //First wire up a callback
            // 

            m_RegisteredWaitHandle = ThreadPool.RegisterWaitForSingleObject(m_InviteEvent, //Event that triggers the callback
                                                    new WaitOrTimerCallback(InviteCallback), //callback to be called
                                                    null, //state to be passed 
                                                    -1,   //Timeout - aplicable only for timers not for events
                                                    false //call us everytime the event is set not just one time 
                                                    ); 

            // 
            //Now call the native API to start the resolution
            //process save the handle for later
            //
 
            PEER_INVITATION pi = new PEER_INVITATION();
            pi.applicationId = CollaborationHelperFunctions.ConvertGuidToGUID(m_applicationId); 
            pi.pwzMessage = m_message; 

            SafeCollabMemory data = null; 
            pi.applicationData.cbData = (m_inviteData != null) ? (UInt32)m_inviteData.Length : 0;

            if ((m_inviteData != null) && (m_inviteData.Length > 0)){
                data = new SafeCollabMemory(m_inviteData.Length); 
                pi.applicationData.pbData = data.DangerousGetHandle();
                Marshal.Copy(m_inviteData, 0, pi.applicationData.pbData, m_inviteData.Length); 
            } 
            else
                pi.applicationData.pbData = IntPtr.Zero; 

            foreach (PeerEndPoint peerEndPoint in m_peerEndPoints)
            {
                try{ 
                    InviteAsyncEndPoint(peerEndPoint, pi);
                } 
                catch (PeerToPeerException){ 
                    if (!m_SafeCollabInvite.IsInvalid && !m_SafeCollabInvite.IsClosed){
                        m_SafeCollabInvite.Dispose(); 
                    }
                    m_RegisteredWaitHandle.Unregister(null);
                    m_RegisteredWaitHandle = null;
                    throw; 
                }
            } 
 
            //
            //Create an async operation with the given 
            //user state
            //
            m_AsyncOp = AsyncOperationManager.CreateOperation(m_userState);
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId,
            "Leaving InviteAsync."); 
        } 

        //  
        // 
        // 
        // 
        //  
        // 
        //  
        //  
        // 
        //  
        // 
        // 
        // 
        [System.Security.SecurityCritical] 
        internal void InviteAsyncEndPoint(PeerEndPoint peerEndPoint, PEER_INVITATION pi)
        { 
            if (Logging.P2PTraceSource.Switch.ShouldTrace(TraceEventType.Information)){ 
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "InviteAsyncEndPoint() is called with the following Info");
                peerEndPoint.TracePeerEndPoint(); 
            }

            PEER_ENDPOINT pep = new PEER_ENDPOINT();
            pep.peerAddress = CollaborationHelperFunctions.ConvertIPEndpointToPEER_ADDRESS(peerEndPoint.EndPoint); 

            // 
            // Pin all the data to pass to native 
            //
            GCHandle pepName = new GCHandle(); 

            if (peerEndPoint.Name != null){
                pepName = GCHandle.Alloc(peerEndPoint.Name, GCHandleType.Pinned);
                pep.pwzEndpointName = pepName.AddrOfPinnedObject(); 
            }
            GCHandle peerEP = GCHandle.Alloc(pep, GCHandleType.Pinned); 
            IntPtr ptrPeerEP = peerEP.AddrOfPinnedObject(); 

            int errorCode; 
            try{
                //
                // Make native call with endpoint with/without contact
                // 
                if (m_peerContact != null){
 
                    // 
                    // Generate native contact
                    // 
                    SafeCollabMemory safeCredentials = null;
                    PEER_CONTACT pc = CollaborationHelperFunctions.ConvertPeerContactToPEER_CONTACT(m_peerContact, ref safeCredentials);

                    try{ 
                        errorCode = UnsafeCollabNativeMethods.PeerCollabAsyncInviteContact(  ref pc,
                                                                                        ptrPeerEP, 
                                                                                        ref pi, 
                                                                                        m_InviteEvent.SafeWaitHandle,
                                                                                        out m_SafeCollabInvite); 
                    }
                    finally{
                        if (safeCredentials != null) safeCredentials.Dispose();
                    } 
                }
                else 
                    errorCode = UnsafeCollabNativeMethods.PeerCollabAsyncInviteEndpoint(ptrPeerEP, ref pi, 
                                                                                m_InviteEvent.SafeWaitHandle,
                                                                                out m_SafeCollabInvite); 

            }
            finally
            { 
                if (pepName.IsAllocated) pepName.Free();
                if (peerEP.IsAllocated) peerEP.Free(); 
            } 

            if (errorCode != 0){ 
                throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_AsyncInviteFailed), errorCode);
            }
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId, "Leaving InviteAsyncEndPoint.");
 
        }
 
        // 
        // Invite callback. Will fire only if i has at least one accepted or when it has all the responses
        // from all the endpoints 
        //
        // 
        // 
        //  
        // 
        //  
        //  
        // 
        //  
        // 
        [System.Security.SecurityCritical]
        internal void InviteCallback(object state, bool timedOut)
        { 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId, "Entering InviteCallback.");
 
            SafeCollabData response = null; 

            int errorCode = 0; 
            InviteCompletedEventArgs inviteCompletedArgs = null;
            Peer peer = null;
            bool fireCallback = false;
            PEER_INVITATION_RESPONSE pir = new PEER_INVITATION_RESPONSE(); 

            try 
            { 
                lock (m_Lock){
                    if (m_Cancelled || m_Completed){ 
                        Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId, "Invite cancelled({0}) or completed({1}). Returning without doing anything.", m_Cancelled, m_Completed);
                        return;
                    }
                    errorCode = UnsafeCollabNativeMethods.PeerCollabGetInvitationResponse(m_SafeCollabInvite, out response); 
                }
 
                if ((errorCode != 0) && (errorCode != UnsafeCollabReturnCodes.PEER_E_TIMEOUT)){ 
                    m_latestException = PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_AsyncInviteException), errorCode);
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId, "Got an exception {0}. Storing it in latest exception.", m_latestException); 
                }
                else
                {
                    pir = (PEER_INVITATION_RESPONSE)Marshal.PtrToStructure(response.DangerousGetHandle(), 
                                                    typeof(PEER_INVITATION_RESPONSE));
 
                    // 
                    // Store the responses
                    // 
                    lock (m_responses)
                        m_responses.Add(pir.action);

                    if (pir.action == PeerInvitationResponseType.Accepted){ 
                        inviteCompletedArgs = new InviteCompletedEventArgs(new PeerInvitationResponse(pir.action), null, false,
                                                                            m_AsyncOp.UserSuppliedState); 
                        fireCallback = true; 

                        // 
                        // Got an accepted. unregister callback to disable all othe other endpoint callbacks
                        //

                        Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId, "Found an accepted. About to fire callback."); 

                        m_RegisteredWaitHandle.Unregister(null); 
                    } 
                }
 

                Interlocked.Increment(ref m_numberOfResponses);

                if ((!fireCallback) && (m_numberOfResponses == m_peerEndPoints.Count) && (!m_aboutToFireCallback)){ 
                    //
                    // Two threads can be here at the same time when all the responses have been 
                    // received and only one should be allowed to call the callback 
                    //
                    lock (m_aboutToFireCallbackLock){ 
                        if (m_aboutToFireCallback)
                            return;

                        m_aboutToFireCallback = true; 

                        bool foundDeclined = false; 
                        bool foundExpired = false; 

                        fireCallback = true; 

                        //
                        // Got all responses; make a decision
                        // 

                        foreach (PeerInvitationResponseType responseType in m_responses) 
                        { 
                            if (responseType == PeerInvitationResponseType.Expired){
                                foundExpired = true; 
                            }
                            else if (responseType == PeerInvitationResponseType.Declined){
                                foundDeclined = true;
                                break; 
                            }
                        } 
 
                        //
                        // If at least one is declined, return declined. 
                        //

                        if (foundDeclined){
                            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId, "Got a declined invite response."); 
                            inviteCompletedArgs = new InviteCompletedEventArgs(new PeerInvitationResponse(PeerInvitationResponseType.Declined), null, false,
                                                        m_AsyncOp.UserSuppliedState); 
                        } 
                        else if (foundExpired){
                            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId, "Got an expired invite response but no accepted or declined."); 
                            inviteCompletedArgs = new InviteCompletedEventArgs(new PeerInvitationResponse(PeerInvitationResponseType.Expired), null, false,
                                                        m_AsyncOp.UserSuppliedState);
                        }
                        else{ 
                            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId, "Got all error responses");
                            inviteCompletedArgs = new InviteCompletedEventArgs(null, (m_latestException != null ? m_latestException : new PeerToPeerException("InviteAsync failure.")), false, 
                                                        m_AsyncOp.UserSuppliedState); 
                        }
                    } 
                }
                //
                //Last chance to prevent the callback
                // 
                if (fireCallback){
                    peer = m_peerWeakReference.Target as Peer; 
                    if (!m_Completed && (peer != null)){ 
                        lock (m_Lock){
                            // 
                            // Async op may be cancelled already
                            //
                            if (!m_Completed && !m_Cancelled){
 
                                //
                                //Mark as completed so that this gets fired only once 
                                // 
                                m_Completed = true;
                                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId, "Firing callback with response type {0}.", inviteCompletedArgs.InviteResponse); 
                                peer.PrepareToRaiseInviteCompletedEvent(m_AsyncOp, inviteCompletedArgs);
                            }
                        }
                    } 
                }
            } 
            finally{ 
                if (response != null) response.Dispose();
            } 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId, "Leaving InviteCallback.");

       }
 
        // 
        //  
        //  
        // 
        //  
        [System.Security.SecurityCritical]
        public void ContinueCancelCallback(object state)
        {
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId, "Entering ContineCancelCallback."); 

            try{ 
                lock (m_Lock){ 
                    if (m_Completed) return;
                    m_Cancelled = true; 

                    int errorCode = UnsafeCollabNativeMethods.PeerCollabCancelInvitation(m_SafeCollabInvite);
                    if (errorCode != 0){
                        Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabCancelInvitation returned with errorcode {0}", errorCode); 
                    }
 
                    m_SafeCollabInvite.Dispose(); 
                }
 
                Peer peer = m_peerWeakReference.Target as Peer;
                if (peer != null){
                    InviteCompletedEventArgs e = new InviteCompletedEventArgs(null, null, true, m_AsyncOp.UserSuppliedState);
                    peer.PrepareToRaiseInviteCompletedEvent(m_AsyncOp, e); 
                }
            } 
            catch (ObjectDisposedException ex){ 
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Critical, 0, "Exception while cancelling the call {0}", ex);
            } 

            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId, "Leaving ContineCancelCallback.");

        } 

        //  
        //  
        // 
        [System.Security.SecurityCritical] 
        public void CancelAsync(object state)
        {
            //
            //Defer the work to a callback 
            //
 
            ThreadPool.QueueUserWorkItem(new WaitCallback(ContinueCancelCallback), state); 
        }
 
        // 
        // 
        // 
        [System.Security.SecurityCritical] 
        public void Dispose()
        { 
            Dispose(true); 
            GC.SuppressFinalize(this);
        } 

        // 
        // 
        //  
        // 
        //  
        [System.Security.SecurityCritical] 
        public void Dispose(bool disposing)
        { 
            if (!m_Disposed){
                if (!m_SafeCollabInvite.IsInvalid){
                    m_SafeCollabInvite.Dispose();
                } 

                if (m_RegisteredWaitHandle != null){ 
                    m_RegisteredWaitHandle.Unregister(null); 
                    m_RegisteredWaitHandle = null;
                } 

                if (m_InviteEvent != null){
                    m_InviteEvent.Close();
                } 
            }
            m_Disposed = true; 
        } 

        public override int GetHashCode() 
        {
            return m_TraceEventId;
        }
 
        internal int TraceEventId
        { 
            get{ 
                return m_TraceEventId;
            } 
        }

    }
 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

namespace System.Net.PeerToPeer.Collaboration 
{ 
    using System;
    using System.Collections; 
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Text;
    using System.Runtime.InteropServices; 
    using System.Net.Sockets;
    using System.Net.Mail; 
    using System.ComponentModel; 
    using System.Threading;
    using System.Diagnostics; 
    using System.Runtime.Serialization;
    using System.Security.Permissions;
    using System.IO;
 
    /// 
    /// This is the object changed event args class we give back when 
    /// we have have an object changed event fired by native 
    /// 
    public class ObjectChangedEventArgs : EventArgs 
    {
        private PeerEndPoint m_peerEndPoint;
        private PeerContact m_peerContact;
        private PeerChangeType m_peerChangeType; 
        private PeerObject m_peerObject;
 
        internal ObjectChangedEventArgs(PeerEndPoint peerEndPoint, PeerContact peerContact, 
                                        PeerChangeType peerChangeType, PeerObject peerObject)
        { 
            m_peerEndPoint = peerEndPoint;
            m_peerContact = peerContact;
            m_peerChangeType = peerChangeType;
            m_peerObject = peerObject; 
        }
 
        public PeerEndPoint PeerEndPoint 
        {
            get 
            {
                return m_peerEndPoint;
            }
        } 

        public PeerContact PeerContact 
        { 
            get
            { 
                return m_peerContact;
            }
        }
 
        public PeerChangeType PeerChangeType
        { 
            get 
            {
                return m_peerChangeType; 
            }
        }

        public PeerObject PeerObject 
        {
            get 
            { 
                return m_peerObject;
            } 
        }
    }

    ///  
    /// This is the presence changed event args class we give back when
    /// we have have presence changed event fired by native 
    ///  
    public class PresenceChangedEventArgs : EventArgs
    { 
        private PeerEndPoint m_peerEndPoint;
        private PeerContact m_peerContact;
        private PeerChangeType m_peerChangeType;
        private PeerPresenceInfo m_peerPresenceInfo; 

        internal PresenceChangedEventArgs(PeerEndPoint peerEndPoint, PeerContact peerContact, 
                                        PeerChangeType peerChangeType, PeerPresenceInfo peerPresenceInfo) 
        {
            m_peerEndPoint = peerEndPoint; 
            m_peerContact = peerContact;
            m_peerChangeType = peerChangeType;
            m_peerPresenceInfo = peerPresenceInfo;
        } 

        public PeerEndPoint PeerEndPoint 
        { 
            get
            { 
                return m_peerEndPoint;
            }
        }
 
        public PeerContact PeerContact
        { 
            get 
            {
                return m_peerContact; 
            }
        }

        public PeerChangeType PeerChangeType 
        {
            get 
            { 
                return m_peerChangeType;
            } 
        }

        public PeerPresenceInfo PeerPresenceInfo
        { 
            get
            { 
                return m_peerPresenceInfo; 
            }
        } 
    }

    /// 
    /// This is the event args class we give back when 
    /// we have completed the subscribeasync call
    ///  
    public class SubscribeCompletedEventArgs : AsyncCompletedEventArgs 
    {
        private PeerNearMe m_peerNearMe; 
        private PeerContact m_peerContact;

        internal SubscribeCompletedEventArgs(PeerNearMe peerNearMe,
                                        PeerContact peerContact, 
                                        Exception error,
                                        bool cancelled, 
                                        object userToken) 
            : base(error, cancelled, userToken)
        { 
            m_peerNearMe = peerNearMe;
            m_peerContact = peerContact;
        }
 
        public PeerNearMe PeerNearMe
        { 
            get 
            {
                return m_peerNearMe; 
            }
        }

        public PeerContact PeerContact 
        {
            get 
            { 
                return m_peerContact;
            } 
        }
    }

    ///  
    /// This is the event args class we give back when
    /// we have completed the refreshendpoint async call 
    ///  
    public class RefreshDataCompletedEventArgs : AsyncCompletedEventArgs
    { 
        private PeerEndPoint m_peerEndPoint;
        internal RefreshDataCompletedEventArgs(PeerEndPoint peerEndPoint,
                                                        Exception error,
                                                        bool cancelled, 
                                                        object userToken)
            : base(error, cancelled, userToken) 
        { 
            m_peerEndPoint = peerEndPoint;
        } 

        public PeerEndPoint PeerEndPoint
        {
            get 
            {
                return m_peerEndPoint; 
            } 
        }
    } 

    /// 
    /// This is the event args class we give back when
    /// we have completed the inviteasync call 
    /// 
    public class InviteCompletedEventArgs : AsyncCompletedEventArgs 
    { 
        private PeerInvitationResponse m_peerInvResponse;
        internal InviteCompletedEventArgs(PeerInvitationResponse peerInvResponse, 
                                                        Exception error,
                                                        bool cancelled,
                                                        object userToken)
            : base(error, cancelled, userToken) 
        {
            m_peerInvResponse = peerInvResponse; 
        } 

        public PeerInvitationResponse InviteResponse 
        {
            get
            {
                return m_peerInvResponse; 
            }
        } 
    } 

    ///  
    /// Has the common interface for PeerNearMe and PeerContact which derive from it
    /// 
    [Serializable]
    public abstract class Peer : IDisposable, IEquatable, ISerializable 
    {
        private PeerEndPointCollection m_peerEndPoints = new PeerEndPointCollection(); 
        private ISynchronizeInvoke m_synchronizingObject; 

        public virtual PeerEndPointCollection PeerEndPoints 
        {
            get {
                if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
 
                return m_peerEndPoints;
            } 
        } 

        public bool IsOnline 
        {
            get{
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Get Isonline called.");
                if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName); 

                bool isOnline = false; 
                PeerPresenceInfo presenceInfo; 

                foreach (PeerEndPoint peerEndPoint in PeerEndPoints){ 
                    presenceInfo = null;

                    try{
                        presenceInfo = GetPresenceInfo(peerEndPoint); 
                    }
                    catch (Exception e){ 
                        Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "Exception thrown {0}", e.Message); 
                    }
                    if ((presenceInfo != null) && (presenceInfo.PresenceStatus == PeerPresenceStatus.Online)){ 
                        isOnline = true;
                        break;
                    }
                } 
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Leaving Isonline called with {0}.", isOnline);
                return isOnline; 
            } 
        }
 
        /// 
        /// Gets and set the object used to marshall event handlers calls for stand alone
        /// events
        ///  
        [Browsable(false), DefaultValue(null), Description(SR.SynchronizingObject)]
        public ISynchronizeInvoke SynchronizingObject 
        { 
            get
            { 
                if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
                return m_synchronizingObject;
            }
            set 
            {
                if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName); 
                m_synchronizingObject = value; 
            }
        } 

        static internal Guid CurrentApplicationGuid
        {
            //  
            // 
            //  
            //  
            [System.Security.SecurityCritical]
            get{ 
                Guid guid = Guid.Empty;

                //
                // Get path and args of app 
                //
                string path = Path.Combine( Environment.CurrentDirectory, Process.GetCurrentProcess().ProcessName + ".exe"); 
                string arguments = null; 
                string[] argsArray = Environment.GetCommandLineArgs();
                int length = argsArray.Length; 
                if (length > 1){
                    StringBuilder argsBuilder = new StringBuilder();
                    for (int i = 1; i < length; ++i){
                        argsBuilder.Append(argsArray[i]); 
                        if (i != (length - 1)) argsBuilder.Append(' ');
                    } 
 
                    arguments = argsBuilder.ToString();
                } 

                //
                // Find a matching registered application and return its guid
                // 
                PeerApplicationCollection peerApplications = PeerCollaboration.GetLocalRegisteredApplications();
 
                foreach (PeerApplication peerApplication in peerApplications){ 
                    if ((peerApplication.CommandLineArgs == arguments) &&
                        (peerApplication.Path == path)) 
                        return peerApplication.Id;
                }
                return guid;
            } 
        }
 
        internal Peer(){ 
            OnInviteCompletedDelegate = new SendOrPostCallback(InviteCompletedWaitCallback);
        } 

        /// 
        /// Constructor to enable serialization
        ///  
        protected Peer(SerializationInfo serializationInfo, StreamingContext streamingContext):this()
        { 
            m_peerEndPoints = (PeerEndPointCollection)serializationInfo.GetValue("_PeerEndPoints", typeof(PeerEndPointCollection)); 
        }
 
        //
        // Gets the presence info from collab for a specific endpoint
        //
        //  
        // 
        //  
        //  
        // 
        //  
        // 
        // 
        // 
        //  
        // 
        [System.Security.SecurityCritical] 
        public PeerPresenceInfo GetPresenceInfo(PeerEndPoint peerEndPoint) 
        {
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "GetPresenceInfo()called."); 
            if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
            PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();

            if (peerEndPoint == null) 
                throw new ArgumentNullException("peerEndPoint");
 
            if (peerEndPoint.EndPoint == null) 
                throw new ArgumentException(SR.GetString(SR.Collab_NoEndPointInPeerEndPoint));
 
            if (Logging.P2PTraceSource.Switch.ShouldTrace(TraceEventType.Information)){
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Getting presence for the following endpoint.");
                peerEndPoint.TracePeerEndPoint();
            } 

            SafeCollabData presenceInfo = null; 
            PeerPresenceInfo peerPresenceInfo = null; 
            int errorCode;
 
            PEER_ENDPOINT pep = new PEER_ENDPOINT();
            pep.peerAddress = CollaborationHelperFunctions.ConvertIPEndpointToPEER_ADDRESS(peerEndPoint.EndPoint);

            // 
            // Pin all the data to pass to native
            // 
            GCHandle pepName = new GCHandle(); 

            if (peerEndPoint.Name != null){ 
                pepName = GCHandle.Alloc(peerEndPoint.Name, GCHandleType.Pinned);
                pep.pwzEndpointName = pepName.AddrOfPinnedObject();
            }
 
            GCHandle peerEP = GCHandle.Alloc(pep, GCHandleType.Pinned);
            IntPtr ptrPeerEP = peerEP.AddrOfPinnedObject(); 
 
            //
            // Refresh data for getting presence info 
            //
            RefreshIfNeeded();

            try{ 
                errorCode = UnsafeCollabNativeMethods.PeerCollabGetPresenceInfo(ptrPeerEP, out presenceInfo);
                if (errorCode != 0){ 
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabGetPresenceInfo returned with errorcode {0}", errorCode); 
                    throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_GetPresenceFailed), errorCode);
                } 

                IntPtr ptrPeerPresenceInfo = presenceInfo.DangerousGetHandle();
                PEER_PRESENCE_INFO ppi = (PEER_PRESENCE_INFO)Marshal.PtrToStructure(ptrPeerPresenceInfo, typeof(PEER_PRESENCE_INFO));
                peerPresenceInfo = new PeerPresenceInfo(); 
                peerPresenceInfo.PresenceStatus = ppi.status;
                peerPresenceInfo.DescriptiveText = ppi.descText; 
            } 
            finally{
                if (pepName.IsAllocated) pepName.Free(); 
                if (peerEP.IsAllocated) peerEP.Free();
                if (presenceInfo != null) presenceInfo.Dispose();
            }
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Leaving GetPresenceInfo()."); 

            return peerPresenceInfo; 
        } 

        // 
        // Gets all the objects for all the endpoints
        //
        // 
        //  
        // 
        [System.Security.SecurityCritical] 
        public PeerObjectCollection GetObjects() 
        {
            PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand(); 

            return InternalGetAllObjects(Guid.Empty, false);
        }
 
        //
        // Gets specific object for all the endpoints 
        // 
        // 
        //  
        // 
        [System.Security.SecurityCritical]
        public PeerObjectCollection GetObjects(Guid objectId)
        { 
            PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
 
            return InternalGetAllObjects(objectId, true); 
        }
 
        internal abstract void RefreshIfNeeded();

        // 
        //  
        // 
        [System.Security.SecurityCritical] 
        private PeerObjectCollection InternalGetAllObjects(Guid objectId, bool guidSupplied) 
        {
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Entering InternalGetAllObjects() with ObjectId {0}.", objectId);

            Dictionary mergedObjects = new Dictionary();
            PeerObjectCollection peerObjectCollection; 

            // 
            // Refresh the data at the endpoint before calling get objs 
            //
            RefreshIfNeeded(); 

            foreach (PeerEndPoint peerEndPoint in PeerEndPoints)
            {
                peerObjectCollection = InternalGetObjects(objectId, guidSupplied, peerEndPoint); 

                // 
                // Special case. If we have already found an endpoint with the user guid then 
                // we just return it
                // 
                if (guidSupplied && peerObjectCollection.Count != 0)
                    return peerObjectCollection;

                foreach (PeerObject peerObject in peerObjectCollection) 
                {
                    mergedObjects[peerObject.Id] = peerObject; 
                } 
            }
 
            //
            // Return the object collection from the dictionary
            //
 
            Dictionary.ValueCollection objects = mergedObjects.Values;
            peerObjectCollection = new PeerObjectCollection(); 
            foreach (PeerObject peerObject in objects) 
            {
                peerObjectCollection.Add(peerObject); 
            }

            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Leaving InternalGetAllObjects(). " +
            "Returning collection with {0} objects.", peerObjectCollection.Count); 

            return peerObjectCollection; 
        } 

        // 
        // Gets specific objects for an endpoint
        //
        // 
        //  
        // 
        //  
        //  
        // 
        //  
        // 
        // 
        // 
        //  
        // 
        //  
        //  
        // 
        //  
        // 
        [System.Security.SecurityCritical]
        internal static PeerObjectCollection InternalGetObjects(Guid objectId, bool guidSupplied, PeerEndPoint peerEndPoint)
        { 
            if (Logging.P2PTraceSource.Switch.ShouldTrace(TraceEventType.Information)){
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Entering InternalGetObjects() with the following PeerEndPoint"); 
                peerEndPoint.TracePeerEndPoint(); 
            }
 
            PeerObjectCollection peerObjectColl = new PeerObjectCollection();
            SafeCollabEnum handlePeerEnum = null;
            UInt32 objectCount = 0;
            int errorCode = 0; 

 
            GCHandle guidHandle = new GCHandle(); 
            IntPtr guidPtr = IntPtr.Zero;
 
            if (guidSupplied){
                GUID guid = CollaborationHelperFunctions.ConvertGuidToGUID(objectId);
                guidHandle = GCHandle.Alloc(guid, GCHandleType.Pinned);
                guidPtr = guidHandle.AddrOfPinnedObject(); 
            }
 
            PEER_ENDPOINT pep = new PEER_ENDPOINT(); 
            pep.peerAddress = CollaborationHelperFunctions.ConvertIPEndpointToPEER_ADDRESS(peerEndPoint.EndPoint);
 
            //
            // Pin data to pass to native
            //
 
            GCHandle pepName = new GCHandle();
 
            if (peerEndPoint.Name != null){ 
                pepName = GCHandle.Alloc(peerEndPoint.Name, GCHandleType.Pinned);
                pep.pwzEndpointName = pepName.AddrOfPinnedObject(); 
            }
            GCHandle peerEP = GCHandle.Alloc(pep, GCHandleType.Pinned);
            IntPtr ptrPeerEP = peerEP.AddrOfPinnedObject();
 
            try{
                // 
                // Enumerate through the objects for the endpoint 
                //
 
                errorCode = UnsafeCollabNativeMethods.PeerCollabEnumObjects(ptrPeerEP, guidPtr, out handlePeerEnum);

                if (errorCode != 0){
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabEnumObjects returned with errorcode {0}", errorCode); 
                    throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_GetObjectsFailed), errorCode);
                } 
 
                errorCode = UnsafeCollabNativeMethods.PeerGetItemCount(handlePeerEnum, ref objectCount);
                if (errorCode != 0){ 
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerGetItemCount returned with errorcode {0}", errorCode);
                    throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_GetObjectsFailed), errorCode);
                }
 
                if (objectCount == 0){
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "No PeerObjects found."); 
                    return peerObjectColl; 
                }
                unsafe 
                {
                    SafeCollabData objectArray;
                    errorCode = UnsafeCollabNativeMethods.PeerGetNextItem(handlePeerEnum, ref objectCount, out objectArray);
                    if (errorCode != 0){ 
                        Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerGetNextItem returned with errorcode {0}", errorCode);
                        throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_GetObjectsFailed), errorCode); 
                    } 

                    IntPtr pPEER_OBJECT = objectArray.DangerousGetHandle(); 
                    IntPtr* pObjects = (IntPtr*)pPEER_OBJECT;

                    //
                    // Loop through the applications array from native 
                    //
                    for (ulong i = 0; i < objectCount; i++){ 
                        PEER_OBJECT* pPeerObject = (PEER_OBJECT*)pObjects[i]; 
                        byte[] data = null;
 
                        if (pPeerObject->data.cbData != 0){
                            data = new byte[pPeerObject->data.cbData];
                            Marshal.Copy(pPeerObject->data.pbData, data, 0, (int)pPeerObject->data.cbData);
                        } 

                        PeerObject peerObject = new PeerObject(CollaborationHelperFunctions.ConvertGUIDToGuid(pPeerObject->guid), data, (PeerScope)pPeerObject->dwPublicationScope); 
 
                        if (Logging.P2PTraceSource.Switch.ShouldTrace(TraceEventType.Information)){
                            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Retrieved following Object"); 
                            peerObject.TracePeerObject();
                        }

                        peerObjectColl.Add(peerObject); 
                    }
                } 
            } 
            finally{
                if (guidHandle.IsAllocated) guidHandle.Free(); 
                if (pepName.IsAllocated) pepName.Free();
                if (peerEP.IsAllocated) peerEP.Free();
                if (handlePeerEnum != null) handlePeerEnum.Dispose();
            } 

            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Leaving InternalGetApplications(). " + 
            "Returning collection with {0} objects.", peerObjectColl.Count); 

            return peerObjectColl; 
        }

        public abstract PeerInvitationResponse Invite();
 
        public abstract PeerInvitationResponse Invite(PeerApplication applicationToInvite, string message, byte[] invitationData);
 
        // 
        // Invites an endpoint with passed data. Includes a contact if it was passed in.
        // 
        // 
        // 
        // 
        //  
        // 
        //  
        //  
        // 
        //  
        // 
        // 
        // 
        //  
        // 
        //  
        //  
        // 
        //  
        [System.Security.SecurityCritical]
        internal static PeerInvitationResponse InternalInviteEndPoint(Guid applicationToInviteGuid,
                                                                string message, byte[] invitationData,
                                                                PeerEndPoint peerEndPoint, PeerContact peerContact) 
        {
 
            if (Logging.P2PTraceSource.Switch.ShouldTrace(TraceEventType.Information)){ 
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Entering InternalInviteEndPoint() with the following information.");
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Invitation Message: ", message); 
                if (Logging.P2PTraceSource.Switch.ShouldTrace(TraceEventType.Verbose) && (invitationData != null)){
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "\tInvitation data:");
                    Logging.DumpData(Logging.P2PTraceSource, TraceEventType.Verbose, Logging.P2PTraceSource.MaxDataSize, invitationData, 0, invitationData.Length);
                } 
                else
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Invitation Data length: ", (invitationData != null ? invitationData.Length : 0)); 
 
                if (peerEndPoint != null) peerEndPoint.TracePeerEndPoint();
            } 

            PEER_INVITATION pi = new PEER_INVITATION();
            pi.applicationId = CollaborationHelperFunctions.ConvertGuidToGUID(applicationToInviteGuid);
            pi.pwzMessage = message; 

            SafeCollabMemory data = null; 
            pi.applicationData.cbData = (invitationData != null) ? (UInt32)invitationData.Length : 0; 

            // 
            // Marshal Invitation Data
            //
            if ((invitationData != null) && (invitationData.Length > 0))
            { 
                data = new SafeCollabMemory(invitationData.Length);
                pi.applicationData.pbData = data.DangerousGetHandle(); 
                Marshal.Copy(invitationData, 0, pi.applicationData.pbData, invitationData.Length); 
            }
            else 
                pi.applicationData.pbData = IntPtr.Zero;


            PEER_ENDPOINT pep = new PEER_ENDPOINT(); 
            pep.peerAddress = CollaborationHelperFunctions.ConvertIPEndpointToPEER_ADDRESS(peerEndPoint.EndPoint);
 
            // 
            // Pin data to pass to native
            // 
            GCHandle pepName = new GCHandle();

            if (peerEndPoint.Name != null){
                pepName = GCHandle.Alloc(peerEndPoint.Name, GCHandleType.Pinned); 
                pep.pwzEndpointName = pepName.AddrOfPinnedObject();
            } 
            GCHandle peerEP = GCHandle.Alloc(pep, GCHandleType.Pinned); 
            IntPtr ptrPeerEP = peerEP.AddrOfPinnedObject();
 
            SafeCollabData safeResponse = null;
            PeerInvitationResponse peerInvResponse = null;
            int errorCode;
 
            try{
                // 
                // Make native call with endpoint with/without contact 
                //
                if (peerContact != null){ 

                    //
                    // Generate native contact
                    // 
                    SafeCollabMemory safeCredentials = null;
                    PEER_CONTACT pc = CollaborationHelperFunctions.ConvertPeerContactToPEER_CONTACT(peerContact, ref safeCredentials); 
 
                    try{
                        errorCode = UnsafeCollabNativeMethods.PeerCollabInviteContact(ref pc, 
                                                                                        ptrPeerEP,
                                                                                        ref pi,
                                                                                        out safeResponse);
                    } 
                    finally{
                        if (safeCredentials != null) safeCredentials.Dispose(); 
                    } 
                }
                else 
                    errorCode = UnsafeCollabNativeMethods.PeerCollabInviteEndpoint(ptrPeerEP, ref pi, out safeResponse);

                if (errorCode != 0){
                    if ((errorCode == UnsafeCollabReturnCodes.PEER_E_TIMEOUT) || (errorCode == UnsafeCollabReturnCodes.ERROR_TIMEOUT)){ 
                        Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0,
                            "Timed out. Leaving InternalInviteEndPoint() with InvitationResponseType expired."); 
 
                        return new PeerInvitationResponse(PeerInvitationResponseType.Expired);
                    } 

                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, ((peerContact != null) ? "PeerCollabInviteContact" : "PeerCollabInviteEndpoint")
                        + " returned with errorcode {0}", errorCode);
                    throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_InviteFailed), errorCode); 
                }
 
                if (!safeResponse.IsInvalid){ 
                    PEER_INVITATION_RESPONSE pir = (PEER_INVITATION_RESPONSE)Marshal.PtrToStructure(safeResponse.DangerousGetHandle(),
                                                                                                    typeof(PEER_INVITATION_RESPONSE)); 
                    peerInvResponse = new PeerInvitationResponse(pir.action);
                }
            }
            finally{ 
                if (safeResponse != null) safeResponse.Dispose();
                if (pepName.IsAllocated) pepName.Free(); 
                if (peerEP.IsAllocated) peerEP.Free(); 
            }
 

            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0,
                "Leaving InternalInviteEndPoint() with InvitationResponse {0}.", peerInvResponse);
 
            return peerInvResponse;
        } 
 

        private event EventHandler m_inviteCompleted; 
        public event EventHandler InviteCompleted
        {
            add{
                if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName); 
                PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
 
                m_inviteCompleted += value; 
            }
            remove{ 
                if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
                PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();

                m_inviteCompleted -= value; 
            }
        } 
 
        public abstract void InviteAsync(Object userToken);
 
        public abstract void InviteAsync(   PeerApplication applicationToInvite, string message,
                                            byte[] invitationData, Object userToken);

 
        #region Invite Async variables
        SendOrPostCallback OnInviteCompletedDelegate; 
 
        internal Dictionary m_inviteAsyncHelperList = new Dictionary();
        #endregion 

        // 
        // 
        //  
        [System.Security.SecurityCritical]
        internal void InternalInviteAsync(Guid applicationToInviteGuid, 
                                        string message, byte[] invitationData, 
                                        PeerEndPointCollection peerEndPoints, PeerContact peerContact,
                                        Object userToken) 
        {
            InviteAsyncHelper inviteAsyncHelper = null;

            // 
            //The userToken can't be duplicate of what is in the
            //current list. These are the requriments for the new Async model 
            //that supports multiple outstanding async calls 
            //
            int newTraceEventId = NewTraceEventId; 

            lock (m_inviteAsyncHelperList){
                if (m_inviteAsyncHelperList.ContainsKey(userToken)){
                    throw new ArgumentException(SR.GetString(SR.DuplicateUserToken)); 
                }
 
                inviteAsyncHelper = new InviteAsyncHelper(  peerContact, this, peerEndPoints, 
                                                            applicationToInviteGuid, message,
                                                            invitationData, userToken, newTraceEventId); 
                m_inviteAsyncHelperList[userToken] = inviteAsyncHelper;
            }

            try{ 
                //
                //Start resolution on that resolver 
                // 
                inviteAsyncHelper.InviteAsync();
            } 
            catch{
                //
                //If an exception happens clear the userState from the
                //list so that that token can be reused 
                //
                lock (m_inviteAsyncHelperList){ 
                    m_inviteAsyncHelperList.Remove(userToken); 
                }
                throw; 
            }

        }
 
        protected virtual void OnInviteCompleted(InviteCompletedEventArgs e)
        { 
            EventHandler handlerCopy = m_inviteCompleted; 

            if (handlerCopy != null){ 
                handlerCopy(this, e);
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Fired the invite completed event callback.");
            }
        } 

        void InviteCompletedWaitCallback(object operationState) 
        { 
            OnInviteCompleted((InviteCompletedEventArgs)operationState);
        } 

        internal void PrepareToRaiseInviteCompletedEvent(AsyncOperation asyncOP, InviteCompletedEventArgs args)
        {
            lock (m_inviteAsyncHelperList){ 
                InviteAsyncHelper helper = m_inviteAsyncHelperList[args.UserState];
                if (helper == null){ 
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Critical, 0, "userState for which we are about to call Completed event does not exist in the pending async list"); 
                }else{
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Critical, helper.TraceEventId, 
                         "userState {0} is being removed from the pending async list", args.UserState.GetHashCode());
                    m_inviteAsyncHelperList.Remove(args.UserState);
                }
            } 
            asyncOP.PostOperationCompleted(OnInviteCompletedDelegate, args);
        } 
 
        // 
        //  
        // 
        [System.Security.SecurityCritical]
        public void InviteAsyncCancel(Object userToken)
        { 
            if (userToken == null)
                throw new ArgumentNullException("userToken"); 
 
            InviteAsyncHelper helper;
            lock (m_inviteAsyncHelperList){ 
                if (!m_inviteAsyncHelperList.TryGetValue(userToken, out helper)){
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Warning, 0, "InviteAsyncCancel called with a userState token that is not in the pending async list - returning");
                    return;
                } 
            }
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, helper.TraceEventId, 
                    "Proceeding to cancel the pending async"); 
            helper.CancelAsync(userToken);
        } 

        //
        // Used to track inviteasynchelpers
        // 
        private static int s_TraceEventId = 1;
        internal static int NewTraceEventId 
        { 
            get{
                Interlocked.CompareExchange(ref s_TraceEventId, 0, int.MaxValue); 
                Interlocked.Increment(ref s_TraceEventId);
                return s_TraceEventId;
            }
        } 

        public bool Equals(Peer other) 
        { 
            if (other != null){
                if (other.PeerEndPoints != null){ 
                    return other.PeerEndPoints.Equals(PeerEndPoints);
                }
            }
            return false; 
        }
 
        public override string ToString() 
        {
            return PeerEndPoints.ToString(); 
        }

        private bool m_Disposed;
 
        public void Dispose()
        { 
 
            Dispose(true);
            GC.SuppressFinalize(this); 
        }

        // 
        //  
        // 
        [System.Security.SecurityCritical] 
        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter, SerializationFormatter = true)] 
        void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
        { 
            GetObjectData(info, context);
        }

        ///  
        /// This is made virtual so that derived types can be implemented correctly
        ///  
        ///  
        /// 
        [SecurityPermission(SecurityAction.LinkDemand, SerializationFormatter = true)] 
        protected virtual void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("_PeerEndPoints", PeerEndPoints);
        } 

        protected virtual void Dispose(bool disposing) 
        { 
            if (!m_Disposed){
                m_Disposed = true; 
            }
        }
    }
 
    /// 
    /// Helps in all the async invites sent from Peer, PeerContact and PeerNearMe 
    ///  
    internal class InviteAsyncHelper : IDisposable
    { 
        internal object m_userState;
        internal SafeCollabInvite m_SafeCollabInvite;
        internal AutoResetEvent m_InviteEvent = new AutoResetEvent(false);
 
        //
        //The WaitHandle that hooks up a callback to the 
        //event 
        //
        internal RegisteredWaitHandle m_RegisteredWaitHandle; 

        //
        //Disposed or not
        // 
        internal bool m_Disposed;
 
        internal bool m_Cancelled; 

        // 
        //Async operation to ensure synchornization
        //context
        //
        AsyncOperation m_AsyncOp; 

        // 
        //A link to the resolver to avoid 
        //circular dependencies and enable GC
        // 
        WeakReference m_peerWeakReference;

        //
        //Lock to make sure things don't mess up stuff 
        //
        object m_Lock = new Object(); 
 
        //
        //EventID or Just a tracking id 
        //
        int m_TraceEventId;

        // 
        // Store the latest exception
        // 
        Exception m_latestException; 

        // 
        // Stores reponses from all endpoints
        //
        Collection m_responses = new Collection();
 
        //
        // Callback called 
        // 
        bool m_Completed;
 
        //
        // Used to ensure only on thread calls the callback
        //
        bool m_aboutToFireCallback; 
        object m_aboutToFireCallbackLock = new object();
 
        // 
        // Number of reponses received
        // 
        int m_numberOfResponses;

        PeerContact m_peerContact;
        PeerEndPointCollection m_peerEndPoints; 
        Guid m_applicationId;
        string m_message; 
        byte[] m_inviteData; 

        internal InviteAsyncHelper( PeerContact peerContact, Peer parentPeer, PeerEndPointCollection peerEndPoints, 
                                    Guid applicationId, string message, byte[] inviteData,
                                    object userState, int NewTraceEventId)
        {
            m_userState = userState; 
            m_peerContact = peerContact;
            m_applicationId = applicationId; 
            m_message = message; 
            m_inviteData = inviteData;
            m_peerEndPoints = peerEndPoints; 
            m_TraceEventId = NewTraceEventId;
            m_peerWeakReference = new WeakReference(parentPeer);

            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId, "New InviteAsyncHelper created with TraceEventID {0}", m_TraceEventId); 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId,
                "\tPeerContact: {0}, App Guid: {1}, userState {2}, ParentReference {3}", 
                (m_peerContact != null ? m_peerContact.ToString() : "null"), 
                applicationId.ToString(),
                userState.GetHashCode(), 
                m_peerWeakReference.Target.GetHashCode()
                );

        } 

        //  
        //  
        // 
        //  
        // 
        // 
        // 
        //  
        // 
        //  
        //  
        // 
        [System.Security.SecurityCritical] 
        internal void InviteAsync()
        {
            if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId,
            "InviteAsync called"); 
            // 
            //First wire up a callback
            // 

            m_RegisteredWaitHandle = ThreadPool.RegisterWaitForSingleObject(m_InviteEvent, //Event that triggers the callback
                                                    new WaitOrTimerCallback(InviteCallback), //callback to be called
                                                    null, //state to be passed 
                                                    -1,   //Timeout - aplicable only for timers not for events
                                                    false //call us everytime the event is set not just one time 
                                                    ); 

            // 
            //Now call the native API to start the resolution
            //process save the handle for later
            //
 
            PEER_INVITATION pi = new PEER_INVITATION();
            pi.applicationId = CollaborationHelperFunctions.ConvertGuidToGUID(m_applicationId); 
            pi.pwzMessage = m_message; 

            SafeCollabMemory data = null; 
            pi.applicationData.cbData = (m_inviteData != null) ? (UInt32)m_inviteData.Length : 0;

            if ((m_inviteData != null) && (m_inviteData.Length > 0)){
                data = new SafeCollabMemory(m_inviteData.Length); 
                pi.applicationData.pbData = data.DangerousGetHandle();
                Marshal.Copy(m_inviteData, 0, pi.applicationData.pbData, m_inviteData.Length); 
            } 
            else
                pi.applicationData.pbData = IntPtr.Zero; 

            foreach (PeerEndPoint peerEndPoint in m_peerEndPoints)
            {
                try{ 
                    InviteAsyncEndPoint(peerEndPoint, pi);
                } 
                catch (PeerToPeerException){ 
                    if (!m_SafeCollabInvite.IsInvalid && !m_SafeCollabInvite.IsClosed){
                        m_SafeCollabInvite.Dispose(); 
                    }
                    m_RegisteredWaitHandle.Unregister(null);
                    m_RegisteredWaitHandle = null;
                    throw; 
                }
            } 
 
            //
            //Create an async operation with the given 
            //user state
            //
            m_AsyncOp = AsyncOperationManager.CreateOperation(m_userState);
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId,
            "Leaving InviteAsync."); 
        } 

        //  
        // 
        // 
        // 
        //  
        // 
        //  
        //  
        // 
        //  
        // 
        // 
        // 
        [System.Security.SecurityCritical] 
        internal void InviteAsyncEndPoint(PeerEndPoint peerEndPoint, PEER_INVITATION pi)
        { 
            if (Logging.P2PTraceSource.Switch.ShouldTrace(TraceEventType.Information)){ 
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "InviteAsyncEndPoint() is called with the following Info");
                peerEndPoint.TracePeerEndPoint(); 
            }

            PEER_ENDPOINT pep = new PEER_ENDPOINT();
            pep.peerAddress = CollaborationHelperFunctions.ConvertIPEndpointToPEER_ADDRESS(peerEndPoint.EndPoint); 

            // 
            // Pin all the data to pass to native 
            //
            GCHandle pepName = new GCHandle(); 

            if (peerEndPoint.Name != null){
                pepName = GCHandle.Alloc(peerEndPoint.Name, GCHandleType.Pinned);
                pep.pwzEndpointName = pepName.AddrOfPinnedObject(); 
            }
            GCHandle peerEP = GCHandle.Alloc(pep, GCHandleType.Pinned); 
            IntPtr ptrPeerEP = peerEP.AddrOfPinnedObject(); 

            int errorCode; 
            try{
                //
                // Make native call with endpoint with/without contact
                // 
                if (m_peerContact != null){
 
                    // 
                    // Generate native contact
                    // 
                    SafeCollabMemory safeCredentials = null;
                    PEER_CONTACT pc = CollaborationHelperFunctions.ConvertPeerContactToPEER_CONTACT(m_peerContact, ref safeCredentials);

                    try{ 
                        errorCode = UnsafeCollabNativeMethods.PeerCollabAsyncInviteContact(  ref pc,
                                                                                        ptrPeerEP, 
                                                                                        ref pi, 
                                                                                        m_InviteEvent.SafeWaitHandle,
                                                                                        out m_SafeCollabInvite); 
                    }
                    finally{
                        if (safeCredentials != null) safeCredentials.Dispose();
                    } 
                }
                else 
                    errorCode = UnsafeCollabNativeMethods.PeerCollabAsyncInviteEndpoint(ptrPeerEP, ref pi, 
                                                                                m_InviteEvent.SafeWaitHandle,
                                                                                out m_SafeCollabInvite); 

            }
            finally
            { 
                if (pepName.IsAllocated) pepName.Free();
                if (peerEP.IsAllocated) peerEP.Free(); 
            } 

            if (errorCode != 0){ 
                throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_AsyncInviteFailed), errorCode);
            }
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId, "Leaving InviteAsyncEndPoint.");
 
        }
 
        // 
        // Invite callback. Will fire only if i has at least one accepted or when it has all the responses
        // from all the endpoints 
        //
        // 
        // 
        //  
        // 
        //  
        //  
        // 
        //  
        // 
        [System.Security.SecurityCritical]
        internal void InviteCallback(object state, bool timedOut)
        { 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId, "Entering InviteCallback.");
 
            SafeCollabData response = null; 

            int errorCode = 0; 
            InviteCompletedEventArgs inviteCompletedArgs = null;
            Peer peer = null;
            bool fireCallback = false;
            PEER_INVITATION_RESPONSE pir = new PEER_INVITATION_RESPONSE(); 

            try 
            { 
                lock (m_Lock){
                    if (m_Cancelled || m_Completed){ 
                        Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId, "Invite cancelled({0}) or completed({1}). Returning without doing anything.", m_Cancelled, m_Completed);
                        return;
                    }
                    errorCode = UnsafeCollabNativeMethods.PeerCollabGetInvitationResponse(m_SafeCollabInvite, out response); 
                }
 
                if ((errorCode != 0) && (errorCode != UnsafeCollabReturnCodes.PEER_E_TIMEOUT)){ 
                    m_latestException = PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_AsyncInviteException), errorCode);
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId, "Got an exception {0}. Storing it in latest exception.", m_latestException); 
                }
                else
                {
                    pir = (PEER_INVITATION_RESPONSE)Marshal.PtrToStructure(response.DangerousGetHandle(), 
                                                    typeof(PEER_INVITATION_RESPONSE));
 
                    // 
                    // Store the responses
                    // 
                    lock (m_responses)
                        m_responses.Add(pir.action);

                    if (pir.action == PeerInvitationResponseType.Accepted){ 
                        inviteCompletedArgs = new InviteCompletedEventArgs(new PeerInvitationResponse(pir.action), null, false,
                                                                            m_AsyncOp.UserSuppliedState); 
                        fireCallback = true; 

                        // 
                        // Got an accepted. unregister callback to disable all othe other endpoint callbacks
                        //

                        Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId, "Found an accepted. About to fire callback."); 

                        m_RegisteredWaitHandle.Unregister(null); 
                    } 
                }
 

                Interlocked.Increment(ref m_numberOfResponses);

                if ((!fireCallback) && (m_numberOfResponses == m_peerEndPoints.Count) && (!m_aboutToFireCallback)){ 
                    //
                    // Two threads can be here at the same time when all the responses have been 
                    // received and only one should be allowed to call the callback 
                    //
                    lock (m_aboutToFireCallbackLock){ 
                        if (m_aboutToFireCallback)
                            return;

                        m_aboutToFireCallback = true; 

                        bool foundDeclined = false; 
                        bool foundExpired = false; 

                        fireCallback = true; 

                        //
                        // Got all responses; make a decision
                        // 

                        foreach (PeerInvitationResponseType responseType in m_responses) 
                        { 
                            if (responseType == PeerInvitationResponseType.Expired){
                                foundExpired = true; 
                            }
                            else if (responseType == PeerInvitationResponseType.Declined){
                                foundDeclined = true;
                                break; 
                            }
                        } 
 
                        //
                        // If at least one is declined, return declined. 
                        //

                        if (foundDeclined){
                            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId, "Got a declined invite response."); 
                            inviteCompletedArgs = new InviteCompletedEventArgs(new PeerInvitationResponse(PeerInvitationResponseType.Declined), null, false,
                                                        m_AsyncOp.UserSuppliedState); 
                        } 
                        else if (foundExpired){
                            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId, "Got an expired invite response but no accepted or declined."); 
                            inviteCompletedArgs = new InviteCompletedEventArgs(new PeerInvitationResponse(PeerInvitationResponseType.Expired), null, false,
                                                        m_AsyncOp.UserSuppliedState);
                        }
                        else{ 
                            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId, "Got all error responses");
                            inviteCompletedArgs = new InviteCompletedEventArgs(null, (m_latestException != null ? m_latestException : new PeerToPeerException("InviteAsync failure.")), false, 
                                                        m_AsyncOp.UserSuppliedState); 
                        }
                    } 
                }
                //
                //Last chance to prevent the callback
                // 
                if (fireCallback){
                    peer = m_peerWeakReference.Target as Peer; 
                    if (!m_Completed && (peer != null)){ 
                        lock (m_Lock){
                            // 
                            // Async op may be cancelled already
                            //
                            if (!m_Completed && !m_Cancelled){
 
                                //
                                //Mark as completed so that this gets fired only once 
                                // 
                                m_Completed = true;
                                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId, "Firing callback with response type {0}.", inviteCompletedArgs.InviteResponse); 
                                peer.PrepareToRaiseInviteCompletedEvent(m_AsyncOp, inviteCompletedArgs);
                            }
                        }
                    } 
                }
            } 
            finally{ 
                if (response != null) response.Dispose();
            } 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId, "Leaving InviteCallback.");

       }
 
        // 
        //  
        //  
        // 
        //  
        [System.Security.SecurityCritical]
        public void ContinueCancelCallback(object state)
        {
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId, "Entering ContineCancelCallback."); 

            try{ 
                lock (m_Lock){ 
                    if (m_Completed) return;
                    m_Cancelled = true; 

                    int errorCode = UnsafeCollabNativeMethods.PeerCollabCancelInvitation(m_SafeCollabInvite);
                    if (errorCode != 0){
                        Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabCancelInvitation returned with errorcode {0}", errorCode); 
                    }
 
                    m_SafeCollabInvite.Dispose(); 
                }
 
                Peer peer = m_peerWeakReference.Target as Peer;
                if (peer != null){
                    InviteCompletedEventArgs e = new InviteCompletedEventArgs(null, null, true, m_AsyncOp.UserSuppliedState);
                    peer.PrepareToRaiseInviteCompletedEvent(m_AsyncOp, e); 
                }
            } 
            catch (ObjectDisposedException ex){ 
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Critical, 0, "Exception while cancelling the call {0}", ex);
            } 

            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId, "Leaving ContineCancelCallback.");

        } 

        //  
        //  
        // 
        [System.Security.SecurityCritical] 
        public void CancelAsync(object state)
        {
            //
            //Defer the work to a callback 
            //
 
            ThreadPool.QueueUserWorkItem(new WaitCallback(ContinueCancelCallback), state); 
        }
 
        // 
        // 
        // 
        [System.Security.SecurityCritical] 
        public void Dispose()
        { 
            Dispose(true); 
            GC.SuppressFinalize(this);
        } 

        // 
        // 
        //  
        // 
        //  
        [System.Security.SecurityCritical] 
        public void Dispose(bool disposing)
        { 
            if (!m_Disposed){
                if (!m_SafeCollabInvite.IsInvalid){
                    m_SafeCollabInvite.Dispose();
                } 

                if (m_RegisteredWaitHandle != null){ 
                    m_RegisteredWaitHandle.Unregister(null); 
                    m_RegisteredWaitHandle = null;
                } 

                if (m_InviteEvent != null){
                    m_InviteEvent.Close();
                } 
            }
            m_Disposed = true; 
        } 

        public override int GetHashCode() 
        {
            return m_TraceEventId;
        }
 
        internal int TraceEventId
        { 
            get{ 
                return m_TraceEventId;
            } 
        }

    }
 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK