Search code examples
clinuxrecvfrom

What byte order does recvfrom() save src_addr as?


size_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen)

In what byte order is the src_addr argument written? Network or host? I couldn't find this in the recvfrom man page or a search through google and SO.


Solution

  • Assuming the socket is an IPv4 or IPv6 socket, the host and port stored in src_addr will be in network byte order.

    This is documented in the man page for IPv4 (man 7 ip) as follows:

    Address format

    An IP socket address is defined as a combination of an IP interface address and a 16-bit port number. The basic IP protocol does not supply port numbers, they are implemented by higher level protocols
    like udp(7) and tcp(7). On raw sockets sin_port is set to the IP protocol.

       struct sockaddr_in {
           sa_family_t    sin_family; /* address family: AF_INET */
           in_port_t      sin_port;   /* port in network byte order */
           struct in_addr sin_addr;   /* internet address */
       };
    
       /* Internet address. */
       struct in_addr {
           uint32_t       s_addr;     /* address in network byte order */
       };
    

    sin_family is always set to AF_INET. This is required; in Linux 2.2 most networking functions return EINVAL when this setting is missing. sin_port contains the port in network byte order. The port numbers below 1024 are called privileged ports (or sometimes: reserved ports). Only a privileged process (on Linux: a process that has the CAP_NET_BIND_SERVICE capability in the user namespace governing its network namespace) may bind(2) to these sockets. Note that the raw IPv4 protocol as such has no concept of a port, they are implemented only by higher protocols like tcp(7) and udp(7).

    sin_addr is the IP host address. The s_addr member of struct in_addr contains the host interface address in network byte order. in_addr should be assigned one of the INADDR_* values (e.g., INADDR_LOOPBACK) using htonl(3) or set using the inet_aton(3), inet_addr(3), inet_makeaddr(3) library functions or directly with the name resolver (see gethostbyname(3)).

    The ipv6 man page has similar wording.

    So when reading the port number, use ntohs to extract it. When reading the address, use inet_ntop to convert it to text form.