Blog literacki, portal erotyczny - seks i humor nie z tej ziemi
Do spisu tresci tematu 9
9.2.2 Struktury danych, zmienne, stale
Spis tresci
Wprowadzenie
Poziom funkcji systemowych
System plikow i gniazda
Deskryptory gniazd i struktura file
I-wezly
Struktura socket
Dziedziny ogolnie
Inicjacja dziedzin (struktury i zmienne)
Identyfikacja dziedzin
Struktura sockaddr
Pozostale typy danych i stale ogolne
Struktura msghdr
Struktura iovec
Dziedzina Unixa
Wstep
Funkcje dziedziny
Strukura sock i zmienna unix_socket_list
Struktura unix_opt
Struktura sockaddr_un.
Struktura cmsghdr.
Struktura sk_buff
Dziedzina Inernetu
Wstep
Funkcje dziedziny
Strukura proto
Struktura sock
Struktura sockaddr_in
Struktura sk_buff
Bibliografia
Wprowadzenie
Gniazda sa wbudowane w system plikow, dlatego na poczatku bede opisywal gniazdowe struktury danych z nim zwiazane. Nastepnie bede pisal o dziedzinach i na koncu o protokolach.
System plikow i gniazda
Oto diagram ilustrujacy jak gniazda sa wbudowane w system plikow:
Deskryptory gniazd i struktura file
I-wezly
Struktura socket
Cos o proto_ops
Wstep do systemu plikow
System plikow
Deskryptory gniazd i struktura file
Kazde gniazdo jest identyfikowane przez swoj deskryptor, zwracany przez funkcje systemowe je tworzace. Taki deskryptor jest indeksem w tablicy deskryptorow procesu (current->files->fd). Pod tym indeksem tej tablicy znajduje sie wskaznik do struktury file w tablicy plikow.
include/linux/fs.h
struct file {
mode_t f_mode;
loff_t f_pos;
unsigned short f_flags;
unsigned short f_count;
...
int f_owner;
struct inode * f_inode;
struct file_operations * f_op;
...
};
Funkcje tworzace gniazdo inicjuja pobieraja wolna struktury file i inicjuja w niej pola. Pobieraja i-wezel i przypisuja wskaznik do niego na pole f_inode. Ponadto podstawiaja pod pole f_op wskaznik do statycznie zdefiniowanej zmiennej socket_file_ops , ktora definiuje operacje plikowe na gniazdach:
net/socket.c
static struct file_operations socket_file_ops = {
sock_lseek,
sock_read,
sock_write,
NULL,
sock_select,
sock_ioctl,
NULL,
NULL,
sock_close,
NULL,
sock_fasync
};
Zobacz rowniez:
Temat o systemie plikow
I-wezly
Z kazdym gniazdem zwiazany jest i-wezel wskazywany przez pole f_inode z tablicy plików. Jest przydzielany przez funkcje tworz±ce gniazdo.
include/linux/fs.h
struct inode {
kdev_t i_dev;
unsigned long i_ino;
umode_t i_mode;
nlink_t i_nlink;
uid_t i_uid;
gid_t i_gid;
kdev_t i_rdev;
off_t i_size;
struct wait_queue *i_wait;
...
unsigned char i_sock;
...
union {
...
struct socket socket_i;
} u;
};
Istotne dla gniazd pola to pole unii u : struct socket socket_i oraz znacznik: char i_sock - informujacy czy i-wezel zwiazany jest z gniazdem (ustawiany na 1 gdy tak). Ponadto kolejka procesow : i_wait. Do tej kolejki sa odkladane procesy przy blokujacych funkcjach systemowych.
Struktura socket
Jedna z ważniejszych struktur danych zwiazanych z
gniazdami. Jest przechowywana w
i-wezle. Przy wykonywaniu funkcji dla dziedzin jest zawsze przekazywana jako argument.
include/linux/net.h
struct socket {
short type;
socket_state state;
long flags;
struct proto_ops *ops;
void *data;
struct socket *conn;
struct socket *iconn;
struct socket *next;
struct wait_queue **wait;
struct inode *inode;
struct fasync_struct *fasync_list;
struct file *file;
};
Znaczenie pol:
type - typ gniazda ustawiany przy tworzeniu;
możliwe warto¶ci (include/linux/socket.h):
SOCK_STREAM - gniazdo strumieniowe
SOCK_DGRAM - gniazdo datagramowe
SOCK_RAW - gniazdo surowe
SOCK_RDM - gniazdo komunikatow niezawodnie doreczanych
SOCK_SEQPACKET - gniazdo pakietow uporzadkowanych
SOCK_PACKET - gniazdo pakietow (tylko Linux)
state - status gniazda;
oto definicja socket_state z include/linux/net.h
wraz ze znaczeniem pol:
typedef enum {
SS_FREE = 0, /* niezaalokowane */
SS_UNCONNECTED, /* niepolaczone */
SS_CONNECTING, /* w trakcie laczenia */
SS_CONNECTED, /* polaczone z innym gniazdem*/
SS_DISCONNECTING /* w trakcie rozlaczania */
} socket_state;
flags - flagi gniazd; możliwe warto¶ci (include/linux/net.h)
SO_ACCEPTCON - ustawiane jesli funkcja listen
zakonczyla sie poprawnie
SO_WAITDATA - oczekuje na dane
SO_NOSPACE - nie ma miejsca na wyslanie
ops - wskazniki do funkcji wlasciwych dla danego protokolu;
ustawiane przy tworzeniu gniazda;
patrz struct proto_ops i tablica pops
data - wykorzystywane w funkcjach protokolow;
np w dziedzinach Unixa i Inetu wskazuje na strukture
sock por.dziedziny: Unix, Internet
conn - nie jest wykorzystywane (wbrew komentarzom)
iconn - to pole jest wykorzystywane tylko do zapamiętania
partnera przy socketpair (dziedzina Unixa)
wait_queue - taki sam jak w i-wezle;
kolejka procesow czekajacych na polaczenie lub i/o
inode - wskaznik do i-wezla (w tablicy i-wezlow)
fasync_list - lista ze wskaznikami do struktur file zwiazanymi
z otwartymi gniazdami; okresla grupe procesow zwiazanych
z gniazdem; jest wykorzystywana do tzw. wejscia/wyjscia
asynchronicznego
file - wskaznik do struktury file w tablicy plikow
Inicjacja dziedzin (struktury i zmienne)
Nastepuje przy wywolaniu funkcji sock_init i proto_init wykonywanych przy bootowaniu systemu. Do inicjowania wykorzystuje sie strukture net_proto zawierajaca: nazwe i wskaznik do funkcji inicjujacej.
include/linux/net.h
struct net_proto {
const char *name;
void (*init_func)(struct net_proto *);
};
Informacje w strukturach net_proto o wszystkich dostepnych protokolach przechowuje tablica protocols zdefiniowana w
net/protocols.c.
Identyfikacja dziedzin
Do tego celu wykorzystywana jest tablica pops rozmiaru NPROTO (obecnie 16) zawierajaca wskazniki do struktur proto_ops przechowywujacych wskazniki do funkcji na gniazdach odpowiednich dla dziedzin. Jej inicjacja nastepuje przy wykonaniu funkcji proto_init, ktora korzysta z tablicy protocols.
include/linux/net.h
struct proto_ops {
int family;
int (*create) (struct socket *sock, int protocol);
int (*dup) (struct socket *newsock, struct socket *oldsock);
int (*release)(struct socket *sock, struct socket *peer);
int (*bind)(struct socket *sock, struct sockaddr *umyaddr,
int sockaddr_len);
int (*connect) (struct socket *sock, struct sockaddr
*uservaddr, int sockaddr_len, int flags);
int (*socketpair)(struct socket *sock1, struct socket sock2);
int (*accept) (struct socket *sock, struct socket
newsock, int flags);
int (*getname)(struct socket *sock, struct sockaddr *uaddr,
int *usockaddr_len, int peer);
int (*select) (struct socket *sock, int sel_type,
select_table *wait);
int (*ioctl) (struct socket *sock, unsigned int cmd,
unsigned long arg);
int (*listen) (struct socket *sock, int len);
int (*shutdown) (struct socket *sock, int flags);
int (*setsockopt) (struct socket *sock, int level, int
optname, char *optval, int optlen);
int (*getsockopt) (struct socket *sock, int level, int
optname, char *optval, int *optlen);
int (*fcntl) (struct socket *sock, unsigned int cmd,
unsigned long arg);
int (*sendmsg) (struct socket *sock, struct msghdr *m, int
total_len, int nonblock, int flags);
int (*recvmsg) (struct socket *sock, struct msghdr *m, int
total_len, int nonblock, int flags, int *addr_len);
};
Pole family przyjmuje jedna z wartosci (AF_...) PF_... np.: PF_UNIX, PF_INET... Odpowiada wartosci family podawanej przy funkcji systemowej
socket.
Opis struktury msghdr .
Struktura sockaddr
Patrz:
nazwy gniazd.
Struktury msghdr i iovec
Funkcje systemowe sendmsg i recvmsg korzystaja z tych struktur. Ponadto
kazda funkcja systemowa odbierajaca i wysylajaca dane korzysta z funkcji dla
protokolow : xx_recvmsg, xx_sendmsg (patrz: proto_ops), ktorych argumentem jest wskaznik do struktury msghdr.
include/linux/uio.h
struct iovec
{
void *iov_base;
int iov_len;
};
Ta struktura definiuje pojedynczy blok danych. Pole iov_base jest wskaznikiem na obszar danych, iov_len okresla jego dlugosc.
include/linux/socket.h
struct msghdr
{
void * msg_name;
int msg_namelen;
struct iovec * msg_iov;
int msg_iovlen;
void * msg_control;
int msg_controllen;
int msg_flags;
};
Pola msg_name i msg_namelen okreslaja nazwe gniazda. Wskaznik msg_iov definuje tablice blokow danych o liczbie elementow msg_iovlen, ktora nie moze byc wieksza niz
MAXIOVLEN (obecnie 16). Pola msg_control i msg_controllen umozliwiaja przekazywanie
praw dostepu i deskryptorow plikow w protokole Unixa (patrz opis struktury cmsghdr w protokole Unixa).
Flagi (pole flags) moga byc zerem lub alternatywa stalych:
MSG_OOB, MSG_PEEK lub MSG_DONTROUTE - analogicznie jak argument flags funkcji
systemowych 'recv' i 'send'.
Uwaga: R.Stevens podaje inne nazwy niektorych pol w tej strukturze. Ponadto przyklady
Stevensa dotyczace przekazywania deskryptorow w dziedzinie Unixa nie beda dzialac
ma Linux-ie (trzeba dokonac kilku zmian), ze wzgledu na koniecznosc uzycia struktury
cmsghdr.
Wstep - dziedzina Unixa
W tej dziedzinie nie wyrozniamy protokolow.
Wystepuja tylko dwa rodzaje gniazd:datagramowe i
strumieniowe. W odroznieniu od innych dziedzin procesy
moga komunikowac sie tylko w obrebie tego samego systemu.
Jadro dba bez uzycia rzesylania
w sieci o przekazywanie komunikatow z jednego procesu
do innego. Jest to pewna forma komunikacji miedzyprocesowej
wbudowana w interfejs gniazd. Wazna cecha gniazd Unixa
(i tylko Unixa) jest mozliwosc przesylania deskryptorow
plikow i praw dostepu miedzy nie powiazanymi procesami.
Gniazda identyfikujemy za pomoca specjalnych plikow,
ktore sa tworzone w systemie.
Funkcje dziedziny Unixa
Wskazniki do funkcji implementujacych operacje na gniazdach dla dziedziny Unixa zawarte sa w zmiennej unix_proto_ops zdefiniowanej w
net/unix/af_unix.c
Patrz: opis struktury proto_ops.
Strukura sock i zmienna unix_socket_list
Strukura sock jest zdefiniowana w
include/net/sock.hi jest podstawowa struktura
danych przechowujaca informacje o obslugiwanych gniazdach
(rowniez w dziedzinie Internetu). Posiada pole:
struct sock *next
umozliwiajace tworzenie list gniazd. W dziedzinie Unixa
na glowe listy wszystkich gniazd wskazuje zmienna:
unix_socket_list.
Tylko pola wykorzystywane przez d. Unixa:
struct sock
{ atomic_t wmem_alloc;
atomic_t rmem_alloc;
volatile char dead,
struct sock *next;
struct sk_buff_head write_queue, receive_queue;
struct wait_queue **sleep;
volatile unsigned short shutdown;
volatile unsigned char state;
unsigned char ack_backlog;
unsigned char max_ack_backlog;
unsigned short rcvbuf;
unsigned short sndbuf;
unsigned short type;
union
{ ...
struct unix_opt af_unix;
} protinfo;
struct timer_list timer;
struct socket *socket;
void (*state_change)(struct sock *sk);
void (*data_ready)(struct sock *sk,int bytes);
void (*write_space)(struct sock *sk);
void (*error_report)(struct sock *sk);
};
wmem_alloc, rmem_alloc - ile pamieci dla buforow odbioru
i wysylania zaalokowano dla tego gniazda; por. pola
rcvbuf i sndbuf ponizej
dead - znacznik ustawiany na 1 (martwe gniazdo), gdy gnia-
zdo usunieto z listy gniazd, ale zostaly polaczenia
(por. timer)
next - nastepna struktura sock na liscie
receive_queue - kolejka komunikatow do odebrania
sleep - kolejka spiacych procesow; ta sama co w i-wezle
shutdown - okresla tryb zamkniecia gniazda (patrz fcja
shutdown) moze przyjac wartoeci stalych
(flag bitowych): SND_SHUTDOWN, RCV_SHUTDOWN i maski
SHUTDOWN_MASK
state - okresla stan gniazda; wykorzystuje stale TCP_CLOSE,
TCP_LISTEN,...
ack_backlog - aktualna liczba polaczen; nie jest sprawdzana
wartosc tego pola
max_ack_backlog - maksymalna liczba polaczen; przekazywane
przy fcji listen; wartosc
tego pola nigdzie nie jest sprawdzana
rcvbuf, sndbuf - przechowuja informacje o rozmiarach bufo-
row dla kolejek danych wysylanych i odbieranych;
mozna zmienic przez fcje setsockopt
i opcje SO_RCVBUF, SO_SNDBUF;
type - typ gniazda; to samo co w socket.type
unia protinfo i pole af_unix - patrz unix_opt
timer - inicjowany przy usunieciu gniazda, z ktorym byly
polaczenia; najpierw po 1 sek. pozniej co 10 sek.
wywoluje procedure sprawdzajaca czy wszystkie
polaczenia zostaly zamkniete, gdy tak to struktura
sock zostaje usunieta z pamieci
socket - wskaznik do struktury socket w i-wezle
wskazniki do funkcji def_callback1, def_callback2,
def_callback3 z net/unix/af_unix.c:
state_change - obudz spiacych w kolejce sleep
write_space, error_report, data_ready - j/w i ponadto
wyslij sygnal SIGIO do grupy procesow zwiazanych
z gniazdem o ile pozwalaja na to flagi gniazda
error_report - tak samo jak state_change
Porownaj w dziedzinie Internetu.
Struktura unix_opt
Wykorzystywana jako pole unii protinfo
w strukturze sock. Okresla specyficzne dla Unixa wlasnosci.
struct unix_opt
{
int family;
char * name;
int locks;
struct inode * inode;
struct semaphore readsem;
struct sock * other;
int marksweep;
int inflight;
};
family - zawsze AF_UNIX
locks - z iloma gniazdami jest polaczenie
inode - i-wezel zwiazany z gniazdem po wykonaniu funkcji
unix_bind; to nie jest i-wezel, o ktorym pisze
wczesniej
readsem - semafor uzywany przy odbiorze (unix_recvmsg)
other - partner z ktorym jest polaczenie
marksweep - ustawiany podczas wykonywania funkcji
usuwajacych zbedne deskryptory plikow przekazywane
przez funkcje gniazd
inflight - inkrementowany jesli deskryptor tego gniazda
jest przekazywany do innego procesu (sendmsg) i
dekrementowany po przekazaniu (recvmsg);
marksweep - wykorzystywany przy usuwaniu zbednych
deskryptorow plikow podczas przekazywania ich
przez gniazdo
Struktura sockaddr_un
Patrz:
nazwy gniazd.
Struktura cmsghdr
Uzywana przy przekazywaniu deskryptorow i praw dostepu za pomoca funkcji
systemowych sendmsg i recvmsg.
linux/un.h
struct cmsghdr {
unsigned int cmsg_len;
int cmsg_level;
int cmsg_type;
unsigned char cmsg_data[0];
};
W celu przeslania deskryptorow nalezy wskaznik na te strukture nalezy
przypisac polu msg_control w odpowiedniej
strukturze msghdr (patrz opis)
i przypisac wartosci: cmsg_level=SCM_RIGHTS, cmsg_type=SOL_SOCKET,
cmsg_len=sizeof(struct cmsghdr)+
rozmiar cmsg_data. Pole cmsg_data
traktujemy
jako tablice int i zapisujemy tam deskryptory
plikow, ktore chcemy przekazac.
Patrz rowniez: sendmsg,
recvmsg
Struktura sk_buff (Unix)
W dziedzinie Unixa funkcje buforow przechowujacych przesylane komunikaty pelni lista struktur sk_buff. Ponadto jest zdefiniowana glowa listy (straznik) - struktura sk_buff_head. Funkcja wysylajaca (unix_sendmsg) tworzy i wstawia bufor bezposrednio do kolejki (sock.receive_queue) odbiorcy.
linux/skbuff.h
struct sk_buff_head
{
struct sk_buff * next;
struct sk_buff * prev;
__u32 qlen;
};
struct sk_buff
{
struct sk_buff * next;
struct sk_buff * prev;
struct sk_buff_head * list;
struct sock *sk;
union
{
...
void *filp;
} h;
struct sk_buff *data_skb;
unsigned char *head;
unsigned char *data;
unsigned char *tail;
unsigned char *end;
void (*destructor)(struct sk_buff *);
};
Istotne pola:
next, prev, list - struktura listowa
sk - wskaznik na gniazdo, z ktorym jest zwiazany bufor
pole unii h.filp - tablica deskryptorow przekazywana przez
gniazdo (tylko pr.Unixa); patrz struktury msghdr,
cmsghdr
len - aktualna dlugosc danych w buforze
truesize - rozmiar bufora
head - wskaznik do bufora
data - wskaznik do pierwszego elementu danych w buforze
tail - wskaznik do ostatniego elementu danych+1 (bufor
moze byc niezapelniony)
end - wskaznik do ostatniego elementu bufora (data_skb
+truesize)
destructor - wskaznik do funkcji usuwajacej bufor
Ta struktura jest rowniez wykorzystywana w dziedzine Internetu.
Wstep - dziedzina Internetu
Dziedzina Internetu udostepnia trzy protokoly:
TCP (strumieniowy), UDP (datagramowy) i RAW (gniazda
surowe). W odroznieniu od dziedziny Unixa ta dziedzina
jest prawdziwie sieciowa tzn. umozliwia komunikacje
miedzy roznymi komputerami.
Funkcje dziedziny Internetu
Wskazniki do funkcji systemowych implementujacych operacje na gniazdach
sa zawarte w zmiennej inet_proto_ops w
net/ipv4/af_inet.c
Patrz opis struktury proto_ops
Struktura proto
Definuje dane o gniazdach i operacje na gniazdach dla protokolow dziedziny
Internetu. Kazdy protokol posiada zdefiniowana zmienna wskazujaca na ta strukture:
tcp_prot, udp_prot , raw_prot.
Odpowiedni wskaznik jest przypisywany przy tworzeniu gniazda
polu prot w strukturze sock.
Funkcje dziedziny Internetu wywoluja
odpowiednie funkcje dla protokolow korzystajac wlasnie z tego pola.
net/sock.h
struct proto
{
void (*close)(struct sock *sk, unsigned long timeout);
int (*build_header)(struct sk_buff *skb,
__u32 saddr,
__u32 daddr,
struct device **dev, int type,
struct options *opt, int len,
int tos, int ttl, struct rtable ** rp);
int (*connect)(struct sock *sk,
struct sockaddr_in *usin, int addr_len);
struct sock * (*accept) (struct sock *sk, int flags);
void (*queue_xmit)(struct sock *sk,
struct device *dev, struct sk_buff *skb,
int free);
void (*retransmit)(struct sock *sk, int all);
void (*write_wakeup)(struct sock *sk);
void (*read_wakeup)(struct sock *sk);
int (*rcv)(struct sk_buff *buff, struct device *dev,
struct options *opt, __u32 daddr,
unsigned short len, __u32 saddr,
int redo, struct inet_protocol *protocol);
int (*select)(struct sock *sk, int which,
select_table *wait);
int (*ioctl)(struct sock *sk, int cmd,
unsigned long arg);
int (*init)(struct sock *sk);
void (*shutdown)(struct sock *sk, int how);
int (*setsockopt)(struct sock *sk, int level, int optname,
char *optval, int optlen);
int (*getsockopt)(struct sock *sk, int level, int optname,
char *optval, int *option);
int (*sendmsg)(struct sock *sk, struct msghdr *msg, int len,
int noblock, int flags);
int (*recvmsg)(struct sock *sk, struct msghdr *msg, int len,
int noblock, int flags, int *addr_len);
int (*bind)(struct sock *sk, struct sockaddr *uaddr, int addr_len);
unsigned short max_header;
unsigned long retransmits;
char name[32];
int inuse, highestinuse;
struct sock * sock_array[SOCK_ARRAY_SIZE];
};
Wskazniki do funkcji okreslaja operacje na gniazdach
dla protokolow. Tablica sock_array
jest tablica haszujaca (operacje na niej zdefiniowane
w af_inet.c). Jej elementami
sa listy struktur sock, kluczem
jest pole sock.num. MAX_ARRAY_SOCK
obecnie wynosi 256
Pole inuse zawiera liczbe wszystkich
struktur sockw sock_array.
Pole highestinuse
zawiera najwieksza wartosc, ktora dotychczas przyjal
inuse (tylko do celow
statystycznych).
Struktura sock
Ta struktura przechowuje wszystkie informacje o gniezdzie
w dziedzinie Internetu. Umozliwia tworzenie
list, ktore sa elementami tablicy haszujacej w
strukturach
protodla kazdego z protokolow.
Czesc pol jest wykorzystywana przez
protokoly i nizsze warstwy obslugujace polaczenia.
Tam mozna obejrzec strukture sock:
net/sock.h
Czesc z pol tej struktury ma analogiczne znaczenie jak dla protokolu Unixa.
proc - identyfikator procesu lub grupy gniazd
write_queue, receive_queue - kolejki buforow sk_buf
prot - wskaznik na strukture proto dla odpowiedniego
protokolu
daddr - adres stacji-partnera (32 bitowy id-sieci/
id-stacji);
do lub z funkcji systemowych przekazywany razem ze
struktura sockaddr_in w polu sin_addr.s_addr
saddr - adres wysylajacego
rcv_saddr - zwykle ten sam co wyzej; wyjatek w przypadku
opcji broadcast lub mulitcast
mtu - max rozmiar transmisji (nie mozna przesylac wiekszych
pakietow niz mtu)
mss - wykorzystywany przy ustalaniu mtu
user_mss - ustalony mtu przez uzytkownika
num - klucz do tablicy haszujacej sock_array
w strukturze proto
err, err_soft - kody bledow
protocol - identyfikator protokolu
state - status gniazda; patrz stale statusow
ack_backlog - biezaca liczba polaczen
max_ack_backlog - max liczba polaczen (podawane przy
listen)
debug - ustawione na niezerowa wartosc powoduje wypisywanie
komunikatow
type - type gniazda (SOCK_DGRAM, SOCK_STREAM,...)
socket - wskaznik do struktury socket
Porownaj z dziedzina Unixa.
Struktura sockaddr_in
Patrz:
nazwy gniazd.
Struktura sk_buff (Internet)
Dokladnie ta sama struktura co w
dziedzine Unixa i
o analogicznym znaczeniu. W niej mozna zapisywac
dane do wyslania i odebrania. Umozliwia tworzenie list
i na takie listy wskazuja pola write_queue
i recv_queue
struktury sock. Czesc pol
sk_buff jest wykorzystywana
przez protokoly nizszych warstw.
Bibliografia
Pliki zrodlowe jadra Linux-a 2.0.0.
include/linux/fs.h
include/linux/net.h
include/linux/socket.h
include/linux/uio.h
include/net/sock.h
include/linux/un.h
include/linux/skbuff.h
net/core/skbuff.c
net/core/iovec.c
net/core/sock.c
net/ipv4/af_inet.c
net/unix/af_unix.c
net/unix/garbage.c
net/socket.c
net/protocols.c.
net/ipv4/tcp.c
net/ipv4/udp.c
net/ipv4/raw.c
R. Stevens: "Programowanie zastosowan sieciowych w systemie Unix".
Dokumentacja biblioteki libc dostepna w /usr/info/.
Kernel Hackers Guide.
Pytania i odpowiedzi
Gniazda sa baaaardzo interesujacym i calkiem latwym tematem, dlatego nikt
nie zadal mi zadnych pytan.
Autor: Pawel Gorecki