oracular (3) getaddrinfo.3.gz

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⟩.