inet_ntop and getaddrinfo
Hello folks,
I came across a really weird "bug" in my code.
Here is the code, without the header files (assume the correct header
files are included)
-- snip.c --
int main(int argc, char **argv) {
char buf[INET6_ADDRSTRLEN];
struct addrinfo *ptr;
int ret;
/* ./a.out google.com 80 */
if(argc != 3)
return -1;
if((ret = getaddrinfo(argv[1], argv[2], NULL, &ptr)) != 0) {
gai_strerror(ret);
return -1;
}
while(ptr != NULL) {
ret = socket(ptr->ai_family, ptr->ai_socktype, ptr-[color=blue]
>ai_protocol);[/color]
if(ret == -1)
perror("socket");
else {
if(connect(ret, ptr->ai_addr, ptr->ai_addrlen) == -1)
perror("connect");
else {
/* doesnt work, prints nonsense */
printf("connected to %s\n", inet_ntop(ptr->ai_family,
ptr->ai_addr, buf, sizeof buf));
/* works, notice the & in ptr->ai_addr */
printf("connected to %s\n", inet_ntop(ptr->ai_family,
&ptr->ai_addr, buf, sizeof buf));
}
close(ret);
}
ptr = ptr->ai_next;
}
return 0;
}
-- snip.c --
I have completely no idea why this happends.
inet_ntop() requires a pointer to a structure.
the ai_addr member of the addrinfo struct is 'struct sockaddr *',
which means &ai_addr is 'struct sockaddr **'
It only makes sense to pass ptr->ai_addr. The expression ptr->ai_addr
evaluates to a pointer to a structure, which is what inet_ntop wants.
Please help me with this matter..
Re: inet_ntop and getaddrinfo
[email]vippstar@gmail.com[/email] writes:
[please see original for code]
[color=blue]
> -- snip.c --
>
> I have completely no idea why this happends.
> inet_ntop() requires a pointer to a structure.
> the ai_addr member of the addrinfo struct is 'struct sockaddr *',[/color]
inet_ntop requires a pointer to an actual address, not a pointer to
a struct sockaddr. Assuming the address would be an IPv4-address, the
'actual type' of the returned address structure would be struct
sockaddr_in, defined as
struct sockaddr_in {
sa_family_t sin_family;
u_int16_t sin_port;
struct in_addr sin_addr;
};
and the correct argument to inet_ntop would be the address of the
sin_addr member of this structure. An equivalent way to pass the
same argument would be to use
ptr->ai_addr->sa_data + 2
sa_data is the (protocol specific) address data area of a struct
sockaddr, ie exluding metainformation like the address family, and
the increment skips over the two bytes representing the port.
Re: inet_ntop and getaddrinfo
On Mar 16, 5:03 pm, Rainer Weikusat <rweiku...@mssgmbh.com> wrote:[color=blue]
> vipps...@gmail.com writes:
>
> [please see original for code]
>[color=green]
> > -- snip.c --[/color]
>[color=green]
> > I have completely no idea why this happends.
> > inet_ntop() requires a pointer to a structure.
> > the ai_addr member of the addrinfo struct is 'struct sockaddr *',[/color]
>
> inet_ntop requires a pointer to an actual address, not a pointer to
> a struct sockaddr. Assuming the address would be an IPv4-address, the
> 'actual type' of the returned address structure would be struct
> sockaddr_in, defined as
>
> struct sockaddr_in {
> sa_family_t sin_family;
> u_int16_t sin_port;
> struct in_addr sin_addr;
> };
>
> and the correct argument to inet_ntop would be the address of the
> sin_addr member of this structure. An equivalent way to pass the
> same argument would be to use
>
> ptr->ai_addr->sa_data + 2
>
> sa_data is the (protocol specific) address data area of a struct
> sockaddr, ie exluding metainformation like the address family, and
> the increment skips over the two bytes representing the port.[/color]
Thanks a lot, so what's the correct way to pass what's returned from
getaddrinfo() to inet_ntop()?
&ptr->ai_addr? or ptr->ai_addr->sa_data + 2?
Or both are OK?
Re: inet_ntop and getaddrinfo
[email]vippstar@gmail.com[/email] writes:[color=blue]
> On Mar 16, 5:03 pm, Rainer Weikusat <rweiku...@mssgmbh.com> wrote:[color=green]
>> vipps...@gmail.com writes:
>>
>> [please see original for code]
>>[color=darkred]
>> > -- snip.c --[/color]
>>[color=darkred]
>> > I have completely no idea why this happends.
>> > inet_ntop() requires a pointer to a structure.
>> > the ai_addr member of the addrinfo struct is 'struct sockaddr *',[/color]
>>
>> inet_ntop requires a pointer to an actual address, not a pointer to
>> a struct sockaddr. Assuming the address would be an IPv4-address, the
>> 'actual type' of the returned address structure would be struct
>> sockaddr_in, defined as
>>
>> struct sockaddr_in {
>> sa_family_t sin_family;
>> u_int16_t sin_port;
>> struct in_addr sin_addr;
>> };
>>
>> and the correct argument to inet_ntop would be the address of the
>> sin_addr member of this structure. An equivalent way to pass the
>> same argument would be to use
>>
>> ptr->ai_addr->sa_data + 2
>>
>> sa_data is the (protocol specific) address data area of a struct
>> sockaddr, ie exluding metainformation like the address family, and
>> the increment skips over the two bytes representing the port.[/color]
>
> Thanks a lot, so what's the correct way to pass what's returned from
> getaddrinfo() to inet_ntop()?
> &ptr->ai_addr? or ptr->ai_addr->sa_data + 2?[/color]
,----
| inet_ntop requires a pointer to an actual address, not a pointer to
| a struct sockaddr.
|
| [struct sockaddr_in]
|
| the correct argument to inet_ntop would be the address of the
| sin_addr member of this structure.
`----
This means one option would be to convert the struct sockaddr *
to a struct sockaddr_in * and use the address of the sin_addr member
of that, eg
struct sockaddr_in const *sin;
sin = (void *)ptr->ai_addr;
... inet_ntop(..., &sin->sin_addr)
A struct sockaddr consists of
- a 'common' metadata field (aka 'address family')
- a char array holding per-protocol address information
The name of the later is sa_data. The per-protocol address information
of a struct sockaddr_in consists of a 16-bit port number, followed by
the (32 bit) IPv4 address. This means, assuming the definitions etc
above, that
ptr->ai_addr->sa_data + 2 == (char *)&sin->sin_addr
Your program actually prints nonsense when passing &ptr->ai_addr,
too. Just more reasonably appearing nonsense. The correct output would
be (one set of it):
[rw@fever]/tmp $./a.out [url]www.google.de[/url] 80
connected to 209.85.129.99
connected to 209.85.129.99
connected to 209.85.129.104
connected to 209.85.129.104
connected to 209.85.129.147
connected to 209.85.129.147
(2nd output statement deleted). The code generating this:
struct sockaddr_in const *sin;
[...]
sin = (struct sockaddr_in *)ptr->ai_addr;
printf("connected to %s\n", inet_ntop(ptr->ai_family, &sin->sin_addr, buf, sizeof buf));
Re: inet_ntop and getaddrinfo
On Mar 16, 6:17 pm, Rainer Weikusat <rweiku...@mssgmbh.com> wrote:[color=blue]
> | inet_ntop requires a pointer to an actual address, not a pointer to
> | a struct sockaddr.[/color]
I know you said this before but it's now that I understood it; thanks
for being patient..
It's weird I ignored that EVEN after reading the manual of inet_ntop
or your post.
I certainly need some sleep. ;-)[color=blue]
> <explanation of the sockaddr struct & other info>
> Your program actually prints nonsense when passing &ptr->ai_addr,
> too. Just more reasonably appearing nonsense. The correct output would
> be (one set of it):[/color]
Oh, that's an embarrassing mistake..
This settles it. My whole confusion was based on the false assumption
that &ptr->ai_addr works.[color=blue]
> [rw@fever]/tmp $./a.outwww.google.de80[/color]
The google interface appears to be buggy, it eats the whitespace
here.. I wonder why.[color=blue]
> <ip addresses of google>
> (2nd output statement deleted). The code generating this:
>
> struct sockaddr_in const *sin;
>
> [...]
>
> sin = (struct sockaddr_in *)ptr->ai_addr;
> printf("connected to %s\n", inet_ntop(ptr->ai_family, &sin->sin_addr, buf, sizeof buf));[/color]
Yep. thanks :D.