Hvor bør jeg starte?
Lag 1 er ett greit sted å starte, uten fungerende lag 1 er det vanskelig å teste det andre.
Skal jeg bruke gethostbyname eller getaddrinfo?
gethostbyname-funksjonen er foreldet ("obsolete"), og det anbefales at nye programmer bruker getaddrinfo.
Blant annet kan du få morsomme feil hvis du angir en ukomplett ip-addresse til gethostbyname (f.eks "10.1").
Hvordan fungerer getaddrinfo
?
getaddrinfo vil slå opp en dns-navn eller en ip-addresse på ascii-form (f.eks "127.0.0.2") og gi deg en sockaddr du kan gi til funksjoner som sendto.
getaddrinfo tar imot følgende parametre:
- node - dns-navn eller ip
- service - "service" det skal kobles til, kan være f.eks. http, ssh, eller en port i tekstform "1337". Den kan også være NULL, da må du fylle ut porten i sockaddr-strukturen selv.
- hints - en addrinfo-struktur som bruker som "hint" til funksjonen, som "address family" (AF_INET) og prototoll (SOCK_DGRAM), disse er da ferdig fylt ut i sockaddr-strukturen du får tilbake.
- res - Lenket liste av resultater (allokeres av getaddrinfo!)
res er den vanskeligste av parametrene, getaddrinfo-funksjonen vil putte en peker til det første elementet i den lenkede listen i res, denne listen blir også allokert av getaddrinfo, dette fordi du ikke kan vite størrelsen på listen på forhånd. Du skal lage en peker til en addrinfo-struktur, denne skal ikke malloc-es, bare la den peke på NULL. Så skal du gi en peker til denne pekeren til getaddrinfo. Husk også å free-e resultatlisten med freeaddrinfo etter du er ferdig med den, hvis ikke vil du lekke minne.
Koden blir altså noe som:
struct addrinfo *result = NULL;
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
/* masse andre ting her */
getaddrinfo(host, NULL, &hints, &result); /* <- &result er nå en peker til en peker */
/* Sjekk returverdi og bruk result her */
freeaddrinfo(result);
Programmet mitt segfaulter, hva gjør jeg?
- Sørg for at du kompilerer med flagget
-g
tilgcc
, hvis du ikke gjør dette så vil ikke debuggingsinformasjon bli lagt ved. - Kjør programmet ditt med
gdb
. Hvis du vanligvis ville kjørt./main 1234 1
, så gjør dette:gdb ./main
, og når gdb har startet opp skriver durun 1234 1
- Når programmet ditt da segfaulter, skriv
bt full
, da vil du se alle funksjonskallene (og argumentene til disse) som ledet opp til kræsjet, hvis du kun får opp spørsmålstegn så har du ødelagt stakken, da har du mest sannsynlig skrevet for mye til en variabel av typenchar a[100];
. - Fiks feilen.
Skal jeg blocke i l1_connect?
Kommentarer i prekoden nevner to forskjellige måter å implementere l1_connect på. Den ene innebærer å blocke i l1_connect helt tilkoblingen er ferdig, da må du lage din egen select-løkke i l1_connect. Den andre er å bare sende connect-pakken, markere tilkoblingen som connecting og la handle_events gjøre noe smart med up-pakken når disse kommer. (Hint: sistnevnte er enklest).
Hvordan fungerer sizeof i C?
I C vil sizeof gi deg størrelsen på elementet du gir inn til sizeof, hvis du gir inn en peker vil du mest sannsynlig få ut 4 eller 8, og altså ikke lengden på et malloc-et buffer. Du kan bruke sizeof på stakkallokerte arrays av konstant størrelse (f.eks char a[100];), men du vil da få ut den maksimale størrelsen, og ikke hvor mye data du har puttet inn i den. Vær også obs på at sizeof vil returnere antall bytes, ikke antall elementer. Hvis du vil ha størrelsen i antall elementer av f.eks. et array int-er, int b[100];, må du da bruke sizeof(b)/sizeof(int).
Hvordan bør jeg skrive ut debuginformasjon?
Når du kompilerer koden med make debug
vil gcc bli kjørt med opsjonen -DDEBUG
, dette kan du bruke til å kun printe debugoutput hvis programmet blir kompilert med make debug
. Her er et eksempel på en makro DPRINT()
som fungerer som printf
, som også vil skrive ut filnavn og linjenummer, men ikke skrive ut noe hvis du kompilerer uten -DDEBUG
.
#ifdef DEBUG
#define DPRINT(args...) fprintf(stderr,"%10s:%-3d - ", __FILE__, __LINE__); fprintf(stderr, args);
#else
#define DPRINT(args...)
#endif
Hva er portene som gis til l4_send?
Det er de virtuelle portene som lag 4 bruker, slik at du i teorien skal kunne ha flere lag 5-programmer.
Du skal ikke bruke portene du angir på kommandolinjen når du starter programmet, da portene på lag 4 i vår implementasjon må være under 1024.
De virtuelle portene på lag 4 blir aldri sjekket, du kan derfor trygt angi 0 som begge portene til l4_send.
Difference in the return values of l2_send() in the pre-code vs. oblig1 document!
Some of you may have noticed that there is a difference in the return values explained in the oblig1 text vs. the precode given. For example, l2_send() is expected to return 0 or 1 values in the document text while in the precode, it is expected to return the number of bytes sent in case of no-error. While we don't claim the precode to be error-free and we do our best to solve any possible bug/error in it, we would like to highlight that the provided precode is "indicative only" and students are free to implement and change the code or write it from scratch as they wish.