getaddrinfo() only return 127.0.0.1 even with WIFI connected

3,469 views
Skip to first unread message

technicware

unread,
Jun 3, 2012, 11:32:17 PM6/3/12
to andro...@googlegroups.com
Hi,

The following code works on Linux, Windows, MacOS and Solaris, but on an Android device, it can only return 127.0.0.1 even when ifconfig shows the WIFI address is available:

        static struct addrinfo hint = {
            0,           // int ai_flags;
            AF_INET,     // int ai_family;
            SOCK_DGRAM,  // int ai_socktype;
            IPPROTO_UDP, // int ai_protocol;
            0,           // size_t ai_addrlen;
            NULL,        // char* ai_canonname;
            NULL,        // struct sockaddr* ai_addr;
            NULL         // struct addrinfo* ai_next;
        };
        struct addrinfo *_info;
        if (getaddrinfo(addr, port, &hint, &_info) != 0) {
            syslog(LOG_ERR, "Cannot reach %s", addr);
            return 0;
        }

The 'port' value is fixed (e.g. 6084). I have tried passing 'addr' with the value from gethostname(), but getaddrinfo() always return one and only one item, which is 127.0.0.1. I think the problem is gethostname() returns 'localhost'. Is there another way to get the host name so that getaddrinfo() can return all addresses, including WIFI address?

Please don't suggest getting WIFI address from Java. I only like to know if bionic fully supports getaddrinfo() and can return WIFI address.

Thanks

--Michael

Angus Lees

unread,
Jun 4, 2012, 12:12:35 AM6/4/12
to andro...@googlegroups.com
I think you're confused as to what getaddrinfo() does...

On Mon, Jun 4, 2012 at 1:32 PM, technicware <techn...@gmail.com> wrote:
Hi,

The following code works on Linux, Windows, MacOS and Solaris, but on an Android device, it can only return 127.0.0.1 even when ifconfig shows the WIFI address is available:

        static struct addrinfo hint = {
            0,           // int ai_flags;
            AF_INET,     // int ai_family;
            SOCK_DGRAM,  // int ai_socktype;
            IPPROTO_UDP, // int ai_protocol;
            0,           // size_t ai_addrlen;
            NULL,        // char* ai_canonname;
            NULL,        // struct sockaddr* ai_addr;

(You have canonname and addr around the wrong way, although it's harmless here)
 
            NULL         // struct addrinfo* ai_next;
        };
        struct addrinfo *_info;
        if (getaddrinfo(addr, port, &hint, &_info) != 0) {
            syslog(LOG_ERR, "Cannot reach %s", addr);
            return 0;
        }

The 'port' value is fixed (e.g. 6084). I have tried passing 'addr' with the value from gethostname(), but getaddrinfo() always return one and only one item, which is 127.0.0.1. I think the problem is gethostname() returns 'localhost'. Is there another way to get the host name so that getaddrinfo() can return all addresses, including WIFI address?

Please don't suggest getting WIFI address from Java. I only like to know if bionic fully supports getaddrinfo() and can return WIFI address.

getaddrinfo() works on Android - but isn't meant to return a list of local addresses, which is what you seem to be wanting.  getaddrinfo() is used for finding a suitable end point (either active or passive end) for a socket connection.  Indeed, if you wanted to connect to using IPv4 UDP to localhost port 6084 (this is what you're asking in your example above) then there is almost certainly only a single sockaddr answer required.

To get the list of local addresses you either need to use ioctl(SIOCGIFADDR) (IPv4-only), or netlink (IPv4+IPv6, but Linux-specific) - or call into the Java functions which will hide that rather unpleasant code from you.

You may also find that you don't actually want a list of all addresses, since some will probably be private or otherwise unusable for whatever you're trying to do.  If you want something in particular then there may be some other way of getting the answer you really want.  We'd need more context to help you there.

 - Gus

technicware

unread,
Jun 5, 2012, 1:10:51 AM6/5/12
to andro...@googlegroups.com
Gus,

Like I said, that same piece of code works on 4 other platforms and reliably return all possible local address of 'addr', and 'addr' comes from a call to gethostname().

Why don't we concentrate on gethostname() instead of getaddrinfo().

I believe on all 4 other platforms, gethostname() returns the local host name, which will resolve to all possible addresses, including multiple network cards, WIFI, PPP, VPN, etc.

The problem with Android is that gethostname() returns "localhost" instead of the host name. As an result, 'localhost' can only resolve into 127.0.0.1 and nothing else. See a similar thread with no definitive answer:

  http://comments.gmane.org/gmane.comp.handhelds.android.ndk/11967

Why gethostname() only Android cannot return a host name other than 'localhost'?

By the way, I am porting an ICE implementation to Android that works on all 4 platforms mentioned above. I know what I am doing:

  http://tools.ietf.org/html/rfc5245

Thanks

--Michael



On Sunday, June 3, 2012 9:12:35 PM UTC-7, Angus Lees wrote:
I think you're confused as to what getaddrinfo() does...

Angus Lees

unread,
Jun 5, 2012, 3:47:40 AM6/5/12
to andro...@googlegroups.com
On Tue, Jun 5, 2012 at 3:10 PM, technicware <techn...@gmail.com> wrote:
Gus,

Like I said, that same piece of code works on 4 other platforms and reliably return all possible local address of 'addr', and 'addr' comes from a call to gethostname(). 

Why don't we concentrate on gethostname() instead of getaddrinfo().

I believe on all 4 other platforms, gethostname() returns the local host name, which will resolve to all possible addresses, including multiple network cards, WIFI, PPP, VPN, etc.

Oh right.  As you say, this works in other situations because gethostname() returns something that getaddrinfo() then looks up in DNS/WINS/hosts/whatever and returns all the addresses configured in that name service for whatever gethostname() returned.  In particular, it does not return all the addresses on the local machine (it won't return 127.0.0.1 loopback, link local IPv6, IPv6 privacy addresses, VPN addresses, or a whole lot of other addresses that just happen to be configured at the moment.  I doubt it returns anything more than what your DHCP response also said, for example).

The problem with Android is that gethostname() returns "localhost" instead of the host name. As an result, 'localhost' can only resolve into 127.0.0.1 and nothing else. See a similar thread with no definitive answer:

  http://comments.gmane.org/gmane.comp.handhelds.android.ndk/11967

Why gethostname() only Android cannot return a host name other than 'localhost'?

This is hard - what hostname should it return for an unmanaged device like a phone?  It is unlikely that your phone has an entry in any name service (particularly for its 3G interface), and configuring something fake locally in /etc/hosts (or equivalent) and then resolving that fake name using getaddrinfo() will only return whatever addresses had been placed in the fake /etc/hosts entry.  It's a rather round about way to get the local addresses and I imagine it wouldn't be flexible enough to get what you wanted anyway (the address for your wifi interface is highly unlikely to ever appear against the same 'hostname' as your 3G interface or a corporate VPN inner address, for example).

By the way, I am porting an ICE implementation to Android that works on all 4 platforms mentioned above. I know what I am doing:

  http://tools.ietf.connectedorg/html/rfc5245

Nice!  In that case you really want to know all the (non-host-local) addresses.  As far as I know, your options on Android are:
1. ioctl(SIOCGIFADDR)  (bsd-compatible, but IPv4 only so no good for new code)
2. socket(AF_NETLINK, ..., NETLINK_ROUTE)  (aka rtnetlink.  Linux only and gives access to all information you could possibly want, but a bit awkward to use)
3. Use JNI to call into java.net.NetworkInterface (Android/Java platforms only) to walk the interfaces and their addresses

(3) is obvious from the Android API docs.  You should be able to find examples of (1) and (2) on the broader internet - normal Linux code for these should work just fine on Android, possibly with a few missing kernel headers required (it's a stable Linux kernel ABI - the magic numbers aren't going to change any time soon).

 - Gus

On Sunday, June 3, 2012 9:12:35 PM UTC-7, Angus Lees wrote:
I think you're confused as to what getaddrinfo() does...

On Mon, Jun 4, 2012 at 1:32 PM, technicware wrote:
Hi,

The following code works on Linux, Windows, MacOS and Solaris, but on an Android device, it can only return 127.0.0.1 even when ifconfig shows the WIFI address is available:

        static struct addrinfo hint = {
            0,           // int ai_flags;
            AF_INET,     // int ai_family;
            SOCK_DGRAM,  // int ai_socktype;
            IPPROTO_UDP, // int ai_protocol;
            0,           // size_t ai_addrlen;
            NULL,        // char* ai_canonname;
            NULL,        // struct sockaddr* ai_addr;

(You have canonname and addr around the wrong way, although it's harmless here)
 
            NULL         // struct addrinfo* ai_next;
        };
        struct addrinfo *_info;
        if (getaddrinfo(addr, port, &hint, &_info) != 0) {
            syslog(LOG_ERR, "Cannot reach %s", addr);
            return 0;
        }

The 'port' value is fixed (e.g. 6084). I have tried passing 'addr' with the value from gethostname(), but getaddrinfo() always return one and only one item, which is 127.0.0.1. I think the problem is gethostname() returns 'localhost'. Is there another way to get the host name so that getaddrinfo() can return all addresses, including WIFI address?

Please don't suggest getting WIFI address from Java. I only like to know if bionic fully supports getaddrinfo() and can return WIFI address.

getaddrinfo() works on Android - but isn't meant to return a list of local addresses, which is what you seem to be wanting.  getaddrinfo() is used for finding a suitable end point (either active or passive end) for a socket connection.  Indeed, if you wanted to connect to using IPv4 UDP to localhost port 6084 (this is what you're asking in your example above) then there is almost certainly only a single sockaddr answer required.

To get the list of local addresses you either need to use ioctl(SIOCGIFADDR) (IPv4-only), or netlink (IPv4+IPv6, but Linux-specific) - or call into the Java functions which will hide that rather unpleasant code from you.

You may also find that you don't actually want a list of all addresses, since some will probably be private or otherwise unusable for whatever you're trying to do.  If you want something in particular then there may be some other way of getting the answer you really want.  We'd need more context to help you there.p;- Gus

--
You received this message because you are subscribed to the Google Groups "android-ndk" group.
To view this discussion on the web visit https://groups.google.com/d/msg/android-ndk/-/5nJhRZ_e1SkJ.

To post to this group, send email to andro...@googlegroups.com.
To unsubscribe from this group, send email to android-ndk...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/android-ndk?hl=en.

Jakob Bohm

unread,
Jun 5, 2012, 10:52:06 PM6/5/12
to android-ndk
On Jun 5, 9:47 am, Angus Lees <gusl...@gmail.com> wrote:
> On Tue, Jun 5, 2012 at 3:10 PM, technicware <technicw...@gmail.com> wrote:
> > Gus,
>
> > Like I said, that same piece of code works on 4 other platforms and
> > reliably return all possible local address of 'addr', and 'addr' comes from
> > a call to gethostname().
> > Why don't we concentrate on *gethostname()* instead of getaddrinfo().
>
> > I believe on all 4 other platforms, gethostname() returns the local host
> > name, which will *resolve* to all possible addresses, including multiple
> > network cards, WIFI, PPP, VPN, etc.
>
> Oh right.  As you say, this works in other situations because gethostname()
> returns something that getaddrinfo() then looks up in
> DNS/WINS/hosts/whatever and returns all the addresses configured in that
> name service for whatever gethostname() returned.  In particular, it does
> not return all the addresses on the local machine (it won't return
> 127.0.0.1 loopback, link local IPv6, IPv6 privacy addresses, VPN addresses,
> or a whole lot of other addresses that just happen to be configured at the
> moment.  I doubt it returns anything more than what your DHCP response also
> said, for example).
>
> > The problem with Android is that gethostname() returns "*localhost*"
> > instead of the host name. As an result, 'localhost' can only resolve into
> > 127.0.0.1 and nothing else. See a similar thread with no definitive answer:
> > http://comments.gmane.org/gmane.comp.handhelds.android.ndk/11967
> > Why *gethostname()* only Android cannot return a host name other than
> > 'localhost'?
>
> This is hard - what hostname should it return for an unmanaged device like
> a phone?  It is unlikely that your phone has an entry in any name service
> (particularly for its 3G interface), and configuring something fake locally
> in /etc/hosts (or equivalent) and then resolving that fake name using
> getaddrinfo() will only return whatever addresses had been placed in the
> fake /etc/hosts entry.  It's a rather round about way to get the local
> addresses and I imagine it wouldn't be flexible enough to get what you
> wanted anyway (the address for your wifi interface is highly unlikely to
> ever appear against the same 'hostname' as your 3G interface or a corporate
> VPN inner address, for example).
>

This problem was previously solved (by multiple companies, not just
MS) in
3rd party TCP/IP stacks for 16 bit Windows 3.1 as follows:

1. gethostname() returns the (configurable) name that the device
presents
itself as in other contexts, such as Bluetooth. This is not always
unique,
but it can be made to be if the user wants to. No domain is appended
by
default, so it won't clash with anything resolvable on DNS servers
etc. It
is never the reserved string "localhost".

2. The local resolver code (getaddrinfo, getnameinfo and their
traditional
IPv4 cousins) special cases the name returned be gethostname and
returns the locally available addresses without bothering the name
servers (or /etc/hosts) or allowing them to spoof, confuse or
otherwise
override information the local machine knows first hand. Internally
the
resolver code does whatever platform specific tricks are needed to get
the (ever changing) local IP configuration rather than some cached
result. For instance getting a new address from DHCP, ICMPv6, RARP,
PPP, UMTS, IPv6 privacy extensions etc. changes the return value even
in already running processes (if they repeat the call to the resolver
they
will get the updated info).

This method (also used by the OP) tends to be much more portable
than trying to come up with unwieldy sequences of OS specific IOCTL
calls to enumerate and then filter local interfaces. It is a very
clean and
portable solution that works just about anywhere the resolver library
authors have actually thought about it.

Unfortunately a few platforms have naive resolvers that forget this
special
case and expect the outside DNS servers or /etc/hosts to somehow
know the local configuration better than the kernel. I have
previously
seen this brokenness on a few old Linux distributions and possibly on
some UNIX variant (not to be named as I am not certain). For these
there
is little choice for applications but to include tons of complex code
that
tries to figure out (at runtime) the exact platform version and then
make
a bunch of calls to extract the interface configuration from the
system
and filter out the weed from the chaff.

Code to do this unwieldy manual task can be found in a number of isc
maintained programs such as bind, various DHCP servers etc. in the
libisc
subdirectories of the source tarballs.

As bionic is already at version 4.x, we can hardly expect this to be
fixed
on existing devices, but it would be nice if future bionic versions
added the
missing functionality so applications only need their own special case
code
to handle existing platforms while being shielded from future API
changes.

> By the way, I am porting an ICE implementation to Android that works on all
>
> > 4 platforms mentioned above. I know what I am doing:
>
> >  http://tools.ietf.connectedorg/html/rfc5245<http://tools.ietf.org/html/rfc5245>

Angus Lees

unread,
Jun 6, 2012, 3:18:28 PM6/6/12
to andro...@googlegroups.com
2. The local resolver code (getaddrinfo, getnameinfo and their
traditional
IPv4 cousins) special cases the name returned be gethostname and
returns the locally available addresses without bothering the name
servers (or /etc/hosts) or allowing them to spoof, confuse or
otherwise
override information the local machine knows first hand.

Oh interesting!   My experience is almost entirely around Linux (and a few other Unix variants) where I've never seen such a feature.
 
I have previously seen this brokenness on a few old Linux distributions and possibly on
some UNIX variant (not to be named as I am not certain).

Really?  Can you point me to a Linux (or Unix) distro/version that does this?  I'd be interested in seeing how/where they chose to implement it.
(I've seen examples of where local addresses are reverse resolved and expected to find "official" DNS hostnames (not some magic internal host name) which seems like it would be broken by the logic you describe above, so I'm curious...)

.. and we're off-topic for android-ndk now, so perhaps we should move further discussion off-list.

 - Gus 

Aluvala Suman

unread,
Nov 23, 2012, 12:43:54 AM11/23/12
to Android NDK Google Group, gus...@gmail.com
I tried trying to get the local IP address in the native layer and in-vain. So wrote a code to get the IP address in the Java layer by making use of the connection manager then getting the IP address in the native by making use of the JNI. [Calling java function from the native layer]. Pasting Java code below for your convenience.

public static synchronized String getLocalAddress() {
        Context cntxt = getApplicationContext();
        ConnectivityManager connectivityManager = (ConnectivityManager) cntxt.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo activeNetworkInfo = connectivityManager
                .getActiveNetworkInfo();
        if (activeNetworkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
            WifiManager myWifiManager = (WifiManager) cntxt
                    .getSystemService(Context.WIFI_SERVICE);
            WifiInfo myWifiInfo = myWifiManager.getConnectionInfo();
            int ipAddress = myWifiInfo.getIpAddress();

            return android.text.format.Formatter.formatIpAddress(ipAddress);
        } else if (activeNetworkInfo.getType() == ConnectivityManager.TYPE_MOBILE) {
            try {
                Enumeration<NetworkInterface> interfs = NetworkInterface
                        .getNetworkInterfaces();
                NetworkInterface activeInterf = null;
                String hostName = NetworkInterface.getByInetAddress(
                        InetAddress.getLocalHost()).getName();
                InetAddress ret = null;

                while (interfs.hasMoreElements()) {
                    try {
                        activeInterf = interfs.nextElement();
                        if (activeInterf.isLoopback()) {
                            continue;
                        } else if (!hostName.equalsIgnoreCase(activeInterf
                                .getDisplayName())) {
                            ret = activeInterf.getInetAddresses().nextElement();

                            break;
                        }
                    } catch (NoSuchElementException e) {
                        continue;
                    }
                }

                return ret.getHostAddress();
            } catch (Exception e) {

            }
        } else {
            return null;
        }

        return null;
    }


On Thu, Nov 22, 2012 at 5:39 PM, PD <prasun...@gmail.com> wrote:
Hi,

I write 1 application to extract the IP address of a m/c. The application is given below:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>

#include <sys/socket.h>
#include <arpa/inet.h>

#include <netdb.h>
#define HAVE_GETADDRINFO 1

int main(int argc,char **argv)
{
int z;
char buf[1056];

z = gethostname(buf,sizeof buf);

if ( z == -1 )
{
fprintf(stderr, "%s: gethostname(2)\n",
strerror(errno));
exit(1);
}

struct addrinfo *result = NULL;
struct addrinfo *result1= NULL;
struct addrinfo *ptr = NULL;
struct addrinfo *rp = NULL;
struct addrinfo hints;

int sfd, s;

memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
hints.ai_socktype = SOCK_STREAM; /* Datagram socket */
hints.ai_flags= AI_ADDRCONFIG;

s = getaddrinfo(buf, "2345\0", &hints, &result);

for (rp = result; rp != NULL; rp = rp->ai_next)
{
printf("Addr\n");
char ipstr[INET6_ADDRSTRLEN];
void *addr;
char *ipver;

// get the pointer to the address itself,
// different fields in IPv4 and IPv6:
if (rp->ai_family == AF_INET) { // IPv4
struct sockaddr_in *ipv4 = (struct sockaddr_in *)rp->ai_addr;
addr = &(ipv4->sin_addr);
ipver = "IPv4";
} else { // IPv6
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)rp->ai_addr;
addr = &(ipv6->sin6_addr);
ipver = "IPv6";
}

// convert the IP to a string and print it:
inet_ntop(rp->ai_family, addr, ipstr, sizeof ipstr);
printf("%s: %s\n", ipver, ipstr);
//std::cout << " Val : " << INET6_ADDRSTRLEN << std::endl;

}
printf("host name = '%s'\n",buf);

return 0;
}

By using the application, proper addresses are not returned in newer version of solaris. I am always getting the link local address like - ::1 and 127.0.0.1.
But in older version of solaris, the application is working fine..

Any one can suggest to solve this type of issue in solaris 10/11.

Regards,
Prasun.

Edited by: 972649 on Nov 21, 2012 11:15
I want to extract the IP address of a m/c. Is there any other way?

--
You received this message because you are subscribed to the Google Groups "android-ndk" group.
To view this discussion on the web visit https://groups.google.com/d/msg/android-ndk/-/IX-g3al8nQkJ.
Reply all
Reply to author
Forward
0 new messages