CMSG(3)

NAZWA
CMSG_ALIGN, CMSG_SPACE, CMSG_NXTHDR, CMSG_FIRSTHDR - dostęp do danych pomocniczych

SKŁADNIA
#include <sys/socket.h>

struct cmsghdr *CMSG_FIRSTHDR(struct msghdr *msgh);
struct cmsghdr *CMSG_NXTHDR(struct msghdr *msgh, struct cmsghdr *cmsg);
size_t CMSG_ALIGN(size_t length);
size_t CMSG_SPACE(size_t length);
size_t CMSG_LEN(size_t length);
unsigned char *CMSG_DATA(struct cmsghdr *cmsg);

struct cmsghdr {
	socklen_t	cmsg_len;	/* liczba bajtów danych, włączając nagłówek */
	int	cmsg_level;	/* protokół źródłowy */
	int	cmsg_type;	/* zależny od protokołu typ */
/* następuje po nim  unsigned char	cmsg_data[]; */
};

OPIS
Makrodefinicje te służą do tworzenia i dostępu do komunikatów sterujących (zwanych również danymi pomocniczymi), które nie są częścią gniazda. Te informacje sterujące mogą zawierać: interfejs, przez który pakiet został odebrany, różne rzadko używane pola nagłówka, rozszerzony opis błędu, zestaw deskryptorów plików lub uwierzytelnień uniksowych. Na przykład, komunikaty sterujące mogą służyć do ustawiania dodatkowych pól nagłówka, takich jak opcje IP, dla wysyłanych pakietów. Dane pomocnicze są wysyłane poprzez wywołanie sendmsg(2) a otrzymywane poprzez wywołanie recvmsg(2). Więcej informacji znajduje się na stronach podręcznika man dla tych poleceń.

Dane pomocnicze są ciągiem struktur struct cmsghdr z dodanymi danymi. Dostęp do tego ciągu powinien się odbywać wyłącznie poprzez opisane na tej stronie podręcznika makrodefinicje, nigdy zaś bezpośrednio. Dostępne rodzaje komunikatów sterujących opisano na stronach podręcznika dla poszczególnych protokołów. Maksymalny rozmiar bufora danych pomocniczych dla gniazda można ustawić za pomocą sysctl-a net.core.optmem_max; patrz socket(7).

CMSG_FIRSTHDR zwraca wskaźnik do pierwszego cmsghdr w buforze danych pomocniczych związanym z przekazanym msghdr.

CMSG_NXTHDR zwraca następny poprawny cmsghdr po przekazanym cmsghdr. Zwraca NULL, gdy brak dostatecznej ilości miejsca w buforze.

CMSG_ALIGN, zadana długość, zwraca ją włączając niezbędne wyrównanie. Jest to wyrażenie stałe.

CMSG_SPACE zwraca liczbę bajtów elementu pomocniczego włączając długość, jaką zajmują przekazane dane. Jest to wyrażenie stałe.

CMSG_DATA zwraca wskaźnik do części cmsghdr zawierającej dane.

CMSG_LEN zwraca wartość, która ma być przechowywana w elemencie cmsg_len struktury cmsghdr, biorąc pod uwagę wszelkie niezbędne wyrównania. Jako argument pobiera długość danych. Jest to wyrażenie stałe.

Aby utworzyć dane pomocnicze, należy najpierw zainicjalizować element msg_controllen struktury msghdr długością bufora komunikatów sterujących. Należy użyć CMSG_FIRSTHDR dla msghdr, aby otrzymać pierwszy komunikat sterujący oraz CMSG_NEXTHDR, aby otrzymać wszystkie następne. Dla każdego komunikatu sterującego należy zainicjalizować cmsg_len (za pomocą CMSG_LEN), inne pola nagłówka cmsghdr oraz część zawierającą dane za pomocą CMSG_DATA. Ostatecznie pole msg_controllen struktury msghdr powinno zawierać sumę CMSG_SPACE dla długości wszystkich komunikatów sterujących w buforze. Więcej informacji dotyczących msghdr, znajduje się w recvmsg(2).

Gdy bufor komunikatów sterujących jest za krótki, aby przechować wszystkie komunikaty, ustawiany jest znacznik MSG_CTRUNC elementu msg_flags struktury msghdr.

PRZYKŁAD
Następujący kod poszukuje opcji IP_TTL w otrzymanym buforze pomocniczym:

    struct msghdr msgh;
    struct cmsghdr *cmsg;
    int *ttlptr;
    int received_ttl;
    /* Otrzymywanie danych z zewnątrz do msgh */
    for (cmsg = CMSG_FIRSTHDR(&msgh);
         cmsg != NULL;
         cmsg = CMSG_NXTHDR(&msgh,cmsg) {
    	if (cmsg->cmsg_level == SOL_IP
    	  && cmsg->cmsg_type == IP_TTL) {
    		ttlptr = (int *) CMSG_DATA(cmsg);
    		received_ttl = *ttlptr;
    		break;
    	}
    }
    if (cmsg == NULL) {
    	/*
    	 * Błąd: IP_TTL not jest włączone, za mały bufor lub
    	 * błąd I/O.
    	 */
    }

Poniższy kod przekazuje tablicę deskryptorów plików poprzez gniazdo Uniksa SCM_RIGHTS:

    struct msghdr msg = {0};
    struct cmsghdr *cmsg;
    int myfds[NUM_FD]; /* Zawiera przekazywane deskryptory plików. */
    char buf[CMSG_SPACE(sizeof myfds)];  /* bufor danych pomocniczych */
    int *fdptr;
    msg.msg_control = buf;
    msg.msg_controllen = sizeof buf;
    cmsg = CMSG_FIRSTHDR(&msg);
    cmsg->cmsg_level = SOL_SOCKET;
    cmsg->cmsg_type = SCM_RIGHTS;
    cmsg->cmsg_len = CMSG_LEN(sizeof(int) * NUM_FD);
    /* Inicjalizacja: */
    fdptr = (int *)CMSG_DATA(cmsg);
    memcpy(fdptr, myfds, NUM_FD * sizeof(int));
    /* Suma długości wszystkich komunikatów sterujących w buforze: */
    msg.msg_controllen = cmsg->cmsg_len;

UWAGI
Dla przenośności, dostęp do danych pomocniczych powinien się odbywać jedynie za pomocą opisanych tu makrodefinicji. CMSG_ALIGN jest rozszerzeniem Linuksa i nie powinno być używane w przenośnych programach.

W Linuksie, CMSG_LEN, CMSG_DATA, i CMSG_ALIGN są wyrażeniami stałymi (zakładając, że ich argument jest stały) - można to wykorzystać do zadeklarowania rozmiaru zmiennych globalnych. Jednakże, może się to okazać nieprzenośnym.

ZGODNE Z
Ten model danych pomocniczych jest zgodny ze szkicem POSIX.1003.1g, z 4.4BSD-Lite, z zaawansowanym API dla IPv6 opisanym w RFC2292 oraz ze specyfikacją Single Unix v2. CMSG_ALIGN jest rozszerzeniem Linuksa.

ZOBACZ TAKŻE
sendmsg(2), recvmsg(2)

RFC 2292