Files
Datakomm_1/ftp_layer.c
2026-03-05 13:37:25 +01:00

365 lines
9.7 KiB
C

/* FTP-layer av Daniel W och Anders W för datakommunikation-lab! */
#include "student.h"
#include "signal_prim.h"
#define FPATH "./ftp_socket"
#define LPATH "./link_socket"
#define AF 1 /* send AF_Abort_Ind to app with cancel() */
#define L 0 /* send L_Abort_Req to linker with cancel()*/
#define IsFTP 0x80 /* set the ID-bit to indicate FTP & !chat */
#define OPMASK 0x7f /* to mask out the 'operation'-field */
#define SIGPACKLEN 3 /* lenght of a sigpacket; primitive or PDU */
#define MAXDATALEN 200 /* max datalen to tfr between ftp and linker */
#define IDLE 0
#define UUUK 1
#define UIUK 2
#define DATA 3
#define UUNK 4
#define UINK 5
#define TERROR 6 /* the states */
#define CR 1
#define CA 2
#define DR 3
#define DA 4
#define RR 5
#define RA 6
#define DT 7 /* the PDU's */
/* #define NULL 0 */
void do_something(void);
int Polla(int,int); /* handles error from PollSocket() */
void cancel(int); /* sets 'state' to IDLE */
void WriteSigToApp(int); /* write a sig and handle error */
void WriteSigToLink(int); /* write a sig and handle error */
int WriteDataToLink(char*, int); /* cancel(AF/L) if no L_Stat from link */
void WriteDataToApp(char*,int);
int doSigPacket(int); /* uses WriteDataToLink() */
int ConnToLinker(void); /* executes cancel(AF/L) on error */
void DiscFromLinker(void); /* executes cancel(L) on error */
int lSock_fd, fSock_fd, state=IDLE, stderr=2;
main(int argc,char *argv[]) {
int temp_fd;
printf("FTP_LAYER startat\n");
if((fSock_fd=CreateUnixClientSocket(FPATH))<0) {
fprintf(stderr,"Can't create client signal socket to application!\n");
exit(1);
}
printf("FTP_Layer har startat APP-socket...\n");
if((temp_fd=CreateUnixServerSocket(LPATH))<0) {
fprintf(stderr,"Can't create server signal socket to linker!\n");
exit(2);
}
printf("FTP_Layer har startat LINK-socket...\n");
switch(fork()) {
case -1:
fprintf(stderr,"Fork failed in FTP-layer!\n");
exit(4);
case 0:
close(fSock_fd);
close(temp_fd);
execv("./link_layer",argv);
exit(0);
default:
if((lSock_fd=AcceptConnection(temp_fd))<0) {
fprintf(stderr,"Can't accept client signal socket from application!\n");
exit(3);
}
do_something();
exit(0);
}
}
int Polla(int fd1, int fd2) {
int poll;
poll=PollSocket(fd1,fd2,NULL);
if(poll==-1) {
fprintf(stderr,"PollSocket-error in FTP-layer, quitting!\n\n");
exit(8);
}
return poll-1;
}
void do_something() {
int sig, poll;
char buf[MAXDATALEN+SIGPACKLEN], x;
long len;
while(1) {
poll=Polla(fSock_fd,lSock_fd);
if(poll==fSock_fd) { /* signal från applikationen */
sig=ReadSignalfromSocket(fSock_fd,SIGPACKLEN);
if(sig==AF_Abort_Req)
cancel(L);
else if(sig==-1) {
fprintf(stderr,"ReadSignal-error in FTP-layer, quitting!\n\n");
exit(15);
}
else {
switch(state) {
case IDLE:
if(sig==AF_Con_Req) {
if(ConnToLinker())
if(doSigPacket(CR)) state=UUUK;
}
else
cancel(AF);
break;
case UIUK:
if(sig==AF_Con_Resp)
if(doSigPacket(CA)) state=DATA;
else {
cancel(AF);
cancel(L);
}
break;
case DATA:
if(sig==AF_Data_Req) {
PollSocket(fSock_fd,fSock_fd,NULL);
ReadDatafromSocket(fSock_fd, (char*)&len,sizeof(long));
if(len) {
PollSocket(fSock_fd,fSock_fd,NULL);
while(len>0) {
x=ReadDatafromSocket(fSock_fd,buf+3,len>MAXDATALEN?MAXDATALEN:len);
if(x>0) {
buf[0]=x+2;
buf[1]=x;
buf[2]=IsFTP | DT;
if(!WriteDataToLink(buf,x+SIGPACKLEN)) break;
len-=x;
}
else if(x==-1) {
fprintf(stderr,"Readerror in FTP-layer, quitting!\n\n");
exit(14);
}
}
}
}
else if(sig==AF_Disc_Req)
if(doSigPacket(DR)) state=UUNK;
else {
cancel(AF);
cancel(L);
}
break;
case UINK:
if(sig==AF_Disc_Resp) {
if(doSigPacket(DA)) {
state=IDLE;
DiscFromLinker();
}
}
else {
cancel(AF);
cancel(L);
}
break;
case TERROR:
if(sig==AF_Rej_Resp)
if(doSigPacket(RA)) state=IDLE;
else
cancel(AF);
cancel(L);
break;
default: /* I UUUK & UUNK ska man inte få signaler från app */
cancel(AF);
cancel(L);
}
}
}
else if(poll==lSock_fd) { /* signal från linkern */
sig=ReadSignalfromSocket(lSock_fd,SIGPACKLEN);
if(sig==L_Abort_Ind)
cancel(AF);
else if(sig==L_Data_Ind)
Polla(lSock_fd,lSock_fd);
else if(sig==-1) {
fprintf(stderr,"ReadSignal-error in FTP-layer, quitting!\n\n");
exit(15);
}
else {
switch(state) {
case IDLE:
if(sig==L_Con_Ind) {
WriteSigToLink(L_Con_Resp);
Polla(lSock_fd,lSock_fd);
if(ReadSignalfromSocket(lSock_fd,SIGPACKLEN)==L_Data_Req) {
Polla(lSock_fd,lSock_fd);
ReadDatafromSocket(lSock_fd,buf,1);
Polla(lSock_fd,lSock_fd);
ReadDatafromSocket(lSock_fd,buf,buf[0]);
if(buf[1] & IsFTP) {
if((buf[1] & OPMASK)==CR) {
WriteSigToApp(AF_Con_Ind);
state=UIUK;
}
else
cancel(L);
}
}
else
cancel(L);
}
else {
cancel(AF);
cancel(L);
}
break;
case UUUK:
if(sig==L_Data_Ind) {
ReadDatafromSocket(lSock_fd,buf,1);
Polla(lSock_fd,lSock_fd);
ReadDatafromSocket(lSock_fd,buf,buf[0]);
if(buf[1] & IsFTP) {
if((buf[1] & OPMASK)==CA) {
WriteSigToApp(AF_Con_Conf);
state=DATA;
}
else if((buf[1] & OPMASK)==RR) {
WriteSigToApp(AF_Rej_Ind);
state=TERROR;
}
}
}
else
cancel(AF);
break;
case DATA:
if(sig==L_Data_Ind) {
ReadDatafromSocket(lSock_fd,buf,1);
Polla(lSock_fd,lSock_fd);
ReadDatafromSocket(lSock_fd,buf,buf[0]);
if(buf[1] & IsFTP) {
if((buf[1] & OPMASK)==DT) {
len=buf[0];
WriteDataToApp((char*)&len,sizeof(long));
WriteDataToApp(buf+2,len);
}
else if((buf[1] & OPMASK)==DR) {
WriteSigToApp(AF_Disc_Ind);
state=UINK;
}
else {
cancel(AF);
cancel(L);
}
}
}
else {
cancel(AF);
cancel(L);
}
break;
case UUNK:
if(sig==L_Data_Ind) {
ReadDatafromSocket(lSock_fd,buf,1);
Polla(lSock_fd,lSock_fd);
ReadDatafromSocket(lSock_fd,buf,buf[0]);
if(buf[1] & IsFTP) {
if((buf[1] & OPMASK)==DA) {
WriteSigToApp(AF_Disc_Conf);
state=IDLE;
DiscFromLinker();
}
else {
cancel(AF);
cancel(L);
}
}
}
else {
cancel(AF);
cancel(L);
}
break;
default: /* i UIUK, UINK & TERROR ska man inte få sig. från linker */
cancel(AF);
cancel(L);
}
}
}
}
}
void cancel(int af_abort) {
if(af_abort)
WriteSigToApp(AF_Abort_Ind);
else
WriteSigToLink(L_Abort_Req);
state=IDLE;
}
void WriteSigToLink(int flag) {
if(WriteSignaltoSocket(lSock_fd,flag,SIGPACKLEN)==-1) {
fprintf(stderr,"Write-error to linker, quitting!\n\n");
exit(10);
} }
void WriteSigToApp(int flag) {
if(WriteSignaltoSocket(fSock_fd,flag,SIGPACKLEN)==-1) {
fprintf(stderr,"Write-error to application, quitting!\n\n");
exit(11);
} }
int WriteDataToLink(char* buf,int len) {
int x;
WriteSigToLink(L_Data_Req);
PollSocket(lSock_fd,lSock_fd,NULL);
if(ReadSignalfromSocket(lSock_fd,SIGPACKLEN)!=L_Status) {
cancel(AF);
cancel(L);
return 0;
}
if((x=WriteDatatoSocket(lSock_fd,buf,len))==-1) {
fprintf(stderr,"Write-error to linker, quitting!\n\n");
exit(13);
}
else
while(x<len) x+=WriteDatatoSocket(lSock_fd,buf+x,len-x);
return 1;
}
void WriteDataToApp(char* buf,int len) {
int x;
WriteSigToApp(AF_Data_Ind);
if((x=WriteDatatoSocket(fSock_fd,buf,len))==-1) {
fprintf(stderr,"Write-error to application, quitting!\n\n");
exit(13);
}
else
while(x<len) x+=WriteDatatoSocket(lSock_fd,buf+x,len-x);
}
int doSigPacket(int flag) {
char head[3];
head[0]=2;
head[1]=0;
head[2]=IsFTP | flag;
return WriteDataToLink(head,SIGPACKLEN);
}
int ConnToLinker() {
WriteSigToLink(L_Con_Req);
Polla(lSock_fd,lSock_fd);
switch(ReadSignalfromSocket(lSock_fd,SIGPACKLEN)) {
case L_Con_Conf:
return 1;
case L_Abort_Ind:
cancel(AF);
return 0;
default:
cancel(AF);
cancel(L);
return 0;
} }
void DiscFromLinker() {
WriteSigToLink(L_Disc_Req);
Polla(lSock_fd,lSock_fd);
if(ReadSignalfromSocket(lSock_fd,SIGPACKLEN)!=L_Disc_Conf) {
cancel(AF);
cancel(L);
} }