Provided by: manpages-pl-dev_4.23.1-1_all bug

NAZWA

       getaddrinfo, freeaddrinfo, gai_strerror - tłumaczy adresy i usługi sieciowe

BIBLIOTEKA

       Standardowa biblioteka C (libc, -lc)

SKŁADNIA

       #include <sys/types.h>
       #include <sys/socket.h>
       #include <netdb.h>

       int getaddrinfo(const char *restrict node,
                       const char *restrict service,
                       const struct addrinfo *restrict hints,
                       struct addrinfo **restrict res);

       void freeaddrinfo(struct addrinfo *res);

       const char *gai_strerror(int errcode);

   Wymagane ustawienia makr biblioteki glibc (patrz feature_test_macros(7)):

       getaddrinfo(), freeaddrinfo(), gai_strerror():
           Od glibc 2.22:
               _POSIX_C_SOURCE >= 200112L
           glibc 2.21 i wcześniejsze:
               _POSIX_C_SOURCE

OPIS

       Dla  danego  węzła  node i usługi service, które identyfikują stację i usługę internetową,
       getaddrinfo() zwraca jedną lub więcej struktur addrinfo, każda  z  których  zawiera  adres
       internetowy,   który   można   podać  w  wywołaniu  do  bind(2)  lub  connect(2).  Funkcja
       getaddrinfo()  łączy  funkcjonalność  udostępnianą  przez   funkcje   gethostbyname(3)   i
       getservbyname(3)  w  jeden  interfejs,  lecz w przeciwieństwie do nich, getaddrinfo() jest
       wielobieżna i umożliwia programom wyeliminowanie zależności od IPv4 lub IPv6.

       Struktura addrinfo używana przez getaddrinfo() zawiera następujące pola:

           struct addrinfo {
               int              ai_flags;
               int              ai_family;
               int              ai_socktype;
               int              ai_protocol;
               socklen_t        ai_addrlen;
               struct sockaddr *ai_addr;
               char            *ai_canonname;
               struct addrinfo *ai_next;
           };

       Argument hints wskazuje na strukturę addrinfo,  która  określa  kryteria  wyboru  struktur
       adresów  gniazd  zwracanych  w  liście wskazywanej przez res. Jeśli hints nie wynosi NULL,
       wskazuje na strukturę addrinfo, której pola ai_family, ai_socktype i ai_protocol określają
       kryteria  ograniczające  zbiory  adresów  gniazd  zwracane  przez getaddrinfo(), zgodnie z
       poniższym opisem:

       ai_family
              Pole określa żądaną rodzinę adresów wobec zwracanych adresów.  Prawidłowe  wartości
              tego pola obejmują AF_INET i AF_INET6. Wartość AF_UNSPEC wskazuje, że getaddrinfo()
              powinno zwrócić adresy gniazd dla dowolnej rodziny adresów  (np.  IPv4  lub  IPv6),
              których można użyć z node i service.

       ai_socktype
              Pole  określa preferowany typ gniazda np. SOCK_STREAM lub SOCK_DGRAM. Podanie w tym
              polu wartości 0 wskazuje, że getaddrinfo() może  zwrócić  adresy  gniazd  dowolnego
              typu.

       ai_protocol
              Pole  określa  protokół  zwracanych  adresów  gniazd. Podanie w tym polu wartości 0
              wskazuje, że getaddrinfo() może zwrócić adresy gniazd dowolnego protokołu.

       ai_flags
              Pole określa dodatkowe opcje, opisane poniżej. Można podać wiele flag,  sumując  je
              bitowo (OR).

       Wszystkie pozostałe pola w strukturze na którą wskazuje hints, muszą zawierać albo 0, albo
       pusty wskaźnik (w zależności od pola).

       Podanie hints jako NULL  jest  równoważne  ustawieniu  ai_socktype  i  ai_protocol  na  0;
       ai_family  na  AF_UNSPEC;  a ai_flags na (AI_V4MAPPED | AI_ADDRCONFIG) (POSIX określa inną
       wartość domyślną dla ai_flags; zob. UWAGI). node zawiera albo  adres  sieciowy  w  postaci
       numerycznej   (dla   IPv4:  w  formacie  liczb  i  kropek  takim,  jak  obsługiwany  przez
       inet_aton(3); dla IPv6: w formacie szesnastkowego łańcucha takim,  jak  obsługiwany  przez
       init_pton(3)),   albo  nazwę  stacji,  dla  której  adresy  sieciowe  będą  poszukiwane  i
       rozwiązane. Jeśli hints.ai_flags zawiera znacznik AI_NUMERICHOST, to node musi być adresem
       sieciowym   w   postaci   numerycznej.  Znacznik  AI_NUMERICHOST  eliminuje  jakiekolwiek,
       potencjalnie długotrwałe, poszukiwania adresu sieciowego stacji.

       Jeśli w hints.ai_flags podano znacznik AI_PASSIVE, a node wynosi NULL, to zwracane  adresy
       gniazd  będą  odpowiednie  do  przypisywania  (bind(2))  gniazd,  które  będą  akceptowały
       (accept(2)) połączenia.  Zwracany  adres  gniazda  będzie  zawierał  „adres  wieloznaczny”
       („wildcard  address”;  INADDR_ANY  w  przypadku adresów IPv4, IN6ADDR_ANY_INIT w przypadku
       adresów IPv6). Adres wieloznaczny jest używany przez  aplikacje  (zwykle  serwery),  które
       mają  zamiar akceptować połączenia na dowolnym z adresów sieciowych stacji. Jeśli node nie
       wynosi NULL, to znacznik AI_PASSIVE jest ignorowany.

       Jeśli w hints.ai_flags nie podano znacznika AI_PASSIVE, to  zwracane  adresy  gniazd  będą
       odpowiednie do korzystania z connect(2), sendto(2) lub sendmsg(2). Jeśli node wynosi NULL,
       to adres sieciowy będzie ustawiony na adres interfejsu pętli zwrotnej  (INADDR_LOOPBACK  w
       przypadku  adresów  IPv4, IN6ADDR_LOOPBACK_INIT w przypadku adresów IPv6); jest to używane
       przez aplikacje, które mają zamiar komunikować się z innymi  aplikacjami  działającymi  na
       tej samej stacji.

       service  ustawia  port w każdej zwracanej strukturze adresu. Jeśli argument ten jest nazwą
       usługi (zob. services(5)), to jest tłumaczona na odpowiedni numer portu. Argument ten może
       być  też  liczbą  dziesiętną, wówczas jest jedynie przekształcana na liczbę binarną. Jeśli
       service wynosi  NULL,  to  numer  portu  zwracanych  adresów  gniazd  będzie  pozostawiony
       niezainicjowany.  Jeśli w hints.ai_flags podano AI_NUMERICSERV, a service nie wynosi NULL,
       to service musi wskazywać na łańcuch zawierający numeryczny numer portu. Znacznik ten jest
       używany  do  powstrzymania  rozwiązywania  nazw  w  przypadkach, w których wiadomo, że nie
       będzie to konieczne.

       Parametry node i service mogą być równe NULL, ale nie oba naraz.

       Funkcja getaddrinfo() alokuje i inicjuje podlinkowaną listę struktur addrinfo,  po  jednej
       dla  każdego adresu sieciowego, który pasuje do node i service, jest przedmiotem wszelkich
       ograniczeń nałożonych przez hints, a zwraca wskaźnik do początku listy w res.  Pozycje  na
       podlinkownej liście są linkowane za pomocą pola ai_next.

       Istnieje  wiele  powodów,  dla  których  podlinkowana  lista  może  mieć  więcej niż jedną
       strukturę addrinfo m.in.: stacja sieciowa  może  być  wieloadresowa,  dostępna  za  pomocą
       różnych  protokołów  (np.  AF_INET  oraz  AF_INET6);  albo ta sama usługa jest dostępna za
       pomocą różnych typów gniazd  (np.  jeden  adres  SOCK_STREAM  i  inny  adres  SOCK_DGRAM).
       Aplikacja zwykle spróbuje użyć adresy w zwracanej kolejności. Funkcja sortowania używana w
       getaddrinfo() jest zdefiniowana w RFC 3484; kolejność można dostosować dla danego systemu,
       edytując plik /etc/gai.conf (dostępny od glibc 2.5).

       Jeśli  hints.ai_flags  zawiera  znacznik AI_CANONNAME, to pole ai_canonname w pierwszej ze
       struktur addrinfo w zwracanej liście, jest ustawiane na oficjalną nazwę stacji.

       Pozostałe pola w każdej ze  zwracanych  struktur  addrinfo  są  inicjowane  w  następujący
       sposób:

       •  Pola  ai_family,  ai_socktype  i  ai_protocol zwracają parametry tworzenia gniazd (tzn.
          pola  te  mają  takie  samo  znaczenie,  jak  odpowiadające  im  argumenty  socket(2)).
          Przykładowo  ai_family  może  zwrócić  AF_INET  lub  AF_INET6; ai_socktype może zwrócić
          SOCK_DGRAM lub SOCK_STREAM; a ai_protocol zwróci protokół gniazda.

       •  Wskaźnik do adresu gniazda jest umieszczany w polu ai_addr, a długość adresu gniazda  w
          bajtach, jest umieszczana w polu ai_addrlen.

       Jeśli  hints.ai_flags zawiera znacznik AI_ADDRCONFIG, to adresy IPv4 są zwracane w liście,
       na którą wskazuje res tylko, gdy lokalny system ma skonfigurowany przynajmniej jeden adres
       IPv4,  a  adresy IPv6 są zwracane tylko, gdy lokalny system ma skonfigurowany przynajmniej
       jeden adres IPv6. Adres pętli zwrotnej nie jest w  tym  przypadku  uważany  za  prawidłowy
       skonfigurowany adres. Znacznik ten jest przydatny np. w systemach korzystających wyłącznie
       z IPv4 aby zapewnić, że  getaddrinfo()  nie  zwróci  adresów  gniazd  IPv6,  które  zawsze
       zawiodłyby w connect(2) lub bind(2).

       Jeśli  hints.ai_flags określa znacznik AI_V4MAPPED, a hints.ai_family podano jako AF_INET6
       oraz nie da się znaleźć pasującego adresu IPv6,  to  w  liście,  na  którą  wskazuje  res,
       zwracane  są  adresy  IPv4  zmapowane jako IPv6. Jeśli w hints.ai_flags podano AI_V4MAPPED
       oraz AI_ALL, to zwracane są adresy IPv6 oraz adresy IPv4 zmapowane jako IPv6. AI_ALL  jest
       ignorowane, jeśli nie podano również AI_V4MAPPED.

       Funkcja freeaddrinfo() zwalnia pamięć przydzieloną dla dynamicznie zaalokowanej listy res.

   Rozszerzenia getaddrinfo() dla domen ze znakami spoza ASCII (IDN)
       Od   glibc   2.3.4,   getaddrinfo()   rozszerzono   w   celu  umożliwiania  wybiórczego  i
       przezroczystego konwertowania przychodzących i wychodzących nazw  stacji  z  i  na  format
       Internationalized  Domain  Name  (IDN;  zob.  RFC 3490, Internationalizing Domain Names in
       Applications (IDNA)). Zdefiniowano cztery nowe znaczniki:

       AI_IDN Jeśli znacznik jest podany, nazwa węzła podana w node jest konwertowana  na  format
              IDN,   jeśli   to  konieczne.  Kodowanie  źródłowe  jest  takie,  jak  w  bieżących
              ustawieniach regionalnych (locale).

              Jeśli nazwa wejściowa zawiera znaki spoza ASCII, to używane jest kodowanie IDN.  Te
              fragmenty  nazwy  węzła  (oddzielone  kropką), które zawierają znaki spoza ASCII są
              kodowane za pomocą ASCII Compatible Encoding, przed  ich  przekazaniem  do  funkcji
              rozwiązywania nazw.

       AI_CANONIDN
              Po  pomyślnym  wyszukaniu  nazwy,  jeśli  podano AI_CANONNAME, getaddrinfo() zwróci
              kanoniczną nazwę węzła odnoszącą się do wartości struktury  addrinfo  przekazywanej
              zwrotnie.  Zwracana  wartość  jest  dokładną kopią wartości zwracanej przez funkcję
              rozwiązywania nazw.

              Jeśli nazwa jest zakodowana za pomocą ACE, to będzie zawierać  przedrostek  xn--  w
              jednej lub więcej składowych nazw. Aby przekształcić te składowe w czytelną postać,
              oprócz znacznika AI_CANONNAME można podać też AI_CANONIDN. Wynikowy łańcuch  będzie
              kodowany przy użyciu kodowania z bieżących ustawieniach regionalnych (locale).

       AI_IDN_ALLOW_UNASSIGNED
       AI_IDN_USE_STD3_ASCII_RULES
              Ustawienie  tych  znaczników  włączy  znaczniki, odpowiednio, IDNA_ALLOW_UNASSIGNED
              (zezwala na  nieprzypisane  kody  Unikodu)  i  IDNA_USE_STD3_ASCII_RULES  (sprawdza
              wyjście,  aby  upewnić  się  że  jest  to  nazwa  stacji zgodna z STD3) do użycia w
              obsłudze IDNA.

WARTOŚĆ ZWRACANA

       getaddrinfo() zwraca 0,  gdy  zakończy  się  pomyślnie,  a  w  przeciwnym  razie  jeden  z
       następujących niezerowych kodów błędów:

       EAI_ADDRFAMILY
              Podana stacja nie posiada żadnego adresu sieciowego dla zadanej rodziny adresów.

       EAI_AGAIN
              Serwer nazw zwrócił błąd tymczasowy. Należy spróbować później.

       EAI_BADFLAGS
              hints.ai_flags   zawiera  nieprawidłowe  znaczniki;  lub  hints.ai_flags  zawierało
              AI_CANONNAME i node wynosiło NULL.

       EAI_FAIL
              Serwer nazw zwrócił błąd trwały.

       EAI_FAMILY
              Żądana rodzina adresów nie jest obsługiwana.

       EAI_MEMORY
              Brak pamięci.

       EAI_NODATA
              Podana stacja sieciowa istnieje, ale  nie  zdefiniowano  dla  niej  żadnego  adresu
              sieciowego.

       EAI_NONAME
              node lub service nie jest znane; albo zarówno node jak i service wynoszą NULL; albo
              w hints.ai_flags podano AI_NUMERICSERV, a service nie  było  numerycznym  łańcuchem
              numeru portu.

       EAI_SERVICE
              Żądana  usługa  nie  jest  dostępna  dla  żądanego typu portu. Może być dostępna za
              pomocą innego typu portu. Ten błąd może wystąpić  na  przykład,  gdy  jako  service
              podano   „shell”   (usługa   dostępna   tylko   na   gniazdach  strumieniowych),  a
              hints.ai_protocol wynosiło IPPROTO_UDP albo hints.ai_socktype wynosiło  SOCK_DGRAM;
              albo błąd może wystąpić gdy service nie wynosiło NULL, a hints.ai_socktype wynosiło
              SOCK_RAW (typ gniazda, w ogóle nie obsługujący koncepcji usług).

       EAI_SOCKTYPE
              Żądany typ gniazda nie jest obsługiwany. Może  się  to  zdarzyć  na  przykład,  gdy
              hints.ai_socktype  i  hints.ai_protocol  są  niespójne  (np.  wynoszą, odpowiednio,
              SOCK_DGRAM i IPPROTO_TCP).

       EAI_SYSTEM
              Inny błąd systemowy; ustawiane jest errno aby wskazać błąd.

       Funkcja gai_strerror()  tłumaczy  te  kody  błędów  na  czytelny  dla  człowieka  łańcuch,
       odpowiedni do zgłaszania błędów.

PLIKI

       /etc/gai.conf

ATRYBUTY

       Informacje   o   pojęciach   używanych   w  tym  rozdziale  można  znaleźć  w  podręczniku
       attributes(7).

       ┌─────────────────────────────────────┬────────────────────────┬──────────────────────────┐
       │InterfejsAtrybutWartość                  │
       ├─────────────────────────────────────┼────────────────────────┼──────────────────────────┤
       │getaddrinfo()                        │ Bezpieczeństwo wątkowe │ MT-bezpieczne env locale │
       ├─────────────────────────────────────┼────────────────────────┼──────────────────────────┤
       │freeaddrinfo(), gai_strerror()       │ Bezpieczeństwo wątkowe │ MT-bezpieczne            │
       └─────────────────────────────────────┴────────────────────────┴──────────────────────────┘

WERSJE

       Zgodnie z POSIX.1, określenie hints jako NULL, powinno powodować przyjęcie  ai_flags  jako
       0.    Biblioteka    GNU    C    zamiast   tego   przyjmuje   w   tym   przypadku   wartość
       (AI_V4MAPPED | AI_ADDRCONFIG), ponieważ wartość ta jest uważana za lepszą od przewidzianej
       normą.

STANDARDY

       POSIX.1-2008.

       getaddrinfo()
              RFC 2553.

HISTORIA

       POSIX.1-2001.

       AI_ADDRCONFIG
       AI_ALL
       AI_V4MAPPED
              glibc 2.3.3.

       AI_NUMERICSERV
              glibc 2.3.4.

UWAGI

       getaddrinfo()  obsługuje  notację adres%identyfikator-zasięgu do określenia identyfikatora
       zasięgu IPv6.

PRZYKŁADY

       Poniższe programy  demonstrują  użycie  getaddrinfo(),  gai_strerror(),  freeaddrinfo()  i
       getnameinfo(3). Programy są serwerem i klientem typu echo dla datagramów UDP.

   Program serwera

       #include <netdb.h>
       #include <stdio.h>
       #include <stdlib.h>
       #include <string.h>
       #include <sys/socket.h>
       #include <sys/types.h>
       #include <unistd.h>

       #define BUF_SIZE 500

       int
       main(int argc, char *argv[])
       {
           int                      sfd, s;
           char                     buf[BUF_SIZE];
           ssize_t                  nread;
           socklen_t                peer_addrlen;
           struct addrinfo          hints;
           struct addrinfo          *result, *rp;
           struct sockaddr_storage  peer_addr;

           if (argc != 2) {
               fprintf(stderr, "Użycie: %s port\n", argv[0]);
               exit(EXIT_FAILURE);
           }

           memset(&hints, 0, sizeof(hints));
           hints.ai_family = AF_UNSPEC;    /* Zezwala na IPv4 lub IPv6 */
           hints.ai_socktype = SOCK_DGRAM; /* Gniazdo datagramowe */
           hints.ai_flags = AI_PASSIVE;    /* Dla wieloznacznego adresu IP */
           hints.ai_protocol = 0;          /* Dowolny protokół */
           hints.ai_canonname = NULL;
           hints.ai_addr = NULL;
           hints.ai_next = NULL;

           s = getaddrinfo(NULL, argv[1], &hints, &result);
           if (s != 0) {
               fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
               exit(EXIT_FAILURE);
           }

           /* getaddrinfo() zwraca listę struktur adresów. Próbowany
              jest każdy adres do momentu pomyślnego bind(2).
              Jeśli socket(2) (lub bind(2)) zawiedzie, (gniazdo jest
              jest zamykane i) próbowany jest następny adres. */

           for (rp = result; rp != NULL; rp = rp->ai_next) {
               sfd = socket(rp->ai_family, rp->ai_socktype,
                            rp->ai_protocol);
               if (sfd == -1)
                   continue;

               if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0)
                   break;                  /* Powodzenie */

               close(sfd);
           }

           freeaddrinfo(result);           /* Nie jest już potrzebne */

           if (rp == NULL) {               /* Nie udało się z żadnym adresem */
               fprintf(stderr, "Przypisanie nie powiodło się\n");
               exit(EXIT_FAILURE);
           }

           /* Odczytuje datagramy i odsyła je wysyłającemu. */

           for (;;) {
               char host[NI_MAXHOST], service[NI_MAXSERV];

               peer_addrlen = sizeof(peer_addr);
               nread = recvfrom(sfd, buf, BUF_SIZE, 0,
                                (struct sockaddr *) &peer_addr, &peer_addrlen);
               if (nread == -1)
                   continue;               /* Ignoruje niepomyślne żądanie */

               s = getnameinfo((struct sockaddr *) &peer_addr,
                               peer_addrlen, host, NI_MAXHOST,
                               service, NI_MAXSERV, NI_NUMERICSERV);
               if (s == 0)
                   printf("Otrzymano %zd bajtów z %s:%s\n",
                          nread, host, service);
               else
                   fprintf(stderr, "getnameinfo: %s\n", gai_strerror(s));

               if (sendto(sfd, buf, nread, 0, (struct sockaddr *) &peer_addr,
                          peer_addrlen) != nread)
               {
                   fprintf(stderr, "Błąd przy wysyłaniu odpowiedzi\n");
               }
           }
       }

   Program klienta

       #include <netdb.h>
       #include <stdio.h>
       #include <stdlib.h>
       #include <string.h>
       #include <sys/socket.h>
       #include <sys/types.h>
       #include <unistd.h>

       #define BUF_SIZE 500

       int
       main(int argc, char *argv[])
       {
           int              sfd, s;
           char             buf[BUF_SIZE];
           size_t           len;
           ssize_t          nread;
           struct addrinfo  hints;
           struct addrinfo  *result, *rp;

           if (argc < 3) {
               fprintf(stderr, "Użycie: %s stacja port komunik...\n", argv[0]);
               exit(EXIT_FAILURE);
           }

           /* Pozyskuje adres(y) pasującej stacji/portu. */

           memset(&hints, 0, sizeof(hints));
           hints.ai_family = AF_UNSPEC;    /* Zezwala na IPv4 lub IPv6 */
           hints.ai_socktype = SOCK_DGRAM; /* Gniazdo datagramowe */
           hints.ai_flags = 0;
           hints.ai_protocol = 0;          /* Dowolny protokół */

           s = getaddrinfo(argv[1], argv[2], &hints, &result);
           if (s != 0) {
               fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
               exit(EXIT_FAILURE);
           }

           /* getaddrinfo() zwraca listę struktur adresów. Próbuje
              każdego adresu, do pomyślnego połączenia (connect(2)).
              Jeśli socket(2) (lub connect(2)) zawiedzie, (zamykamy
              gniazdo i) próbujemy następny adres. */

           for (rp = result; rp != NULL; rp = rp->ai_next) {
               sfd = socket(rp->ai_family, rp->ai_socktype,
                            rp->ai_protocol);
               if (sfd == -1)
                   continue;

               if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1)
                   break;                  /* Powodzenie */

               close(sfd);
           }

           freeaddrinfo(result);           /* Nie jest już potrzebne */

           if (rp == NULL) {               /* Nie udało się z żadnym adresem */
               fprintf(stderr, "Nie udało się połączyć\n");
               exit(EXIT_FAILURE);
           }

           /* Wysyła pozostałe argumenty wiersza poleceń jako oddzielne
              datagramy i odczytuje odpowiedzi z serwera. */

           for (size_t j = 3; j < argc; j++) {
               len = strlen(argv[j]) + 1;
                       /* +1 dla końcowego bajtu null */

               if (len > BUF_SIZE) {
                   fprintf(stderr,
                       "Ignorowanie długiego komunikatu w argumencie %zu\n", j);
                   continue;
               }

               if (write(sfd, argv[j], len) != len) {
                   fprintf(stderr, "częściowy/nieudany zapis\n");
                   exit(EXIT_FAILURE);
               }

               nread = read(sfd, buf, BUF_SIZE);
               if (nread == -1) {
                   perror("read");
                   exit(EXIT_FAILURE);
               }

               printf("Otrzymano %zd bajtów: %s\n", nread, buf);
           }

           exit(EXIT_SUCCESS);
       }

ZOBACZ TAKŻE

       getaddrinfo_a(3),  gethostbyname(3),  getnameinfo(3),  inet(3),  gai.conf(5), hostname(7),
       ip(7)

TŁUMACZENIE

       Autorami polskiego tłumaczenia niniejszej strony podręcznika  są:  Andrzej  Krzysztofowicz
       <ankry@green.mf.pg.gda.pl> i Michał Kułach <michal.kulach@gmail.com>

       Niniejsze  tłumaczenie  jest  wolną  dokumentacją. Bliższe informacje o warunkach licencji
       można   uzyskać   zapoznając   się   z   GNU   General   Public   License   w   wersji   3
       ⟨https://www.gnu.org/licenses/gpl-3.0.html⟩   lub   nowszej.   Nie  przyjmuje  się  ŻADNEJ
       ODPOWIEDZIALNOŚCI.

       Błędy w tłumaczeniu  strony  podręcznika  prosimy  zgłaszać  na  adres  listy  dyskusyjnej
       ⟨manpages-pl-list@lists.sourceforge.net⟩.