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;
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 = 30;
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();
}
}
}