Files
cws/notes/basic-concepts.md

4.4 KiB

Basic concepts

Before reading, this document could contain errors, please check everything you read.

Socket

When Unix programs do some I/O they do it reading/writing to a file descriptor. A file descriptor is an integer associated with an open file, it can be anything. To communicate over the internet using a file descriptor we'll make a call to the socket() system routine.

Internet sockets

There are two types of Internet sockets:

  1. Stream Sockets (SOCK_STREAM) - error-free and a realiable two-way communication (TCP)
  2. Datagram Sockets (SOCK_DGRAM) - connectionless (UDP)

Byte Order

  • Big-Endian (also called Network Byte Order)
  • Little-Endian

Before making any transmission we have to convert the byte order to a Network Byte Order, we can do this with simple functions:

Function Description
htons() Host to Network Short
htonl() Host to Network Long
ntohs() Network to Host Short
ntohl() Network to Host Long

And convert the answer to the host byte order.

Structs

struct addrinfo

This struct prepares the socket address strcutures for subsequent use.

struct addrinfo {
    int              ai_flags;     // AI_PASSIVE, AI_CANONNAME, etc.
    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; // full canonical hostname

    struct addrinfo *ai_next;      // linked list, next node
};

struct sockaddr

Inside the struct we can see there is a pointer to the struct sockaddr, that is defined as follows:

struct sockaddr {
    unsigned short    sa_family;    // address family, AF_xxx
    char              sa_data[14];  // 14 bytes of protocol address
};

struct sockaddr_in

But, we can avoid to pack manually the stuff inside this struct and use the struct sockaddr_in (or struct sockaddr_in6 for IPv6) with a fast cast that is made for the Internet:

struct sockaddr_in {
    short int          sin_family;  // Address family, AF_INET
    unsigned short int sin_port;    // Port number
    struct in_addr     sin_addr;    // Internet address
    unsigned char      sin_zero[8]; // Same size as struct sockaddr
};

sin_zero is used to pad the struct to the length of a sockaddr and it should be set to all zeros (memset()).

struct sockaddr_storage

This struct is designed to storage both IPv4 and IPv6 structures. Example, when a client is going to connect to your server you don't know if it is a IPv4 or IPv6 so you use this struct and then cast to what you need (check the ss_family first).

struct sockaddr_storage {
    sa_family_t  ss_family;     // address family

    // all this is padding, implementation specific, ignore it:
    char      __ss_pad1[_SS_PAD1SIZE];
    int64_t   __ss_align;
    char      __ss_pad2[_SS_PAD2SIZE];
};

IP Addresses

Here's a way to convert an IP address string into a struct.

struct sockaddr_in sa;
struct sockaddr_in6 sa6;

inet_pton(AF_INET, "192.168.0.1", &(sa.sin_addr));
inet_pton(AF_INET6, "2001:db8:63b3:1::3490", &(sa6.sin6_addr));

There is a very easy function called inet_pton(), pton stands for Presentation to network. If you want to do the same but from binary to string you have inet_ntop().

getaddrinfo()

int getaddrinfo(const char *node,     // e.g. "www.example.com" or IP
                const char *service,  // e.g. "http" or port number
                const struct addrinfo *hints,
                struct addrinfo **res);

The node could be a host name or IP address. service could be a port number or a service found in /etc/services (e.g. "http" or "ftp" or "telnet"). hints points to a struct you already filled and res contains a linked list of results.