//------------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//------------------------------------------------------------------------------
namespace System.Net.PeerToPeer.Collaboration
{
using System;
using System.Net.Mail;
using System.Threading;
using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;
using System.Diagnostics;
using System.ComponentModel;
using System.Runtime.Serialization;
///
/// This class handles events specific to my contact in windows collaboration and
/// also acts as a conventional peer contact.
///
[Serializable]
internal class MyContact : PeerContact, ISerializable
{
//
//
//
[System.Security.SecurityCritical]
internal MyContact() { }
///
/// Constructor to enable serialization
///
[System.Security.SecurityCritical]
internal MyContact(SerializationInfo serializationInfo, StreamingContext streamingContext)
: base(serializationInfo, streamingContext)
{ }
internal override bool InternalIsSubscribed()
{
return true;
}
internal override SubscriptionType InternalSubscribeAllowedGet()
{
return SubscriptionType.Allowed;
}
internal override void InternalSubscribeAllowedSet(SubscriptionType value)
{
throw new PeerToPeerException(SR.GetString(SR.Collab_SubscribeLocalContactFailed));
}
//
// Event to handle presence changed for my contact
//
private event EventHandler m_presenceChanged;
//
//
//
//
//
//
//
[System.Security.SecurityCritical]
internal override void AddPresenceChanged(EventHandler callback)
{
//
// Register a wait handle if one has not been registered already
//
lock (LockPresenceChangedEvent){
if (m_presenceChanged == null){
PresenceChangedEvent = new AutoResetEvent(false);
//
// Register callback with a wait handle
//
PresenceChangedWaitHandle = ThreadPool.RegisterWaitForSingleObject(PresenceChangedEvent, //Event that triggers the callback
new WaitOrTimerCallback(PresenceChangedCallback), //callback to be called
null, //state to be passed
-1, //Timeout - aplicable only for timers
false //call us everytime the event is set
);
PEER_COLLAB_EVENT_REGISTRATION pcer = new PEER_COLLAB_EVENT_REGISTRATION();
pcer.eventType = PeerCollabEventType.MyPresenceChanged;
pcer.pInstance = IntPtr.Zero;
//
// Register event with collab
//
int errorCode = UnsafeCollabNativeMethods.PeerCollabRegisterEvent(
PresenceChangedEvent.SafeWaitHandle,
1,
ref pcer,
out m_safePresenceChangedEvent);
if (errorCode != 0){
Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabRegisterEvent returned with errorcode {0}", errorCode);
throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_PresenceChangedRegFailed), errorCode);
}
}
m_presenceChanged += callback;
}
Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "AddMyPresenceChanged() successful.");
}
//
//
//
[System.Security.SecurityCritical]
internal override void RemovePresenceChanged(EventHandler callback)
{
Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "RemovePresenceChanged() called.");
lock (LockPresenceChangedEvent){
m_presenceChanged -= callback;
if (m_presenceChanged == null){
CleanContactPresenceEventVars();
}
}
Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "RemovePresenceChanged() successful.");
}
protected override void OnPresenceChanged(PresenceChangedEventArgs presenceChangedArgs)
{
EventHandler handlerCopy = m_presenceChanged;
if (handlerCopy != null){
handlerCopy(this, presenceChangedArgs);
Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Fired the presence changed event callback.");
}
}
//
//
//
//
//
//
//
//
//
//
//
[System.Security.SecurityCritical]
internal override void PresenceChangedCallback(object state, bool timedOut)
{
SafeCollabData eventData = null;
int errorCode = 0;
Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "PresenceChangedCallback() called.");
if (m_Disposed) return;
while (true)
{
PresenceChangedEventArgs presenceChangedArgs = null;
//
// Get the event data for the fired event
//
try{
lock (LockPresenceChangedEvent){
if (m_safePresenceChangedEvent.IsInvalid) return;
errorCode = UnsafeCollabNativeMethods.PeerCollabGetEventData(m_safePresenceChangedEvent,
out eventData);
}
if (errorCode == UnsafeCollabReturnCodes.PEER_S_NO_EVENT_DATA)
break;
else if (errorCode != 0){
Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabGetEventData returned with errorcode {0}", errorCode);
throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_GetPresenceChangedDataFailed), errorCode);
}
PEER_COLLAB_EVENT_DATA ped = (PEER_COLLAB_EVENT_DATA)Marshal.PtrToStructure(eventData.DangerousGetHandle(),
typeof(PEER_COLLAB_EVENT_DATA));
if (ped.eventType == PeerCollabEventType.MyPresenceChanged){
PEER_EVENT_PRESENCE_CHANGED_DATA presenceData = ped.presenceChangedData;
PeerPresenceInfo peerPresenceInfo = null;
if (presenceData.pPresenceInfo != IntPtr.Zero)
{
PEER_PRESENCE_INFO ppi = (PEER_PRESENCE_INFO)Marshal.PtrToStructure(presenceData.pPresenceInfo, typeof(PEER_PRESENCE_INFO));
peerPresenceInfo = new PeerPresenceInfo();
peerPresenceInfo.PresenceStatus = ppi.status;
peerPresenceInfo.DescriptiveText = ppi.descText;
}
PeerEndPoint peerEndPoint = null;
if (presenceData.pEndPoint != IntPtr.Zero){
PEER_ENDPOINT pe = (PEER_ENDPOINT)Marshal.PtrToStructure(presenceData.pEndPoint, typeof(PEER_ENDPOINT));
peerEndPoint = CollaborationHelperFunctions.ConvertPEER_ENDPOINTToPeerEndPoint(pe);
}
presenceChangedArgs = new PresenceChangedEventArgs(peerEndPoint,
null,
presenceData.changeType,
peerPresenceInfo);
}
}
finally{
if (eventData != null) eventData.Dispose();
}
//
// Fire the callback with the marshalled event args data
//
if(presenceChangedArgs!= null)
OnPresenceChanged(presenceChangedArgs);
}
Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Leaving PresenceChangedCallback().");
}
//
// Event to handle application changed for my contact
//
private event EventHandler m_applicationChanged;
//
//
//
//
//
//
//
[System.Security.SecurityCritical]
internal override void AddApplicationChanged(EventHandler callback)
{
//
// Register a wait handle if one has not been registered already
//
lock (LockAppChangedEvent){
if (m_applicationChanged == null){
AppChangedEvent = new AutoResetEvent(false);
//
// Register callback with a wait handle
//
AppChangedWaitHandle = ThreadPool.RegisterWaitForSingleObject(AppChangedEvent, //Event that triggers the callback
new WaitOrTimerCallback(ApplicationChangedCallback), //callback to be called
null, //state to be passed
-1, //Timeout - aplicable only for timers
false //call us everytime the event is set
);
PEER_COLLAB_EVENT_REGISTRATION pcer = new PEER_COLLAB_EVENT_REGISTRATION();
pcer.eventType = PeerCollabEventType.MyApplicationChanged;
pcer.pInstance = IntPtr.Zero;
//
// Register event with collab
//
int errorCode = UnsafeCollabNativeMethods.PeerCollabRegisterEvent(
AppChangedEvent.SafeWaitHandle,
1,
ref pcer,
out m_safeAppChangedEvent);
if (errorCode != 0){
Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabRegisterEvent returned with errorcode {0}", errorCode);
throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_ApplicationChangedRegFailed), errorCode);
}
}
m_applicationChanged += callback;
}
Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "AddApplicationChanged() successful.");
}
//
//
//
[System.Security.SecurityCritical]
internal override void RemoveApplicationChanged(EventHandler callback)
{
Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "RemoveApplicationChanged() called.");
lock (LockAppChangedEvent){
m_applicationChanged -= callback;
if (m_applicationChanged == null){
CleanContactObjEventVars();
}
}
Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "RemoveApplicationChanged() successful.");
}
protected override void OnApplicationChanged(ApplicationChangedEventArgs appChangedArgs)
{
EventHandler handlerCopy = m_applicationChanged;
if (handlerCopy != null){
handlerCopy(this, appChangedArgs);
Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Fired the application changed event callback.");
}
}
//
//
//
//
//
//
//
//
//
//
//
//
[System.Security.SecurityCritical]
internal override void ApplicationChangedCallback(object state, bool timedOut)
{
SafeCollabData eventData = null;
int errorCode = 0;
Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "ApplicationChangedCallback() called.");
if (m_Disposed) return;
while (true)
{
ApplicationChangedEventArgs appChangedArgs = null;
//
// Get the event data for the fired event
//
try{
lock (LockAppChangedEvent){
if (m_safeAppChangedEvent.IsInvalid) return;
errorCode = UnsafeCollabNativeMethods.PeerCollabGetEventData(m_safeAppChangedEvent,
out eventData);
}
if (errorCode == UnsafeCollabReturnCodes.PEER_S_NO_EVENT_DATA)
break;
else if (errorCode != 0){
Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabGetEventData returned with errorcode {0}", errorCode);
throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_GetApplicationChangedDataFailed), errorCode);
}
PEER_COLLAB_EVENT_DATA ped = (PEER_COLLAB_EVENT_DATA)Marshal.PtrToStructure(eventData.DangerousGetHandle(),
typeof(PEER_COLLAB_EVENT_DATA));
if (ped.eventType == PeerCollabEventType.MyApplicationChanged){
PEER_EVENT_APPLICATION_CHANGED_DATA appData = ped.applicationChangedData;
PEER_APPLICATION pa = (PEER_APPLICATION)Marshal.PtrToStructure(appData.pApplication, typeof(PEER_APPLICATION));
PeerApplication peerApplication = CollaborationHelperFunctions.ConvertPEER_APPLICATIONToPeerApplication(pa); ;
PeerEndPoint peerEndPoint = null;
if (appData.pEndPoint != IntPtr.Zero){
PEER_ENDPOINT pe = (PEER_ENDPOINT)Marshal.PtrToStructure(appData.pEndPoint, typeof(PEER_ENDPOINT));
peerEndPoint = CollaborationHelperFunctions.ConvertPEER_ENDPOINTToPeerEndPoint(pe);
}
appChangedArgs = new ApplicationChangedEventArgs(peerEndPoint,
null,
appData.changeType,
peerApplication);
}
}
finally{
if (eventData != null) eventData.Dispose();
}
//
// Fire the callback with the marshalled event args data
//
if(appChangedArgs != null)
OnApplicationChanged(appChangedArgs);
}
Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Leaving ApplicationChangedCallback().");
}
//
// Event to handle object changed for my contact
//
private event EventHandler m_objectChanged;
//
//
//
//
//
//
//
[System.Security.SecurityCritical]
internal override void AddObjectChangedEvent(EventHandler callback)
{
//
// Register a wait handle if one has not been registered already
//
lock (LockObjChangedEvent)
{
if (m_objectChanged == null)
{
ObjChangedEvent = new AutoResetEvent(false);
//
// Register callback with a wait handle
//
ObjChangedWaitHandle = ThreadPool.RegisterWaitForSingleObject(ObjChangedEvent, //Event that triggers the callback
new WaitOrTimerCallback(ObjectChangedCallback), //callback to be called
null, //state to be passed
-1, //Timeout - aplicable only for timers
false //call us everytime the event is set
);
PEER_COLLAB_EVENT_REGISTRATION pcer = new PEER_COLLAB_EVENT_REGISTRATION();
pcer.eventType = PeerCollabEventType.MyObjectChanged;
pcer.pInstance = IntPtr.Zero;
//
// Register event with collab
//
int errorCode = UnsafeCollabNativeMethods.PeerCollabRegisterEvent(
ObjChangedEvent.SafeWaitHandle,
1,
ref pcer,
out m_safeObjChangedEvent);
if (errorCode != 0)
{
Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabRegisterEvent returned with errorcode {0}", errorCode);
throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_ObjectChangedRegFailed), errorCode);
}
}
m_objectChanged += callback;
}
Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "AddObjectChanged() successful.");
}
//
//
//
[System.Security.SecurityCritical]
internal override void RemoveObjectChangedEvent(EventHandler callback)
{
Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "RemoveObjectChangedEvent() called.");
lock (LockObjChangedEvent){
m_objectChanged -= callback;
if (m_objectChanged == null){
CleanContactObjEventVars();
}
}
Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "RemoveObjectChangedEvent() successful.");
}
protected override void OnObjectChanged(ObjectChangedEventArgs objChangedArgs)
{
EventHandler handlerCopy = m_objectChanged;
if (handlerCopy != null){
if (SynchronizingObject != null && SynchronizingObject.InvokeRequired)
SynchronizingObject.BeginInvoke(handlerCopy, new object[] { this, objChangedArgs });
else
handlerCopy(this, objChangedArgs);
Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Fired the object changed event callback.");
}
}
//
//
//
//
//
//
//
//
//
//
//
//
[System.Security.SecurityCritical]
internal override void ObjectChangedCallback(object state, bool timedOut)
{
SafeCollabData eventData = null;
int errorCode = 0;
Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "ObjectChangedCallback() called.");
if (m_Disposed) return;
while (true){
ObjectChangedEventArgs objChangedArgs = null;
//
// Get the event data for the fired event
//
try{
lock (LockObjChangedEvent){
if (m_safeObjChangedEvent.IsInvalid) return;
errorCode = UnsafeCollabNativeMethods.PeerCollabGetEventData(m_safeObjChangedEvent,
out eventData);
}
if (errorCode == UnsafeCollabReturnCodes.PEER_S_NO_EVENT_DATA)
break;
else if (errorCode != 0){
Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabGetEventData returned with errorcode {0}", errorCode);
throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_GetObjectChangedDataFailed), errorCode);
}
PEER_COLLAB_EVENT_DATA ped = (PEER_COLLAB_EVENT_DATA)Marshal.PtrToStructure(eventData.DangerousGetHandle(),
typeof(PEER_COLLAB_EVENT_DATA));
if (ped.eventType == PeerCollabEventType.MyObjectChanged){
PEER_EVENT_OBJECT_CHANGED_DATA objData = ped.objectChangedData;
PEER_OBJECT po = (PEER_OBJECT)Marshal.PtrToStructure(objData.pObject, typeof(PEER_OBJECT));
PeerObject peerObject = CollaborationHelperFunctions.ConvertPEER_OBJECTToPeerObject(po); ;
PeerEndPoint peerEndPoint = null;
if (objData.pEndPoint != IntPtr.Zero){
PEER_ENDPOINT pe = (PEER_ENDPOINT)Marshal.PtrToStructure(objData.pEndPoint, typeof(PEER_ENDPOINT));
peerEndPoint = CollaborationHelperFunctions.ConvertPEER_ENDPOINTToPeerEndPoint(pe);
}
objChangedArgs = new ObjectChangedEventArgs(peerEndPoint,
null,
objData.changeType,
peerObject);
}
}
finally{
if (eventData != null) eventData.Dispose();
}
//
// Fire the callback with the marshalled event args data
//
if(objChangedArgs != null)
OnObjectChanged(objChangedArgs);
}
Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Leaving ObjectChangedCallback().");
}
//
// My Contact is always subscribed. So this is no op
//
public override void Subscribe()
{
if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
}
public override void SubscribeAsync(object userToken)
{
//
// My Contact is always subscribed. So this is no op. Just call the callback
//
if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
if (userToken == null)
throw new ArgumentNullException("userToken");
Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Entering SubscribeAsync() with user token {0}.", userToken);
lock (AsyncLock){
if (AsyncOp != null)
throw new PeerToPeerException(SR.GetString(SR.Collab_DuplicateSubscribeAsync));
AsyncOp = AsyncOperationManager.CreateOperation(userToken);
}
this.PrepareToRaiseSubscribeCompletedEvent(AsyncOp, new SubscribeCompletedEventArgs(null, this, null, false, userToken));
Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Leaving SubscribeAsync().");
}
//
// Cannot unsubscribe for the MyContact, so we always throw
//
public override void Unsubscribe()
{
if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
throw new PeerToPeerException(SR.GetString(SR.Collab_UnsubscribeLocalContactFail));
}
private bool m_Disposed;
//
//
//
[System.Security.SecurityCritical]
protected override void Dispose(bool disposing)
{
if (!m_Disposed){
try{
m_Disposed = true;
}
finally{
base.Dispose(disposing);
}
}
}
}
}