Click here to Skip to main content
15,886,639 members
Articles / Programming Languages / C#

Peer Graph - Peers and Connections

Rate me:
Please Sign up or sign in to vote.
3.19/5 (7 votes)
17 Nov 20055 min read 51.1K   1K   20  
Peer Graph - Peers and Connections using Microsoft's Peer-to-Peer technology.
using System;
using System.Runtime.InteropServices;
//using Peer.Identity;

namespace Peer.NameResolution
{
	/// <summary>
	/// Singleton for WSA* to guarantee startup/shudown once.
	/// </summary>
	internal sealed class WSAService
	{
		private WSAService()
		{
			WSAData data = new WSAData();
			int err = PnrpNative.WSAStartup(0x202, ref data);
			if (err != 0) throw new System.Net.Sockets.SocketException(PnrpNative.WSAGetLastError());
		}
		~WSAService()
		{
			PnrpNative.WSACleanup();
		}
		public static readonly WSAService Instance = new WSAService();
	}
	
	public class PeerRegistration
	{
		internal SOCKADDR_IN6 address;
		private string name = string.Empty;
		private string peerName = string.Empty;
		private string cloudName;
		private string comment = string.Empty;
		private PNRP_RESOLVE_CRITERIA criteria = PNRP_RESOLVE_CRITERIA.Default;

		public PeerRegistration()
		{
		}

		public PeerRegistration(string Name, string CloudName)
		{
			this.Name = Name.Replace(" ", string.Empty);
			cloudName = CloudName;
		}

		public string PeerName
		{
			get
			{
				return peerName;
			}
			set
			{
				peerName = value;
			}
		}

		public string Name
		{
			get
			{
				return name;
			}
			set
			{
				name = value;
				peerName = "0." + name;
			}
		}

		public string Identity
		{
			get
			{
				return string.Empty;
			}
		}

		public string CloudName
		{
			get
			{
				return cloudName;
			}
			set
			{
				cloudName = value;
			}
		}

		public string Comment
		{
			get
			{
				return comment;
			}
			set
			{
				comment = value;
			}
		}

		public System.Net.IPEndPoint Address
		{
			get
			{
				System.Net.IPAddress ip;
				if (address.sin6_addr == null)
				{
					ip = new System.Net.IPAddress(0);
				}
				else
				{
					ip = new System.Net.IPAddress(address.sin6_addr);
				}
				return new System.Net.IPEndPoint(ip, address.sin6_port);
			}
			set
			{
				address.sin6_addr = value.Address.GetAddressBytes();
				address.sin6_family = (short)value.AddressFamily;
				address.sin6_port = (ushort)value.Port;
			}
		}

		public PNRP_RESOLVE_CRITERIA Criteria
		{
			get
			{
				return criteria;
			}
			set
			{
				criteria = value;
			}
		}
	};

	public class Pnrp
	{
		private static WSAService service = WSAService.Instance;
		private static Guid SVCID_PNRPNAMEV1 = new Guid(0xc2239ce5, 0xc0, 0x4fbf, 0xba, 0xd6, 0x18, 0x13, 0x93, 0x85, 0xa4, 0x9a);
		private static Guid SVCID_PNRPNAMEV2 = new Guid(0xc2239ce7, 0xc0, 0x4fbf, 0xba, 0xd6, 0x18, 0x13, 0x93, 0x85, 0xa4, 0x9a);

		public static void Register(PeerRegistration Registration)
		{
			CSADDR_INFO csaAddr = new CSADDR_INFO();
			PNRPINFO pnrpInfo = new PNRPINFO();
			BLOB blPnrpData = new BLOB();
			WSAQUERYSET querySet = new WSAQUERYSET();
				
			//
			// fill a CSADDR_INFO structure from the address
			//
			csaAddr.iProtocol = 6;			// IPPROTO_TCP
			csaAddr.iSocketType = 1;		// SOCK_STREAM;
			csaAddr.LocalAddr.iSockaddrLength = Marshal.SizeOf(typeof(SOCKADDR_IN6));
			csaAddr.LocalAddr.lpSockaddr = Marshal.AllocHGlobal(csaAddr.LocalAddr.iSockaddrLength);
			Marshal.StructureToPtr(Registration.address, csaAddr.LocalAddr.lpSockaddr, false);

			//
			// build the WSAQUERYSET required to register
			//
			pnrpInfo.dwSize = Marshal.SizeOf(typeof(PNRPINFO));
			pnrpInfo.dwLifetime = 60*60*8;	// 8 hours
			if (Registration.Identity != string.Empty) pnrpInfo.lpwszIdentity = Marshal.StringToHGlobalUni(Registration.Identity);

			blPnrpData.cbSize = Marshal.SizeOf(typeof(PNRPINFO));
			blPnrpData.pBlobData = Marshal.AllocHGlobal(blPnrpData.cbSize);
			Marshal.StructureToPtr(pnrpInfo, blPnrpData.pBlobData, false);

			querySet.dwSize = Marshal.SizeOf(typeof(WSAQUERYSET));
			querySet.dwNameSpace = 38;			// NS_PNRPNAME
			querySet.dwNumberOfCsAddrs = 1;		// one address
			querySet.lpServiceClassId = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Guid)));
			Marshal.StructureToPtr(SVCID_PNRPNAMEV1, querySet.lpServiceClassId, false);
			querySet.lpszServiceInstanceName = Registration.PeerName;
			if (Registration.CloudName != string.Empty) querySet.lpszContext = Marshal.StringToHGlobalUni(Registration.CloudName);
			if (Registration.Comment != string.Empty) querySet.lpszComment = Marshal.StringToHGlobalUni(Registration.Comment);

			querySet.lpcsaBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(CSADDR_INFO)));
			Marshal.StructureToPtr(csaAddr, querySet.lpcsaBuffer, false);

			querySet.lpBlob = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(BLOB)));
			Marshal.StructureToPtr(blPnrpData, querySet.lpBlob, false);

			IntPtr qryptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(WSAQUERYSET)));
			Marshal.StructureToPtr(querySet, qryptr, false);

			int err = PnrpNative.WSASetService(qryptr, WSAESETSERVICEOP.Register, 0);
			if (err != 0) throw new System.Net.Sockets.SocketException(PnrpNative.WSAGetLastError());

			System.Diagnostics.Debug.WriteLine(Registration.PeerName + " registered");
		}

		public static void Unregister(PeerRegistration Registration)
		{
			PNRPINFO pnrpInfo = new PNRPINFO();
			BLOB blPnrpData = new BLOB();
			WSAQUERYSET querySet = new WSAQUERYSET();
				
			//
			// build the WSAQUERYSET required to register
			//
			pnrpInfo.dwSize = Marshal.SizeOf(typeof(PNRPINFO));
			pnrpInfo.dwLifetime = 60*60*8;	// 8 hours
			if (Registration.Identity != string.Empty) pnrpInfo.lpwszIdentity = Marshal.StringToHGlobalUni(Registration.Identity);

			blPnrpData.cbSize = Marshal.SizeOf(typeof(PNRPINFO));
			blPnrpData.pBlobData = Marshal.AllocHGlobal(blPnrpData.cbSize);
			Marshal.StructureToPtr(pnrpInfo, blPnrpData.pBlobData, false);

			querySet.dwSize = Marshal.SizeOf(typeof(WSAQUERYSET));
			querySet.dwNameSpace = 38;			// NS_PNRPNAME
			querySet.lpServiceClassId = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Guid)));
			Marshal.StructureToPtr(SVCID_PNRPNAMEV1, querySet.lpServiceClassId, false);
			querySet.lpszServiceInstanceName = Registration.PeerName;
			if (Registration.CloudName != string.Empty) querySet.lpszContext = Marshal.StringToHGlobalUni(Registration.CloudName);

			querySet.lpBlob = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(BLOB)));
			Marshal.StructureToPtr(blPnrpData, querySet.lpBlob, false);

			IntPtr qryptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(WSAQUERYSET)));
			Marshal.StructureToPtr(querySet, qryptr, false);

			int err = PnrpNative.WSASetService(qryptr, WSAESETSERVICEOP.Delete, 0);
			if (err != 0) throw new System.Net.Sockets.SocketException(PnrpNative.WSAGetLastError());

			System.Diagnostics.Debug.WriteLine(Registration.PeerName + " registered");
		}

		internal static int LookupServiceNext(IntPtr hLookup, out IntPtr pResults)
		{
			int size = Marshal.SizeOf(typeof(WSAQUERYSET))+0x100;
			pResults = Marshal.AllocHGlobal(size);

			int err = PnrpNative.WSALookupServiceNext(hLookup, 0, ref size, pResults);
			if (err != 0)
			{
				int lasterr = PnrpNative.WSAGetLastError();
				if (lasterr == PnrpNative.WSA_E_NO_MORE ) return err;

				if (lasterr == PnrpNative.WSAEFAULT)
				{
					Marshal.FreeHGlobal(pResults);
					pResults = Marshal.AllocHGlobal(size);
					err = PnrpNative.WSALookupServiceNext(hLookup, 0, ref size, pResults);
				}
				else
					throw new System.Net.Sockets.SocketException(lasterr);
			}
			return err;
		}

		public static bool Lookup(PeerRegistration Registration)
		{
			PNRPINFO pnrpInfo = new PNRPINFO();
			BLOB  blPnrpData = new BLOB();
			WSAQUERYSET querySet = new WSAQUERYSET();

			pnrpInfo.dwSize = Marshal.SizeOf(typeof(PNRPINFO));
			pnrpInfo.nMaxResolve = 1;
			pnrpInfo.dwTimeout = 5;
			pnrpInfo.enResolveCriteria = Registration.Criteria;

			blPnrpData.cbSize = Marshal.SizeOf(typeof(PNRPINFO));
			blPnrpData.pBlobData = Marshal.AllocHGlobal(blPnrpData.cbSize);
			Marshal.StructureToPtr(pnrpInfo, blPnrpData.pBlobData, false);

			querySet.dwSize = Marshal.SizeOf(typeof(WSAQUERYSET));
			querySet.dwNameSpace = 38;		// NS_PNRPNAME
			querySet.lpServiceClassId = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Guid)));
			Marshal.StructureToPtr(SVCID_PNRPNAMEV1, querySet.lpServiceClassId, false);
			querySet.lpszServiceInstanceName = Registration.PeerName;
			if (Registration.CloudName != string.Empty) querySet.lpszContext = Marshal.StringToHGlobalUni(Registration.CloudName);

			querySet.lpBlob = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(BLOB)));
			Marshal.StructureToPtr(blPnrpData, querySet.lpBlob, false);

			IntPtr qryptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(WSAQUERYSET)));
			Marshal.StructureToPtr(querySet, qryptr, false);

			IntPtr hLookup;
			int err = PnrpNative.WSALookupServiceBegin(qryptr, WSALookup.LUP_RETURN_NAME | WSALookup.LUP_RETURN_ADDR | WSALookup.LUP_RETURN_COMMENT, out hLookup);
			if (err != 0) throw new System.Net.Sockets.SocketException(PnrpNative.WSAGetLastError());

			System.Diagnostics.Debug.Write("Lookup " + Registration.PeerName);
			IntPtr pResults;
			err = LookupServiceNext(hLookup, out pResults);

			bool found = false;
			if (err == 0)
			{
				System.Diagnostics.Debug.WriteLine(" succeeded");
				querySet = (WSAQUERYSET)Marshal.PtrToStructure(pResults, typeof(WSAQUERYSET));
				CSADDR_INFO csaAddr = (CSADDR_INFO)Marshal.PtrToStructure(querySet.lpcsaBuffer, typeof(CSADDR_INFO));
				// return the first IPv6 address found
				for (int i = 0; i < querySet.dwNumberOfCsAddrs; i++)
				{
					if (csaAddr.iProtocol == (int)System.Net.Sockets.ProtocolType.Tcp &&
						csaAddr.RemoteAddr.iSockaddrLength == Marshal.SizeOf(typeof(SOCKADDR_IN6)))
					{
						SOCKADDR_IN6 addr = (SOCKADDR_IN6)Marshal.PtrToStructure(csaAddr.RemoteAddr.lpSockaddr, typeof(SOCKADDR_IN6));
						Registration.Address = new System.Net.IPEndPoint(new System.Net.IPAddress(addr.sin6_addr), addr.sin6_port);
						found = true;
						break;
					}
				}
				Marshal.FreeHGlobal(pResults);
			}

			PnrpNative.WSALookupServiceEnd(hLookup);
			return found;
		}

		public static string PnrpToDns(string PnrpName)
		{
			int length = 255;
			System.Text.StringBuilder DnsName = new System.Text.StringBuilder(length);
			//int err = PnrpNative.PeerNameToPeerHostName(PnrpName, DnsName, ref length);
			int err = PnrpNative.PeerPnrpToDnsName(PnrpName, DnsName, ref length);
			if (err != 0) throw new System.Net.Sockets.SocketException(err);
			return DnsName.ToString();
		}

		public static string DnsToPnrp(string DnsName)
		{
			int length = 255;
			System.Text.StringBuilder PnrpName = new System.Text.StringBuilder(255);
			//int err = PnrpNative.PeerHostNameToPeerName(DnsName, PnrpName, ref length);
			int err = PnrpNative.PeerDnsToPnrpName(DnsName, PnrpName, ref length);
			if (err != 0) throw new System.Net.Sockets.SocketException(err);
			return PnrpName.ToString();
		}
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Canada Canada
Adrian Moore is the Development Manager for the SCADA Vision system developed by ABB Inc in Calgary, Alberta.

He has been interested in compilers, parsers, real-time database systems and peer-to-peer solutions since the early 90's. In his spare time, he is currently working on a SQL parser for querying .NET DataSets (http://www.queryadataset.com).

Adrian is a Microsoft MVP for Windows Networking.

Comments and Discussions