Date: Thu, 13 Mar 2008 22:57:03 -0700 From: Patrick Mahan <mahan@mahan.org> To: Andrew Falanga <af300wsm@gmail.com> Cc: FreeBSD Questions <freebsd-questions@freebsd.org> Subject: Re: Network programming question Message-ID: <47DA13AF.5090804@mahan.org> In-Reply-To: <340a29540803131111g20315740n629ee146bc2f8602@mail.gmail.com> References: <340a29540803130910l2a5badacxe50cd81ace87e1f7@mail.gmail.com> <47D9682B.5060402@mahan.org> <340a29540803131111g20315740n629ee146bc2f8602@mail.gmail.com>
next in thread | previous in thread | raw e-mail | index | archive | help
Andrew Falanga presented these words - circa 3/13/08 11:11 AM-> > On Thu, Mar 13, 2008 at 11:45 AM, Patrick Mahan <mahan@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
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?47DA13AF.5090804>