
Programming System
Socket programming
Tutorial class by Philippe Décogné
25/01/2003 (dd/mm/yy)
Creating and binding a socket
Give the definition of socket and the format of the primitive which creates it.
Which are the processes that can use the socket after its creation?
Which is the primitive that binds a networking address to a socket?
Socket's definition
It is a bidirectional communication mean between processes on independent machines.
The socket is represented by a special file which serves as communication endpoint for a process to send and receive information.
An inode is associated with each socket. The socket's descriptor is similar to a file descriptor (entry in the descriptor table).
Caption
• table des descripteurs du processus: process descriptors table
• table des fichiers ouverts: open files table
• table des i-noeuds: inodes table

Primitive for creating a socket
Socket: int socket(int domain, int type, int protocol);
Creates a communication endpoint and returns a descriptor.
The parameter domain specifies the communications domain which communication will take place in. It is bound to the protocols family used for the communication (see sys/socket.h for families definition). The most used domains are:
- AF_LOCAL (previously AF_UNIX) for local communications
- AF_INET for remote communications
The parameter type specifies the type of communications. It indicates the sequencing, the reliability, the connection mode, and the encoding. The most commonly used type are the following:
- SOCK_STREAM for sequenced, reliable two-way full-duplex connection, in connected state, based on bytes streams.
- SOCK_DGRAM for unreliable, connectionless connection, based on datagrams of a fixed length (typically small messages).
The parameter protocol indicates the type of protocol to be used on the socket. Generally a unique protocol handles a given socket type, but it may happen that several protocols handle the same given socket type, in which case the parameter protocol indicates the desired protocol (see /etc/protocols for protocols definition and netinet/in.h for parameters IPPROTO). Most commonly used specifications:
- 0: the system chooses the default protocol
- TCP with SOCK_STREAM
- UDP with SOCK_DGRAM
- IPPROTO_UDP: UDP within AF_INET domain
- IPPROTO_TCP: TCP within AF_INET domain
On success, returns the socket's descriptor, otherwise -1.
Libraries to be used: sys/types.h and sys/socket.h.
Man page: socket(2) - system calls
Communication management
The socket's inode catalogs both pending and running queues.
Caption
• I-noeud: inode
• Protocole: protocol
• État: state
• Connexions en attente: pending connections
• Connexions en cours: running connections
• Données à émettre: pending outcoming messages
• Données à recevoir: pending incoming messages

Processes that can use the socket
As the socket is known through a file descriptor, the processes that can use it are the following:
- the socket's creator
- any child by duplicating the process environment
Binding a socket to a networking address
The primitive bind allows to bind a socket to a networking address.
Primitive to be used
Bind: int bind(int s, const struct sockaddr *name, int namelen);
Assigns the name name of length namelen to an anonymous socket with descriptor s (the socket created by the primitive socket() is an anonymous socket).
Returns 0 on success, otherwise -1.
Within the UNIX domain the name is a full path to a file. Within the INET domain the name matches an IP address.
name is a pointer to the socket's address. The address structure depends on the socket's domain.
Address structure within AF_UNIX domain
struct sockaddr-un {
uint8_t sun_len; // structure length
sa_family_t sun_family; // AF_UNIX
char sun_path[104]; // reference
}
The parameter sun_path should be a character string ending with \0.
Socket's iPv4 address structure
struct sockaddr-in {
uint8_t sin_len; // structure length
sa_family_t sin_family; // AF_INET
in_port_t sin_port; // TCP or UDP port number
struct in_addr sin_addr; // machine's IPv4 address structure
char sin-zero[8]; // padding
}
The parameter sin_len does not exist on all systems (it exists on Mac OS X), when it exists, it is used by the kernel for routed sockets.
Machine's IPv4 address structure
struct in-addr {
in_addr_t s_addr;
}
Socket's IPv6 address structure
struct sockaddr-in6 {
uint8_t sin6_len; // structure length
sa_family_t sin6_family; // AF_INET6
in_port_t sin6_port; // transport layer's port
uint32_t sin6_flowinfo // priority & flow label
struct in6_addr sin6_addr; // machine's IPv6 address structure
char sin-zero[8]; // padding
}
Machine's IPv6 address structure
struct in6-addr {
uint8_t s6_addr[16];
}
Libraries to be used: sys/types.h and sys/socket.h.
Man page: bind(2) - system calls
Example: creating a socket and binding it to a UNIX address
Primitives to be used
Unlink: int unlink(const char *path);
Removes the link path from the directory where it is located and decrements the link count of the file referenced by the link.
If the link count reaches zero and there is no other process that uses the file, the the file is closed. If there is a process which uses the file when the link count reaches zero, the link is removed, but the removal of the file is delayed till all processes which reference that file have closed it.
Returns 0 on success, otherwise -1
Library to be used: unistd.h.
Man page: unlink(2) - system calls
Bzero: void bzero(void *b, size_t len);
Write len zero bytes into the string b.
Library to be used: string.h.
Man page: bzero(3) - subroutines
Getsockname: int getsockname(int s, struct sockaddr *name, int *namelen);
Returns into name the current name of the socket s. The parameter namelen should be initialized to the length of the structure name. On return it will contain the length in bytes of the returned name.
Returns 0 on success, otherwise -1.
Library to be used: sys/socket.h.
Man page: getsockname(2) - system calls
Computing the address length

Code
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
int sock1;
int socklen;
// Define the full pathname to socket name
char pathname[] = "/tmp/foo.bar";
struct sockaddr_un addr1;
// Create the socket
if ( (sock1 = socket(AF_LOCAL, SOCK_STREAM, 0)) == -1)
{
perror("error socket");
exit(EXIT_FAILURE);
}
// Delete the eventual link to pathname
unlink(pathname);
// Fill in the structure with zeros
bzero(&addr1, sizeof(struct sockaddr_un));
// Define the domain of the socket
addr1.sun_family = AF_LOCAL;
// Fill in the pathname member with given pathname
strcpy(addr1.sun_path, pathname);
// Compute the length of the path in the structure
socklen = sizeof(struct sockaddr_un) -sizeof(addr1.sun_path) +
strlen(addr1.sun_path);
// Attach the address to the socket
bind(sock1, (struct sockaddr_un *) &addr1, socklen);
// Get the name of the socket
getsockname(sock1, (struct sockaddr *) &addr1, &socklen);
// Print it
printf("Bound name: %s, returned len: %d\n", addr1.sun_path,
socklen);
// Remove the link
unlink(pathname);
// Exit
exit(0);
}
Caution: this program should handle errors on all primitives. One example is given with perror(). But it would be better to wrap each primitive inside a new function which handles the most relevant errors.
The program first deletes the eventual link to the socket path, as if a link already exists the bind primitive issues an error. Then the address structure is zeroed, so that we begin in a clean state. Then we define the family and the name, and finally we compute the address length.
Once the address structure is defined, it is possible to bind it to the socket, retrieve its name and the address length, and print them. Finally we should delete the link created previously to get out of the program in a clean state.
Networking address
Storage of networking addresses, and more generally storage of bytes, may be made locally in two ways depending on the system (some systems use both types of storage):
- big endian (used on Mac OS X)
- little endian
Big endian byte order vs little endian byte order for a 16-bit integer (2 bytes of 8 bits).
• Byte de plus fort poids: high-order byte
• Byte de plus faible poids: low-order byte
• Adresse: address
• Sens de l'adressage: increasing memory address

For a simple application to retrieve the machine's byte ordering, see FindByteOrder for a version with a GUI and ByteOrder for a version without a GUI.
On the contrary, Internet protocols use always big endian byte ordering. Some primitives and structures use also big endian order, no matter which byte ordering is used on the host. Therefore we need primitives to convert between both types of bytes orders.
Primitives to be used
Inet_pton: int inet_pton(int af, const char *src, void *dst);
Converts an address in decimal format held in the character string src to an address in big endian network format which will be held in the dst structure.
Returns 1 if the address is valid for the protocols family af, 0 if the address is not valid for the family af, and -1 if some system error occurs.
Libraries to be used: sys/types.h, sys/socket.h, netinet/in.h, arpa/inet.h
Man page: inet_pton(3) - subroutines
Inet_ntoa: char * inet_ntoa(struct in_addr in);
Converts an address in big endian network format held in the structure in to an address in decimal format held in an ASCII character string.
Libraries to be used: sys/types.h, sys/socket.h, netinet/in.h, arpa/inet.h
Man page: inet_pton(3) - subroutines
Htons: uint16_t htons(uint16_t hostshort);
Converts a 16-bits value hostshort in host format to the same value in big endian network format.
On a Mac, the macro is defined as identity.
Library to be used: arpa/inet.h
Man page: byteorder(3) - subroutines
Htonl: uint32_t htonl(uint32_t hostlong);
Converts a 32-bits value hostlong in host format to the same value in big endian network format.
On a Mac, the macro is defined as identity.
Library to be used: arpa/inet.h
Man page: byteorder(3) - subroutines
For simple applications using those primitives, see TimeService and TimeService1 for versions with a GUI, and timeservice and timeservice1 for versions without a GUI.
Global error handing
Here we use the so called variadic functions, which can handle as many arguments as the caller passes, combined with the functions dedicated to printing character strings and which accept a variable number of arguments.
Basics
1 - We define a function that accepts a variable number of arguments using an ellipsis in the argument list:
void function(int b, ...)
2 - Inside this function we declare a variable argument list va_list
3 - We initialize a pointer on that list with:
va_start
4 - We call a function that use some printing primitives passing the argument variable list as parameter.
5 - On return we delete the pointer to the argument variable list with:
va_end
See The GNU C Library - Variadic Functions for further explanations and other usage of those functions.
Library to be used: starg.h.
Man page: stdarg(3) - subroutines
Primitives to be used
Vsnprintf: int vsnprintf(char *str, size_t size, const char *format, va_list ap);
Writes at most size - 1 characters in the buffer str using the arguments supplied by the list ap and converted to format format.
Returns the number of characters that would have been written if the buffer's size were unlimited. If the number of characters to be written is greater than the buffer's size, truncates the character string.
Library to be used: stdio.h.
Man page: printf(3) - subroutines
Snprintf: int snprintf(char *str, size_t size, const char *format, ...);
Writes at most -1 characters in the buffer str, the string is converted to the format format.
Returns the number of characters that would have been written if the buffer's size were unlimited. If the number of characters to be written is greater than the buffer's size, truncates the character string.
Library to be used: stdio.h.
Man page: printf(3) - subroutines
Example: creating and binding an Internet address
Primitives to be used
Strlen: size_t strlen(const char *s);
Returns the number of characters inside the string s, excluding the terminating NUL character.
Library to be used: string.h.
Man page: strlen(3) - subroutines
Strcat: char * strcat(char *s, const char *append);
Appends the string append to the end of the string s.
Returns the pointer s.
Library to be used: string.h.
Man page: strcat(3) - subroutines
Fflush: int fflush(FILE *stream);
Forces a write of all buffered data in the file stream.
Returns 0 on success, otherwise EOF.
Library to be used: stdio.h.
Man page: fflush(3) - subroutines
Fputs: int puts(const char *str, FILE *stream);
Writes the string str to stream.
Returns a positive integer on success, otherwise EOF.
Library to be used: stdio.h.
Man page: fputs(3) - subroutines
Bzero: void bzero(void *b, size_t len);
Writes len zero bytes in the string b.
Library to be used: string.h.
Man page: bzero(3) - subroutines
Getsockname: int getsockname(int s, struct sockaddr *name, int *namelen);
Returns into name the current name of the socket s. The parameter namelen should be initialized to the length of the structure name. On return it will contain the length in bytes of the returned name.
Returns 0 on success, otherwise -1.
Library to be used: sys/socket.h.
Man page: getsockname(2) - system calls
Code
/* Includes */
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <string.h>
#include <unistd.h>
#include <sys/errno.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdarg.h>
/* Defines */
#define MAXLINE 1024 /* buffer size */
#define SA struct sockaddr /* convenience to make the code easier to read */
#define socklen_t unsigned int /* defined before the right type be defined */
/* Function declarations */
void err_doit(const char *fmt, va_list ap); /* to handle errors */
void err_sys(const char *fmt, ...); /* to handle variadic functions */
int Socket(int family, int type, int protocol); /* wrapper to socket */
void Bind(int fd, const struct sockaddr *sa, socklen_t salen); /* wrapper to bind */
void Close(int fd); /* wrapper to close */
/* Main */
int main(int argc, char **argv)
{
int listenfd; /* active socket */
int port_served = 9877; /* bounded port */
struct sockaddr_in servaddr; /* server's address structure */
int socklen; /* length of address structure */
/* Create an active TCP socket */
listenfd = Socket(AF_INET, SOCK_STREAM, 0);
/* Fill in the address structure with zeros */
bzero(&servaddr, sizeof(servaddr));
/* Set up the domain */
servaddr.sin_family = AF_INET;
/* Set up the port */
servaddr.sin_port = htons(port_served);
/* The system will choose the address at connect time.
At bind time, the given address is 0.0.0.0 */
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
/* Attach the socket to the address */
Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));
/* Computes the length of the address structure */
socklen = sizeof(servaddr);
/* Get the address */
getsockname(listenfd, (SA *) &servaddr, &socklen);
/* Print it */
printf("The socket %d will be attached to port %d, bounded on name %s
with an address length of %d bits.\n", listenfd, port_served,
inet_ntoa(servaddr.sin_addr), socklen);
/* Close the socket */
Close(listenfd);
}
/* Primitives with error handling */
int Socket(int family, int type, int protocol)
{
int n; /* for return */
if ( (n = socket(family, type, protocol)) < 0)
{
err_sys("socket error");
}
return n;
}
void Bind(int fd, const struct sockaddr *sa, socklen_t salen)
{
if (bind(fd, sa, salen) < 0)
{
err_sys("bind error");
}
}
void Close(int fd)
{
if (close(fd) == -1)
{
err_sys("close error");
}
}
void err_sys(const char *fmt, ...)
{
va_list ap; /* list of variable arguments */
/* Define the pointer to the list */
va_start(ap, fmt);
/* Branch to the effective error handler */
err_doit(fmt, ap);
/* Remove the pointer */
va_end(ap);
exit(EXIT_FAILURE);
}
void err_doit(const char *fmt, va_list ap)
{
int errno_save; /* to save the error number passed to the function */
int n; /* buffer size holding the error message */
char buf[MAXLINE + 1]; /* buffer to hold the error message */
/* Save the error number passed to the function
before another error overrides it eventually */
errno_save = errno;
/* Put the message passed to the function into buf */
vsnprintf(buf, MAXLINE, fmt, ap);
/* Computes the buffer length */
n = strlen(buf);
/* Append the error message corresponding to the error number
to the buffer */
snprintf(buf + n, MAXLINE - n, ": %s", strerror(errno_save));
/* Append the end-of-line character to the buffer */
strcat(buf, "\n");
/* Force a write of the buffer to standard output device */
fflush(stdout);
/* Put buffer into standard error device */
fputs(buf, stderr);
/* Force a write of the buffer to standard error device */
fflush(stderr);
return;
}
We first create an active socket. Then we clean up the address structure. Thereafter, wed define the protocol family, the port and the address converting them to big endian format as needed.
Then we attach the address structure to the socket, retrieve the name and length of the address, and print them. Finally, we close the socket to get out of the program in a clean state.
Variant
In place of the generic address INADDR_ANY, you can use a given address as 127.0.0.1, or 192.168..., or your Apache server's address. In this case, replace the following line in the code:
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
by:
inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
Error test on bind
To check if an error occurs on bind due to address already in use, just:
1 - insert the following line just before the close call:
sleep(10);
2 - recompile the code with:
cc myprog.c -o myprog
3 - open two xterm or equivalent, type ./myprog in both of them, push the return key in both xterm (we have 10 seconds to do so).