I'm using Xamarin + MonoTouch on iOS to browse for a web server on the network that I can then download files from.
The NSNetService that is passed into the resolve event handler contains addresses as NSData. I can't find a good way to turn that NSData into an actual IP address that I can then build a URL from, i.e. http:// < IPAddress > /folder/file.htm
This is my NSNetService.AddressResolved event handler:
private void OnServiceResolved(object sender, EventArgs args)
{
NSNetService service = (NSNetService)sender;
// service.Port is valid.
// service.HostName is valid.
// but we want the IP addres, which is in service.Addresses.
// None of the following four methods works quite right.
IPAddress address = (IPAddress)service.Addresses [0]; // Cannot convert type NSData to IPAddress
SocketAddress address2 = (SocketAddress)service.Addresses[0]; // Cannot convert NSData to SocketAddress. A binary copy might work?
IPHostEntry entry = (IPHostEntry)service.Addresses [0]; // Cannot convert NSData to IPHostEntry
IPHostEntry entry2 = Dns.GetHostByName (service.HostName); // This kinda works, but is dumb. Didn't we just resolve?
}
What's the right way to get the IP address of the service from an NSNetService in a resolve event?
The NSNetService.Addresses
property gives you NSData
instances which must be converted into something that IPAddress
(or other .NET types) can digest. E.g.
MemoryStream ms = new MemoryStream ();
(ns.Addresses [0] as NSData).AsStream ().CopyTo (ms);
IPAddress ip = new IPAddress (ms.ToArray ());
Note that this can return you an IPv6 address (or format that IPAddress
won't accept). You might want to iterate all the Addresses
to find the best one.
I'll look into adding a convenience method into future versions of Xamarin.iOS.
UPDATE
A more complete version, that returns an IPAddress
, would look like:
static IPAddress CreateFrom (NSData data)
{
byte[] address = null;
using (MemoryStream ms = new MemoryStream ()) {
data.AsStream ().CopyTo (ms);
address = ms.ToArray ();
}
SocketAddress sa = new SocketAddress (AddressFamily.InterNetwork, address.Length);
// do not overwrite the AddressFamily we provided
for (int i = 2; i < address.Length; i++)
sa [i] = address [i];
IPEndPoint ep = new IPEndPoint (IPAddress.Any, 0);
return (ep.Create (sa) as IPEndPoint).Address;
}