unix

UNIX(7)                 PodrÄcznik programisty Linuksa                 UNIX(7)



NAZWA
       unix - gniazda lokalnej komunikacji miÄdzyprocesowej

SKÅADNIA
       #include <sys/socket.h>
       #include <sys/un.h>

       unix_socket = socket(AF_UNIX, type, 0);
       error = socketpair(AF_UNIX, type, 0, int *sv);

OPIS
       Rodzina gniazd AF_UNIX (znana również jako AF_LOCAL) sÅuży do
       wydajnej komunikacji pomiÄdzy procesami na tej samej maszynie. Zgodnie
       z tradycjÄ, gniazda domeny uniksowej mogÄ byÄ albo anonimowe (tworzone
       przez socketpair(2)), albo skojarzone z plikiem typu gniazda. Linux
       wspiera również abstrakcyjnÄ przestrzeÅ nazw, niezależnÄ od systemu
       plików.

       Poprawne typy gniazd w domenie Uniksa to: SOCK_STREAM dla gniazd
       strumieniowych, SOCK_DGRAM dla  gniazd datagramowych, które zachowujÄ
       granice komunikatów (w przypadku wiÄkszoÅci implementacji Uniksa
       gniazda uniksowe sÄ zawsze niezawodne i nie zmieniajÄ kolejnoÅci
       datagramów), oraz (od wersji Linuksa 2.6.4) SOCK_SEQPACKET dla gniazd
       pakietów sekwencyjnych zorientowanych poÅÄczeniowo, które zachowujÄ
       granice komunikatu i dostarczajÄ komunikaty w kolejnoÅci ich wysyÅania.

       Za poÅrednictwem pomocniczych danych można przez gniazda domeny
       uniksowej przekazywaÄ do innych procesów deskryptory plików i
       uwierzytelnienia procesów.

   Format adresu
       Adres gniazda domeny uniksowej jest reprezentowany przez nastÄpujÄcÄ
       strukturÄ:

           struct sockaddr_un {
               sa_family_t sun_family;               /* AF_UNIX */
               char        sun_path[108];            /* Åcieżka dostÄpu */
           };

       Pole sun_family zawsze zawiera AF_UNIX. W Linuksie sun_path ma rozmiar
       108 bajtów, zob. też UWAGI poniżej.

       Różne wywoÅania systemowe (np. bind(2), connect(2) i sendto(2))
       przyjmujÄ argument sockaddr_un jako wejÅcie. Niektóre inne wywoÅania
       systemowe (np. getsockname(2), getpeername(2), recvfrom(2) i accept(2))
       zwracajÄ argument tego typu.

       W strukturze sockaddr_un rozróżniane sÄ trzy typy adresów:

       *  pathname: gniazdo domeny uniksowej może zostaÄ zwiÄzane z
          zakoÅczonÄ znakiem NULL nazwÄ Åcieżki systemowej za pomocÄ bind(2).
          JeÅli adres Åcieżki gniazda jest zwracany (przez jedno z ww.
          wywoÅaÅ systemowych) to jego dÅugoÅciÄ jest

              offsetof(struct sockaddr_un, sun_path) + strlen(sun_path) + 1

          a sun_path zawiera zakoÅczonÄ null ÅcieżkÄ. (W Linuksie powyższe
          wyrażenie offsetof() jest równe tej samej wartoÅci co
          sizeof(sa_family_t), lecz niektóre inne implementacje
          doÅÄczajÄ inne pola przed sun_path, wiÄc bardziej przenoÅnie,
          wyrażenie offsetof() opisuje rozmiar struktury adresu).

          WiÄcej informacji o Åcieżkach gniazd znajduje siÄ poniżej.

       *  unnamed: Gniazdo strumieniowe nie zwiÄzane z nazwÄ Åcieżki za
          pomocÄ bind(2) nie jest nazwane. Podobnie dwa gniazda utworzone
          przez socketpair(2) nie sÄ nazwane. JeÅli adres nienazwanego gniazda
          jest zwracany, to jego dÅugoÅciÄ jest sizeof(sa_family_t), a
          zawartoÅÄ sun_path nie powinna byÄ sprawdzana.

       *  abstract: adres gniazda abstrakcyjnego jest rozróżniany (od adresu
          Åcieżki) po tym, że sun_path[0] jest bajtem NULL ("\0"). Adres
          gniazda znajduje siÄ w przestrzeni nazw podanej w dodatkowych
          bajtach w sun_path, które sÄ pokryte przez dÅugoÅÄ struktury adresu
          (Bajty NULL w nazwie nie majÄ Å¼adnego specjalnego znaczenia). Nazwa
          nie ma żadnego powiÄzania z nazwÄ pliku w systemie plików.
          Zwracany adres gniazda abstrakcyjnego ma w polu addrlen ustawionÄ
          dÅugoÅÄ wiÄkszÄ niż sizeof(sa_family_t) (tj. wiÄkszÄ niż 2), a
          nazwa gniazda zawarta jest w pierwszych (addrlen -
          sizeof(sa_family_t)) bajtach pola sun_path. PrzestrzeÅ nazw gniazd
          abstrakcyjnych jest  nieprzenaszalnym rozszerzeniem Linuksa.

   Åcieżki gniazd
       Przy przypisywaniu gniazda do Åcieżki powinno siÄ przestrzegaÄ kilku
       zasad w celu maksymalnej przenoÅnoÅci i ÅatwoÅci programowania:

       *  Åcieżka w sun_path powinna byÄ zakoÅczona znakiem NULL.

       *  DÅugoÅÄ Åcieżki, w tym koÅczÄcy bajt null nie powinna przekraczaÄ
          rozmiaru sun_path.

       *  Argument addrlen opisujÄcy obejmujÄcÄ strukturÄ sockaddr_un powinien
          mieÄ wartoÅÄ przynajmniej:

              offsetof(struct sockaddr_un, sun_path)+strlen(addr.sun_path)+1

          lub, proÅciej, addrlen powinien byÄ podany jako sizeof(struct
          sockaddr_un).

       W różnych implementacjach różnie obsÅugiwane sÄ adresy gniazd domen
       Uniksa, które nie przestrzegajÄ powyższych zaleceÅ. Na przykÅad
       niektóre (lecz nie wszystkie) implementacje dodajÄ koÅczÄcy znak null,
       jeÅli nie jest on obecny w przekazanej sun_path.

       Przy programowaniu przenoÅnych aplikacji proszÄ wziÄÄ pod uwagÄ, że
       niektóre implementacjÄ majÄ sun_path o dÅugoÅci zaledwie 92 bajtów.

       Różne wywoÅania systemowe (accept(2), recvfrom(2), getsockname(2),
       getpeername(2)) zwracajÄ struktury adresów gniazd. Gdy chodzi o
       gniazda domeny Uniksa, wartoÅÄ-rezultat argumentu addrlen umieszczonego
       w wywoÅaniu powinna byÄ zainicjowana jw. Gdy jest zwracany, argument
       ten jest ustawiany aby przedstawiaÄ aktualny rozmiar struktury adresu.
       WywoÅujÄcy powinien sprawdziÄ wartoÅÄ zwracanÄ w tym argumencie, jeÅli
       wartoÅÄ wyjÅciowa przekracza wartoÅÄ wejÅciowÄ, to nie ma gwarancji,
       że koÅczÄcy znak null jest obecny w sun_path (zob PROBLEMY).

   Opcje gniazda
       Ze wzglÄdów historycznych nastÄpujÄce opcje gniazd sÄ podawane przy
       typie SOL_SOCKET, pomimo że sÄ one specyficzne dla AF_UNIX. Można je
       ustawiÄ za pomocÄ setsockopt(2), a odczytaÄ za pomocÄ getsockopt(2),
       podajÄc SOL_SOCKET jako rodzinÄ gniazd.

       SO_PASSCRED
              WÅÄcza otrzymywanie uwierzytelnieÅ od procesu wysyÅajÄcego
              komunikat pomocniczy. Przy wÅÄczonej tej opcji i niepoÅÄczonym
              jeszcze gnieździe, unikatowa nazwa gniazda z abstrakcyjnej
              przestrzeni nazw jest generowana automatycznie. Oczekiwany jest
              logiczny znacznik typu caÅkowitego.

   Automatyczne przypisywanie adresów
       JeÅli w wywoÅaniu bind(2) podane zostanie addrlen równe
       sizeof(sa_family_t) lub opcja SO_PASSCRED gniazda byÅa ustawiona dla
       gniazda nieprzypisanego do adresu, wtedy gniazdo jest automatycznie
       przypisywane do adresu abstrakcyjnego. Adres ten skÅada siÄ z bajtu
       NULL, po którym nastÄpuje 5 bajtów ze zbioru znaków [0-9a-f]. W
       zwiÄzku z tym liczba automatycznie przypisywanych adresów jest
       ograniczona przez 2^20. (W Linuksie 2.1.15, w którym dodano możliwoÅÄ
       automatycznego przypisywania adresów, i w kolejnych wersjach używane
       byÅo 8 bajtów, a limit wynosiÅ 2^32 adresów. ZostaÅo to zmienione na
       5 bajtów w Linuksie 2.3.15).

   API gniazd
       W kolejnych paragrafach opisano pewne szczegóÅy implementacji API
       gniazd domeny UNIX specyficzne dla Linuksa oraz cechy niewspierane.

       Gniazda z domeny uniksowej nie obsÅugujÄ zawiadomienia o danych
       autonomicznych (flaga MSG_OOB funkcji send(2) i recv(2)).

       Flaga MSG_MORE funkcji send(2) nie jest obsÅugiwana dla gniazd domeny
       uniksowej.

       Użycie MSG_TRUNC w argumencie flags funkcji recv(2) nie jest
       obsÅugiwane dla gniazd domeny uniksowej.

       Opcja SO_SNDBUF dziaÅa w przypadku gniazd domeny uniksowej, ale opcja
       SO_RCVBUF już nie. Dla gniazd datagramowych wartoÅÄ SO_SNDBUF nakÅada
       górny limit na rozmiar wychodzÄcych datagramów. Limit ten jest
       liczony jako podwojona (patrz socket(7)) wartoÅÄ opcji minus 32 bajty
       wymagane na informacje nie bÄdÄce danymi.

   Komunikaty pomocnicze
       Dane pomocnicze sÄ wysyÅane i odbierane za pomocÄ sendmsg(2) i
       recvmsg(2). Ze wzglÄdów historycznych komunikaty pomocnicze
       poniższych typów sÄ podawane przy typie SOL_SOCKET, pomimo że sÄ one
       specyficzne dla AF_UNIX. Aby je wysÅaÄ, należy ustawiÄ pole cmsg_level
       struktury cmsghdr na SOL_SOCKET, a pole cmsg_type na typ. WiÄcej
       informacji można znaleÅºÄ w cmsg(3).

       SCM_RIGHTS
              Odbieranie od innego procesu lub wysyÅanie do niego zbioru
              otwartych deskryptorów plików. Porcja danych zawiera tablicÄ
              liczb caÅkowitych bÄdÄcych deskryptorami plików. Przekazane
              deskryptory plików zachowujÄ siÄ tak, jakby zostaÅy utworzone
              za pomocÄ dup(2).

       SCM_CREDENTIALS
              Odbieranie lub wysyÅanie uwierzytelnieÅ uniksowych. Może
              sÅużyÄ do autoryzacji. Uwierzytelnienia sÄ przekazywane jako
              komunikat pomocniczy typu struct ucred, zdefiniowanego w
              <sys/socket.h> nastÄpujÄco:

                  struct ucred {
                      pid_t pid;  /* identyfikator procesu wysyÅajÄcego */
                      uid_t uid;  /* ident. użytkownika procesu wysyÅajÄcego */
                      gid_t gid;  /* ident. grupy procesu wysyÅajÄcego */
                  };

              PoczÄwszy od wersji 2.8 biblioteki glibc, aby uzyskaÄ dostÄp do
              definicji powyższej struktury, należy zdefiniowaÄ makro
              _GNU_SOURCE (przed doÅÄczeniem jakichkolwiek plików
              nagÅówkowych).

              JÄdro sprawdza uwierzytelnienia podane przez wysyÅajÄcego.
              Proces o efektywnym ID użytkownika równym 0 może podaÄ
              wartoÅci, które różniÄ siÄ od jego wÅasnych. W pozostaÅych
              przepadkach wysyÅajÄcy musi podaÄ swój wÅasny identyfikator
              procesu (o ile nie ma ustawionego znacznika CAP_SYS_ADMIN),
              swój wÅasny identyfikator użytkownika, efektywny identyfikator
              użytkownika lub ustawiony identyfikator użytkownika (o ile nie
              ma ustawionego znacznika CAP_SETUID) oraz swój wÅasny
              identyfikator grupy, efektywny identyfikator grupy lub ustawiony
              identyfikator grupy (o ile nie ma ustawionego znacznika
              CAP_SETGID). Aby otrzymaÄ komunikat typu struct ucred, dla
              gniazda musi byÄ wÅÄczona opcja SO_PASSCRED.

   Kontrolki systemowe (ioctl)
       NastÄpujÄce wywoÅania ioctl(2) zwracajÄ informacje w parametrze value.
       Poprawna skÅadnia to:

              int value;
              error = ioctl(unix_socket, ioctl_type, &value);

       ioctl_type może przyjmowaÄ wartoÅÄ:

       SIOCINQ
              Dla gniazda SOCK_STREAM funkcja zwraca iloÅÄ nieprzeczytanych
              jeszcze danych znajdujÄcych siÄ w kolejce buforu odbierajÄcego.
              Gniazdo nie może siÄ znajdowaÄ w stanie "LISTEN"; w przeciwnym
              wypadku zostanie zwrócony bÅÄd (EINVAL). SIOCINQ jest
              zdefiniowany w <linux/sockios.h>. Alternatywnie można użyÄ
              synonimu FIONREAD zdefiniowanego w <sys/ioctl.h>. Dla gniazda
              SOCK_DGRAM, zwracana wartoÅÄ jest taka sama jak w przypadku
              datagramowego gniazda domeny Internet; zob. udp(7).

BÅÄDY
       EADDRINUSE
              Podany adres lokalny jest zajÄty lub obiekt gniazda w systemie
              plików już istnieje.

       ECONNREFUSED
              Adres zdalny podany w connect(2) nie odnosiÅ siÄ do gniazda
              nasÅuchujÄcego. BÅÄd może także wystÄpiÄ jeÅli docelowa
              Åcieżka nie jest gniazdem.

       ECONNRESET
              Zdalne gniazdo zostaÅo nieoczekiwanie zamkniÄte.

       EFAULT NieprawidÅowy adres pamiÄci użytkownika.

       EINVAL Podano nieprawidÅowy argument. NajczÄstszÄ przyczynÄ jest brak
              ustawionego AF_UNIX w polu sun_type przekazywanych gniazdu
              adresów lub nieprawidÅowy dla danej operacji stan gniazda.

       EISCONN
              WywoÅano connect(2) dla już poÅÄczonego gniazda lub podano
              adres docelowy dla poÅÄczonego gniazda.

       ENOENT Nie istnieje Åcieżka dla zdalnego adresu przekazanego do
              connect(2).

       ENOMEM Brak pamiÄci.

       ENOTCONN
              Operacja na gnieździe wymaga adresu docelowego, a gniazdo nie
              jest poÅÄczone.

       EOPNOTSUPP
              Operacja strumieniowa wywoÅana dla gniazda niestrumieniowego lub
              próba użycia opcji danych autonomicznych.

       EPERM  WysyÅajÄcy podaÅ nieprawidÅowe uwierzytelnienia w struct ucred.

       EPIPE  Zdalne gniazdo strumieniowe zostaÅo zamkniÄte. Gdy wÅÄczone,
              wysyÅany jest jednoczeÅnie sygnaÅ SIGPIPE. Można tego uniknÄÄ,
              przekazujÄc znacznik MSG_NOSIGNAL do sendmsg(2) lub recvmsg(2).

       EPROTONOSUPPORT
              Podanym protokoÅem nie jest AF_UNIX.

       EPROTOTYPE
              Typ gniazda zdalnego różni siÄ od typu gniazda lokalnego
              (SOCK_DGRAM wobec SOCK_STREAM)

       ESOCKTNOSUPPORT
              Nieznany typ gniazda.

       Inne bÅÄdy mogÄ zostaÄ wygenerowane przez podstawowÄ warstwÄ gniazd lub
       przez system plików podczas tworzenia obiektu gniazda w systemie
       plików. WiÄcej informacji można znaleÅºÄ na odpowiednich stronach
       podrÄcznika.

WERSJE
       SCM_CREDENTIALS oraz abstrakcyjna przestrzeÅ nazw zostaÅy wprowadzone w
       Linuksie 2.2 i nie należy ich używaÄ w przenoÅnych programach.
       (Niektóre systemy wywodzÄce siÄ z BSD również wspierajÄ
       przekazywanie uwierzytelnieÅ, ale implementacje różniÄ siÄ
       szczegóÅami).

UWAGI
       W linuksowej implementacji dla gniazda widocznych w systemie plików sÄ
       stosowane uprawnienia katalogu, w którym siÄ znajdujÄ. Ich
       wÅaÅciciela, grupÄ oraz prawa dostÄpu można zmieniaÄ. Gdy proces nie
       ma uprawnieÅ do zapisu i przeszukiwania (uruchamiania) do katalogu, w
       którym tworzone jest gniazdo, jego utworzenie siÄ nie powiedzie.
       PoÅÄczenie z obiektem gniazda wymaga praw odczytu/zapisu. Takie
       zachowanie różni siÄ od zachowania wielu systemów wywodzÄcych siÄ z
       BSD, które ignorujÄ uprawnienia dla gniazd uniksowych. Programy
       przenoÅne ze wzglÄdów bezpieczeÅstwa nie powinny polegaÄ na tej cesze.

       W trakcie ÅÄczenia siÄ z gniazdem majÄcym przypisanÄ nazwÄ pliku,
       tworzony jest plik specjalny gniazda w systemie plików, który musi
       zostaÄ usuniÄty (za pomocÄ unlink(2)) przez wywoÅujÄcego, gdy już nie
       bÄdzie potrzebny. Stosuje siÄ tu zwykÅa uniksowa skÅadnia opóźnionego
       zamkniÄcia (ang. close-behind): gniazdo można skasowaÄ w dowolnym
       momencie, ale zostanie ono ostatecznie usuniÄte z systemu plików po
       zamkniÄciu ostatniego odwoÅania do niego.

       Aby przekazaÄ deskryptory plików lub uwierzytelnienia poprzez
       SOCK_STREAM trzeba wysÅaÄ/odebraÄ co najmniej jeden bajt
       niepomocniczych danych w tym samym wywoÅaniu sendmsg(2) lub recvmsg(2)

       Gniazda strumieniowe z domeny uniksowej nie obsÅugujÄ zawiadomienia o
       danych autonomicznych.

PROBLEMY
       Przy wiÄzaniu gniazda z adresem, Linux jest jednÄ z implementacji
       dodajÄcych koÅczÄce null, jeÅli nie poda siÄ go w sun_path. Zwykle jest
       to bezproblemowe, gdy adres gniazda jest pozyskiwany bÄdzie on o jeden
       bajt dÅuższy niż podawany poczÄtkowo. Jest jednak jeden przypadek
       mogÄcy spowodowaÄ mylÄce zachowanie: jeÅli podany zostanie adres 108
       bajtowy, bez znaku null, to dodanie znaku null spowodowaÅoby
       przekroczenie dÅugoÅci Åcieżki poza sizeof(sun_path). W konsekwencji,
       przy pozyskiwaniu adresu gniazda (np. poprzez accept(2)), jeÅli
       wejÅciowy argument addrlen dla pozyskiwanego wywoÅania jest podany jako
       sizeof(struct sockaddr_un), to zwrócona struktura adresu nie bÄdzie
       miaÅa koÅczÄcego null w sun_path.

       Dodatkowo, niektóre implementacje nie wymagajÄ koÅczÄcego null przy
       wiÄzaniu gniazda (argument addrlen jest używany do okreÅlenia dÅugoÅci
       sun_path), a gdy w tych implementacjach jest pozyskiwany adres gniazda,
       to nie ma koÅczÄcego null w sun_path.

       Aplikacje pozyskujÄce adresy gniazd mogÄ posiadaÄ (przenoÅny) kod do
       obsÅugi możliwoÅci, że w sun_path nie ma koÅczÄcego null zauważajÄc
       fakt, że liczba prawidÅowych bajtów w Åcieżce to:

           strnlen(addr.sun_path, addrlen - offsetof(sockaddr_un, sun_path))

       Alternatywnie, aplikacja może pozyskaÄ adres gniazda przez
       przydzielenie buforu o rozmiarze sizeof(struct sockaddr_un)+1 który
       jest wyzerowany przed pozyskaniem. PobierajÄce wywoÅanie może okreÅliÄ
       addrlen jako sizeof(struct sockaddr_un), a dodatkowy bajt zero
       zapewnia, że w ÅaÅcuchu zwróconym w sun_path bÄdzie koÅczÄce null:

          void *addrp;

          addrlen = sizeof(struct sockaddr_un);
          addrp = malloc(addrlen + 1);
          if (addrp == NULL)
              /* ObsÅuga bÅÄdu */ ;
          memset(addrp, 0, addrlen + 1);

          if (getsockname(sfd, (struct sockaddr *) addrp, &addrlen)) == -1)
              /* obsÅuga bÅÄdu */ ;

          printf("sun_path = %s\n", ((struct sockaddr_un *) addrp)->sun_path);

       Tego baÅaganu można uniknÄÄ, jeÅli jest pewnoÅÄ, że aplikacja
       tworzÄca Åcieżki gniazd przestrzega reguÅ opisanych powyżej rozdziale
       Åcieżki gniazd.

PRZYKÅAD
       Poniższy kod demonstruje użycie gniazd pakietów sekwencyjnych do
       lokalnej komunikacji miÄdzyprocesowej. SkÅada siÄ z dwóch programów.
       Serwer czeka na poÅÄczenie z programu klienckiego. Klient wysyÅa każdy
       ze swoich argumentów wiersza poleceÅ w oddzielnych wiadomoÅciach.
       Serwer traktuje przychodzÄce wiadomoÅci jako liczby caÅkowite i dodaje
       je. Klient wysyÅa ÅaÅcuch polecenia "END". Serwer odsyÅa komunikat
       zawierajÄcy sumÄ klienckich liczb caÅkowitych. Klient wypisuje sumÄ i
       wychodzi. Serwer czeka na poÅÄczenie od kolejnego klienta. Aby
       zatrzymaÄ serwer, klient jest wywoÅywany z argumentem wiersza poleceÅ
       "DOWN".

       Podczas dziaÅania serwera w tle i kolejnych uruchomieÅ klienta
       zarejestrowano nastÄpujÄce wyjÅcie. Wykonywanie programu serwera koÅczy
       siÄ, gdy otrzymuje on polecenie "DOWN".

   PrzykÅadowe wyjÅcie
           $ ./server &
           [1] 25887
           $ ./client 3 4
           Result = 7
           $ ./client 11 -5
           Result = 6
           $ ./client DOWN
           Result = 0
           [1]+  Done                    ./server
           $

   Kod źródÅowy programu
       /*
        * Plik connection.h
        */

       #define SOCKET_NAME "/tmp/9Lq7BNBnBycd6nxy.socket"
       #define BUFFER_SIZE 12

       /*
        * Plik server.c
        */

       #include <stdio.h>
       #include <stdlib.h>
       #include <string.h>
       #include <sys/socket.h>
       #include <sys/un.h>
       #include <unistd.h>
       #include "connection.h"

       int
       main(int argc, char *argv[])
       {
           struct sockaddr_un name;
           int down_flag = 0;
           int ret;
           int connection_socket;
           int data_socket;
           int result;
           char buffer[BUFFER_SIZE];

           /*
            * JeÅli program wyszedÅ niejawnie w ostatnim przebiegu,
            * usuwa gniazdo.
            */

           unlink(SOCKET_NAME);

           /* Tworzenie lokalnego gniazda. */

           connection_socket = socket(AF_UNIX, SOCK_SEQPACKET, 0);
           if (connection_socket == -1) {
               perror("socket");
               exit(EXIT_FAILURE);
           }

           /*
            * Dla przenoÅnoÅci wyczyÅÄ caÅÄ strukturÄ, ponieważ niektóre
            * implementacje majÄ dodatkowe (niestandardowe) pola
            * w strukturze.
            */

           memset(&name, 0, sizeof(struct sockaddr_un));

           /* WiÄzanie gniazda z nazwÄ 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(struct sockaddr_un));
           if (ret == -1) {
               perror("bind");
               exit(EXIT_FAILURE);
           }

           /*
            * Przygotowywanie do akceptowania poÅÄczeÅ. Rozmiar bufora jest
            * ustawiany na 20. Podczas przetwarzania jednego żÄdania, inne
            * mogÄ czekaÄ.
            */

           ret = listen(connection_socket, 20);
           if (ret == -1) {
               perror("listen");
               exit(EXIT_FAILURE);
           }

           /* To gÅówna pÄtla do obsÅugi poÅÄczeÅ. */

           for (;;) {

               /* Czekanie na poÅÄczenie przychodzÄce. */

               data_socket = accept(connection_socket, NULL, NULL);
               if (ret == -1) {
                   perror("accept");
                   exit(EXIT_FAILURE);
               }

               result = 0;
               for(;;) {

                   /* Czekanie na nastÄpny pakiet danych. */

                   ret = read(data_socket, buffer, BUFFER_SIZE);
                   if (ret == -1) {
                       perror("read");
                       exit(EXIT_FAILURE);
                   }

                   /* Upewnienie siÄ, że bufor koÅczy siÄ 0. */

                   buffer[BUFFER_SIZE - 1] = 0;

                   /* ObsÅuga poleceÅ. */

                   if (!strncmp(buffer, "DOWN", BUFFER_SIZE)) {
                       down_flag = 1;
                       break;
                   }

                   if (!strncmp(buffer, "END", BUFFER_SIZE)) {
                       break;
                   }

                   /* Dodawanie otrzymanej sumy. */

                   result += atoi(buffer);
               }

               /* WysyÅanie wyniku. */

               sprintf(buffer, "%d", result);
               ret = write(data_socket, buffer, BUFFER_SIZE);

               if (ret == -1) {
                   perror("write");
                   exit(EXIT_FAILURE);
               }

               /* ZamkniÄcie gniazda. */

               close(data_socket);

               /* WyjÅcie po poleceniu DOWN. */

               if (down_flag) {
                   break;
               }
           }

           close(connection_socket);

           /* UsuniÄcie gniazda. */

           unlink(SOCKET_NAME);

           exit(EXIT_SUCCESS);
       }

       /*
        * Plik client.c
        */

       #include <errno.h>
       #include <stdio.h>
       #include <stdlib.h>
       #include <string.h>
       #include <sys/socket.h>
       #include <sys/un.h>
       #include <unistd.h>
       #include "connection.h"

       int
       main(int argc, char *argv[])
       {
           struct sockaddr_un addr;
           int i;
           int ret;
           int data_socket;
           char buffer[BUFFER_SIZE];

           /* Tworzenie lokalnego gniazda. */

           data_socket = socket(AF_UNIX, SOCK_SEQPACKET, 0);
           if (data_socket == -1) {
               perror("socket");
               exit(EXIT_FAILURE);
           }

           /*
            * Dla przenoÅnoÅci wyczyÅÄ caÅÄ strukturÄ, ponieważ niektóre
            * implementacje majÄ dodatkowe (niestandardowe) pola
            * w strukturze.
            */

           memset(&addr, 0, sizeof(struct sockaddr_un));

           /* ÅÄczenie 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(struct sockaddr_un));
           if (ret == -1) {
               fprintf(stderr, "The server is down.\n");
               exit(EXIT_FAILURE);
           }

           /* WysyÅanie argumentów. */

           for (i = 1; i < argc; ++i) {
               ret = write(data_socket, argv[i], strlen(argv[i]) + 1);
               if (ret == -1) {
                   perror("write");
                   break;
               }
           }

           /* Å»Ädanie wyniku. */

           strcpy (buffer, "END");
           ret = write(data_socket, buffer, strlen(buffer) + 1);
           if (ret == -1) {
               perror("write");
               exit(EXIT_FAILURE);
           }

           /* Otrzymanie wyniku. */

           ret = read(data_socket, buffer, BUFFER_SIZE);
           if (ret == -1) {
               perror("read");
               exit(EXIT_FAILURE);
           }

           /* Upewnienie siÄ, że bufor koÅczy siÄ 0. */

           buffer[BUFFER_SIZE - 1] = 0;

           printf("Result = %s\n", buffer);

           /* ZamkniÄcie gniazda. */

           close(data_socket);

           exit(EXIT_SUCCESS);
       }

       PrzykÅad użycia SCM_RIGHTS można znaleÅºÄ w cmsg(3).

ZOBACZ TAKŻE
       recvmsg(2), sendmsg(2), socket(2), socketpair(2), cmsg(3),
       capabilities(7), credentials(7), socket(7), udp(7)

O STRONIE
       Angielska wersja tej strony pochodzi z wydania 4.05 projektu Linux
       man-pages. Opis projektu, informacje dotyczÄce zgÅaszania bÅÄdów, oraz
       najnowszÄ wersjÄ oryginaÅu można znaleÅºÄ pod adresem
       https://www.kernel.org/doc/man-pages/.

TÅUMACZENIE
       Autorami polskiego tÅumaczenia niniejszej strony podrÄcznika man sÄ:
       Andrzej M. Krzysztofowicz (PTM) <ankry@mif.pg.gda.pl>, Robert Luberda
       <robert@debian.org> i MichaÅ KuÅach <michal.kulach@gmail.com>.

       Polskie tÅumaczenie jest czÄÅciÄ projektu manpages-pl; uwagi, pomoc,
       zgÅaszanie bÅÄdów na stronie http://sourceforge.net/projects/manpages-
       pl/. Jest zgodne z wersjÄ  4.05 oryginaÅu.



Linux                             2016-03-15                           UNIX(7)