Download Network Application Programming Interface (API)

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts

Computer network wikipedia , lookup

Piggybacking (Internet access) wikipedia , lookup

Deep packet inspection wikipedia , lookup

AppleTalk wikipedia , lookup

Airborne Networking wikipedia , lookup

Network tap wikipedia , lookup

Parallel port wikipedia , lookup

Wake-on-LAN wikipedia , lookup

List of wireless community networks by region wikipedia , lookup

I²C wikipedia , lookup

TCP congestion control wikipedia , lookup

Real-Time Messaging Protocol wikipedia , lookup

Zero-configuration networking wikipedia , lookup

Internet protocol suite wikipedia , lookup

Recursive InterNetwork Architecture (RINA) wikipedia , lookup

Cracking of wireless networks wikipedia , lookup

Transcript
Network Application Programming Interface (API)
The services provided (often by the operating system) that provide the interface
between application and protocol software.
Network API wish list
 Generic Programming Interface
 Support multiple communication protocol suites (families)
 Address (endpoint) representation independence
 Support for message oriented and connection oriented communication
 Work with existing I/O services (when this makes sense)
 Operating System independence
 Presentation layer services
BSD Networking History
4.2BSD (1983)
First widely available release of
TCP/IP and sockets API
4.3BSD (1986)
TCP performance improvements
4.3BSD Tahoe (1988)
Slow start, congestion avoidance,
fast retransmit
BSD Networking Software Release
1.0 (1989): Net/1
4.3BSD Reno (1990)
Fast recovery, TCP header
prediction, SLIP header
compression, routing table changes;
Length field added to sockaddr(),
control field added to msghdr()
BSD Networking Software Release
2.0 (1991): Net/2
4.4BSD (1993)
Multicasting, long fat pipe
modifications
4.4BSD-Lite (1994) referred to in
text as Net/3
}
BSD/OS
FreeBSD
NetBSD
OpenBSD
4.4BSD-Lite2 (1995)
Figure: History of various BSD releases
The socket API originated with 4.2BSD system, released in 1983. The path down
from 3.2SD through 4.4BSD is the releases from Computer System Research Group
(CSRG) at Berkeley that required the recipient to already have a source code license
for Unix. But all of the networking code, both the kernel support (such as TCP/IP and
Unix domain protocol stacks and the socket interface) along with the applications
(such as Telnet and FTP clients and servers) were developed independently from the
AT&T-derived Unix code.
Therefore starting in 1989 Berkeley provided the first of the BSD networking
releases, which contained all of the networking code and various other pieces of the
BSD system that were not constrained by the Unix source code license. These releases
were publicly available by anonymous FTP.
The final release from Berkeley were 4.4BSD-Lite and BSD-Lite2. These were used
as the base for other systems: BSD/OS, FreeBSD, NetBSD and OpenBSD. These are
still being actively developed and enhanced.
TCP/IP
In the TCP/IP protocol suite there are more members than just TCP and IP. Figure
shows an overview of these protocols.
IPv4 applications
tcpdump
mrouted
ping
traceroute
appl.
appl.
API
TCP
UDP
ICMP
IGMP
IPv4
ARP,
RARP
BPF,
DLPI
data link
Figure: Overview of TCP/IP protocols
The leftmost application tcpdump communicates directly with the datalink using BPF
(BSD Packet Filter) or DLPI (Data Link Provider Interface). The API line in figure is
normally sockets or XTI.
We also see that traceroute uses two sockets: one for ICMP and another for IP.
TCP
Connection oriented protocol that provides a reliable full-duplex, byte
stream for user processes. TCP takes care of details such as
UDP
IGMP
BPF
DLPI
acknowledgement, timeouts, retransmissions etc.
Connectionless protocol.
Internet Group Management Protocol
Used with multicasting
This interface provides access to datalink for a process. Found on Berkeley
derived kernels.
Normally provided with SVR4
TCP Connection Establishment and Termination
Three-Way Handshake
The following scenario occurs when a TCP connection is established:
1. The server must be prepared to accept an incoming connection. This is
normally done by calling socket, bind and listen and is called passive open.
2. The client issues an active open by calling connect. This causes client TCP to
send a SYN segment (Synchonize) to tell the erver the client’s initial sequence
number for the data client will send on the connection.
3. Sever must acknowledge client’s SYN by sending its own SYN. The server
sends its SYN and ACK of the client’s SYN in a single segment.
4. The client must acknowledge the server’s SYN.
Client
Server
socket
connect (blocks)
(active open)
SYN J
socket, bind, listen
accept (blocks)
SYN K, ack J+1
connect returns
ack K+1
accept returns
read (blocks)
Figure: TCP three-way handshake
TCP Connection Termination
1. One application calls close first (active close). This end’s TCP sends FIN
segment, which tells it has finished sending data.
2. The other end’s TCP receives this FIN and performs passive close. The receipt
of FIN is passed to the application as an end-of-file market.
3. Sometimes later the application will close its socket. This causes the TCP to
send FIN.
4. The TCP on the system that receives the final FIN acknowledges the FIN.
Port Numbers
At any time multiple processes can use either TCP or UDP. Both of them use 16 bit
integer port numbers to differentiate between these processes.
When a client wants to contact a server, it must identify it first. Both TCP and UDP
define a group of well known ports to identify well known services. For eg. TCP
assigns port number 21 to the FTP server; UDP assigns port number 69 to TFTP.
Clients on the other hand, use ephemeral ports that is short lived ports.These port
numbers are usually assigned automatically by TCP or UDP.
RFC 1700 contains the list of port number assignments from the Internet Assigned
Numbers Authority (IANA). The port numbers are divided into three ranges:
1. Well known ports: 0 to 1023
These port numbers are controlled and assigned by IANA.
2. The registered ports: 1024 to 49151
These are not controlled by IANA but it lists the use of these ports as a
convenience to the community. For eg. Ports 6000 to 6063 are assigned for an
X Windows server
3. The dynamic of private ports: 49151 to 65535
IANA says nothing about these ports. These are what we call ephemeral ports.
Unix systems have the concept of reserved port, which is any por<1024. These ports
can be assigned to a socket by a superuser process.
Socket Pair
The socket pair for a TCP connection is the 4-tuple that defines the two endpoints of
the connection: the local IP address, local TCP port, foreign IP address and foreign
TCP port. A socket pair uniquely identifies every TCP connections on the internet.
The two values IP and port number are often called a socket. Sockets are: a way to
speak to other programs using standard Unix file descriptors.
Everything in Unix is a file!" When Unix programs do any sort of I/O, they do it by
reading or writing to a file descriptor. A file descriptor is simply an integer associated
with an open file. But (and here’s the catch), that file can be a network connection, a
FIFO, a pipe, a terminal, a real on-the-disk file, or just about anything else.
Everything in Unix is a file! So when you want to communicate with another program
over the Internet you’re going do it through a file descriptor.
Two Types of Internet Sockets
One is "Stream Sockets"; the other is "Datagram Sockets", which may hereafter be
referred to as "SOCK_STREAM" and "SOCK_DGRAM", respectively. Datagram
sockets are sometimes called "connectionless sockets". (Though they can be
connect()’d if you really want.)
Stream sockets are reliable two-way connected communication streams. If you output
two items into the socket in the order "1, 2", they will arrive in the order "1, 2" at the
opposite end. They will also be error free.
What uses stream sockets? Well, you may have heard of the telnet application. It uses
stream sockets. All the characters you type need to arrive in the same order you type
them. Also, web browsers use the HTTP protocol which uses stream sockets to get
pages. Indeed, if you telnet to a web site on port 80, and type "GET /", it’ll dump the
HTML back at you.
How do stream sockets achieve this high level of data transmission quality? They use
"TCP" (see RFC-7935 for extremely detailed info on TCP.)
What about Datagram sockets? Why are they called connectionless? Why are they
unreliable? Well, here are some facts: if you send a datagram, it may arrive. It may
arrive out of order. If it arrives, the data within the packet will be error-free.
Datagram sockets also use IP for routing, but they don’t use TCP; they use the "User
Datagram Protocol", or "UDP" (see RFC-7687.)
Why are they connectionless? Well, basically, it’s because you don’t have to maintain
an open connection as you do with stream sockets. You just build a packet, slap an IP
header on it with destination information, and send it out. No connection needed.
They are generally used for packet-by-packet transfers of information. Sample
applications: tftp, bootp, etc.
"How do these programs even work if datagrams might get lost?!" For example, the
tftp protocol says that for each packet that gets sent, the recipient has to send back a
packet that says, "I got it!" (an "ACK" packet.) If the sender of the original packet
gets no reply in, say, five seconds, he’ll re-transmit the packet until he finally gets an
ACK. This acknowledgment procedure is very important when implementing
SOCK_DGRAM applications.
structs and Data Handling
It’s time now to talk about programming. Firstly we need to know various data types
used by the sockets interface, since some of them are a real bear to figure out. First
the easy one: a socket descriptor.
A socket descriptor is the following type: int
There are two byte orderings: most significant byte (sometimes called an "octet") first,
or least significant byte first. The former is called "Network Byte Order". Some
machines store their numbers internally in Network Byte Order, some don’t. When
something has to be in Network Byte Order, you have to call a function (such as
htons()) to change it from "Host Byte Order". "Network Byte Order" is also know as
"Big-Endian Byte Order".
struct sockaddr
This structure holds socket address information for many types of sockets:
struct sockaddr {
unsigned short sa_family;
char sa_data[14];
};
// address family, AF_xxx
// 14 bytes of protocol address
sa_data contains a destination address and port number for the socket. This is rather
unwieldy since you don’t want to tediously pack the address in the sa_data by hand.
To deal with struct sockaddr, programmers created a parallel structure: struct
sockaddr_in ("in" for "Internet".)
struct sockaddr_in
struct sockaddr_in {
short int sin_family; // Address family
unsigned short int sin_port; // Port number
struct in_addr sin_addr; // Internet address
unsigned char sin_zero[8]; // Same size as struct sockaddr
};
This structure makes it easy to reference elements of the socket address. Note that
sin_zero (which is included to pad the structure to the length of a struct sockaddr)
should be set to all zeros with the function memset(). Also, and this is the important
bit, a pointer to a struct sockaddr_in can be cast to a pointer to a struct sockaddr and
vice-versa. So even though socket() wants a struct sockaddr, you can still use a struct
sockaddr_in and cast it at the last minute. Also, notice that sin_family corresponds to
sa_family in a struct sockaddr and should be set to "AF_INET". Finally, the sin_port
and sin_addr must be in Network Byte Order. “But how can the entire structure, struct
in_addr sin_addr, be in Network Byte Order?" This question requires careful
examination of the structure struct in_addr, one of the worst unions alive:
// Internet address (a structure for historical reasons)
struct in_addr {
unsigned long s_addr; // that’s a 32-bit long, or 4 bytes
};
Well, it used to be a union, but now those days seem to be gone. So if you have
declared ina to be of type struct sockaddr_in, then ina.sin_addr.s_addr references the
4-byte IP address (in Network Byte Order). Note that even if your system still uses the
union for struct in_addr, you can still reference the 4-byte IP address.
Convert the Natives
There are two types that you can convert: short (two bytes) and long (four bytes).
These functions work for the unsigned variations as well. Say you want to convert a
short from Host Byte Order to Network Byte Order. Start with "h" for "host", follow it
with "to", then "n" for "network", and "s" for "short": h-to-n-s, or htons() (read: "Host
to Network Short").
These are other conversion functions:
• htons() – "Host to Network Short"
• htonl() – "Host to Network Long"
• ntohs() – "Network to Host Short"
• ntohl() – "Network to Host Long"
You might also think that since your 68000 machine already uses network byte order,
you don’t have to call htonl() on your IP addresses. You would be right, BUT if you
try to port to a machine that has reverse network byte order, your program will fail.
Remember: put your bytes in Network Byte Order before you put them on the
network.
A final point: why do sin_addr and sin_port need to be in Network Byte Order in a
struct sockaddr_in, but sin_family does not? The answer: sin_addr and sin_port get
encapsulated in the packet at the IP and UDP layers, respectively. Thus, they must be
in Network Byte Order. However, the sin_family field is only used by the kernel to
determine what type of address the structure contains, so it must be in Host Byte
Order. Also, since sin_family does not get sent out on the network, it can be in Host
Byte Order.
IP Addresses and How to Deal With Them
Fortunately for you, there are a bunch of functions that allow you to manipulate IP
addresses.
First, let’s say you have a struct sockaddr_in ina, and you have an IP address
"10.12.110.57" that you want to store into it. The function you want to use,
inet_addr(), converts an IP address in numbers-and-dots notation into an unsigned
long. The assignment can be made as follows:
ina.sin_addr.s_addr = inet_addr("10.12.110.57");
Notice that inet_addr() returns the address in Network Byte Order already–you don’t
have to call htonl().
Now, the above code snippet isn’t very robust because there is no error checking. See,
inet_addr() returns -1 on error. Remember binary numbers. (unsigned)-1 just happens
to correspond to the IP address 255.255.255.255. That’s the broadcast address.
Actually, there’s a cleaner interface you can use instead of inet_addr(): it’s called
inet_aton() ("aton" means "ascii to network"):
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int inet_aton(const char *cp, struct in_addr *inp);
And here’s a sample usage, while packing a struct sockaddr_in (this example will
make more sense to you when you get to the sections on bind() and connect().)
struct sockaddr_in my_addr;
my_addr.sin_family = AF_INET;
// host byte order
my_addr.sin_port = htons(MYPORT);
// short, network byte order
inet_aton("10.12.110.57", &(my_addr.sin_addr));
memset(&(my_addr.sin_zero), ’\0’, 8);
// zero the rest of the struct
inet_aton(), unlike practically every other socket-related function, returns non-zero on
success, and zero on failure and the address is passed back in inp.
Unfortunately, not all platforms implement inet_aton() so, although its use is
preferred, the older more common inet_addr() is used.
Now you can convert string IP addresses to their binary representations. What about
the other way around? What if you have a struct in_addr and you want to print it in
numbers-and-dots notation? In this case, you’ll want to use the function inet_ntoa()
("ntoa" means "network to ascii") like this: printf("%s", inet_ntoa(ina.sin_addr));
That will print the IP address. Note that inet_ntoa() takes a struct in_addr as an
argument, not a long. Also notice that it returns a pointer to a char. This points to a
statically stored char array within inet_ntoa() so that each time you call inet_ntoa() it
will overwrite the last IP address you asked for. For example:
char *a1, *a2;
.
.
a1 = inet_ntoa(ina1.sin_addr); // this is 192.168.4.14
a2 = inet_ntoa(ina2.sin_addr); // this is 10.12.110.57
printf("address 1: %s\n",a1);
printf("address 2: %s\n",a2);
will print:
address 1: 10.12.110.57
address 2: 10.12.110.57
If you need to save the address, strcpy() it to your own character array.