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