Simon Zimmermann: Socket Interface

2009-12-17

Socket Interface

These are my personal notes from Beej’s Guide to Network Programming Using Internet Sockets. I write down what I find important as this makes it easier for me to remember. You should read the guide, not this document. ((http://beej.us/guide/bgnet/))  ((http://beej.us/guide/bgnet/output/html/multipage/sockaddr_inman.html))

IPv4 & IPv6 can be used. We can do bitwise AND operation on Netmask with IP and you get your network address. Didn’t know that. E.g. 192.0.2.12 AND 255.255.255.0 gives 192.0.2.0.

// IPv4 Loopback
127.0.0.1

// IPv6 Looback
0000:0000:0000:0000:0000:0000:0000:0001

// IPv6 Looback (shorthand)
::1

// IPv6 using IPv4
::ffff:127.0.0.1

ports

In addition to IP-addresses and network masks it’s important to remember that 16-bit port-addresses are used as room-numbers for communicating with our programs. Both TCP and UDP uses this.
// Overview of Port's.
# /etc/services

Network Byte Order conversion

There are two ways to store bytes; the Little-Endian (intel processors) and the Big-Endian (Network Byte Order). All computers store bytes in Host Bytes Order which is determined by its processor. The Network Byte Order would store a hex value e.g. 0x0FF3 in two sequential bytes [0F] [F3], while intel processors reverse this.To get the Host Network Order right without knowing the architecture we use a few functions. The functions accept short and long, two and four bytes respectively.

You use these functions to convert the numbers before you send them off on a network, and convert them as they come in off the wire.

htons() // Host to network short.
htonl() // Host to network long.
ntohs() // Network to host short.
ntohl() // Network to host long.

socket interface

A file descriptor is the simplest struct and is only an int.

Of course that doesn’t make all that much sense, an int is an int. structs are used to define a frame of a set of properties used to simplify and classify something. addrinfo is a structure used to prepare socket address’ for subsequent use.

struct addrinfo

A structure used for host name lookups and service name lookups. It’s one of the things we call when making a connection. getaddrinfo() returns a pointer to a new linked list of these structures filled out.

struct addrinfo {
    int             ai_flags; // AI_PASSIVE, AI_CANONNAME
    int         ai_family; // AF_INET, AF_INET6, AF_UNSPEC
    int             ai_socktype; // SOCK_STREAM, SOCK_DGRAM
    int             ai_protocol; // use  0 for "any"
    size_t          ai_addrlen; // size of ai_addr in bytes
    struct sockaddr *ai_addr; // struct sockaddr_in or _in6
    char            *ai_canonname; // canonical hostname
    struct addrinfo *ai_next; // linked list, next node
};

The addrinfo socket can be forced to use one type of IP version(AF_INET, AF_INET6) or it can be used in a generic way with AF_UNSPEC set. Since this is a linked list *ai_next is a pointer to the next element in the list, if there are any. As a rule of thumb, use the first element.

getaddrinfo() is used to fill out the sockaddr(*ai_addr) struct in struct addrinfo. The sockaddr struct contains a destination address and port number for the socket, within its sa_data char array. This struct can be both IPv4 and IPv6.

“Given node and service, which identify an Internet host and a service, getaddrinfo() returns one or more addrinfo structures, each of which contains an Internet address that can be specified in a call to bind(2) or connect(2). The getaddrinfo() function combines the functionality provided by the getservbyname(3) and getservbyport(3) functions into a single interface, but unlike the latter functions, getaddrinfo() is reentrant and allows programs to eliminate IPv4-versus-IPv6 dependencies.” ((# man getaddrinfo))

struct sockaddr

“Points to a sockaddr structure containing the peer address. The length and format of the address depend on the address family of the socket.” ((# man connect))

struct sockaddr {
    unsigned short  sa_family; // address family, AF_...
    char            sa_data[14]; // 14 byte protocol addr
}

Parallel structures are used to deal with the struct sockaddr; struct sockaddr_in and struct sockaddr_in6. A pointer to a struct sockaddr_in/6 can be cast to a pointer to a struct sockaddr. This is handy since connect() expects a pointer to a struct sockaddr*.

struct sockaddr_in and struct in_addr

struct sockaddr_in {
    short int       sin_family; // address family, AF_INET
    unsigned short int sin_port; // port number
    struct in_addr  sin_addr; // interface address
    unsigned char   sin_zero[8]; // size of sockaddr
}

This struct is used to reference elements of socket address. Use memset() with sin_zero. sin_family corresponds to sa_family in sockaddr, should be AF_INET. sin_port must be in Network Byte Order.

in_addr is referenced in sockaddr_in, and is the 4-byte IP-address in Network Byte Order. We have the same type of struct in a IPv6 specific version.

struct in_addr {
    uint32_t    s_addr; // 4-bytes
}

struct sockaddr_in6 and struct in6_addr

This is basically the same as sockaddr_in and in_addr, just for IPv6.

struct sockaddr_in6 {
    u_int16_t       sin6_family; // AF_INET6
    u_int16_t       sin6_port; // Network Byte Order
    u_int16_t       sin6_flowinfo; // IPv6 flowinfo
    struct in6_addr sin6_addr; // IPv6 address
    u_int32_t       sin6_scope_id; // scope ID
}

struct in6_addr {
    unsigned char   s6_addr[16]; // IPv6 address
}

struct sockaddr_storage

If you don’t know what kind of IP-version you are expecting you use this struct as a temporary storage facility, check ss_family field to see if it’s AF_INET or AF_INET, and then cast it to the appropriate structure.
// Temporary storage facility if you dont know IP-version
struct sockaddr_storage {
    ss_family_t     ss_family; // address family

// ... uninteresting padding ..
};

IP

inet_pton() - presentation to network

Used to convert a string IP to its binary representation.

“This function converts the character string src into a network address structure in the af address family, then copies the network address structure to dst. The af argument must be either AF_INET or AF_INET6.” ((# man inet_pton))

#include <arpa/inet.h>

int inet_pton(int af, const char *src, void *dst);

// example

struct sockaddr_in sa;
struct sockaddr_in6 sa6;

inet_pton(AF_INET, "127.0.0.1", &(sa.sin_addr));
inet_pton(AF_INET6, "::1::8080", &(sa6.sin6_addr));

inet_ntop() - network to presentation

Used to convert a binary IP to its string representation. This is used when you have a in_addr. INET_ADDRSTRLEN are defined in <netinet/in.h>.

This function converts the network address structure src in the af address family into a character string. The resulting string is copied to the buffer pointed to by dst, which must be a non-NULL pointer. The caller specifies the number of bytes available in this buffer in the argument size. ((# man inet_ntop))

#include <arpa/inet.h>

const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);

// example:

// IPv4
char ip4[INET_ADDRSTRLEN] // INET_ADDRSTRLEN : 16
struct sockaddr_in sa;

inet_ntop(AF_INET, &(sa.sin_addr), ip4, INET_ADDRSTRLEN);

// IPv6
char ip6[INET6_ADDRSTRLEN] // INET6_ADDRSTRLEN : 46
struct sockaddr_in6 sa6;

inet_ntop(AF_INET6, &(sa6.sin6_addr), ip6, INET6_ADDRSTRLEN);