UNIX(7) Miscellaneous Information Manual UNIX(7) NAZWA unix - gniazda lokalnej komunikacji miedzyprocesowej SKLADNIA #include #include unix_socket = socket(AF_UNIX, type, 0); error = socketpair(AF_UNIX, type, 0, int *sv); OPIS Rodzina gniazd AF_UNIX (znana rowniez jako AF_LOCAL) sluzy do wydajnej komunikacji pomiedzy procesami na tej samej maszynie. Zgodnie z tradycja, gniazda domeny uniksowej moga byc albo anonimowe (tworzone przez socketpair(2)), albo skojarzone z plikiem typu gniazda. Linux wspiera rowniez abstrakcyjna przestrzen nazw, niezalezna od systemu plikow. Poprawne typy gniazd w domenie Uniksa to: SOCK_STREAM dla gniazd strumieniowych, SOCK_DGRAM dla gniazd datagramowych, ktore zachowuja granice komunikatow (w przypadku wiekszosci implementacji Uniksa gniazda uniksowe sa zawsze niezawodne i nie zmieniaja kolejnosci datagramow), oraz (od wersji Linuksa 2.6.4) SOCK_SEQPACKET dla gniazd pakietow sekwencyjnych zorientowanych polaczeniowo, ktore zachowuja granice komunikatu i dostarczaja komunikaty w kolejnosci ich wysylania. Za posrednictwem pomocniczych danych mozna przez gniazda domeny uniksowej przekazywac do innych procesow deskryptory plikow i uwierzytelnienia procesow. Format adresu Adres gniazda domeny uniksowej jest reprezentowany przez nastepujaca strukture: struct sockaddr_un { sa_family_t sun_family; /* AF_UNIX */ char sun_path[108]; /* Sciezka */ }; Pole sun_family zawsze zawiera AF_UNIX. W Linuksie sun_path ma rozmiar 108 bajtow, zob. tez USTERKI ponizej. Rozne wywolania systemowe (np. bind(2), connect(2) i sendto(2)) przyjmuja argument sockaddr_un jako wejscie. Niektore inne wywolania systemowe (np. getsockname(2), getpeername(2), recvfrom(2) i accept(2)) zwracaja argument tego typu. W strukturze sockaddr_un rozrozniane sa trzy typy adresow: sciezka gniazdo domeny uniksowej moze zostac zwiazane z zakonczona znakiem NULL nazwa sciezki systemowej za pomoca bind(2). Jesli adres sciezki gniazda jest zwracany (przez jedno z ww. wywolan systemowych) to jego dlugoscia jest offsetof(struct sockaddr_un, sun_path) + strlen(sun_path) + 1 a sun_path zawiera zakonczona null sciezke. (W Linuksie powyzsze wyrazenie offsetof() jest rowne tej samej wartosci co sizeof(sa_family_t), lecz niektore inne implementacje dolaczaja inne pola przed sun_path, wiec bardziej przenosnie, wyrazenie offsetof() opisuje rozmiar struktury adresu). Wiecej informacji o sciezkach gniazd znajduje sie ponizej. unnamed Gniazdo strumieniowe niezwiazane z nazwa sciezki za pomoca bind(2) nie jest nazwane. Podobnie dwa gniazda utworzone przez socketpair(2) nie sa nazwane. Jesli adres nienazwanego gniazda jest zwracany, to jego dlugoscia jest sizeof(sa_family_t), a zawartosc sun_path nie powinna byc sprawdzana. abstract adres gniazda abstrakcyjnego jest rozrozniany (od adresu sciezki) po tym, ze sun_path[0] jest bajtem NULL ('\0'). Adres gniazda znajduje sie w przestrzeni nazw podanej w dodatkowych bajtach w sun_path, ktore sa pokryte przez dlugosc struktury adresu (Bajty NULL w nazwie nie maja zadnego specjalnego znaczenia). Nazwa nie ma zadnego powiazania z nazwa pliku w systemie plikow. Zwracany adres gniazda abstrakcyjnego ma w polu addrlen ustawiona dlugosc wieksza niz sizeof(sa_family_t) (tj. wieksza niz 2), a nazwa gniazda zawarta jest w pierwszych (addrlen - sizeof(sa_family_t)) bajtach pola sun_path. Sciezki gniazd Przy przypisywaniu gniazda do sciezki powinno sie przestrzegac kilku zasad w celu maksymalnej przenosnosci i latwosci programowania: o Sciezka w sun_path powinna byc zakonczona znakiem NULL. o Dlugosc sciezki, w tym konczacy bajt null nie powinna przekraczac rozmiaru sun_path. o Argument addrlen opisujacy obejmujaca strukture sockaddr_un powinien miec wartosc przynajmniej: offsetof(struct sockaddr_un, sun_path)+strlen(addr.sun_path)+1 lub, prosciej, addrlen powinien byc podany jako sizeof(struct sockaddr_un). W roznych implementacjach roznie obslugiwane sa adresy gniazd domen Uniksa, ktore nie przestrzegaja powyzszych zalecen. Na przyklad niektore (lecz nie wszystkie) implementacje dodaja konczacy znak null, jesli nie jest on obecny w przekazanej sun_path. Przy programowaniu przenosnych aplikacji prosze wziac pod uwage, ze niektore implementacje maja sun_path o dlugosci zaledwie 92 bajtow. Rozne wywolania systemowe (accept(2), recvfrom(2), getsockname(2), getpeername(2)) zwracaja struktury adresow gniazd. Gdy chodzi o gniazda domeny Uniksa, wartosc-rezultat argumentu addrlen umieszczonego w wywolaniu powinna byc zainicjowana jw. Gdy jest zwracany, argument ten jest ustawiany aby przedstawiac aktualny rozmiar struktury adresu. Wywolujacy powinien sprawdzic wartosc zwracana w tym argumencie, jesli wartosc wyjsciowa przekracza wartosc wejsciowa, to nie ma gwarancji, ze konczacy znak null jest obecny w sun_path (zob PROBLEMY). Wlasnosc i uprawnienia sciezki gniazd W implementacji Linuksa, sciezki gniazd honoruja uprawnienia katalogow, w ktorych sie znajduja. Utworzenie nowego gniazda nie powiedzie sie, jesli proces nie ma uprawnien zapisu i wyszukiwania (wykonania) w katalogu, w ktorym tworzone jest gniazdo. W Linuksie, laczenie z gniazdem strumieniowym wymaga uprawnien zapisu w stosunku do tego gniazda; wyslanie datagramu do gniazda datagramowego rowniez wymaga uprawnien zapisu gniazda. POSIX nie zabiera glosu w sprawie efektu uprawnien pliku gniazda i w niektorych systemach (np. starszych wersjach BSD) uprawnienia gniazd sa ignorowane. Przenosne programy nie powinny opierac sie na tym zachowaniu w celu zapewnienia bezpieczenstwa. Przy tworzeniu nowego gniazda, wlasciciel i grupa pliku gniazda sa ustawiani zgodnie ze zwyklymi zasadami. Plik gniazda ma wlaczone wszystkie uprawnienia, poza tym wylaczonymi przez proces umask(2). Wlasciciela, grupe i uprawnienia sciezki gniazda mozna zmienic (za pomoca chown(2) i chmod(2)). Gniazda abstrakcyjne Uprawnienia gniazd nie maja znaczenia dla gniazd abstrakcyjnych: proces umask(2) nie ma wplywu przy kojarzeniu z gniazdem abstrakcyjnym, a zmiana wlasnosci i uprawnien obiektu (za pomoca fchown(2) i fchmod(2)) nie wplywa na dostepnosc gniazda. Gniazda abstrakcyjne automatycznie znikaja po zamknieciu wszystkich otwartych odniesien do takich gniazd. Przestrzen nazw gniazd abstrakcyjnych jest nieprzenosnym rozszerzeniem systemu Linux. Opcje gniazda Ze wzgledow historycznych nastepujace opcje gniazd sa podawane przy typie SOL_SOCKET, pomimo ze sa one specyficzne dla AF_UNIX. Mozna je ustawic za pomoca setsockopt(2), a odczytac za pomoca getsockopt(2), podajac SOL_SOCKET jako rodzine gniazd. SO_PASSCRED Wlaczenie tej opcji gniazda powoduje przekazanie uwierzytelnien wysylajacego procesu w pomocniczej wiadomosci SCM_CREDENTIALS, w kazdej kolejnej odebranej wiadomosci. Zwracanymi uwierzytelnieniami sa te okreslone przez nadawce za pomoca SCM_CREDENTIALS lub, jesli nadawca nie okreslil danych pomocniczych SCM_CREDENTIALS, wartosc domyslna zawierajaca: identyfikator procesu, rzeczywisty identyfikator uzytkownika i rzeczywisty identyfikator grupy nadawcy. Przy wlaczonej tej opcji i niepolaczonym jeszcze gniezdzie, unikatowa nazwa gniazda z abstrakcyjnej przestrzeni nazw jest generowana automatycznie. Podana wartosc jest argumentem do setsockopt(2), a zwracana jako wynik getsockopt(2) jest flaga logiczna bedaca liczba calkowita. SO_PASSSEC Wlacza odbior etykiety bezpieczenstwa SELinux drugiego gniazda w pomocniczym komunikacie typu SCM_SECURITY (zob. nizej). Podana wartosc jest argumentem do setsockopt(2), a zwracana jako wynik getsockopt(2) jest flaga logiczna bedaca liczba calkowita. Opcja SO_PASSSEC jest obslugiwana w datagramowych gniazdach domeny uniksowej od Linuksa 2.6.18; obsluge w gniazdach strumieniowych domeny uniksowej dodano w jadrze Linux 4.2. SO_PEEK_OFF Patrz socket(7). SO_PEERCRED Jest to opcja gniazda tylko do odczytu, ktora zwraca uwierzytelnienia drugiego procesu skojarzonego z tym gniazdem. Zwracanymi uwierzytelnieniami sa te, ktore obowiazywaly w momencie wywolania connect(2), listen(2) lub socketpair(2). Argumentem do getsockopt(2) jest wskaznik do struktury ucred; nalezy zdefiniowac makro testowe _GNU_SOURCE aby pozyskac definicje tej struktury z . Opcji tej mozna uzywac wylacznie w polaczonych gniazdach strumieniowych AF_UNIX oraz w parze gniazda strumieniowego i datagramowego AF_UNIX utworzonej za pomoca socketpair(2). Automatyczne przypisywanie adresow Jesli w wywolaniu bind(2) podane zostanie addrlen rowne sizeof(sa_family_t) lub opcja SO_PASSCRED gniazda byla ustawiona dla gniazda nieprzypisanego do adresu, wtedy gniazdo jest automatycznie przypisywane do adresu abstrakcyjnego. Adres ten sklada sie z bajtu NULL, po ktorym nastepuje 5 bajtow ze zbioru znakow [0-9a-f]. W zwiazku z tym liczba automatycznie przypisywanych adresow jest ograniczona do 2^20. (W Linuksie 2.1.15, w ktorym dodano mozliwosc automatycznego przypisywania adresow, i w kolejnych wersjach uzywane bylo 8 bajtow, a limit wynosil 2^32 adresow. Zostalo to zmienione na 5 bajtow w Linuksie 2.3.15). API gniazd W kolejnych paragrafach opisano pewne szczegoly implementacji API gniazd domeny UNIX specyficzne dla Linuksa oraz cechy niewspierane. Gniazda z domeny uniksowej nie obsluguja zawiadomienia o danych autonomicznych (flaga MSG_OOB funkcji send(2) i recv(2)). Flaga MSG_MORE funkcji send(2) nie jest obslugiwana dla gniazd domeny uniksowej. Przed Linuksem 3.4, uzycie MSG_TRUNC w argumencie flags funkcji recv(2) nie bylo obslugiwane dla gniazd domeny uniksowej. Opcja SO_SNDBUF dziala w przypadku gniazd domeny uniksowej, ale opcja SO_RCVBUF juz nie. Dla gniazd datagramowych wartosc SO_SNDBUF naklada gorny limit na rozmiar wychodzacych datagramow. Limit ten jest liczony jako podwojona (patrz socket(7)) wartosc opcji minus 32 bajty wymagane na informacje niebedace danymi. Komunikaty pomocnicze Dane pomocnicze sa wysylane i odbierane za pomoca sendmsg(2) i recvmsg(2). Ze wzgledow historycznych komunikaty pomocnicze ponizszych typow sa podawane przy typie SOL_SOCKET, pomimo ze sa one specyficzne dla AF_UNIX. Aby je wyslac, nalezy ustawic pole cmsg_level struktury cmsghdr na SOL_SOCKET, a pole cmsg_type na typ. Wiecej informacji mozna znalezc w cmsg(3). SCM_RIGHTS Odbieranie od innego procesu lub wysylanie do niego zbioru otwartych deskryptorow plikow. Porcja danych zawiera tablice liczb calkowitych bedacych deskryptorami plikow. Potocznie, operacja ta jest nazywana "przekazaniem deskryptora pliku" do innego procesu. Jednak przygladajac sie blizej, mozna dostrzec ze przekazywana jest referencja do otwartego deskryptora pliku (zob. open(2)), a w procesie odbierajacym prawdopodobnie uzyty zostanie inny numer deskryptora pliku. Operacja ta jest semantycznie rownowazna duplikacji (dup(2)) deskryptora plikow na tablice deskryptora pliku innego procesu. Jesli bufor uzywany do odebrania danych pomocniczych zawierajacych deskryptory plikow jest zbyt maly (lub jest nieobecny), to dane pomocnicze sa przycinane (lub odrzucane), a nadmiarowe deskryptory plikow sa automatycznie zamykane przez proces odbierajacy. Jesli liczba deskryptorow plikow otrzymana w danych pomocniczych spowodowalaby wykroczenie przez proces poza jego limit zasobow RLIMIT_NOFILE (zob. getrlimit(2)), to nadmiarowe deskryptory plikow zostana automatycznie zamkniete przez proces odbierajacy. Stala jadra SCM_MAX_FD okresla limit liczby deskryptorow plikow w tablicy. Proba wyslania tablicy wiekszej od limitu spowoduje blad EINVAL sendmsg(2). SCM_MAX_FD ma wartosc 253 (lub 255 przed Linuksem 2.6.38). SCM_CREDENTIALS Odbieranie lub wysylanie uwierzytelnien uniksowych. Moze sluzyc do autoryzacji. Uwierzytelnienia sa przekazywane jako komunikat pomocniczy typu struct ucred, zdefiniowanego w nastepujaco: struct ucred { pid_t pid; /* identyfikator procesu wysylajacego */ uid_t uid; /* ident. uzytkownika procesu wysylajacego */ gid_t gid; /* ident. grupy procesu wysylajacego */ }; Poczawszy od wersji 2.8 biblioteki glibc, aby uzyskac dostep do definicji powyzszej struktury, nalezy zdefiniowac makro _GNU_SOURCE (przed dolaczeniem jakichkolwiek plikow naglowkowych). Jadro sprawdza uwierzytelnienia podane przez wysylajacego. Proces uprzywilejowany moze podac wartosci, ktore roznia sie od jego wlasnych. W pozostalych przypadkach wysylajacy musi podac swoj wlasny identyfikator procesu (o ile nie ma ustawionego znacznika CAP_SYS_ADMIN, w przypadku ktorym mozna podac identyfikator dowolnego istniejacego procesu), swoj wlasny, rzeczywisty identyfikator uzytkownika, efektywny identyfikator uzytkownika lub ustawiony identyfikator uzytkownika (o ile nie ma ustawionego znacznika CAP_SETUID) oraz swoj wlasny identyfikator grupy, efektywny identyfikator grupy lub ustawiony identyfikator grupy (o ile nie ma ustawionego znacznika CAP_SETGID). Aby otrzymac komunikat typu struct ucred, dla gniazda musi byc wlaczona opcja SO_PASSCRED. SCM_SECURITY Otrzymuje kontekst bezpieczenstwa SELinux (etykiete bezpieczenstwa) drugiego gniazda. Otrzymywane dane pomocnicze sa lancuchem zakonczonym znakiem null, zawierajacym kontekst bezpieczenstwa. Dla tych danych odbiorca powinien przydzielic co najmniej NAME_MAX bajtow w porcji danych komunikatu pomocniczego. Do otrzymania kontekstu bezpieczenstwa konieczne jest wlaczenie w gniezdzie opcji SO_PASSSEC (zob. wyzej). Przy wysylaniu danych pomocniczych za pomoca sendmsg(2), w wyslanym komunikacie mozna podac tylko po jednej pozycji dla kazdego z powyzszych typow. Przy wysylaniu danych pomocniczych konieczne jest przeslanie choc jednego bajta rzeczywistych danych. W Linuksie jest to wymagane do poprawnego wyslania danych pomocniczych za pomoca gniazda strumieniowego domeny uniksowej. Przy wysylaniu danych pomocniczych za pomoca gniazda datagramowego domeny uniksowej, na Linuksie nie ma koniecznosci wysylania jakichkolwiek rzeczywistych danych. Przenosne aplikacje powinny jednak rowniez wysylac choc jeden bajt rzeczywistych danych przy wysylaniu danych pomocniczych za pomoca gniazda datagramowego. Przy odbieraniu z gniazda strumieniowego, dane pomocnicze stanowia w pewien sposob bariere dla odbieranych danych. Prosze przyjac przykladowo, ze nadawca transmituje: (1) sendmsg(2) o wielkosci czterech bajtow, bez danych pomocniczych. (2) sendmsg(2) o wielkosci jednego bajta, z danymi pomocniczymi. (3) sendmsg(2) o wielkosci czterech bajtow, bez danych pomocniczych. Przyjmijmy, ze odbiorca wykonuje teraz wywolania recvmsg(2), kazde z buforem o wielkosci 20 bajtow. Pierwsze wywolanie otrzyma piec bajtow danych, razem z danymi pomocniczymi wyslanymi przez drugie wywolanie sendmsg(2). Nastepne wywolanie otrzyma pozostale cztery bajty danych. Jesli przestrzen przydzielona do otrzymywanych danych pomocniczych jest zbyt mala, to dane pomocnicze sa przycinane do liczby naglowkow mieszczacych sie w udostepnionym buforze (lub, w przypadku listy deskryptora pliku SCM_RIGHTS, sama lista deskryptorow pliku moze zostac przycieta). Jesli dla przychodzacych danych pomocniczych nie udostepniono bufora (np. pole msg_control struktury msghdr przekazanej do recvmsg(2) wynosi NULL), to przychodzace dane pomocnicze sa odrzucane. W obu tych przypadkach, flaga MSG_CTRUNC zostanie ustawiona na wartosc msg.msg_flags zwrocona przez recvmsg(2). Kontrolki systemowe (ioctl) Nastepujace wywolania ioctl(2) zwracaja informacje w parametrze value. Poprawna skladnia to: int value; error = ioctl(unix_socket, ioctl_type, &value); ioctl_type moze przyjmowac wartosc: SIOCINQ Dla gniazd SOCK_STREAM, wywolanie to zwraca liczbe nieprzeczytanych jeszcze bajtow znajdujacych sie w buforze odbierajacym. Gniazdo nie moze sie znajdowac w stanie "LISTEN"; w przeciwnym wypadku zostanie zwrocony blad (EINVAL). SIOCINQ jest zdefiniowany w . Alternatywnie mozna uzyc synonimu FIONREAD zdefiniowanego w . Dla gniazd SOCK_DGRAM, zwracana wartosc jest taka sama jak w przypadku datagramowych gniazd domeny Internet; zob. udp(7). BLEDY EADDRINUSE Podany adres lokalny jest zajety lub obiekt gniazda w systemie plikow juz istnieje. EBADF Blad moze zajsc dla sendmsg(2), przy wysylaniu deskryptora pliku jako dane pomocnicze za posrednictwem gniazda domeny uniksowej (zob. opis SCM_RIGHTS wyzej) i wskazuje ze wyslany numer deskryptora pliku jest nieprawidlowy (np. nie jest to otwarty deskryptor pliku). ECONNREFUSED Adres zdalny podany w connect(2) nie odnosil sie do gniazda nasluchujacego. Blad moze takze wystapic jesli docelowa sciezka nie jest gniazdem. ECONNRESET Zdalne gniazdo zostalo nieoczekiwanie zamkniete. EFAULT Nieprawidlowy adres pamieci uzytkownika. EINVAL Podano nieprawidlowy argument. Najczestsza przyczyna jest brak ustawionego AF_UNIX w polu sun_type przekazywanych gniazdu adresow lub nieprawidlowy dla danej operacji stan gniazda. EISCONN Wywolano connect(2) dla juz polaczonego gniazda lub podano adres docelowy dla polaczonego gniazda. ENFILE Zostalo osiagniete systemowe ograniczenie na calkowita liczbe otwartych plikow. ENOENT Nie istnieje sciezka dla zdalnego adresu przekazanego do connect(2). ENOMEM Brak pamieci. ENOTCONN Operacja na gniezdzie wymaga adresu docelowego, a gniazdo nie jest polaczone. EOPNOTSUPP Operacja strumieniowa wywolana dla gniazda niestrumieniowego lub proba uzycia opcji danych autonomicznych. EPERM Wysylajacy podal nieprawidlowe uwierzytelnienia w struct ucred. EPIPE Zdalne gniazdo strumieniowe zostalo zamkniete. Gdy wlaczone, wysylany jest jednoczesnie sygnal SIGPIPE. Mozna tego uniknac, przekazujac znacznik MSG_NOSIGNAL do send(2) lub sendmsg(2). EPROTONOSUPPORT Podanym protokolem nie jest AF_UNIX. EPROTOTYPE Typ gniazda zdalnego rozni sie od typu gniazda lokalnego (SOCK_DGRAM wobec SOCK_STREAM). ESOCKTNOSUPPORT Nieznany typ gniazda. ESRCH Przy wysylaniu komunikatow pomocniczych zawierajacych uwierzytelnienie (SCM_CREDENTIALS), wywolujacy podal identyfikator procesu, ktory nie dopasowal zadnego istniejacego procesu. ETOOMANYREFS Blad moze zajsc dla sendmsg(2), przy wysylaniu deskryptora pliku jako dane pomocnicze za posrednictwem gniazda domeny uniksowej (zob. opis SCM_RIGHTS wyzej). Wystepuje, jesli liczba deskryptorow pliku "w locie" wykracza poza limit zasobow RLIMIT_NOFILE, a wywolujacy nie posiada przywileju CAP_SYS_RESOURCE. Przez deskryptor pliku w locie rozumiemy tu taki, ktory zostal wyslany za pomoca sendmsg(2), ale nie zostal jeszcze zaakceptowany przez proces docelowy za pomoca recvmsg(2). Blad ten jest diagnozowany w glownej galezi jadra od Linuksa 4.5 (i w niektorych wczesniejszych wersjach, gdzie zaaplikowano odpowiednia latke). We wczesniejszych wersjach jadra, mozna bylo umiescic nieograniczona liczbe deskryptorow plikow w locie, poprzez wyslanie kazdego z nich za pomoca sendmsg(2), a nastepnie zamkniecie deskryptora pliku, co nie liczylo sie wobec limitu zasobow RLIMIT_NOFILE. Inne bledy moga zostac wygenerowane przez podstawowa warstwe gniazd lub przez system plikow podczas tworzenia obiektu gniazda w systemie plikow. Wiecej informacji mozna znalezc na odpowiednich stronach podrecznika. WERSJE SCM_CREDENTIALS oraz abstrakcyjna przestrzen nazw zostaly wprowadzone w Linuksie 2.2 i nie nalezy ich uzywac w przenosnych programach. (Niektore systemy wywodzace sie z BSD rowniez wspieraja przekazywanie uwierzytelnien, ale implementacje roznia sie szczegolami). UWAGI W trakcie laczenia sie z gniazdem majacym przypisana nazwe pliku, tworzony jest plik specjalny gniazda w systemie plikow, ktory musi zostac usuniety (za pomoca unlink(2)) przez wywolujacego, gdy juz nie bedzie potrzebny. Stosuje sie tu zwykla uniksowa skladnia opoznionego zamkniecia (ang. close-behind): gniazdo mozna skasowac w dowolnym momencie, ale zostanie ono ostatecznie usuniete z systemu plikow po zamknieciu ostatniego odwolania do niego. Aby przekazac deskryptory plikow lub uwierzytelnienia poprzez SOCK_STREAM trzeba wyslac/odebrac co najmniej jeden bajt niepomocniczych danych w tym samym wywolaniu sendmsg(2) lub recvmsg(2) Gniazda strumieniowe z domeny uniksowej nie obsluguja zawiadomienia o danych autonomicznych. USTERKI Przy wiazaniu gniazda z adresem, Linux jest jedna z implementacji dodajacych konczace null, jesli nie poda sie go w sun_path. Zwykle jest to bezproblemowe, gdy adres gniazda jest pozyskiwany bedzie on o jeden bajt dluzszy niz podawany poczatkowo. Jest jednak jeden przypadek mogacy spowodowac mylace zachowanie: jesli podany zostanie adres 108 bajtowy, bez znaku null, to dodanie znaku null spowodowaloby przekroczenie dlugosci sciezki poza sizeof(sun_path). W konsekwencji, przy pozyskiwaniu adresu gniazda (np. poprzez accept(2)), jesli wejsciowy argument addrlen dla pozyskiwanego wywolania jest podany jako sizeof(struct sockaddr_un), to zwrocona struktura adresu nie bedzie miala konczacego null w sun_path. Dodatkowo, niektore implementacje nie wymagaja konczacego null przy wiazaniu gniazda (argument addrlen jest uzywany do okreslenia dlugosci sun_path), a gdy w tych implementacjach jest pozyskiwany adres gniazda, to nie ma konczacego null w sun_path. Aplikacje pozyskujace adresy gniazd moga posiadac (przenosny) kod do obslugi mozliwosci, ze w sun_path nie ma konczacego null zauwazajac fakt, ze liczba prawidlowych bajtow w sciezce to: strnlen(addr.sun_path, addrlen - offsetof(sockaddr_un, sun_path)) Alternatywnie, aplikacja moze pozyskac adres gniazda przez przydzielenie buforu o rozmiarze sizeof(struct sockaddr_un)+1 ktory jest wyzerowany przed pozyskaniem. Pobierajace wywolanie moze okreslic addrlen jako sizeof(struct sockaddr_un), a dodatkowy bajt zero zapewnia, ze w lancuchu zwroconym w sun_path bedzie konczace null: void *addrp; addrlen = sizeof(struct sockaddr_un); addrp = malloc(addrlen + 1); if (addrp == NULL) /* Obsluga bledu */ ; memset(addrp, 0, addrlen + 1); if (getsockname(sfd, (struct sockaddr *) addrp, &addrlen)) == -1) /* obsluga bledu */ ; printf("sun_path = %s\n", ((struct sockaddr_un *) addrp)->sun_path); Tego balaganu mozna uniknac, jesli jest pewnosc, ze aplikacja tworzaca sciezki gniazd przestrzega regul opisanych powyzej rozdziale Sciezki gniazd. PRZYKLADY Ponizszy kod demonstruje uzycie gniazd pakietow sekwencyjnych do lokalnej komunikacji miedzyprocesowej. Sklada sie z dwoch programow. Serwer czeka na polaczenie z programu klienckiego. Klient wysyla kazdy ze swoich argumentow wiersza polecen w oddzielnych wiadomosciach. Serwer traktuje przychodzace wiadomosci jako liczby calkowite i dodaje je. Klient wysyla lancuch polecenia "END". Serwer odsyla komunikat zawierajacy sume klienckich liczb calkowitych. Klient wypisuje sume i wychodzi. Serwer czeka na polaczenie od kolejnego klienta. Aby zatrzymac serwer, klient jest wywolywany z argumentem wiersza polecen "DOWN". Podczas dzialania serwera w tle i kolejnych uruchomien klienta zarejestrowano nastepujace wyjscie. Wykonywanie programu serwera konczy sie, gdy otrzymuje on polecenie "DOWN". Przykladowe wyjscie $ ./server & [1] 25887 $ ./client 3 4; Wynik = 7 $ ./client 11 -5; Wynik = 6 $ ./client DOWN; Wynik = 0 [1]+ Done ./server $ Kod zrodlowy programu /* * Plik connection.h */ #ifndef CONNECTION_H #define CONNECTION_H #define SOCKET_NAME "/tmp/9Lq7BNBnBycd6nxy.socket" #define BUFFER_SIZE 12 #endif // include guard (ochr. przed wielokr. przetw.) /* * Plik server.c */ #include #include #include #include #include #include #include #include "connection.h" int main(void) { int down_flag = 0; int ret; int connection_socket; int data_socket; int result; ssize_t r, w; struct sockaddr_un name; char buffer[BUFFER_SIZE]; /* Tworzenie gniazda lokalnego. */ connection_socket = socket(AF_UNIX, SOCK_SEQPACKET, 0); if (connection_socket == -1) { perror("socket"); exit(EXIT_FAILURE); } /* * Ze wzgledu na przenosnosc konieczne jest wyczyszczenie calej * struktury, poniewaz niektore implementacje zawieraja dodatkowe * (nieprzenosne) pola w strukturze. */ memset(&name, 0, sizeof(name)); /* Skojarzenie gniazda z nazwa gniazda. */ name.sun_family = AF_UNIX; strncpy(name.sun_path, SOCKET_NAME, sizeof(name.sun_path) - 1); ret = bind(connection_socket, (const struct sockaddr *) &name, sizeof(name)); if (ret == -1) { perror("bind"); exit(EXIT_FAILURE); } /* * Przygotowanie do przyjmowania polaczen. Rozmiar dziennika zaleglosci * ustawiony na 20. W trakcie przetwarzania jednego zadania, inne moga * zatem oczekiwac. */ ret = listen(connection_socket, 20); if (ret == -1) { perror("listen"); exit(EXIT_FAILURE); } /* To jest glowna petla do obslugi polaczen. */ for (;;) { /* Oczekiwanie na polaczenie przychodzace. */ data_socket = accept(connection_socket, NULL, NULL); if (data_socket == -1) { perror("accept"); exit(EXIT_FAILURE); } result = 0; for (;;) { /* Oczekiwanie na nastepny pakiet danych. */ r = read(data_socket, buffer, sizeof(buffer)); if (r == -1) { perror("read"); exit(EXIT_FAILURE); } /* Upewnienie sie, ze bufor jest zakonczony 0. */ buffer[sizeof(buffer) - 1] = 0; /* Obsluga polecen. */ if (!strncmp(buffer, "DOWN", sizeof(buffer))) { down_flag = 1; continue; } if (!strncmp(buffer, "END", sizeof(buffer))) { break; } if (down_flag) { continue; } /* Dodanie otrzymanego skladnika. */ result += atoi(buffer); } /* Wyslanie wyniku. */ sprintf(buffer, "%d", result); w = write(data_socket, buffer, sizeof(buffer)); if (w == -1) { perror("write"); exit(EXIT_FAILURE); } /* Zamkniecie gniazda. */ close(data_socket); /* Wyjscie na polecenie DOWN. */ if (down_flag) { break; } } close(connection_socket); /* Odlinkowanie gniazda. */ unlink(SOCKET_NAME); exit(EXIT_SUCCESS); } /* * Plik client.c */ #include #include #include #include #include #include #include #include "connection.h" int main(int argc, char *argv[]) { int ret; int data_socket; ssize_t r, w; struct sockaddr_un addr; char buffer[BUFFER_SIZE]; /* Tworzenie gniazda lokalnego. */ data_socket = socket(AF_UNIX, SOCK_SEQPACKET, 0); if (data_socket == -1) { perror("socket"); exit(EXIT_FAILURE); } /* * Ze wzgledu na przenosnosc konieczne jest wyczyszczenie calej * struktury, poniewaz niektore implementacje zawieraja dodatkowe * (nieprzenosne) pola w strukturze. */ memset(&addr, 0, sizeof(addr)); /* Laczenie gniazda z adresem gniazda. */ addr.sun_family = AF_UNIX; strncpy(addr.sun_path, SOCKET_NAME, sizeof(addr.sun_path) - 1); ret = connect(data_socket, (const struct sockaddr *) &addr, sizeof(addr)); if (ret == -1) { fprintf(stderr, "Serwer jest wylaczony.\n"); exit(EXIT_FAILURE); } /* Wysylanie argumentow. */ for (int i = 1; i < argc; ++i) { w = write(data_socket, argv[i], strlen(argv[i]) + 1); if (w == -1) { perror("write"); break; } } /* Zadanie wyniku. */ strcpy(buffer, "END"); w = write(data_socket, buffer, strlen(buffer) + 1); if (w == -1) { perror("write"); exit(EXIT_FAILURE); } /* Otrzymanie wyniku. */ r = read(data_socket, buffer, sizeof(buffer)); if (r == -1) { perror("read"); exit(EXIT_FAILURE); } /* Upewnienie sie, ze bufor konczy sie 0. */ buffer[sizeof(buffer) - 1] = 0; printf("Wynik = %s\n", buffer); /* Zamkniecie gniazda. */ close(data_socket); exit(EXIT_SUCCESS); } Przyklady uzycia SCM_RIGHTS mozna znalezc w podrecznikach cmsg(3) i seccomp_unotify(2). ZOBACZ TAKZE recvmsg(2), sendmsg(2), socket(2), socketpair(2), cmsg(3), capabilities(7), credentials(7), socket(7), udp(7) TLUMACZENIE Tlumaczenie niniejszej strony podrecznika: Andrzej Krzysztofowicz , Robert Luberda i Michal Kulach Niniejsze tlumaczenie jest wolna dokumentacja. Blizsze informacje o warunkach licencji mozna uzyskac zapoznajac sie z GNU General Public License w wersji 3 lub nowszej. Nie przyjmuje sie ZADNEJ ODPOWIEDZIALNOSCI. Bledy w tlumaczeniu strony podrecznika prosimy zglaszac na adres listy dyskusyjnej . Linux man-pages 6.18 8 lutego 2026 r. UNIX(7)