Code Comments

Programming Forum and web based access to our favorite programming groups.
For Programmers: Free Programming Magazines | New: Database administration forum
Registration is free! Edit your profileCalendarFind other membersFrequently Asked QuestionsSearch -> 
Post New Thread











Thread
Author

Newbie question about getaddrinfo
Hi,

In the program below:


#include <stdio.h>
#include <errno.h>
#include <netdb.h>
#include <sys/socket.h>


int main(int argc, char **argv)
{
struct addrinfo hints, *res;
char ptr_ip[20];
int r;

memset(&hints, 0, sizeof(hints));
hints.ai_flags=AI_CANONNAME;
hints.ai_family=AF_INET;
if (r=getaddrinfo(argv[1], "domain", &hints, &res ))
{
printf("%s\n", gai_strerror(r));
exit(1);
}

inet_ntop(res->ai_family, res->ai_addr->sa_data, ptr_ip,
res->ai_addrlen);
printf("%s %s\n",res->ai_canonname, ptr_ip);
}



opmxopge@sgbe2 : /tmp > a.out sgbe2
sgbe2 0.53.10.95
opmxopge@sgbe2 : /tmp > ping -s sgbe2
PING sgbe2: 56 data bytes
64 bytes from sgbe2 (10.95.26.235): icmp_seq=0. time=0. ms
^C
----sgbe2 PING Statistics----
1 packets transmitted, 1 packets received, 0% packet loss
round-trip (ms)  min/avg/max = 0/0/0
opmxopge@sgbe2 : /tmp >



Why is 'a.out' output '0.53.10.95' ?

Thanks in advance,
Jose Luis.


Report this thread to moderator Post Follow-up to this message
Old Post
jose_luis_fdez_diaz_news@yahoo.es
04-18-05 08:58 PM


Re: Newbie question about getaddrinfo
Hola Jose-Luis!

> In the program below:

[snip]

> Why is 'a.out' output '0.53.10.95' ?

inet_pton() expects as second parameter a pointer to the field sin_addr
of a sockaddr_in structure. However, the res->ai_addr is a pointer to a
generic socket address structure (a struct sockaddr).

Thus, in order to use inet_ntop() with res->ai_addr, you must first cast
the res->ai_addr pointer into a sockaddr_in struct pointer, and then
pass the address of the corresponding sin_addr field:

int
main()
{
struct sockaddr_in* sin;

// ...
// call getaddrinfo

sin = (struct sockaddr_in*) res->ai_addr;
inet_ntop(res->ai_addr->sa_family, &sin->sin_addr, ptr_ip, sizeof(ptr_ip));
printf("%s %s\n",res->ai_canonname, ptr_ip);
}


HTH,
Loic.

Report this thread to moderator Post Follow-up to this message
Old Post
Loic Domaigne
04-19-05 01:58 AM


Re: Newbie question about getaddrinfo
jose_luis_fdez_diaz_news@yahoo.es wrote:
>        struct addrinfo hints, *res;
...
>        if (r=getaddrinfo(argv[1], "domain", &hints, &res ))
...

>        inet_ntop(res->ai_family, res->ai_addr->sa_data, ptr_ip, res->ai_addrlen);[
/color]
...
>Why is 'a.out' output '0.53.10.95' ?

This is the *same* problem that you had previously!  You *must*
provide the correct arguments to these functions, otherwise the
results are garbage.  The man page for inet_ntop(3) states,

const char *inet_ntop(int af, const void *src,
char *dst, socklen_t cnt);

..

src  points  to  a  struct in_addr ...

but what you are providing is *not* a a pointer to struct
in_addr, and will not magically become one until *you* provide
the magic.

And a bit of magic is exactly what it needs, because indeed the
data is buried in that struct addrinfo, though figuring out
where it is and how to get it can be "fun" (spelled
"frustrating" the first time you go through this).

The man page for getaddrinfo(3) says a struct addrinfo looks
like this:

struct addrinfo {
..
struct sockaddr *ai_addr;
char            *ai_canonname;
struct addrinfo *ai_next;
};

So  res->ai_addr is a pointer to struct sockaddr.  A quick
grep though the /usr/include headers comes up with a declaration
for struct sockaddr which looks like this:

struct sockaddr {
unsigned short int sa_prefix;
char sa_data[14];            /* Address data.  */
};

Note that the above is a "reconstructed" declaration.  The
actual declaration in the headers may (or may not) include
typedefs and #define'd macros.  The above one example of what it
all boils down to.

There is no struct in_addr member.  Instead there is a character
array that it says contains the address data...  apparently as
raw data.  You can grep for "struct in_addr" and what you'll
find is that it is a member of a struct sockaddr_in, and that a
struct sockaddr_in is purposely declared to be exactly the same
size as a struct sockaddr.  That is done to allow casting a
pointer to the same data as either a struct sockaddr or a struct
sockaddr_in.  The data can then be accessed in two different
ways, depending on which cast is used.

A struct sockaddr_in looks something like this (again, this is
"reconstructed", and the actual details will very likely be
different):

/* Structure describing an Internet socket address.  */
struct sockaddr_in {
unsigned short int sa_prefix;
unsigned short int sin_port;  /* Port number.  */
struct in_addr sin_addr;      /* Internet address.  */

/* Pad to size of `struct sockaddr'.  */
unsigned char sin_zero[sizeof (struct sockaddr) -
sizeof (unsigned short int) -
sizeof (unsigned short int) -
sizeof (struct in_addr)];
};

Comparing the two different structs gives you the answer to why
your results were so odd.  You are two bytes off!  You've
included the data for the port number as part of the IP address.

The trick is knowing just exactly how far into the
res->ai_addr->sa_data one has to offset in order to find the IP
address, and that is where the sockaddr_in structure is used.
(If you assumed it is always 2 bytes, as the above example
structs indicated, it will probably work just fine on almost
everything... and then you'll want to run it on a platform that
for whatever reason allocates 4 bytes for the port number, and
your the code would fail.  So don't do that!)

Instead, have two pointers to the same data, with one being
a pointer to struct sockaddr and one to struct sockaddr_in.
You already have res->ai_addr, which is a pointer to a sockaddr
structure, so just do something like this,

struct sockaddr_in *si = (struct sockaddr_in) &res->ai_addr;
inet_ntop(res->ai_family, &si->sin_addr.s_addr, ptr_ip, res->ai_addrlen);

--
Floyd L. Davidson           <http://web.newsguy.com/floyd_davidson>
Ukpeagvik (Barrow, Alaska)                         floyd@barrow.com

Report this thread to moderator Post Follow-up to this message
Old Post
Floyd L. Davidson
04-19-05 01:58 AM


Re: Newbie question about getaddrinfo
In article <877jizq0xl.fld@barrow.com>,
floyd@barrow.com (Floyd L. Davidson) wrote:

[snip lengthy explanation]

> Instead, have two pointers to the same data, with one being
> a pointer to struct sockaddr and one to struct sockaddr_in.
> You already have res->ai_addr, which is a pointer to a sockaddr
> structure, so just do something like this,
>
>  struct sockaddr_in *si = (struct sockaddr_in) &res->ai_addr;
>  inet_ntop(res->ai_family, &si->sin_addr.s_addr, ptr_ip, res->ai_addrlen);

Almost right.  The 4th parameter is wrong; it should be the size of the
destination buffer:

inet_ntop(res->ai_family, &si->sin_addr.s_addr, ptr_ip, sizeof(ptr_ip));

(Note that the OP declared ptr_ip to be an array of char, not a pointer.)

Report this thread to moderator Post Follow-up to this message
Old Post
Wayne C. Morris
04-19-05 08:59 AM


Re: Newbie question about getaddrinfo
"Wayne C. Morris" <wayne.morris@this.is.invalid> wrote:
>In article <877jizq0xl.fld@barrow.com>,
> floyd@barrow.com (Floyd L. Davidson) wrote:
>
>[snip lengthy explanation]
> 
>
>Almost right.  The 4th parameter is wrong; it should be the size of the
>destination buffer:
>
>  inet_ntop(res->ai_family, &si->sin_addr.s_addr, ptr_ip, sizeof(ptr_ip));
>
>(Note that the OP declared ptr_ip to be an array of char, not a pointer.)

Technically that will be okay though, as long as sizeof(ptr_up) is larger
than res->ai_addrlen, which it is in this case.

--
Floyd L. Davidson           <http://web.newsguy.com/floyd_davidson>
Ukpeagvik (Barrow, Alaska)                         floyd@barrow.com

Report this thread to moderator Post Follow-up to this message
Old Post
Floyd L. Davidson
04-19-05 01:57 PM


Re: Newbie question about getaddrinfo
Thanks for your long a clear explanation.


Regards,
Jose Luis.

PD. Alaska is a beautiful place. I think you are lucky to live there.

Floyd L. Davidson wrote:
> jose_luis_fdez_diaz_news@yahoo.es wrote: 
> ... 
> ...
> 
res->ai_addrlen);
> ... 
>
> This is the *same* problem that you had previously!  You *must*
> provide the correct arguments to these functions, otherwise the
> results are garbage.  The man page for inet_ntop(3) states,
>
>        const char *inet_ntop(int af, const void *src,
>                              char *dst, socklen_t cnt);
>
>        ...
>
>        src  points  to  a  struct in_addr ...
>
> but what you are providing is *not* a a pointer to struct
> in_addr, and will not magically become one until *you* provide
> the magic.
>
> And a bit of magic is exactly what it needs, because indeed the
> data is buried in that struct addrinfo, though figuring out
> where it is and how to get it can be "fun" (spelled
> "frustrating" the first time you go through this).
>
> The man page for getaddrinfo(3) says a struct addrinfo looks
> like this:
>
>  struct addrinfo {
>    ...
>    struct sockaddr *ai_addr;
>    char            *ai_canonname;
>    struct addrinfo *ai_next;
>  };
>
> So  res->ai_addr is a pointer to struct sockaddr.  A quick
> grep though the /usr/include headers comes up with a declaration
> for struct sockaddr which looks like this:
>
>  struct sockaddr {
>    unsigned short int sa_prefix;
>    char sa_data[14];            /* Address data.  */
>  };
>
> Note that the above is a "reconstructed" declaration.  The
> actual declaration in the headers may (or may not) include
> typedefs and #define'd macros.  The above one example of what it
> all boils down to.
>
> There is no struct in_addr member.  Instead there is a character
> array that it says contains the address data...  apparently as
> raw data.  You can grep for "struct in_addr" and what you'll
> find is that it is a member of a struct sockaddr_in, and that a
> struct sockaddr_in is purposely declared to be exactly the same
> size as a struct sockaddr.  That is done to allow casting a
> pointer to the same data as either a struct sockaddr or a struct
> sockaddr_in.  The data can then be accessed in two different
> ways, depending on which cast is used.
>
> A struct sockaddr_in looks something like this (again, this is
> "reconstructed", and the actual details will very likely be
> different):
>
>  /* Structure describing an Internet socket address.  */
>  struct sockaddr_in {
>     unsigned short int sa_prefix;
>     unsigned short int sin_port;  /* Port number.  */
>     struct in_addr sin_addr;      /* Internet address.  */
>
>     /* Pad to size of `struct sockaddr'.  */
>     unsigned char sin_zero[sizeof (struct sockaddr) -
>                            sizeof (unsigned short int) -
>                            sizeof (unsigned short int) -
>                            sizeof (struct in_addr)];
>  };
>
> Comparing the two different structs gives you the answer to why
> your results were so odd.  You are two bytes off!  You've
> included the data for the port number as part of the IP address.
>
> The trick is knowing just exactly how far into the
> res->ai_addr->sa_data one has to offset in order to find the IP
> address, and that is where the sockaddr_in structure is used.
> (If you assumed it is always 2 bytes, as the above example
> structs indicated, it will probably work just fine on almost
> everything... and then you'll want to run it on a platform that
> for whatever reason allocates 4 bytes for the port number, and
> your the code would fail.  So don't do that!)
>
> Instead, have two pointers to the same data, with one being
> a pointer to struct sockaddr and one to struct sockaddr_in.
> You already have res->ai_addr, which is a pointer to a sockaddr
> structure, so just do something like this,
>
>  struct sockaddr_in *si = (struct sockaddr_in) &res->ai_addr;
>  inet_ntop(res->ai_family, &si->sin_addr.s_addr, ptr_ip,
res->ai_addrlen);
>
> --
> Floyd L. Davidson           <http://web.newsguy.com/floyd_davidson>
> Ukpeagvik (Barrow, Alaska)                         floyd@barrow.com


Report this thread to moderator Post Follow-up to this message
Old Post
jose_luis_fdez_diaz_news@yahoo.es
04-19-05 01:57 PM


Sponsored Links




Last Thread Next Thread Next
Search this forum -> 
Post New Thread

Unix Programming archive

Show a Printable Version Send to friend Email This Page to Someone! subscribe to this thread Receive updates to this thread
Computer Consultants
Programming Jobs
Visual Basic Controls
SQL Server Programming
Webservices
Java Security
Visual Studio
C# Programming
Visual J++
Software engineering
Open source Software
Perl Programming
PHP Programming
ASP Programming
ASP .NET Programming
Visual Basic Programming
Windows Scripting Host
Java Programming
Java Help
Java Beans
VBScript
Cobol
MAC Applications
Unix Programming
Forum Jump:
All times are GMT. The time now is 07:16 PM.

 
Free MCSE Braindumps | Real Estate Topics

Programming forum archive

Copyrights CodeComments.com 2004 - 2006

Powered by vBulletin Copyright 2000-2006 Jelsoft Enterprises Limited.