Discussion:
[nuttx] Changed behaviour of getsockname()
Pelle Windestam Pelle.Windestam@tagmaster.com [nuttx]
2018-02-08 13:02:08 UTC
Permalink
Hi,

We have previously used the getsockname() function on a UDP socket to get our local ip address. When we upgraded to NuttX 7.23 (from 7.21) this stopped working. I traced this down to a change in net/socket/getsockname.c, where the function ipv4_getsockname() was moved to net/inet/ipv4_getsockname.c. The function was also changed such that if the local address (upd_conn.u.ipv4.laddr) is set to 0 (i.e. INADDR_ANY) the returned IP-address is also 0. In the previous version, a local address of zero (for the socket) returned the IP address of the first ethernet device. I was wondering if this is intentional? From the posix spec:
"If the socket has not been bound to a local name, the value stored in the object pointed to by address is unspecified."
We do not bind the socket specifically, but send on it using sendto() which eventually calls udp_connect() which binds the socket to a local port. Not sure if this counts as binding it to a local name or not?

//Pelle
spudarnia@yahoo.com [nuttx]
2018-02-08 13:25:05 UTC
Permalink
We have previously used the getsockname() function on a UDP socket to get our local ip address. When we upgraded to NuttX 7.23 (from 7.21) this stopped working. I traced this down to a change in net/socket/getsockname.c, where the function ipv4_getsockname() was moved to net/inet/ipv4_getsockname.c. The function was also changed such that if the local address (upd_conn.u.ipv4.laddr) is set to 0 (i.e. INADDR_ANY) the returned IP-address is also 0. In the previous version, a local address of zero (for the socket) returned the IP address of the first ethernet device. I was wondering if this is intentional? ...
Yes, this is correct in the newer versions of NuttX. The old versions of NuttX had an option to support only a single network device. It did not matter if the packet was routable or not, it always responding with information about that single network device or, more correctly, the single network supported by the device.

That logic was wrong in previous versions of NuttX!

The current version of NuttX is correct. If asked about anything that requires knowledge of the routing, the query will either fail or will depend on some entry in the routing to table to determine what to do with the packet. In ipv4_getsockname() there it this:

dev = netdev_findby_ipv4addr(lipaddr, ripaddr);

And that will (1) try to find a network device serving the network of the remote address and, if none is found, it will (2) look in the routing table to determine which network device to use. If you only have one network device and you want the similar behavior to the older, incorrect code, you will need to add a default route like:

0.0.0.0/0 -> aa.bb.cc.dd

That will send everything tthat requires routing to network device that serves the network of aa.bb.cc.dd (If you wanted other routing, it should appear BEFORE this one in the routing table).
"If the socket has not been bound to a local name, the value stored in the object pointed to by address is unspecified."
I believe that if you wanted things behave the way you want on any Unix-like platform, you would need a default route in your routing table. I believe that NuttX is compatible with the rest of the world in this way.
We do not bind the socket specifically, but send on it using sendto() which eventually calls udp_connect() which binds the socket to a local port. Not sure if this counts as binding it to a local name or not?
udp_connect() is misnamed since there are no connections with datagrams. This is really just the internal implementation of sendto: When you sendto a remote peer, it will again do the lookup to find the device that serves the network of the remote peer. That device is then simply remembered in by udp_connect() in order to perform the send.

So I don't think this has any relevance (other than it might leave the socket in a bound state after the sendto... that would be wrong).

Greg
spudarnia@yahoo.com [nuttx]
2018-02-08 13:46:45 UTC
Permalink
You should also be aware of these new helper functions that I added to apps/netutils (in case just adding a routing table entry is insufficient):


netlib_ipv4adaptor(): Given the destination address, destipaddr, return the IP address assigned to the network adaptor that connects the sub-net that includes destipaddr.


netlib_ipv4router(): Given a destination address that is not on a local network, query the IPv4 routing table, and return the IPv4 address of the routing that will provide access to the correct sub-net.


These helper functions use network IOCTLs and were intended to support just the kind of operations that you need to do.


Greg
Pelle Windestam Pelle.Windestam@tagmaster.com [nuttx]
2018-02-09 12:08:16 UTC
Permalink
Post by ***@yahoo.com [nuttx]
You should also be aware of these new helper functions that I added to apps/netutils (in case just adding a routing table
netlib_ipv4adaptor():  Given the destination address, destipaddr, return the IP address  assigned to the network adaptor
that connects the sub-net that includes destipaddr.
netlib_ipv4router():   Given a destination address that is not on a local network, query the  IPv4 routing table, and
return the IPv4 address of the routing that  will provide access to the correct sub-net.
These helper functions use network IOCTLs and were intended to support just the kind of operations that you need to do.
Thanks for the detailed reply! This looks just like what we need.

//Pelle

Loading...