//Pytanie: "Przedstaw i omów zagadnienia związane z programowaniem elementów na poziomie warstwy sieciowej modelu OSI w aplikacjach sieciowych."//


Warstwa sieciowa odpowiada za dostarczanie danych do urządzeń nie tylko w danej sieci fizycznej. Organizuje ona ruch pakietów między poszczególnymi sieciami fizycznymi połączonymi w intersieć. Głównym protokołem tej warstwy jest IP. Protokół ten uważa się za zawodny, gdyż nie zapewnia dostarczania pakietu do odbiorcy.

Ważnym elementem warstwy IP są **adresy IP**. Każdy host w Internecie posiada swój unikalny numer(adres) IP. Składa się on (w obecnej 4 wersji protokołu) z 32 bitów. Adresy zapisuje się najczęściej w postaci tekstowej jako cztery bajty oddzielone od siebie kropkami. W pamięci natomiast ułożone są w tzw sieciowym porządku bajtów.

Jednym z interfejsów API używanym w komnikacji jest gniazdo (socket).   
    <sys/socket.h>
    int socket (int family, int type, int protocol);
//family// – określa rodzinę protokołów dla IPv4 – //AF_INET//,\\
//type// – określa typ: strumieniowe(//SOCK_STREAM//), datagramowe(//SOCK_DGRAM//) lub surowe (//SOCK_RAW//).\\
//protocol// – określa szczególny protokół wykorzystywany przez gniazdo.\\

Chcąc programować w warstwie sieciowej, nie korzystając z warstwy transportowej należy utworzyć gniazdo surowe. Dzięki temu proces może pobierać i odsyłać datagramy IP, w których pole protokołu nie jest przetwarzane przez jądro. Korzystając z tego gniazda możemy sami utworzyć własny nagłowek IPv4, posługując się opcją gniazd //IP_HDRINCL//:\\
    int setsockopt(int sockfd,int level,int optname,void* optval,socklen_t optlen);

Gniazda takie mogą być tworzone tylko przez nadzorce – zwykli użytkownicy nie mogą wysyłać własnych datagramów IP do sieci.\\
Zwykłe operacje wyjścia wykonywane są za pomocą operacji //sendto// lub //sendmsg//. Jeżeli opcja //IP_HDRINCL// nie jest ustawiona, to do jądra przekazywane są dane począwszy od pierwszego bajtu za nagłówkiem IP – jądro samo konstruuje nagłówek i umieszcza na początku danych. W przeciwnym wypadku dane są odsyłane począwszy od pierwszego bajtu nagłówka IP ( w wartości określającej rozmiar danych należy uwzględnić rozmiar nagłówka. Suma kontrolna nagłówka jest zawsze obliczana przez jądro. Wartość 0 w polu identyfikacyjnym nagłówka informuje jądro, że ma umieścić tę wartość.

Odbierane pakiety UDP i TCP nigdy nie są przekazywane do gniazda surowego. Chcąc pobierać takie pakiety, należy pobierać je z niższej warstwy – kanałowej. Do gniazda surowego natomiast trafiają pakiety ICMP, IGMP (po zakończeniu przetwarzania przez jądro), oraz wszystkie inne, których pola protokołu jądro nie zrozumie. Datagram, który dotarł pofragmentowany trafi natomiast do procesu dopiero po odebraniu i połączeniu wszystkich jego fragmentów. Każdy datagram przekazany do gniazda surowego IPv4 trafia wraz z nagłówkiem. Dla IPv6 nagłówek nie jest przekazywany.

Jeżeli trzeci argument funkcji //socket// będzie miał wartość różną od zera, to do procesu trafiać będą tylko datagramy, które w polu protokołu nagłówka IP będą miały ustawione taką wartość.\\ 
Jeżeli adres lokalny dowiązany był do gniazda w wyniku funkcji //bind//, to adres docelowy IP odebranego datagramu musi być taki sam, jak ten sam adres.
Jeżeli adres obcy IP był określony dla gniazda surowego w wyniku wywołania funkcji //connect//, to adres źródłowy odebranego datagramu musi być taki sam, jak ten adres przekazany do funkcji //connect//.
Do pobierania datagramów służy funkcja recvfrom.