Network programming question
Patrick Mahan
mahan at mahan.org
Fri Mar 14 05:57:04 UTC 2008
Andrew Falanga presented these words - circa 3/13/08 11:11 AM->
> On Thu, Mar 13, 2008 at 11:45 AM, Patrick Mahan <mahan at mahan.org> wrote:
>>
>> Andrew Falanga presented these words - circa 3/13/08 9:10 AM->
>>
>>> Hi,
>> See man inet_pton . . . for details.
>>
>> Briefly, inet_pton() doesn't understand sockaddr structures. Instead,
>> it only understands in_addr or in6_addr structures which are included
>> inside the sockaddr structure. So your above example should be changed
>> to
>>
>
> Ok, I should have thought of that when reading the manual.
>
>> if ((res = inet_pton(AF_INET, "192.168.0.1", &sa.sin_addr)) < 0)
>> perror("inet_pton");
>>
>>
>> Because it is treating the sockaddr_in structure as an in_addr structure
>> which is clobbering the sin_family field.
>>
>
> If this is true, then why are my packets sent at all? The definition
> of sockaddr_in (from /usr/include/netinet/in.h):
>
> struct sockaddr_in {
> uint8_t sin_len;
> sa_family_t sin_family;
> in_port_t sin_port;
> struct in_addr sin_addr;
> char sin_zero[8];
> };
>
>
> The definition of in_addr (from /usr/include/netinet/in.h):
>
> struct in_addr {
> in_addr_t s_addr;
> };
>
> The definition of in_addr_t (from /usr/include/netinet/in.h):
> typedef uint32_t in_addr_t;
>
> Passing in what I have, the address should indeed (as you've pointed
> out) clobber the sin_family member. However, since in_addr is
> basically an unsigned integer, i.e. 4 bytes wide, shouldn't
> inet_pton(3) clobber sin_len, sin_family & sin_port before ever
> reaching sin_addr? The sin_len & sin_family are 8 bit quantities, the
> sin_port is 16 bits, that's 32. If inet_pton(3) is expecting only an
> in_addr I would think that a call to sendto(2) would fail because the
> address in sin_addr is not filled, correct?
inet_pton() clobbered the fields you pointed out. In fact the sin_family
field was being set to 0x01 which caused your initial EADDRNOTSUPPORT error
you were seeing. You quick change fixed that problem. However, (depending
on how sockaddr_in structure is actually allocated) the sin_addr field was
0.0.0.0. This is actually an accepted form of the broadcast address for UDP
packets. I forget exactly who the culprit was (Sun comes to mind) but there
was a need to allow broadcasts to 0.0.0.0 (which is also know as INADDR_ANY).
So, therefore, sendto() succeeded, just not in the way you expected. Looking
at in_pcbconnect_setup() in the kernel shows that actually the packet is sent
to the local primary interface address.
Let's look at what really happen to that packet -
"192.168.0.1" after being mangled by inet_pton() gives
the field sin_addr.s_addr of 0x0100A8C0. This should make
your sockaddr_in structure look like -
sa.sin_len = 0x01
sa.sin_family = 0x00
sa.sin_port = 0xA8C0 (which is port 49320)
sa.sin_addr.s_addr = 0x00000000
So the sendto() call was sending a packet to your local interface for port 49320.
And since UDP is a connectionless protocol, you don't have a way (unless it is
builtin to your application protocol) to determine an error. For example, TFTP
sends back notification for every dgram received.
I hope this helps with your understanding. I highly recommend if you are going
to do more network programming that you obtain at least some books on the subject.
Patrick
More information about the freebsd-questions
mailing list