Navigationskarta Insitutitionen för Datavetenskap Umeå Universitet

Laboration 6: mlogtrace/mcrypt

Del A: mlogtrace

Introduktion

Den första delen av denna lab går ut på att skriva ett verktyg för att hålla koll på en loggfil för en www-server. Programmet kan t.ex. användas för att hålla koll på när någon viss www-sida besöks. När du löser uppgiften kommer du att få öva på I/O multiplexing m.h.a. poll(). Observera att denna uppgift inte ska lösas på någon Solaris-maskin, utan istället lösas på maskinen nelson, som är en AIX-maskin. Detta p.g.a. att nelson är www-server för CS, och du ska kontinuerligt titta på loggfilen för www-servern.

Din uppgift

Du ska skriva ett program som fungerar ungefär som kommandot tail -0f /var/log/apache/www.cs.umu.se/access_log, fast med lite utökad funktionalitet. Du ska använda poll() för att "känna efter" om det finns någon ny data att hämta, och om poll() indikerar att ny data finns ska den datan läsas in och visas på skärmen, precis som tail -0f ....

Ditt program ska dessutom kunna läsa in kommandon från tangentbordet (stdin). De kommandon som finns är:

Inläsning av datat

Du har två möjligheter vid inläsning av datan: Den första är att använda funktionen popen() för att köra kommandot tail -0f /var/log/apache/www.cs.umu.se/access_log, och sedan använda fileno() för att få en fildeskriptor att ge till poll(). Andra möjligheten är att skriva din egen popen()-funktion (tips finns i kurslitteraturen) som kör tail -0f /var/log/apache/www.cs.umu.se/access_log, och som returnerar en fildeskriptor som poll() kan använda.

Val av mönster

När användaren trycker 's' så betyder det att de nästa tecknen som matas in är en sträng som måste finnas i en loggrad om den loggraden ska skrivas ut. Med andra ord så filtreras alla rader bort som inte innehåller detta mönster. Inmatningen av mönstret avslutas med ett tryck på enter-tangenten. Om ett tomt mönster matas in betyder det att mönstret nollställs, och alla nya rader som dyker upp i loggfilen ska skrivas ut.

Det är svårt att lösa inmatningen av mönstret på ett bra sätt. Användaren ska ju kunna se mönstret medan det skrivs in, men om det kommer nya loggrader som ska skrivas ut under tiden kommer de förstås att 'hacka upp' utskriften av mönstret. Ett snyggt sätt att lösa detta är att använda fönsterteknik, men det är tyvärr ganska invecklat. Det är därför tillåtet att istället lösa problemet genom att skriva ut mönstret igen om det kommer en ny loggrad. Ett exempel på hur detta bör se ut är följande:

...
Loggrad 77
Loggrad 78 användaren trycker 's' efter att denna rad skrivits ut.
[] Loggrad 78 rad 78 skrivs ut på nytt, med [] för att indikera att ett mönster ska matas in.
[a] Loggrad 78 rad 78 skrivs så ut en gång till om användaren skriver in 'a' innan nästa loggrad upptäcks.
[a] Loggrad 79 rad 79 skrivs ut med [a] i början.
...
[ath] Loggrad 99 mönstret 'ath' har skrivits in.
Loggrad 99 användaren har tryckt på enter, loggraden skrivs ut igen bara om den innehåller 'ath'!
Loggrad 5051 loggrad 5051 skrivs ut eftersom den innehåller 'ath'
Loggrad 8088 loggrad 8088 skrivs ut eftersom den innehåller 'ath'

Hädanefter skrivs bara rader som innehåller mönstret 'ath' ut, ända tills ett tomt mönster matas in.

Tips

Del B: mcrypt

Introduktion

I denna del av laborationen får du öva på att använda delat minne och hantera processynkronisering. Delat minne är en effektiv form av interprocesskommunikation (IPC). Det kan bland annat användas för klient/server-applikationer, förutsatt att klienten och servern körs på samma maskin. Det delade minnesblocket utnyttjas då för att överföra data mellan klienten och servern. Servern tillhandahåller ett delat minnesblock, som klienten kan skriva sina data i. När klienten är klar behandlar servern dessa data, och klienten kan sedan avläsa resultatet.

Naturligtvis måste klienten och servern synkroniseras med varandra. När klienten har skrivit sina data måste den ju vänta tills servern är färdig innan den kan avläsa resultatet. På samma sätt måste servern ibland vänta på klienten.

Din uppgift

Du ska konstruera en kryptoserver, mcryptd, som fungerar under Solaris. Servern ska skapa ett 8 kB stort delat minnesblock som en klientprocess kan skriva till. När klienten har skrivit sina data krypteras de av servern. Klienten kan då läsa av dem, och sedan börjar processen om på nytt.

Dessutom ska du skriva en klient, mcrypt, som kan arbeta tillsammans med din server. Klienten ska läsa data från stdin, kryptera dem med hjälp av servern och skriva resultatet till stdout.

Synkroniseringstips

Det finns många sätt att lösa synkroniseringen. Vårt enda krav är att din lösning bygger på SysV-semaforer (sådana man får från semget()) och att den fungerar. Att den fungerar innebär bland annat att dödlägen inte kan uppstå och att det bara är en process i taget, antingen servern eller klienten, som arbetar med det delade minnesblocket.

En metod är att använda två binära semaforer: ccw ("client can write") och scw ("server can write"). När klienten vill skriva gör den semaforoperationen wait(ccw), och när den har skrivit klart meddelar den servern att den kan skriva genom att köra signal(scw). Båda semaforerna initieras till 0.

Klient Server
Skriv källdata till minnesblocket
signal(scw)
wait(ccw)
Läs resultatet från minnesblocket
Börja om (tills indata är slut)
wait(scw)
Läs källdata från minnesblocket
Skriv resultatet till minnesblocket
signal(ccw)
Börja om (i evighet, eller i praktiken tills processen avbryts av en signal)

Lägg märke till att det hela tiden är servern som talar om när klienten får skriva och tvärtom. En process kan inte ge sig själv tillstånd att skriva. När körningen börjar har klienten underförstått tillstånd att skriva, dvs den behöver inte köra wait() på en semafor först utan kan börja skriva direkt. (En mer stilren lösning är att initiera semaforen ccw till 1 och låta klienten köra wait(ccw) det första den gör. Det blir i praktiken samma sak.)

Observera att servern måste startas först, annars finns det inget minnesblock för klienten att skriva till.

Kryptering

För enkelhets skull lagras lösenordet i servern (på så vis slipper man överföra lösenord från klienten till servern). Lösenordet anges som första och enda argument på serverns kommandorad. Dessutom ska du använda en krypteringsalgoritm som fungerar åt båda hållen, så att samma funktion och lösenord kan användas både för att kryptera och dekryptera:

kryptera("test", "hemligt") => "%(!!"
kryptera("%(!!", "hemligt") => "test"

Om du inte vill göra en egen implementation av någon lämplig krypteringsalgoritm kan du använda vår XOR-kryptering. Ett dilemma är att klienten kanske inte har fyllt hela minnesblocket, men det kan du strunta i: servern krypterar alltid ett helt minnesblock på 8 kB, och det är upp till klienten att läsa tillbaka lika mycket som den har skrivit. (Detta förutsätter förstås att krypteringsalgoritmen inte ändrar längden på den krypterade texten).

Exempel

peppar% mcryptd secret_password &
Server started.
peppar% cat hemligt.txt
Ett meddelande i klartext.
peppar% mcrypt < hemligt.txt > hemligt.cry
peppar% cat hemligt.cry
peppar% (Obegripliga binärdata)
peppar% mcrypt < hemligt.cry
Ett meddelande i klartext.
peppar%

Tips

Överkurs

Försättsblad

Ett försättsblad ska skrivas under och häftas ihop med labrapporten.

Filer att lämna in

Alla filer ska finnas i katalogen ~/edu/sysprog/lab6a/ respektive ~/edu/sysprog/lab6b/ och vara läsbara för labrättarna. Din lösning ska gå att kompilera, köra och rätta utan att vi ska behöva kopiera några andra filer. Vi vill också ha två make-filer (en för del A, en för del B).

Sista inlämningsdag: Kl. 23:59 den 23:e oktober 1999.

Inlämnat detta sista datum ska vara mcrypt och mcryptd (exekverbara på Solaris-maskiner), mlogtrace (exekverbart på AIX-maskiner), en välskriven laborationsrapport (i pappersformat) samt välkommenterad kod (tillsammans med labbrapporten).

[an error occurred while processing this directive]