/*================================================================ LAB I DATAKOMMUNIKATION FTP_APPLICATION Stefan Sonesson Christian Ohlsson Karlstad 981215 -----------------------------------------------------------------*/ #include "header_ftp.h" #include "signal_prim.h" #include "state.h" #include "student.h" /*================================================================ meny() Skriver ut menyn på skärmen pre : none post : Menyn är utskriven calls: none -----------------------------------------------------------------*/ void meny() { printf ("Meny\n"); printf ("====\n"); printf("1. Send a file\n"); printf("2. Quit\n"); } /*================================================================ sendIt() Skickar en data request, filstorleken (som long), filnamn samt själva datan till ftp-layer så länge som det finns tecken i bufferten. pre : Filen finns post : Filen är skickad calls: WriteDatatoSocket, WriteSignaltoSocket -----------------------------------------------------------------*/ void sendIt(long fileSize, char *fileName, int fd) { char buffer[BUFSIZE]; int len; printf("FileSize: %d\n", fileSize); len = strlen(fileName)+1; WriteSignaltoSocket(FSOCK_FD, AF_Data_Req, SIGLEN); WriteDatatoSocket(FSOCK_FD, (char *)&len, sizeof(long)); WriteDatatoSocket(FSOCK_FD, fileName, len); while(fileSize > 0){ if((len = read(fd, buffer, BUFSIZE)) == -1){ fprintf(stderr, "Can't read from file\n"); return; } WriteSignaltoSocket(FSOCK_FD, AF_Data_Req, SIGLEN); WriteDatatoSocket(FSOCK_FD, (char *)&len, sizeof(long)); WriteDatatoSocket(FSOCK_FD, buffer, len); fileSize -= len; } close(fd); } /*================================================================ sendFile() Ber användaren mata in ett filnamn som skall skickas och ser om filen är öppningsbar. Om filen är öppningsbar anropas sendIt. pre : none post : Filen är öppnad och filstorleken känd calls: sendIt -----------------------------------------------------------------*/ void sendFile() { int toSend; long fileSize; char fileName[FNSIZE]; struct stat st; printf("Skriv in filnamn: \n"); gets(fileName); /*Mata in filnamn*/ if((toSend = open(fileName, 0)) == -1){ /*Går filen att öppna?*/ printf("Unable to open file %s\n", fileName); return; } fstat(toSend, &st); /*Hämta filstorleken*/ fileSize = st.st_size; sendIt(fileSize, fileName, toSend); } /*================================================================ menu() Ber användaren mata in vilken operation som skall utföras och returnerar valet (om val = 0 avslutas programmet). pre : none post : Menyvalet är gjort calls: Beror på menyvalet -----------------------------------------------------------------*/ int menu() { char val; do{ meny(); val=getchar(); /*Mata in menyval*/ switch(val){ case '1' : sendFile();break; case '2' : printf ("Programmet avslutat...\n");break; default : printf ("Felaktigt val...\n");break; } fflush(STDIN); /*Ta bort alla tecken utom det första*/ }while(val != '1' && val != '2'); return (val - 2); } /*================================================================ readData() Öppnar en socket och hämtar filstorlek, och sedan själva datan, som den skriver till den nya filen. pre : none post : Filen är överförd calls: Polla, ReadDatafromSocket -----------------------------------------------------------------*/ int readData(int fd) { int poll, len; char buffer[BUFSIZE]; Polla(FSOCK_FD, FSOCK_FD); /*Hämta filstorlek*/ ReadDatafromSocket(FSOCK_FD, (char *)&len,sizeof(long)); Polla(FSOCK_FD, FSOCK_FD); /*Hämta data*/ ReadDatafromSocket(FSOCK_FD,buffer,len); return write(fd,buffer,len) == -1; } /*================================================================ Polla() Genomför en PollSocket och om det gick bra returneras socket'ens nummer (+1) pre : post : En socket är öppnad calls: Pollsocket -----------------------------------------------------------------*/ int Polla(int fd1,int fd2) { int poll; poll = PollSocket(fd1, fd2, NULL); /*Öppna en socket*/ if(poll == -1){ /*Gick det bra?*/ fprintf(stderr, "PollSocket failed\n"); exit(4); } return poll; /*Returnera socket'ens nummer*/ } /*================================================================ State_IDLE() Om vi i detta tillstånd får en Connect Indication läser vi filstorlek samt själva datan från socket'en pre : none post : TRUE om vi fick en Connect Indication calls: Polla, ReadDatafromSocket, WriteSignaltoSocket -----------------------------------------------------------------*/ int State_IDLE(int sig, long len, char buffer[BUFSIZE], int fd) { if(sig == AF_Con_Ind) { Polla(FSOCK_FD, FSOCK_FD); ReadDatafromSocket(FSOCK_FD, (char *)&len, sizeof(long)); Polla(FSOCK_FD, FSOCK_FD); ReadDatafromSocket(FSOCK_FD, buffer, len); if((fd = open(buffer, O_WRONLY)) == -1) { printf("Unable to open file.\n"); WriteSignaltoSocket(FSOCK_FD, AF_Rej_Req, SIGLEN); return TRUE; } else WriteSignaltoSocket(FSOCK_FD, AF_Con_Resp, SIGLEN); } return FALSE; } /*================================================================ State_UUUK() Känner av om vi får en Connect Confirm, då ropar vi på sendFile, annars felhantering pre : none post : state returnerat calls: sendFile, WriteSignaltoSocket -----------------------------------------------------------------*/ int State_UUUK(int sig) { int state; if(sig == AF_Con_Conf){ state = DATA; sendFile(); } else if(sig == AF_Rej_Ind){ printf("The other side don't wanna play with you..."); WriteSignaltoSocket(FSOCK_FD, AF_Rej_Resp, SIGLEN); state = IDLE; } else{ WriteSignaltoSocket(FSOCK_FD, AF_Abort_Req, SIGLEN); state = IDLE; } return state; } /*================================================================ State_DATA() Känner av om vi får en data indication och då läser vi data från socket'en, annars felhantering pre : none post : state returnerat calls: readData, WriteSignaltoSocket -----------------------------------------------------------------*/ int State_DATA(int sig, int fd) { int state; if(sig == AF_Data_Ind){ if(readData(fd)) { WriteSignaltoSocket(FSOCK_FD,AF_Abort_Req,SIGLEN); printf("Can't write to file\n"); close(fd); state = IDLE; } } else if(sig == AF_Disc_Ind){ close(fd); WriteSignaltoSocket(FSOCK_FD, AF_Disc_Resp, SIGLEN); state = IDLE; } else{ WriteSignaltoSocket(FSOCK_FD, AF_Abort_Req, SIGLEN); close(fd); state = IDLE; } return state; } /*================================================================ State_UUNK() Känner av om vi får en disconnect confirm och ställer oss i IDLE, annars felhantering pre : none post : state returnerat calls: WriteSignaltoSocket -----------------------------------------------------------------*/ int State_UUNK(int sig) { int state; if(sig == AF_Disc_Conf) state = IDLE; else{ WriteSignaltoSocket(FSOCK_FD, AF_Abort_Req, SIGLEN); state = IDLE; } return state; } /*================================================================ State_TERR() Känner av om vi får en reject confirm och ställer oss då i IDLE, annars felhantering pre : none post : state returnerat calls: WriteSignaltoSocket -----------------------------------------------------------------*/ int State_TERR(int sig) { int state; if(sig == AF_Rej_Conf) state = IDLE; else{ WriteSignaltoSocket(FSOCK_FD, AF_Abort_Req, SIGLEN); state = IDLE; } return state; } /*================================================================ do_something() Ligger hela tiden och känner av vilka signaler som kommer in från socketen och genomför lämpliga operationer beroende på insignalen. pre : post : none calls: Polla, WriteSignaltoSocket, ReadSignalfromSocket, sendFile, ReadDatafromSocket -----------------------------------------------------------------*/ void do_something() { int sig, poll, fd, state = IDLE; long len; char buffer[BUFSIZE]; while(1){ /*Loopa alltid*/ poll = Polla(STDIN, FSOCK_FD); if(poll - 1 == STDIN){ switch(state) { case IDLE : /*Tillstånd när inget händer*/ if(menu()){ WriteSignaltoSocket(FSOCK_FD, AF_Con_Req, 3); state = UUUK; } else exit(0); break; case DATA : /*Datafas*/ sendFile(); default : fflush(STDIN); menu(); } } else if(poll - 1 == FSOCK_FD){ sig = ReadSignalfromSocket(FSOCK_FD, 3); if(sig == AF_Abort_Ind) state = IDLE; else switch(state) { case IDLE : /*Tillstånd när inget händer*/ if(State_IDLE(sig, len, buffer, fd)) state = DATA; break; case UUUK : /*Under utgående uppkoppling*/ state = State_UUUK(sig); break; case DATA : /*Datafas*/ state = State_DATA(sig, fd); break; case UUNK : /*Under utgående nedkoppling*/ state = State_UUNK(sig); break; case TERR : /*Transfer error*/ state = State_TERR(sig); break; default: printf("Cancel transfer"); break; } } } } /*================================================================ main() Skapar en socket och kontrollerar så att socket'en är redo för dataöverföring pre : post : Socket'en är skapad, och data kan överföras calls: CreateUnixServerSocket, AcceptConnection, do_something -----------------------------------------------------------------*/ int main(int argc, char *argv[]) { int tmp_fd1, x; printf("FTP_APP startad...\n"); if((tmp_fd1 = CreateUnixServerSocket(S_PATH)) < 0){ fprintf(stderr, "Can't create Unix Server Signal Socket\n"); exit(1); } printf("FTP_APP har skapat FTP_LAYER Socket...\n"); switch(fork()) { case -1: fprintf(stderr, "Fork failed in application\n"); case 0: close(FSOCK_FD); execv(L_PATH, argv); exit(0); default: if((FSOCK_FD = AcceptConnection(tmp_fd1)) < 0){ fprintf(stderr, "Can't accept unix client signal socket\n"); exit(1); } do_something(); exit(1); } }