getaddrinfo(3) Library Functions Manual getaddrinfo(3) NAZWA getaddrinfo, freeaddrinfo, gai_strerror - tlumaczy adresy i uslugi sieciowe BIBLIOTEKA Standardowa biblioteka C (libc, -lc) SKLADNIA #include #include #include 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 wczesniejsze: _POSIX_C_SOURCE OPIS Dla danego wezla node i uslugi service, ktore identyfikuja stacje i usluge internetowa, getaddrinfo() zwraca jedna lub wiecej struktur addrinfo, kazda z ktorych zawiera adres internetowy, ktory mozna podac w wywolaniu do bind(2) lub connect(2). Funkcja getaddrinfo() laczy funkcjonalnosc udostepniana przez funkcje gethostbyname(3) i getservbyname(3) w jeden interfejs, lecz w przeciwienstwie do nich, getaddrinfo() jest wielobiezna i umozliwia programom wyeliminowanie zaleznosci od IPv4 lub IPv6. Struktura addrinfo uzywana przez getaddrinfo() zawiera nastepujace 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 strukture addrinfo, ktora okresla kryteria wyboru struktur adresow gniazd zwracanych w liscie wskazywanej przez res. Jesli hints nie wynosi NULL, wskazuje na strukture addrinfo, ktorej pola ai_family, ai_socktype i ai_protocol okreslaja kryteria ograniczajace zbiory adresow gniazd zwracane przez getaddrinfo(), zgodnie z ponizszym opisem: ai_family Pole okresla zadana rodzine adresow wobec zwracanych adresow. Prawidlowe wartosci tego pola obejmuja AF_INET i AF_INET6. Wartosc AF_UNSPEC wskazuje, ze getaddrinfo() powinno zwrocic adresy gniazd dla dowolnej rodziny adresow (np. IPv4 lub IPv6), ktorych mozna uzyc z node i service. ai_socktype Pole okresla preferowany typ gniazda np. SOCK_STREAM lub SOCK_DGRAM. Podanie w tym polu wartosci 0 wskazuje, ze getaddrinfo() moze zwrocic adresy gniazd dowolnego typu. ai_protocol Pole okresla protokol zwracanych adresow gniazd. Podanie w tym polu wartosci 0 wskazuje, ze getaddrinfo() moze zwrocic adresy gniazd dowolnego protokolu. ai_flags Pole okresla dodatkowe opcje, opisane ponizej. Mozna podac wiele flag, sumujac je bitowo (OR). Wszystkie pozostale pola w strukturze na ktora wskazuje hints, musza zawierac albo 0, albo pusty wskaznik (w zaleznosci od pola). Podanie hints jako NULL jest rownowazne ustawieniu ai_socktype i ai_protocol na 0; ai_family na AF_UNSPEC; a ai_flags na (AI_V4MAPPED | AI_ADDRCONFIG) (POSIX okresla inna wartosc domyslna dla ai_flags; zob. UWAGI). node zawiera albo adres sieciowy w postaci numerycznej (dla IPv4: w formacie liczb i kropek takim, jak obslugiwany przez inet_aton(3); dla IPv6: w formacie szesnastkowego lancucha takim, jak obslugiwany przez init_pton(3)), albo nazwe stacji, dla ktorej adresy sieciowe beda poszukiwane i rozwiazane. Jesli hints.ai_flags zawiera znacznik AI_NUMERICHOST, to node musi byc adresem sieciowym w postaci numerycznej. Znacznik AI_NUMERICHOST eliminuje jakiekolwiek, potencjalnie dlugotrwale, poszukiwania adresu sieciowego stacji. Jesli w hints.ai_flags podano znacznik AI_PASSIVE, a node wynosi NULL, to zwracane adresy gniazd beda odpowiednie do przypisywania (bind(2)) gniazd, ktore beda akceptowaly (accept(2)) polaczenia. Zwracany adres gniazda bedzie zawieral ,,adres wieloznaczny" (,,wildcard address"; INADDR_ANY w przypadku adresow IPv4, IN6ADDR_ANY_INIT w przypadku adresow IPv6). Adres wieloznaczny jest uzywany przez aplikacje (zwykle serwery), ktore maja zamiar akceptowac polaczenia na dowolnym z adresow sieciowych stacji. Jesli node nie wynosi NULL, to znacznik AI_PASSIVE jest ignorowany. Jesli w hints.ai_flags nie podano znacznika AI_PASSIVE, to zwracane adresy gniazd beda odpowiednie do korzystania z connect(2), sendto(2) lub sendmsg(2). Jesli node wynosi NULL, to adres sieciowy bedzie ustawiony na adres interfejsu petli zwrotnej (INADDR_LOOPBACK w przypadku adresow IPv4, IN6ADDR_LOOPBACK_INIT w przypadku adresow IPv6); jest to uzywane przez aplikacje, ktore maja zamiar komunikowac sie z innymi aplikacjami dzialajacymi na tej samej stacji. service ustawia port w kazdej zwracanej strukturze adresu. Jesli argument ten jest nazwa uslugi (zob. services(5)), to jest tlumaczona na odpowiedni numer portu. Argument ten moze byc tez liczba dziesietna, wowczas jest jedynie przeksztalcana na liczbe binarna. Jesli service wynosi NULL, to numer portu zwracanych adresow gniazd bedzie pozostawiony niezainicjowany. Jesli w hints.ai_flags podano AI_NUMERICSERV, a service nie wynosi NULL, to service musi wskazywac na lancuch zawierajacy numeryczny numer portu. Znacznik ten jest uzywany do powstrzymania rozwiazywania nazw w przypadkach, w ktorych wiadomo, ze nie bedzie to konieczne. Parametry node i service moga byc rowne NULL, ale nie oba naraz. Funkcja getaddrinfo() alokuje i inicjuje podlinkowana liste struktur addrinfo, po jednej dla kazdego adresu sieciowego, ktory pasuje do node i service, jest przedmiotem wszelkich ograniczen nalozonych przez hints, a zwraca wskaznik do poczatku listy w res. Pozycje na podlinkownej liscie sa linkowane za pomoca pola ai_next. Istnieje wiele powodow, dla ktorych podlinkowana lista moze miec wiecej niz jedna strukture addrinfo m.in.: stacja sieciowa moze byc wieloadresowa, dostepna za pomoca roznych protokolow (np. AF_INET oraz AF_INET6); albo ta sama usluga jest dostepna za pomoca roznych typow gniazd (np. jeden adres SOCK_STREAM i inny adres SOCK_DGRAM). Aplikacja zwykle sprobuje uzyc adresy w zwracanej kolejnosci. Funkcja sortowania uzywana w getaddrinfo() jest zdefiniowana w RFC 3484; kolejnosc mozna dostosowac dla danego systemu, edytujac plik /etc/gai.conf (dostepny od glibc 2.5). Jesli hints.ai_flags zawiera znacznik AI_CANONNAME, to pole ai_canonname w pierwszej ze struktur addrinfo w zwracanej liscie, jest ustawiane na oficjalna nazwe stacji. Pozostale pola w kazdej ze zwracanych struktur addrinfo sa inicjowane w nastepujacy sposob: o Pola ai_family, ai_socktype i ai_protocol zwracaja parametry tworzenia gniazd (tzn. pola te maja takie samo znaczenie, jak odpowiadajace im argumenty socket(2)). Przykladowo ai_family moze zwrocic AF_INET lub AF_INET6; ai_socktype moze zwrocic SOCK_DGRAM lub SOCK_STREAM; a ai_protocol zwroci protokol gniazda. o Wskaznik do adresu gniazda jest umieszczany w polu ai_addr, a dlugosc adresu gniazda w bajtach, jest umieszczana w polu ai_addrlen. Jesli hints.ai_flags zawiera znacznik AI_ADDRCONFIG, to adresy IPv4 sa zwracane w liscie, na ktora wskazuje res tylko, gdy lokalny system ma skonfigurowany przynajmniej jeden adres IPv4, a adresy IPv6 sa zwracane tylko, gdy lokalny system ma skonfigurowany przynajmniej jeden adres IPv6. Adres petli zwrotnej nie jest w tym przypadku uwazany za prawidlowy skonfigurowany adres. Znacznik ten jest przydatny np. w systemach korzystajacych wylacznie z IPv4 aby zapewnic, ze getaddrinfo() nie zwroci adresow gniazd IPv6, ktore zawsze zawiodlyby w connect(2) lub bind(2). Jesli hints.ai_flags okresla znacznik AI_V4MAPPED, a hints.ai_family podano jako AF_INET6 oraz nie da sie znalezc pasujacego adresu IPv6, to w liscie, na ktora wskazuje res, zwracane sa adresy IPv4 zmapowane jako IPv6. Jesli w hints.ai_flags podano AI_V4MAPPED oraz AI_ALL, to zwracane sa adresy IPv6 oraz adresy IPv4 zmapowane jako IPv6. AI_ALL jest ignorowane, jesli nie podano rowniez AI_V4MAPPED. Funkcja freeaddrinfo() zwalnia pamiec przydzielona dla dynamicznie zaalokowanej listy res. Rozszerzenia getaddrinfo() dla domen ze znakami spoza ASCII (IDN) Od glibc 2.3.4, getaddrinfo() rozszerzono w celu umozliwiania wybiorczego i przezroczystego konwertowania przychodzacych i wychodzacych 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 Jesli znacznik jest podany, nazwa wezla podana w node jest konwertowana na format IDN, jesli to konieczne. Kodowanie zrodlowe jest takie, jak w biezacych ustawieniach regionalnych (locale). Jesli nazwa wejsciowa zawiera znaki spoza ASCII, to uzywane jest kodowanie IDN. Te fragmenty nazwy wezla (oddzielone kropka), ktore zawieraja znaki spoza ASCII sa kodowane za pomoca ASCII Compatible Encoding, przed ich przekazaniem do funkcji rozwiazywania nazw. AI_CANONIDN Po pomyslnym wyszukaniu nazwy, jesli podano AI_CANONNAME, getaddrinfo() zwroci kanoniczna nazwe wezla odnoszaca sie do wartosci struktury addrinfo przekazywanej zwrotnie. Zwracana wartosc jest dokladna kopia wartosci zwracanej przez funkcje rozwiazywania nazw. Jesli nazwa jest zakodowana za pomoca ACE, to bedzie zawierac przedrostek xn-- w jednej lub wiecej skladowych nazw. Aby przeksztalcic te skladowe w czytelna postac, oprocz znacznika AI_CANONNAME mozna podac tez AI_CANONIDN. Wynikowy lancuch bedzie kodowany przy uzyciu kodowania z biezacych ustawieniach regionalnych (locale). AI_IDN_ALLOW_UNASSIGNED AI_IDN_USE_STD3_ASCII_RULES Ustawienie tych znacznikow wlaczy znaczniki, odpowiednio, IDNA_ALLOW_UNASSIGNED (zezwala na nieprzypisane kody Unikodu) i IDNA_USE_STD3_ASCII_RULES (sprawdza wyjscie, aby upewnic sie ze jest to nazwa stacji zgodna z STD3) do uzycia w obsludze IDNA. WARTOSC ZWRACANA getaddrinfo() zwraca 0, gdy zakonczy sie pomyslnie, a w przeciwnym razie jeden z nastepujacych niezerowych kodow bledow: EAI_ADDRFAMILY Podana stacja nie posiada zadnego adresu sieciowego dla zadanej rodziny adresow. EAI_AGAIN Serwer nazw zwrocil blad tymczasowy. Nalezy sprobowac pozniej. EAI_BADFLAGS hints.ai_flags zawiera nieprawidlowe znaczniki; lub hints.ai_flags zawieralo AI_CANONNAME i node wynosilo NULL. EAI_FAIL Serwer nazw zwrocil blad trwaly. EAI_FAMILY Zadana rodzina adresow nie jest obslugiwana. EAI_MEMORY Brak pamieci. EAI_NODATA Podana stacja sieciowa istnieje, ale nie zdefiniowano dla niej zadnego adresu sieciowego. EAI_NONAME node lub service nie jest znane; albo zarowno node jak i service wynosza NULL; albo w hints.ai_flags podano AI_NUMERICSERV, a service nie bylo numerycznym lancuchem numeru portu. EAI_SERVICE Zadana usluga nie jest dostepna dla zadanego typu portu. Moze byc dostepna za pomoca innego typu portu. Ten blad moze wystapic na przyklad, gdy jako service podano ,,shell" (usluga dostepna tylko na gniazdach strumieniowych), a hints.ai_protocol wynosilo IPPROTO_UDP albo hints.ai_socktype wynosilo SOCK_DGRAM; albo blad moze wystapic gdy service nie wynosilo NULL, a hints.ai_socktype wynosilo SOCK_RAW (typ gniazda, w ogole nie obslugujacy koncepcji uslug). EAI_SOCKTYPE Zadany typ gniazda nie jest obslugiwany. Moze sie to zdarzyc na przyklad, gdy hints.ai_socktype i hints.ai_protocol sa niespojne (np. wynosza, odpowiednio, SOCK_DGRAM i IPPROTO_TCP). EAI_SYSTEM Inny blad systemowy; ustawiane jest errno aby wskazac blad. Funkcja gai_strerror() tlumaczy te kody bledow na czytelny dla czlowieka lancuch, odpowiedni do zglaszania bledow. PLIKI /etc/gai.conf ATRYBUTY Informacje o pojeciach uzywanych w tym rozdziale mozna znalezc w podreczniku attributes(7). +----------------+--------------------------+--------------------------+ |Interfejs | Atrybut | Wartosc | +----------------+--------------------------+--------------------------+ |getaddrinfo() | Bezpieczenstwo watkowe | MT-bezpieczne env locale | +----------------+--------------------------+--------------------------+ |freeaddrinfo(), | Bezpieczenstwo watkowe | MT-bezpieczne | |gai_strerror() | | | +----------------+--------------------------+--------------------------+ WERSJE Zgodnie z POSIX.1, okreslenie hints jako NULL, powinno powodowac przyjecie ai_flags jako 0. Biblioteka GNU C zamiast tego przyjmuje w tym przypadku wartosc (AI_V4MAPPED | AI_ADDRCONFIG), poniewaz wartosc ta jest uwazana za lepsza od przewidzianej norma. 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() obsluguje notacje adres%identyfikator-zasiegu do okreslenia identyfikatora zasiegu IPv6. PRZYKLADY Ponizsze programy demonstruja uzycie getaddrinfo(), gai_strerror(), freeaddrinfo() i getnameinfo(3). Programy sa serwerem i klientem typu echo dla datagramow UDP. Program serwera #include #include #include #include #include #include #include #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, "Usage: %s port\n", argv[0]); exit(EXIT_FAILURE); } memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */ hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */ hints.ai_protocol = 0; /* Any protocol */ 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() returns a list of address structures. Try each address until we successfully bind(2). If socket(2) (or bind(2)) fails, we (close the socket and) try the next address. */ 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; /* Success */ close(sfd); } freeaddrinfo(result); /* No longer needed */ if (rp == NULL) { /* No address succeeded */ fprintf(stderr, "Could not bind\n"); exit(EXIT_FAILURE); } /* Read datagrams and echo them back to sender. */ 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; /* Ignore failed request */ s = getnameinfo((struct sockaddr *) &peer_addr, peer_addrlen, host, NI_MAXHOST, service, NI_MAXSERV, NI_NUMERICSERV); if (s == 0) printf("Received %zd bytes from %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, "Error sending response\n"); } } } Program klienta #include #include #include #include #include #include #include #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, "Usage: %s host port msg...\n", argv[0]); exit(EXIT_FAILURE); } /* Obtain address(es) matching host/port. */ memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */ hints.ai_flags = 0; hints.ai_protocol = 0; /* Any protocol */ s = getaddrinfo(argv[1], argv[2], &hints, &result); if (s != 0) { fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s)); exit(EXIT_FAILURE); } /* getaddrinfo() returns a list of address structures. Try each address until we successfully connect(2). If socket(2) (or connect(2)) fails, we (close the socket and) try the next address. */ 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; /* Success */ close(sfd); } freeaddrinfo(result); /* No longer needed */ if (rp == NULL) { /* No address succeeded */ fprintf(stderr, "Could not connect\n"); exit(EXIT_FAILURE); } /* Send remaining command-line arguments as separate datagrams, and read responses from server. */ for (size_t j = 3; j < argc; j++) { len = strlen(argv[j]) + 1; /* +1 for terminating null byte */ if (len > BUF_SIZE) { fprintf(stderr, "Ignoring long message in argument %zu\n", j); continue; } if (write(sfd, argv[j], len) != len) { fprintf(stderr, "partial/failed write\n"); exit(EXIT_FAILURE); } nread = read(sfd, buf, BUF_SIZE); if (nread == -1) { perror("read"); exit(EXIT_FAILURE); } printf("Received %zd bytes: %s\n", nread, buf); } exit(EXIT_SUCCESS); } ZOBACZ TAKZE getaddrinfo_a(3), gethostbyname(3), getnameinfo(3), inet(3), gai.conf(5), hostname(7), ip(7) TLUMACZENIE Autorami polskiego tlumaczenia niniejszej strony podrecznika sa: Andrzej Krzysztofowicz 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.9.1 15 czerwca 2024 r. getaddrinfo(3)