118 lines
4.4 KiB
Markdown
118 lines
4.4 KiB
Markdown
# Basic concepts
|
|
Before reading, this document could contain errors, please check everything you read.
|
|
|
|
- [Basic concepts](#basic-concepts)
|
|
- [Socket](#socket)
|
|
- [Internet sockets](#internet-sockets)
|
|
- [Byte Order](#byte-order)
|
|
- [Structs](#structs)
|
|
- [struct addrinfo](#struct-addrinfo)
|
|
- [struct sockaddr](#struct-sockaddr)
|
|
- [struct sockaddr\_in](#struct-sockaddr_in)
|
|
- [struct sockaddr\_storage](#struct-sockaddr_storage)
|
|
- [IP Addresses](#ip-addresses)
|
|
- [getaddrinfo()](#getaddrinfo)
|
|
|
|
|
|
### 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.
|
|
|
|
```c
|
|
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:
|
|
|
|
```c
|
|
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:
|
|
|
|
```c
|
|
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).
|
|
|
|
```c
|
|
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.
|
|
|
|
```c
|
|
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()
|
|
```c
|
|
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. |