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.
socket
proto_ops
file
(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
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.
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
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.
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
.
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 .
Patrz: nazwy gniazd.
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
.
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.
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.
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.
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.
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_changePorownaj w dziedzinie Internetu.
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
Patrz: nazwy gniazd.
cmsghdr
Uzywana przy przekazywaniu deskryptorow i praw dostepu za pomoca funkcji systemowych sendmsg i recvmsg.
linux/un.hstruct 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
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.
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 buforTa struktura jest rowniez wykorzystywana w dziedzine 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.
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
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.
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 sock
w sock_array
.
Pole highestinuse
zawiera najwieksza wartosc, ktora dotychczas przyjal
inuse
(tylko do celow
statystycznych).
Ta struktura przechowuje wszystkie informacje o gniezdzie
w dziedzinie Internetu. Umozliwia tworzenie
list, ktore sa elementami tablicy haszujacej w
strukturach
proto
dla 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.
Patrz: nazwy gniazd.
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.
Gniazda sa baaaardzo interesujacym i calkiem latwym tematem, dlatego nikt nie zadal mi zadnych pytan.