Računarske mreže Čas 7 Ivana Tanasijević e-mail: ivana@matf.bg.ac.rs Matematički fakultet, Beograd 1
Konvertovanje imena adresa i servisa
Kako se pronalazi ime ili vrednost IP adrese ili servisa Konverzija između numeričkih IP adresa, koje smo do sada koristili, i imena se radi funkcijama gethostbyaddr i gethostbyname. Konverzija između i broja porta i imena servisa se radi pomoću funkcija getservbyport i getservbyname. Kada pozovemo funkcije za konverziju IP adresa, pretražuje se fajl /etc/hosts. Zatim, pomoću UDP se šalje pitanje lokalnim serverima (DNS) navedenim u fajlu /etc/resolv.conf. Ako ni oni nemaju informacije o traženom imenu, pitanje se šalje dalje preko interneta, takođe pomoću UDP. Imena portova se mogu dobiti samo sa lokalnog hosta i to iz fajla /etc/services.
Funkcija gethostbyname Na osnovu jedinog argumenta, imena hosta, vraća strukturu hostent popunjenu informacijama o hostu. Struktura hostent ima sledeće članove: - char *h_name, char **h_aliases, int h_addrtype, int h_length, char **h_addr_list. Ne postavlja errno vrednost, već globalnu promenljivu h_errno. Stoga, za dobijanje opisa greške treba da se koristi funkcija hstrerror umesto strerror. Ostale tri funkcije su slične, pogledati man stranice. Primer: hostserviceinfo
Primer: Pronalaženje imena i broja servisa /* Pokusava se sa dobijanjem broja porta ako je dat naziv servisa. */ if ((serv = getservbyname (argv[1], type))!= NULL) printf ("getservbyname(%s, %s) = %d\n", argv[1], type, ntohs (serv->s_port)); /* Pokusava se sa dobijanjem imena servisa ako je dat broj fajla. * Za tu svrhu se pretrazuje fajl /etc/services. */ else if ((serv = getservbyport (htons (atoi (argv[1])), type))!= NULL) printf ("getservbyport(%s, %s) = %s\n", argv[1], type, serv->s_name); else printf ("File /etc/services does not have information about port/service %s\n", argv[1]);
Nezavisnost od protokola
Skrivanje zavisnosti od protokola Popunjavanje adresne strukture koje je praktikovano do sada zavisi od protokola. Bilo je potrebno da znamo u koji član adresne strukture treba da upisemo rezultat (na primer, sin_addr za IPv4 ili sin6_addr za IPv6). Funkcija getaddrinfo skriva sve zavisnosti od protokola. U aplikaciji se na dalje radi samo sa adresnom strukturom addrinfo koju popunjava ova funkcija, ne vodeći računa o protokolu. Funkcija ima 4 argumenta: ime hosta, servis, strukturu sa specifičnim osobinama koje adresa ipak treba da ima, pokazivač na listu struktura koje je popunila na osnovu prva tri argumenta.
Funkcija getaddrinfo Neki od članova adresne strukture addrinfo su: int ai_flags, int ai_family, int ai_socktype, size_t ai_addrlen, struct sockaddr *ai_addr, struct addrinfo *ai_next. Vrednosti koje korisnik može da postavi preko strukture hints su na primer: ai_flags (AI_PASSIVE, AI_CANONNAME), ai_family (AF_xyz), ai_socktype (SOCK_xyz), ai_protocol. Ako se funkcija uspešno vrati (povratna vrednost je 0), poslednji argument je pokazivač na povezanu listu struktura koje odgovaraju datom zahtevu.
Funkcija getaddrinfo Strukture u ovim listama su već u obliku koje je potreban za pozive funkcija socket, connect, sendto, bind. Argumenti za socket funkciju su ai_family, ai_socktype, ai_protocol. Drugi i treći argument funkcija connect i bind su ai_addr i ai_addrlen. Ova funkcija vrši svu potrebnu dinamičku alokaciju memorije, tako da je potrebno da tu memoriju oslobodimo kada nam više ne treba, funkcijom freeaddrinfo. Ako nam neki podaci trebaju i kasnije, onda je potrebno iskopirati ih, pa tek dealocirati memoriju. Za dobijanje opisa greške koje funkcija može da vrati se koristi funkcija gai_strerror. Primer: daytime6
Primer: Funkcija getaddrinfo struct addrinfo hints; /* Struktura podataka koja opisuje zeljenu adresu. */ struct addrinfo *address; /* Lista adresa koje odgovaraju datom host-u i servisu. */ struct addrinfo *curr; /* Tekuci element gornjeg polja. */ /* Priprema se struktura podataka sa opisom zeljene adrese. */ bzero (&hints, sizeof (struct addrinfo)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; /* Odredjuje se lista adresa koje odgovaraju datom host-u i servisu. */ Getaddrinfo (host, service, &hints, &address)); /* U petlji se prolazi kroz listu adresa i pokusava vezivanje za svaku od njih. */ for (curr = address; curr!= NULL; curr = curr->ai_next) { /* Kreira se socket,... */ if ((server = socket (curr->ai_family, curr->ai_socktype, curr->ai_protocol)) <0) continue; /*...a zatim se pokusava sa povezivanjem. if (connect (server, curr->ai_addr, curr->ai_addrlen) == 0) break;... }
Informacije o soketu
Informacije o soketu Kada je poznat samo fajl deskriptor soketa, za dobijanje informacija o soketu se mogu koristiti funkcije getsockname i getpeername. Obe popunjavaju strukturu sockaddr, prva lokalnom adresom koja je pridružena soketu, dok druga popunjava strukturu adresom sa kojom je konektovan soket. Situacije u kojima se koristi getsockname: - Kada se connect vrati u TCP klijentu, vraća pridruženu IP adresu i lokalni port; posle poziva bind sa brojem porta 0; ako server pozove bind sa wildcard na mestu IP adrese. Kada server pozove exec posle accept, child proces više nema informacije iz adresne strukture koju je popunila accept, pa poziva getpeername. Primer: daytime7
Primer: Informacije o soketu struct sockaddr address; /* Adresa sa informacijma o peer-u. */ socklen_t length; /* Velicina prethodne strukture. */ struct sockaddr_in *addrin; /* Pomocni pokazivac. */ char name[16]; /* Ime adrese. */ /* Getpeername ocekuje da se trecim argumentom prosledi koliko je mesta rezervisano * promenljivom address. U promenljivoj length se nakon povratka nalazi velicina adrese. */ length = sizeof (struct sockaddr); if (getpeername (server, &address, &length) < 0) error_fatal ("%s getpeername() error: %s\n", program, strerror (errno)); /* Ukoliko je u pitanju struktura za IP adrese... */ if (length == sizeof (struct sockaddr_in)) { /*...racuna se prezentacija na osnovu numericke vrednosti... */ addrin = (struct sockaddr_in *) &address; if (inet_ntop (AF_INET, &(addrin->sin_addr), name, 16) == 0) error_fatal ("%s inet_ntop() error: %s\n", program, strerror (errno)); /*...i ispisuju IP adresa i port. */ printf ("Peer info %s:%d\n", name, ntohs (addrin->sin_port)); }
Informacije o soketu Informacije o hostu i servisu se na osnovu strukture sockaddr mogu dobiti i funkcijom getnameinfo. if ((error = getnameinfo (&address, length, hostname, NI_MAXHOST, port, NI_MAXSERV, NI_NUMERICHOST NI_NUMERICSERV))!= 0) printf ("%s getnameinfo() error: %s\n", argv[0], gai_strerror (error)); else printf ("Connection from %s:%s\n", hostname, port);