363 lines
11 KiB
C
363 lines
11 KiB
C
/*================================================================
|
|
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);
|
|
}
|
|
}
|
|
|