Bonjour local host names in Android - android

How can I make an Android network request lookup a local domain name registered with Bonjour?
I get this error when trying to fetch data using Volley.
java.net.UnknownHostException: Unable to resolve host "xxxxx.local": No address associated with hostname

If you control the whole network stack, you can perform DNS service discovery (DNS-SD) through Android's NsdManager. I recommend this guide from the documentation:
https://developer.android.com/training/connect-devices-wirelessly/nsd
In short, it boils down to:
mNsdManager.discoverServices(
SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener);
You can cross-reference the service you wish to resolve to by inspecting the response from dns-sd on Mac:
$ dns-sd -Z . .
_http._tcp PTR myserver._http._tcp
myserver._http._tcp SRV 0 0 80 myserver.local. ; Replace with unicast FQDN of target host
myserver._http._tcp TXT ""
In the NsdManager.DiscoveryListener callback, you can obtain the corresponding IP address from NsdServiceInfo.getHost().

Have you tried with the IP of localhost ? 127.0.0.1 or 10.0.2.2:80 ?

Related

Android Network Service Discovery get hostname (mDNS/Zeroconf)

I am trying to get the hostname from a service that is advertising itself on my local network using mDNS/Zeroconf. I am using Android's Network Service Discovery API, but it seems as if Android doesn't use the advertised hostname but tries to do a reverse DNS lookup and if that fails only returns the IP address.
On my Macbook I do can do the following:
$ dns-sd -B _myservice._tcp
DATE: ---Mon 29 Oct 2018---
17:35:25.332 ...STARTING...
Timestamp A/R Flags if Domain Service Type Instance Name
17:35:25.333 Add 2 10 local. _myservice._tcp. My Service Name
$ dns-sd -L "My Service Name" _myservice._tcp
DATE: ---Mon 29 Oct 2018---
17:38:35.423 ...STARTING...
17:38:35.423 My\032Service\032Name._myservice._tcp.local. can be reached at test.my.service.local.:443 (interface 10)
I can then use the returned hostname (test.my.service.local) to find the corresponding IP. I've got this working correctly on iOS using NSNetServiceBrowser.
On Android in my onServiceDiscovered if I do the following:
private static Map<String, Object> OnServiceDiscovered(NsdServiceInfo info) {
Log.d(TAG, info.getHost().getHostAddress());
Log.d(TAG, info.getHost().getHostName());
}
I do get the correct IP address, but getHostName returns "raspberrypi.local" (from /etc/hostname) or on another network only the IP address. My suspicion is that on Android getHost().getHostName() is doing a reverse DNS lookup and ignores the hostname being advertised with mDNS altogether.
Is there any way to get the hostname from mDNS on Android?

QTcpServer - Unsupported Socket Operation on Android

I am trying to start a server on Android using QTcpServer with Qt 5.3.1 but the server does not start and I get "Unsupported Socket Operation". It works fine on Windows.
Code below:
void StartListening()
{
QHostAddress hostAddress;
hostAddress.setAddress(QString("localhost"));
hostAddress.toIPv4Address();
quint16 portNumber = 9878;
server->setMaxPendingConnections(1);
server->setProxy(QNetworkProxy::NoProxy);
if (server->listen(hostAddress, portNumber))
{
// Ok
}
else
{
Debug("Server did not start. " + server->errorString());
}
}
server->errorString() returns "Unsupported Socket Operation when it runs on Android
Isn't this supported by Qt Android or am I doing something wrong?
Thx
OK! I worked it out.
The problem is with this line:
hostAddress.setAddress(QString("localhost"));
If I replace "localhost" with "127.0.0.1", the server starts fine but no one outside the "device the server is running on" can connect to it. This means, let's say your network is using 192.168.1.xx and your Android device has the following IP address: 192.168.1.2. If you start the server with "127.0.0.1" on your Android device which has an IP address: "192.168.1.2" and then using your PC with an IP address 192.168.1.3 you do telnet 192.168.1.2 9878 it will fail to connect!
So then I decided to start the server by specifying the IP address of the Android device: 192.168.1.2
hostAddress.setAddress(QString("192.168.1.2"));
Voila! That works too! The server starts and I can connect from outside the device! For example if I do telnet 192.168.1.2 9878 from my PC while the server is started on Android, it connects! So all I need to do now is replace the hard coded IP address with the actual IP address of the device! I think QNetworkInterface::allInterfaces() or something like that will give me the ability to get the default IP address.
So just use the actual IP address of the network card rather than localhost or 127.0.0.1 and all should be Ok. All working now.

How to find the name of the wireless network device by IP Address Android?

I have a list of Ip addresses on my local network and I want to know which device holds each address, how can I know?
Quoting from the docs of InetAddress:
Host Name Resolution
Host name-to-IP address resolution is
accomplished through the use of a combination of local machine
configuration information and network naming services such as the
Domain Name System (DNS) and Network Information Service(NIS). The
particular naming services(s) being used is by default the local
machine configured one. For any host name, its corresponding IP
address is returned.
Reverse name resolution means that for any IP address, the host
associated with the IP address is returned.
The InetAddress class provides methods to resolve host names to their
IP addresses and vice versa.
This method would then be InetAddress.getHostName().
Create an InetAddress object with the ip address then call getHostName on it
InetAddress inetAddr = InetAddress.getByName("192.168.1.20");
String hostname = inetAddr.getHostName();
Be aware though that there is no guarantee that reverse lookup is done when instantiating the inetAddress object like this on Android, so you will need to check that the value of hostname is not null before using it.

Why does my service always bind to ipv6 localhost instead of ipv4?

I have a service that creates a ServerSocket and binds to localhost:7060. When I did "netstat -an" on my android device, I see it is using ipV6 localhost instead of ipv4 localhost interface.
The output is like this:
tcp6 0 0 ::ffff:127.0.0.1:7060 :::* LISTEN
The ports that use ipV4 are listed like this:
tcp 0 0 127.0.0.1:5060 0.0.0.0:* LISTEN
What is the trick to force it to use IPv4 always?
I am setting up a port forward rule using iptables. The version I have supports ipv4 destination addresses.
This is how I am creating my Java code for listening on the port.
InetAddress localAddress = Inet4Address.getByName("localhost");
//InetAddress localAddress = Inet4Address.getLocalHost();
sockServer = new ServerSocket(nPort, 20, localAddress);
I followed other advice like setting system property to prefer ipV4 in the startup of my service. That didn't make any difference.
System.setProperty("java.net.preferIPv4Stack", "true");
I am running this on Android 2.3 built for an embedded device.
Update:
I checked InetAddress.java sources in android tree. It is reading the above flag with a line like below.
static boolean preferIPv6Addresses() {
String propertyName = "java.net.preferIPv6Addresses";
String propertyValue = AccessController.doPrivileged(new PriviAction<String>(propertyName));
return Boolean.parseBoolean(propertyValue);
}
Now I am not sure System.setProperty() call is really changing the value read by above code.
In theory a IPv6 server listens to IPv4 as well, since IPv4 address space is a subset of IPv6, is this causing real problems to you?
A trick that might work is to use "127.0.0.1" instead of "localhost", which has IPv4 and IPv6 addresses associated.

How do I resolve a Bonjour domain name on Android?

I need to get my app to play a video file located on my network. I know the url of the file is:
http://something.local/abc.mp4
Now, when I manually substitute "something.local" with its true ip address, the MediaPlayer has no problem playing it. Nonetheless, when I have the above address, the MediaPlayer errors out with error (1, -1007).
So I'm assuming this is because Android doesn't understand "something.local" as being correct.
My question is: How can I "translate" something.local into an ip myself, so that I can then pass it into MediaPlayer?
A small caveat: I believe that MediaPlayer does not work with IPv6 addresses, so please keep that in mind...
Just a side note, in case it makes my situation clearer: When I run ping something.local -4 in the Windows command prompt, it returns:
Pinging something.local [192.168.1.126] with 32 bytes of data:
Reply from 192.168.1.126: bytes=32 time=145ms TTL=64
Reply from 192.168.1.126: bytes=32 time=112ms TTL=64
Reply from 192.168.1.126: bytes=32 time=32ms TTL=64
Reply from 192.168.1.126: bytes=32 time=169ms TTL=64
That translation where windows went from something.local -> 192.168.1.126 is what I want to do in my Android app.
Firstly, you need read document about Bonjour (iOS term) or Zero Config (Linux term).
To understand what's something.local:
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/NetServices/Articles/about.html#//apple_ref/doc/uid/TP40002458-SW1
For example, if a user types steve.local. into a Web browser, this
tells the system to multicast the request for steve on the local
network instead of sending it to the conventional DNS server. If a
Bonjour-enabled computer named steve is on the local network, the
user’s browser is sent the correct IP address for it. This allows
users to access local hosts and services without a conventional DNS
server.
For how to resolve it:
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/NetServices/Articles/NetServicesArchitecture.html#//apple_ref/doc/uid/20001074-SW1
For java library, previous answers provided good enough example.
You should try this snippet with jmDNS library api.. may need some changes.
JmDNS jmdns = JmDNS.create();
DNSEntry addressEntry = jmdns.getCache().getDNSEntry(name, DNSRecordType.TYPE_A, DNSRecordClass.CLASS_ANY);
if (addressEntry instanceof DNSRecord) {
ServiceInfo cachedAddressInfo = ((DNSRecord) addressEntry).getServiceInfo(true);
if (cachedAddressInfo != null) {
for (Inet4Address address : cachedAddressInfo.getInet4Addresses()) {
// use the `address`
}
}
You have access to java,net APIS on android and can use them to resolve adresses.
http://docs.oracle.com/javase/1.4.2/docs/api/java/net/InetAddress.html
However, success will depend on network proper configuration. Your device receives DNS server setup via DHCP - so you are at mercy of network provider

Categories

Resources