363 lines
15 KiB
C#
363 lines
15 KiB
C#
|
//------------------------------------------------------------------------------
|
||
|
// <copyright file="Cloud.cs" company="Microsoft">
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
// </copyright>
|
||
|
//------------------------------------------------------------------------------
|
||
|
namespace System.Net.PeerToPeer
|
||
|
{
|
||
|
using System;
|
||
|
using System.Collections.Generic;
|
||
|
using System.Text;
|
||
|
using System.Runtime.Serialization;
|
||
|
using System.Security.Permissions;
|
||
|
using System.Diagnostics;
|
||
|
using System.Diagnostics.CodeAnalysis;
|
||
|
using System.Runtime.InteropServices;
|
||
|
|
||
|
/// <remarks>
|
||
|
/// The Cloud class directly represents the native cloud concept in the P2P APIs
|
||
|
/// There are two special static readonly members we support
|
||
|
/// Cloud.All and Cloud.AllLinkLocal
|
||
|
/// Cloud.All is really a notational convinience of null in the native world
|
||
|
/// Cloud.AllLinkLocal is equivalent to PEER_PNRP_ALL_LINK_CLOUDS const in the header file (declared in p2p.h)
|
||
|
///
|
||
|
/// This class is serializable.
|
||
|
/// This class is not sealed because there is no reason for it to be sealed.
|
||
|
/// </remarks>
|
||
|
/// <
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
[Serializable]
|
||
|
public class Cloud : ISerializable, IEquatable<Cloud>
|
||
|
{
|
||
|
private const string PEER_PNRP_ALL_LINK_CLOUDS = "PEER_PNRP_ALL_LINKS";
|
||
|
|
||
|
private string m_CloudName; //name of the cloud
|
||
|
private PnrpScope m_PnrpScope; //scope of the cloud
|
||
|
private int m_ScopeId; //scope Id of the scope
|
||
|
|
||
|
/// <summary>
|
||
|
/// Cloud.AllAvailable is a notational convinience. The native side uses a null for cloud parameter
|
||
|
/// to indicate all clouds.
|
||
|
/// </summary>
|
||
|
public static readonly Cloud Available = new Cloud("AllAvailable", PnrpScope.All, -1);
|
||
|
|
||
|
/// <summary>
|
||
|
/// AllLinkLocal is a managed abstraction of the native const PEER_PNRP_ALL_LINK_CLOUDS
|
||
|
/// </summary>
|
||
|
public static readonly Cloud AllLinkLocal = new Cloud("AllLinkLocal", PnrpScope.LinkLocal, -1);
|
||
|
|
||
|
/// <summary>
|
||
|
/// The static constructor serves the purpose of checking the
|
||
|
/// availability of the P2P apis on this platform
|
||
|
/// </summary>
|
||
|
static Cloud()
|
||
|
{
|
||
|
//-------------------------------------------------
|
||
|
//Check for the availability of the simpler PNRP APIs
|
||
|
//-------------------------------------------------
|
||
|
if (!PeerToPeerOSHelper.SupportsP2P)
|
||
|
{
|
||
|
throw new PlatformNotSupportedException(SR.GetString(SR.P2P_NotAvailable));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/// <summary>
|
||
|
/// Constructs an instance of a Cloud.
|
||
|
/// This is not public and accessible for internal members only
|
||
|
/// </summary>
|
||
|
/// <param name="name">Name of the cloud</param>
|
||
|
/// <param name="pnrpScope">scope</param>
|
||
|
/// <param name="scopeId">id ofthe scope</param>
|
||
|
internal Cloud(string name, PnrpScope pnrpScope, int scopeId) {
|
||
|
Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Creating cloud with Name: {0}, PnrpScope: {1}, ScopeID: {2}", name, pnrpScope, scopeId);
|
||
|
m_CloudName = name;
|
||
|
m_PnrpScope = pnrpScope;
|
||
|
m_ScopeId = scopeId;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Name
|
||
|
/// </summary>
|
||
|
public string Name {
|
||
|
get {
|
||
|
if (this == Cloud.AllLinkLocal || this == Cloud.Available)
|
||
|
return null;
|
||
|
return m_CloudName;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal string InternalName
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (this == Cloud.AllLinkLocal)
|
||
|
return PEER_PNRP_ALL_LINK_CLOUDS;
|
||
|
else if (this == Cloud.Available)
|
||
|
return null;
|
||
|
return m_CloudName;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Scope
|
||
|
/// </summary>
|
||
|
public PnrpScope Scope {
|
||
|
get {
|
||
|
return m_PnrpScope;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// ScopeId
|
||
|
/// </summary>
|
||
|
public int ScopeId {
|
||
|
get {
|
||
|
return m_ScopeId;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static Cloud Global
|
||
|
{
|
||
|
// <SecurityKernel Critical="True" Ring="1">
|
||
|
// <ReferencesCritical Name="Method: GetCloudOrClouds(String, Boolean, CloudCollection&, Cloud&):Void" Ring="1" />
|
||
|
// </SecurityKernel>
|
||
|
//[System.Security.SecurityCritical]
|
||
|
get
|
||
|
{
|
||
|
//throw new PeerToPeerException(SR.GetString(SR.Collab_SubscribeLocalContactFailed));
|
||
|
CloudCollection dummy = null;
|
||
|
Cloud cloud = null;
|
||
|
GetCloudOrClouds(null, true, out dummy, out cloud);
|
||
|
return cloud;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// <SecurityKernel Critical="True" Ring="1">
|
||
|
// <ReferencesCritical Name="Method: GetCloudOrClouds(String, Boolean, CloudCollection&, Cloud&):Void" Ring="1" />
|
||
|
// </SecurityKernel>
|
||
|
//[System.Security.SecurityCritical]
|
||
|
public static Cloud GetCloudByName(string cloudName)
|
||
|
{
|
||
|
if (cloudName == null || cloudName.Length == 0)
|
||
|
{
|
||
|
throw new ArgumentException(SR.GetString(SR.Pnrp_CloudNameCantBeNull), "cloudName");
|
||
|
}
|
||
|
CloudCollection dummy = null;
|
||
|
Cloud cloud = null;
|
||
|
GetCloudOrClouds(cloudName, false, out dummy, out cloud);
|
||
|
return cloud;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// The static member returns the list of clouds
|
||
|
/// </summary>
|
||
|
/// <returns></returns>
|
||
|
// <SecurityKernel Critical="True" Ring="1">
|
||
|
// <ReferencesCritical Name="Method: GetCloudOrClouds(String, Boolean, CloudCollection&, Cloud&):Void" Ring="1" />
|
||
|
// </SecurityKernel>
|
||
|
//[System.Security.SecurityCritical]
|
||
|
public static CloudCollection GetAvailableClouds()
|
||
|
{
|
||
|
CloudCollection clouds = null;
|
||
|
Cloud dummy = null;
|
||
|
GetCloudOrClouds(null, false, out clouds, out dummy);
|
||
|
return clouds;
|
||
|
}
|
||
|
|
||
|
// <SecurityKernel Critical="True" Ring="0">
|
||
|
// <CallsSuppressUnmanagedCode Name="UnsafeP2PNativeMethods.PeerPnrpGetCloudInfo(System.UInt32&,System.Net.PeerToPeer.SafePeerData&):System.Int32" />
|
||
|
// <SatisfiesLinkDemand Name="SafeHandle.DangerousGetHandle():System.IntPtr" />
|
||
|
// <SatisfiesLinkDemand Name="Marshal.PtrToStructure(System.IntPtr,System.Type):System.Object" />
|
||
|
// <SatisfiesLinkDemand Name="Marshal.PtrToStringUni(System.IntPtr):System.String" />
|
||
|
// <SatisfiesLinkDemand Name="Marshal.SizeOf(System.Type):System.Int32" />
|
||
|
// <SatisfiesLinkDemand Name="SafeHandle.Dispose():System.Void" />
|
||
|
// <ReferencesCritical Name="Local ArrayOfCloudInfoStructures of type: SafePeerData" Ring="1" />
|
||
|
// <ReferencesCritical Name="Method: UnsafeP2PNativeMethods.PnrpStartup():System.Void" Ring="1" />
|
||
|
// <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
|
||
|
// </SecurityKernel>
|
||
|
[SuppressMessage("Microsoft.Security","CA2129:SecurityTransparentCodeShouldNotReferenceNonpublicSecurityCriticalCode", Justification="System.Net.dll is still using pre-v4 security model and needs this demand")]
|
||
|
[System.Security.SecuritySafeCritical]
|
||
|
private static void GetCloudOrClouds(string cloudName, bool bGlobalCloudOnly, out CloudCollection clouds, out Cloud cloud)
|
||
|
{
|
||
|
cloud = null;
|
||
|
clouds = null;
|
||
|
|
||
|
Logging.Enter(Logging.P2PTraceSource, "Cloud::GetCloudOrClouds()");
|
||
|
|
||
|
//-------------------------------------------------
|
||
|
//Demand for the Unrestricted Pnrp Permission
|
||
|
//-------------------------------------------------
|
||
|
PnrpPermission.UnrestrictedPnrpPermission.Demand();
|
||
|
|
||
|
Int32 result = 0;
|
||
|
UInt32 numClouds = 0;
|
||
|
SafePeerData ArrayOfCloudInfoStructures = null;
|
||
|
if (cloudName == null)
|
||
|
{
|
||
|
//-----------------------------------------
|
||
|
//We need the collection only when we are not
|
||
|
//getting a specific cloud
|
||
|
//-----------------------------------------
|
||
|
clouds = new CloudCollection();
|
||
|
}
|
||
|
try
|
||
|
{
|
||
|
//---------------------------------------------------------------
|
||
|
//No perf hit here, real native call happens only one time if it
|
||
|
//did not already happen
|
||
|
//---------------------------------------------------------------
|
||
|
UnsafeP2PNativeMethods.PnrpStartup();
|
||
|
|
||
|
result = UnsafeP2PNativeMethods.PeerPnrpGetCloudInfo(out numClouds, out ArrayOfCloudInfoStructures);
|
||
|
if (result != 0)
|
||
|
{
|
||
|
throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Pnrp_CouldNotEnumerateClouds), result);
|
||
|
}
|
||
|
if (numClouds != 0)
|
||
|
{
|
||
|
Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Number of clouds returned {0}", numClouds);
|
||
|
IntPtr pPEER_PNRP_CLOUD_INFO = ArrayOfCloudInfoStructures.DangerousGetHandle();
|
||
|
for (ulong i = 0; i < numClouds; i++)
|
||
|
{
|
||
|
PEER_PNRP_CLOUD_INFO cloudinfo = (PEER_PNRP_CLOUD_INFO)Marshal.PtrToStructure(pPEER_PNRP_CLOUD_INFO, typeof(PEER_PNRP_CLOUD_INFO));
|
||
|
string nativeCloudName = Marshal.PtrToStringUni(cloudinfo.pwzCloudName);
|
||
|
pPEER_PNRP_CLOUD_INFO = (IntPtr)((long)pPEER_PNRP_CLOUD_INFO + Marshal.SizeOf(typeof(PEER_PNRP_CLOUD_INFO)));
|
||
|
Cloud c = new Cloud(nativeCloudName, (PnrpScope)((int)cloudinfo.dwScope), (int)cloudinfo.dwScopeId);
|
||
|
if (cloudName == null && !bGlobalCloudOnly)
|
||
|
{
|
||
|
clouds.Add(c);
|
||
|
continue;
|
||
|
}
|
||
|
//If a specific cloud by name is required, then test for name
|
||
|
//note that scope is PnrpScope.All but we don't test that now
|
||
|
if (cloudName != null && cloudName == nativeCloudName)
|
||
|
{
|
||
|
cloud = c;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (bGlobalCloudOnly && c.Scope == PnrpScope.Global)
|
||
|
{
|
||
|
cloud = c;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Logging.P2PTraceSource.TraceEvent(TraceEventType.Warning, 0, "No Clouds returned from the native call");
|
||
|
}
|
||
|
}
|
||
|
finally
|
||
|
{
|
||
|
if (ArrayOfCloudInfoStructures != null)
|
||
|
{
|
||
|
ArrayOfCloudInfoStructures.Dispose();
|
||
|
}
|
||
|
}
|
||
|
if (cloudName != null && cloud == null)
|
||
|
{
|
||
|
Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "The specific cloud name {0} asked for is not found", cloudName);
|
||
|
}
|
||
|
Logging.Leave(Logging.P2PTraceSource, "Cloud::GetCloudOrClouds()");
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/// <summary>
|
||
|
/// Two Clouds are equal only when all of the information matches
|
||
|
/// </summary>
|
||
|
/// <param name="obj"></param>
|
||
|
/// <returns></returns>
|
||
|
public bool Equals(Cloud other)
|
||
|
{
|
||
|
if (other == null) return false;
|
||
|
return other.Name == Name && other.Scope == Scope && other.ScopeId == ScopeId;
|
||
|
}
|
||
|
|
||
|
public override bool Equals(object obj)
|
||
|
{
|
||
|
if (obj == null) return false;
|
||
|
Cloud other = obj as Cloud;
|
||
|
if (other == null)
|
||
|
return false;
|
||
|
return Equals(other);
|
||
|
|
||
|
}
|
||
|
/// <summary>
|
||
|
/// The hash code comes from just the cloud name - for no partular reason.
|
||
|
/// This implementation seems sufficient - since the cloud names or typically
|
||
|
/// unique
|
||
|
/// </summary>
|
||
|
/// <returns></returns>
|
||
|
public override int GetHashCode()
|
||
|
{
|
||
|
return m_CloudName.GetHashCode();
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// A friendly string for the Cloud object
|
||
|
/// </summary>
|
||
|
/// <returns></returns>
|
||
|
public override string ToString()
|
||
|
{
|
||
|
StringBuilder sb = new StringBuilder();
|
||
|
sb.Append("Cloud Name:");
|
||
|
sb.Append(Name);
|
||
|
sb.Append(" Scope:");
|
||
|
sb.Append(Scope);
|
||
|
sb.Append(" ScopeId:");
|
||
|
sb.Append(ScopeId);
|
||
|
return sb.ToString();
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Constructor to enable serialization
|
||
|
/// </summary>
|
||
|
/// <param name="serializationInfo"></param>
|
||
|
/// <param name="streamingContext"></param>
|
||
|
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
|
||
|
protected Cloud(SerializationInfo info, StreamingContext context)
|
||
|
{
|
||
|
m_CloudName = info.GetString("_CloudName");
|
||
|
m_PnrpScope = (PnrpScope)info.GetValue("_CloudScope", typeof(PnrpScope));
|
||
|
m_ScopeId = info.GetInt32("_CloudScopeId");
|
||
|
}
|
||
|
|
||
|
// <SecurityKernel Critical="True" Ring="0">
|
||
|
// <SatisfiesLinkDemand Name="GetObjectData(SerializationInfo, StreamingContext):Void" />
|
||
|
// </SecurityKernel>
|
||
|
[SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase", Justification = "System.Net.dll is still using pre-v4 security model and needs this demand")]
|
||
|
[System.Security.SecurityCritical]
|
||
|
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter, SerializationFormatter = true)]
|
||
|
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
|
||
|
{
|
||
|
GetObjectData(info, context);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// This is made virtual so that derived types can be implemented correctly
|
||
|
/// </summary>
|
||
|
/// <param name="serializationInfo"></param>
|
||
|
/// <param name="streamingContext"></param>
|
||
|
[SecurityPermission(SecurityAction.LinkDemand, SerializationFormatter = true)]
|
||
|
protected virtual void GetObjectData(SerializationInfo info, StreamingContext context)
|
||
|
{
|
||
|
//Name is tricky since it can be null for AllLinkLocal and Available clouds
|
||
|
//but internally we represent them with non null strings
|
||
|
//so we should use the property here
|
||
|
info.AddValue("_CloudName", Name);
|
||
|
info.AddValue("_CloudScope", m_PnrpScope);
|
||
|
info.AddValue("_CloudScopeId", m_ScopeId);
|
||
|
}
|
||
|
}
|
||
|
}
|