Try   HackMD

CS:APP CH11 Network Programming

CMU 2015 Fall: 15-213 Lecture 21
CMU 2015 Fall: 15-213 Lecture 22
CS:APP Code Examples

Key words: processes, signals, byte ordering, memory mapping, dynamic storage allocation.

Be careful, this book will not discuss IPv6 in any detail and will focus exclusively on the concepts behind IPv4.

11.2 Networks

To a host, a netork is just another I/O device that serves as a source and sink for data:

Data received from the network are copied from the adapter across the I/O and memory buses into memory, typically by a DMA transfer. Similarly, data can also be copied from memory to the network.

11.3 The Global IP Internet

Because Internet hosts can have different host byte orders, TCP/IP defines a uniform network byte order (big-endian) for any integer data item, such as an IP address, that is carried across the network in a packet header.

Unix provides the following functions for coverting between network and host byte order:

/* IP address structure */
struct in_addr {
    uint32_t s_addr; /* big-endian */
};
#include <arpa/inet.h>
// From host byte order to network byte order
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);

// From network byte order to host byte order
uint32_t ntonl(uint32_t netlong);
uint16_t ntons(uint16_t netshort);

port

  • Ephemeral: Assigned automaitcally by the client kernel when the client makes a connection request.
  • Well-known: Associated with some service provided by a server. The mapping between well-known names and well-known ports is contained in a file called /etc/services.

11.4 The Sockets Interface

Socket address structure:

/* IP socket address structure */
struct scokaddr_in {
    uint16_t        sin_family;   /* Protocal family (always AF_INET) */
    uint19_t        sin_port;     /* Port number in network byte order */
    struct in_addr  sin_addr;     /* IP address in network byte order */
    unsigned char   sin_zero[8];  /* Pad to sizeof(struct sockaddr) */
};

/* Generic socket address structure (for connect, bind, and accept) */
struct sockaddr {
    uint16_t  sa_family;    /* Protocol family */
    char      sa_data[14];  /* Address data */
};

The problem faced by the designeds of the sockets interface was how to define these functions to accept any kind of socket address structure. Today, we would use the generic void * pointer, which did not exist in C at that time. Their solution was to define sockets functions to expect a pointer to a generic sockaddr structure and then require applications to cast any pointers to protocol-specific structures to this generic structure.

socket()

  • Create a socket descriptor.
  • AF_INET indicates that we are using 32-bit IP addresses.
  • SOCK_STREAM indicates that the socket will be an end point for a connection.
  • See socket(2).
  • The best practice is to use getaddrinfo() to generate these parameters automically, so that the code is protocol-independent. (11.4.8)
  • Return nonnegative descriptor if OK, -1 on error.
int socket(int domain, int type, int ptotocol);

connect()

  • A client establishes a connection with a server by calling the connect().
  • Return: 0 if OK, -1 on error.
int connect(int clientfd, const struct sockaddr *addr, socklen_t addrlen);

bind()

  • Ask the kernel to associate the server's socket address in addr with the socket descriptor sockfd.
  • The best practice is to use getaddrinfo() to supply the arguments. (11.4.8)
  • Return: 0 if OK, -1 on error.
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

listen()

  • Convert sockfd from an active socket to a listening socket that can accept connection requests from clients.
  • The backlog argument is a hint about the number of outstanding connection requests that the kernel should queue up before it starts to refuse requests.
  • Return: 0 if OK, -1 on error.
int listen(int sockfd, int backlog);

accept()

  • Wait for a connection request from a client to arrive on the listening descriptor listenfd, then fills in the client's socket address in addr, and returns a connected descriptor that can be used to communicate with the client usong Unix I/O functions.
  • Return nonnegative descriptor if OK, -1 on error.
int accept(int listenfd, struct sockaddr *addr, int *addrlen);

getaddrinfo()

  • Convert string representations of host names, host addresses, service names, and port numbers into socket address structures.
  • Replace obsolete gethostbyname(), getservbyname().
  • It is reentrant and works with any protocol.
int getaddrinfo(const char *host,             /* Host name or address */
                const char *service,          /* Port or service name */
                const struct addrinfo *hints, /* Input parameters */
                struct addrinfo **result);    /* Output linked list */

void freeaddrinfo(struct addrinfo *result);   /* Free linked list */

const char *gai_strerror(int errcode);        /* Return error message */

The addrinfo structure:

struct addrinfo {
    int              ai_flags;     /* Hints argument flags */
    int              ai_family;    /* First arg to socket function */
    int              ai_socktype;  /* Second arg to socket function */
    int              ai_protocol;  /* Third arg to socket function */
    char            *ai_canonname; /* Canonical hostname */
    size_t           ai_addrlen;   /* Size of ai_addr struct */
    struct sockaddr *ai_addr;      /* Ptr to socket address structure */
    struct addrinfo *ai_next;      /* Ptr to next item in linked list */
};

11.5 Web Servers