commit 00233de9384c81e313fb8f9bd8480f08d3e3f9e2 Author: Christian Ohlsson Date: Thu Mar 5 13:37:25 2026 +0100 Startpunkten diff --git a/body.c b/body.c new file mode 100644 index 0000000..5ab839f --- /dev/null +++ b/body.c @@ -0,0 +1,45 @@ +#include "student.h" + +#define PATH ".phys_socket" +#define LPATH ".link_socket" + +int PSOCK_FD, LSOCK_FD; + +void do_something(void) +{ + PollSOcket(LSOCK_FD, PSOCK_FD, NULL); +} + +void main(int argc, char *argv[]) +{ + int tmp_fd1; + + if((LSOCK_FD = CreateUnixClientSocket(LPATH)) < 0) + { + fprintf(stderr, "Can't create unix client socket\n"); + exit(1); + } + + if((tmp_fd1 = CreateUnixServerSocket(PATH) < 0) + { + fprintf(stderr, "Can't create unix server socket\n"); + exit(1); + } + + switch(fork()) + { + case -1: fprintf(stderr, "Fork failed\n"); + case 0: close(PSOCK_FD); + close(LSOCK_FD); + execv("./physical_layer", argv); + exit(1); + default: if((PSOCK_FD = AcceptConnection(tmp_fd1)) < 0 + { + fprintf(stderr, "Can't accept unix client signal socket\n"); + exit(1); + } + + do_something(); + exit(1); + } +} diff --git a/ftp_app b/ftp_app new file mode 100644 index 0000000..b43d924 Binary files /dev/null and b/ftp_app differ diff --git a/ftp_app.c b/ftp_app.c new file mode 100644 index 0000000..5e7f546 --- /dev/null +++ b/ftp_app.c @@ -0,0 +1,362 @@ +/*================================================================ + 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); + } +} + diff --git a/ftp_layer.c b/ftp_layer.c new file mode 100644 index 0000000..3e74934 --- /dev/null +++ b/ftp_layer.c @@ -0,0 +1,364 @@ +/* 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 +#include +#include +#include +#define FALSE 0 +#define TRUE 1 +#define ENTER 13 +#define BACKSPACE 8 +#define PERMS 0644 +#define BUFSIZE 4000 +#define FNSIZE 300 +#define SIGLEN 3 +#define S_PATH "./ftp_socket" +#define L_PATH "./ftp_layer" +#define STDIN 0 +int FSOCK_FD; + +#endif diff --git a/link.cpp b/link.cpp new file mode 100644 index 0000000..8cec7ee --- /dev/null +++ b/link.cpp @@ -0,0 +1,689 @@ +#include "physlayer.h" +#include +#include +#include +#include "link_signal.h" +#include "link.h" +#include "student.h" + + +const CONTROL_FRAME_SIZE = 14; +int PSOCK_FD; +int USOCK_FD; + +typedef enum state{IDLE, UICON, UOCON, DATA, UIDCON, UODCON}state; +state LINK_STATE = IDLE; + +static action ALIST[] = { +{ L_DATA_REQUEST , DataRequest }, +{ L_DATA_INDICATION , DataIndication }, +{ L_CONNECT_REQUEST , ConnectRequest }, +{ L_CONNECT_INDICATION , ConnectIndication }, +{ L_CONNECT_RESPONSE , ConnectResponse }, +{ L_CONNECT_CONFIRM , ConnectConfirm }, +{ L_DISCONNECT_REQUEST , DisconnectRequest }, +{ L_DISCONNECT_INDICATION , DisconnectIndication }, +{ L_DISCONNECT_RESPONSE , DisconnectResponse }, +{ L_DISCONNECT_CONFIRM , DisconnectConfirm }, +{ L_ABORT_REQUEST , AbortRequest }, +{ L_ABORT_INDICATION , AbortIndication }, +{ SYSTEM_FAILURE , SystemError }, +{ DEFAULT , Default }, +}; + +int incoming_frame_status = 0, incoming_frame_index = 0; // global! +int incoming_frame_length = 0; +struct Frame +{ + char start_header[6]; + short control; + short length; + short cc; + char *data; + char end_header[6]; +}; + +Frame incoming_frame; // global! (tillfälligt). + +int ConnectRequest(void) +{ + int return_value; + + if(LINK_STATE == IDLE) + { + return_value = WriteSignaltoSocket(PSOCK_FD, F_CONNECT_REQUEST, SIG_LEN); + if(return_value < 0) + return SYSTEM_FAILURE; + + LINK_STATE = UOCON; + } + else + { + return_value = Abort(BO); + if(return_value < 0) + return SYSTEM_FAILURE; + } + + return SUCCESS; +} + +int ConnectIndication(void) +{ + int return_value; + + if(LINK_STATE == IDLE) + { + return_value = WriteSignaltoSocket(PSOCK_FD, F_CONNECT_RESPONSE, SIG_LEN); + if(return_value < 0) + return SYSTEM_FAILURE; + + LINK_STATE = UICON; + } + else + { + return_value = Abort(BO); + if(return_value < 0) + return SYSTEM_FAILURE; + } + + return SUCCESS; +} + + +int ConnectConfirm(void) +{ + Frame frame; + int return_value, frame_length; + + if(LINK_STATE == IDLE) + { + return_value = Abort(SP); + if(return_value < 0) + return SYSTEM_FAILURE; + } + else if(LINK_STATE == UOCON) + { + frame_length = PutDataInFrame("", 0, &frame, SABM); + if(frame_length == -10) + return SYSTEM_FAILURE; + + return_value = SendFrame(&frame, PSOCK_FD); + if(return_value < 0) + return SYSTEM_FAILURE; + } + else + { + return_value = Abort(BO); + if(return_value < 0) + return SYSTEM_FAILURE; + } + + return SUCCESS; +} + +int ConnectResponse(void) +{ + Frame frame; + int return_value, frame_length; + + if(LINK_STATE == IDLE) + { + return_value = Abort(SU); + if(return_value < 0) + return SYSTEM_FAILURE; + } + else if(LINK_STATE == UICON) + { + frame_length = PutDataInFrame("", 0, &frame, UA); + if(frame_length == -10) + return SYSTEM_FAILURE; + + return_value = SendFrame(&frame, PSOCK_FD); + if(return_value < 0) + return SYSTEM_FAILURE; + + LINK_STATE = DATA; + } + else + { + return_value = Abort(BO); + if(return_value < 0) + return SYSTEM_FAILURE; + } + + return SUCCESS; +} + +int DisconnectRequest(void) +{ + Frame frame; + int return_value, frame_length; + + if(LINK_STATE == IDLE) + { + return_value = Abort(SU); + if(return_value < 0) + return SYSTEM_FAILURE; + + LINK_STATE = IDLE; + } + else if(LINK_STATE == DATA) + { + frame_length = PutDataInFrame("", 0, &frame, DISC); + if(frame_length == -10) + return SYSTEM_FAILURE; + + return_value = SendFrame(&frame, PSOCK_FD); + if(return_value < 0) + return SYSTEM_FAILURE; + + LINK_STATE = UODCON; + } + else + { + return_value = Abort(BO); + if(return_value < 0) + return SYSTEM_FAILURE; + } + + return SUCCESS; +} + +int DisconnectIndication(void) +{ + int return_value; + + if(LINK_STATE == IDLE) + { + return_value = Abort(SP); + if(return_value < 0) + return SYSTEM_FAILURE; + } + else if(LINK_STATE == UIDCON) + { + return_value = WriteSignaltoSocket(PSOCK_FD, F_DISCONNECT_RESPONSE, SIG_LEN); + if(return_value < 0) + return SYSTEM_FAILURE; + + LINK_STATE = IDLE; + } + else + { + return_value = Abort(BO); + if(return_value < 0) + return SYSTEM_FAILURE; + } + + return SUCCESS; +} + +int DisconnectResponse(void) +{ + Frame frame; + int return_value, frame_length; + + if(LINK_STATE == IDLE) + { + return_value = Abort(SU); + if(return_value < 0) + return SYSTEM_FAILURE; + + LINK_STATE = IDLE; + } + else if(LINK_STATE == UIDCON) + { + frame_length = PutDataInFrame("", 0, &frame, UA); + if(frame_length == -10) + return SYSTEM_FAILURE; + + return_value = SendFrame(&frame, PSOCK_FD); + if(return_value < 0) + return SYSTEM_FAILURE; + } + else + { + return_value = Abort(BO); + if(return_value < 0) + return SYSTEM_FAILURE; + } + + return SUCCESS; +} + +int DisconnectConfirm(void) +{ + int return_value; + + if(LINK_STATE == IDLE) + { + return_value = Abort(SP); + if(return_value < 0) + return SYSTEM_FAILURE; + } + else if(LINK_STATE == UODCON) + LINK_STATE = IDLE; + else + { + return_value = Abort(BO); + if(return_value < 0) + return SYSTEM_FAILURE; + } + + return SUCCESS; +} + +int AbortRequest(void) +{ + int return_value; + + if(LINK_STATE == IDLE) + // Do nothing. + ; + else + { + return_value = Abort(SP); + if(return_value < 0) + return SYSTEM_FAILURE; + } + + return SUCCESS; +} + +int AbortIndication(void) +{ + int return_value; + + if(LINK_STATE == IDLE) + ;// Do nothing. + + else + { + return_value = Abort(SU); + if(return_value < 0) + return SYSTEM_FAILURE; + } + + return SUCCESS; +} + +int Status(void) +{ + int return_value; + char frame_status; + + frame_status = CheckFrame(&incoming_frame); + + return_value = WriteSignaltoSocket(USOCK_FD, L_STATUS, SIG_LEN); + if(return_value < 0) + return SYSTEM_FAILURE; + + return_value = WriteDatatoSocket(USOCK_FD, &frame_status, sizeof(char)); + if(return_value < 0) + return SYSTEM_FAILURE; + + return SUCCESS; +} + +int Abort(short who) +{ + int return_value; + + if((who == SU) || (who == BO)) + { + return_value = WriteSignaltoSocket(USOCK_FD, L_ABORT_INDICATION, SIG_LEN); + if(return_value < 0) + return SYSTEM_FAILURE; + } + if((who == SP) || (who == BO)) + { + return_value = WriteSignaltoSocket(PSOCK_FD, F_ABORT_REQUEST, SIG_LEN); + if(return_value < 0) + return SYSTEM_FAILURE; + } + + LINK_STATE = IDLE; + + return SUCCESS; +} + +int Checksum(int data_length) +{ + int sum; + + // Vet ej varför, men det står i laborationshäftet. + sum = data_length % 128; + + return sum; +} + +int PutDataInFrame(char *data, short data_length, Frame *frame, short control) +{ + int frame_length, cc = 0; + + strcat(frame->start_header, "DLEST"); + frame->start_header[5] = 'X'; + + frame->control = control; + frame->length = data_length; + + if(control == I) + cc = Checksum(data_length); + else + { + frame->cc = cc; + data_length = sizeof(frame->data); + } + + frame->data = data; + + strcat(frame->start_header, "DLEET"); + frame->end_header[5] = 'X'; + + frame_length = 6 + 6 + 2 + 2 + 2 + data_length; + + return frame_length; +} + +int ClearFrame(Frame *frame) +{ + frame->start_header[0] = 0; + frame->end_header[0] = 0; + frame->control = 0; + frame->length = 0; + frame->cc = 0; + if(frame->data != NULL) + { + delete[] frame->data; + frame->data = NULL; + } + + incoming_frame_status = 0; // Global variabel. + incoming_frame_index = 0; // Global variabel. +} + +int FillInFrame(Frame *frame, char data, char *charframe) +{ + int status; + + if(CheckFrame(frame) == -1) + return FRAME_ERROR; + + if(incoming_frame_status) + return FRAME_IS_FULL; + + if(incoming_frame_index == 12) + { + if(frame->control == I) + { + frame->data = new char[frame->length]; + if(frame->data == NULL) + return SYSTEM_FAILURE; + + charframe[incoming_frame_index] = data; + incoming_frame_index++; + } + } + else + { + charframe[incoming_frame_index] = data; + incoming_frame_index++; + } + + return CheckFrame(frame); +} + +int CheckFrame(Frame *frame) +{ + int start, end, cc; + + if(incoming_frame_index == 10) // HEADER_LENGTH = 22 + incoming_frame_length = HEADER_LENGTH + frame->length; + + if(incoming_frame_index >= 10) + { + if(incoming_frame_index == incoming_frame_length) + { + start = CheckStartHeader((char*)frame); + end = CheckEndHeader((char*)frame); + cc = CheckCC(frame); + FixFrameData(frame); // tar bort de onödiga DLE om det behövs. + + if(start == 0 && end == 0 && cc == 0) + { + incoming_frame_status = 1; + return FRAME_IS_FULL; // frame_is_full = 1 + } + else + return FRAME_ERROR; // frame_error = -1 + } + } + + return FRAME_NOT_READY; // frame_not_ready = 0 +} + +int CheckStartHeader(char *frame) +{ + int index; + char start[7]; + start[7] = '\0'; + + for(index = 0; index < 6; index++) + start[index] = (char)frame[index]; + + return strcmp(start, "DLESTX"); +} + +int CheckEndHeader(char *frame) +{ + if(incoming_frame_status != 1) + return FRAME_ERROR; + + int index; + char start[7]; + start[7] = '\0'; + + for(index = 0; index < 6; index++) + start[index] = (char)frame[incoming_frame_index - 5 + index]; + + return strcmp(start, "DLEETX"); +} + +int CheckCC(Frame *frame) +{ + int cc; + cc = Checksum(frame->length); + + if(cc == frame->cc) + return 0; + + return FRAME_ERROR; +} + +int FixFrameData(Frame *frame) +{ + char *tmp; + int length, index, tmpindex, before = 0; + length = frame->length; + + for(index = 0; index < frame->length; index++) + { + if(frame->data[index] == 'D' && frame->data[index+1] == 'L' && frame->data[index+2] +== 'E') { + if(before == 1) + { length--; before = 0; } + else + before = 1; + } + } + + if(length == frame->length) + return SUCCESS; + + tmp = new char[length]; + if(tmp == NULL) + return SYSTEM_FAILURE; + + for(index = 0, tmpindex = 0; index < frame->length; index++, tmpindex++) + { + if(frame->data[index] == 'D' && frame->data[index+1] == 'L' && frame->data[index+2] == 'E') + { + if(before == 1) + { before = 0; index += 3; } + else + before = 1; + } + + if(index < frame->length) + tmp[tmpindex]; + } + + delete[] frame->data; + frame->data = tmp; + frame->length = length; + return SUCCESS; +} + +int SendFrame(Frame *frame, int socket_id) +{ + int frame_length, index = 0, return_value; + frame_length = GetFrameLength(frame); + + if(socket_id == USOCK_FD) + { + return_value = WriteSignaltoSocket(USOCK_FD, L_DATA_INDICATION, SIG_LEN); + if(return_value < 0) + return SYSTEM_FAILURE; + + return_value = WriteDatatoSocket(USOCK_FD, frame->data, +frame->length); if(return_value < 0) + return SYSTEM_FAILURE; + } + else if(socket_id == PSOCK_FD) + { + for(index = 0; index < frame_length; index++) + { + return_value = WriteSignaltoSocket(PSOCK_FD, F_DATA_REQUEST, SIG_LEN); + if(return_value < 0) + return SYSTEM_FAILURE; + + return_value = WriteDatatoSocket(PSOCK_FD, (char +*)&frame[index], sizeof(char)); if(return_value < 0) + return SYSTEM_FAILURE; } + } + else + return SYSTEM_FAILURE; + + return SUCCESS; +} + +int DataIndication(void) +{ + /*Frame *frame; + char temp = 'a'; + int return_value, frame_length; + + if(LINK_STATE == IDLE) + Abort(SP); + else if(LINK_STATE == UICON) + { + return_value = ReadDatafromSocket(PSOCK_FD, &temp, TWO_BYTES); + if(return_value < 0) + return SYSTEM_FAILURE; + + return_value = ReadDatafromSocket(PSOCK_FD, temp, BYTE_LEN); + if(return_value < 0) + return SYSTEM_FAILURE; + } + else + { + return_value = Abort(BO); + if(return_value < 0) + return SYSTEM_FAILURE; + } + + if(frame != NULL) + delete[] frame; */ + + return SUCCESS; + +} + +void main(int argc, char *argv[]) +{ + int tmp_fd1, PSOCK; + printf("LINK_LAYER har startat...\n"); + + if((PSOCK = CreateUnixClientSocket(UPATH)) < 0) + { + fprintf(stderr, "Can't create unix client signal socket 111\n"); + exit(1); + } + printf("LINK_LAYER har skapat FTP_LAYER Socket...\n"); + if((tmp_fd1 = CreateUnixServerSocket(PPATH)) < 0) + { + fprintf(stderr, "Can't create unix server signal socket.\n"); + exit(1); + } + printf("LINK_LAYER har skapat PHYS_LAYER Socket...\n"); + switch(fork()) + { + case -1: + fprintf(stderr, "Fork failed.\n"); + + case 0: + printf("Fuck you\n\n"); + close(PSOCK_FD); + close(USOCK_FD); + execv("./phys_layer", argv); + exit(1); + + default: + if((PSOCK = AcceptConnection(tmp_fd1)) < 0) + { + fprintf(stderr, "Can't accept unix client signal socket.\n"); + exit(1); + } + + MainLoop(); + exit(1); + } +} + +void MainLoop(void) +{ + int return_value; + do + { + return_value = PollSocket(PSOCK_FD, USOCK_FD, NULL); + if(return_value < 0) + return; + + return_value = ReadSignalfromSocket(return_value - 1, SIG_LEN); + return_value = (* FindAction(return_value, ALIST))(); + if(return_value < 0) + return ; + + } while(return_value >= 0); + +} + +int DataRequest(void) +{ + return 10; +} + +int Default(void) +{ + return 10; +} + + +int GetFrameLength(Frame *frame) +{ + return frame->length; +} + +int SystemError(void) +{ + return 108; +} diff --git a/link.h b/link.h new file mode 100644 index 0000000..eddda43 --- /dev/null +++ b/link.h @@ -0,0 +1,52 @@ +#ifndef _link_h_ +#define _link_h_ + +#define SABM 401 +#define UA 403 +#define I 405 +#define RR 406 +#define DISC 407 +#define SIG_LEN 2 +#define BO 2 +#define SU 1 +#define SP 3 +#define DEFAULT 10 +#define FRAME_ERROR 13 +#define FRAME_IS_FULL 34 +#define FRAME_NOT_READY 123 +#define HEADER_LENGTH 22 +#define TWO_BYTES 56 +#define UPATH "./link_socket" +#define PPATH "./.phys_socket" + +struct Frame; +int SystemError(void); +int GetFrameLength(Frame *frame); +int Default(void); +int DataRequest(void); +int ConnectRequest(void); +int ConnectIndication(void); +int ConnectConfirm(void); +int ConnectResponse(void); +int DisconnectRequest(void); +int DisconnectIndication(void); +int DisconnectResponse(void); +int DisconnectConfirm(void); +int AbortRequest(void); +int AbortIndication(void); +int Status(void); +int Abort(short who); +int Checksum(int data_length); +int PutDataInFrame(char *data, short data_length, Frame *frame, short control); +int ClearFrame(Frame *frame); +int FillInFrame(char *frame, char data, char *charframe); +int CheckFrame(Frame *frame); +int CheckStartHeader(char *frame); +int CheckEndHeader(char *frame); +int CheckCC(Frame *frame); +int FixFrameData(Frame *frame); +int SendFrame(Frame *frame, int socket_id); +int DataIndication(void); +void MainLoop(void); + +#endif diff --git a/link_signal.h b/link_signal.h new file mode 100644 index 0000000..cc0473d --- /dev/null +++ b/link_signal.h @@ -0,0 +1,48 @@ +#ifndef ___SIGNAL_PRIM___ +#define ___SIGNAL_PRIM___ + +#define L_CONNECT_REQUEST 101 +#define L_CONNECT_INDICATION 102 +#define L_CONNECT_RESPONSE 103 +#define L_CONNECT_CONFIRM 104 +#define L_DATA_REQUEST 105 +#define L_DATA_INDICATION 106 +#define L_DISCONNECT_REQUEST 107 +#define L_DISCONNECT_RESPONSE 108 +#define L_DISCONNECT_INDICATION 109 +#define L_DISCONNECT_CONFIRM 110 +#define L_ABORT_REQUEST 111 +#define L_ABORT_INDICATION 112 +#define L_STATUS 113 + +#define AF_Con_Req 201 +#define AF_Con_Ind 202 +#define AF_Con_Resp 203 +#define AF_Con_Conf 204 +#define AF_Data_Req 205 +#define AF_Data_Ind 206 +#define AF_Disc_Req 207 +#define AF_Disc_Ind 208 +#define AF_Disc_Resp 209 +#define AF_Disc_Conf 210 +#define AF_Rej_Req 211 +#define AF_Rej_Ind 212 +#define AF_Rej_Resp 213 +#define AF_Rej_Conf 214 +#define AF_Abort_Req 215 +#define AF_Abort_Ind 216 + +#define AI_Con_Req 301 +#define AI_Con_Ind 302 +#define AI_Con_Resp 303 +#define AI_Con_Conf 304 +#define AI_Data_Req 305 +#define AI_Data_Ind 306 +#define AI_Disc_Req 307 +#define AI_Disc_Ind 308 +#define AI_Disc_Resp 309 +#define AI_Disc_Conf 310 +#define AI_Abort_Req 311 +#define AI_Abort_Ind 312 + +#endif diff --git a/physerr.log b/physerr.log new file mode 100644 index 0000000..015d23e --- /dev/null +++ b/physerr.log @@ -0,0 +1,3 @@ +Wed Dec 16 14:55:03 1998 +System failure +No such file or directory \ No newline at end of file diff --git a/physlayer.c b/physlayer.c new file mode 100644 index 0000000..c8ca4b2 --- /dev/null +++ b/physlayer.c @@ -0,0 +1,1886 @@ +/****************************************************************************** +* +* (c) Copyright 1998, University of Karlstad. +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 1, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +* Please report any bugs you find in this code or any improvements to: +* +* Hans Hedbom, Dept. of Computer Science, +* University of Karlstad, Sweden. +* +* Phone: +46 54 838157 +* E-mail: Hans.Hedbom@hks.se +* +* ============================================================================ +* +* FILE: +* +* physlayer.c [ the Data Communication I course programming project ] +* +* AUTHORS: +* +* Jonny Wiederholm +* E-mail: fr7wied@cse.hks.se or +* jonnwied@hks.se +* +* Per-Ola Gustafsson +* E-mail: fr7gust@cse.hks.se +* +* CREATION DATE: +* +* Jan, 08, 1998 +* +* DESCRIPTION: +* +* Implementation of the Physical Layer, which is part of the example +* implementation of the Data Communication I course programming project. +* +* NOTE: +* +* All debug functions ( prefixed FDbg or FDebug ) are ignored ( at least from +* an abstract point of view ) if the constant DEBUG is undefined. The window +* debugger is only available under Linux and since it is implemented using +* Tcl-Tk and Tcl-Tk uses a different technique when polling sockets we have +* to provide two so called file event handlers, one for each socket, namely +* FDbgPESocketEventHandler() and FDbgSUSocketEventHandler(). These functions +* are not really part of the Physical Layer module ( they should have been +* included in the physdebuglib.c library ) but they were placed here since +* we wanted to avoid having global variables that could be accessed outside +* this module ( lets keep things private ). +* +* MODIFICATIONS: Date Changes +* ---------------------------------------------------------------------------- +* +*/ + +/****************************************************************************** +* INCLUDE FILES +*/ + +#include "systems.h" +#include "udefs.h" +#include "error.h" +#include "ustring.h" +#include "ustdlib.h" +#include "memory.h" +#include "utime.h" +#include "file.h" +#include "sockets.h" +#include "socketio.h" +#include "unixsockets.h" +#include "inetsockets.h" +#include "uselect.h" +#include "usignal.h" +#include "student.h" +#include "transmissionerror.h" +#include "physservices.h" +#include "physdebug.h" +#include "physlayer.h" + +/****************************************************************************** +* DEFINE CONSTANTS +*/ + +/* + Value returned when recieving non state transition signals when in state + idle. + */ +#define IGNORE_SIGNAL SUCCESS + +/* The number of arguments required when starting as server. */ +#define SERVER 5 + +/* The number of arguments required when starting as server. */ +#define CLIENT 6 + +/* Position in command line of arguments. */ +#define PORTPOS 1 /* Port number. */ +#define HOSTNAMEPOS 2 /* Host name or ip address. */ + +/* Relative position of arguments in the command line counting from the end. */ +#define RELLOSEBYTEPOS 1 /* Probability of loosing a byte. */ +#define RELDELAYPOS 2 /* Probability of a transmission delay. */ +#define RELFAULTPOS 3 /* Probability that a byte will get corrupted. */ + +/* Time of the delay in seconds. */ +#define DELAYTIME 1 + +/* The maximum allowed port number. */ +#define MAX_PORT 50000 + +/* The minimum allowed port number. */ +#define MIN_PORT 1023 + +/* Path to the debug file. */ +#define DBGLOG_NAME "./physdebug.log" + +/* Path to the error log file. */ +#define ERRLOG_NAME "./physerr.log" + +/* Integer format. */ +#define INT_FORMAT "%d" + +/* + Passed as parameter to kill() to kill all processes in the same process + group. +*/ +#define PROCESS_GROUP 0 + +/* Protocol signals.*/ +#define WANT_CONNECTION 120 +#define WANT_DISCONNECTION 122 +#define CONNECTION_REQUEST_REPLY 124 +#define DISCONNECTION_REQUEST_REPLY 126 +#define INCOMING_DATA 128 +#define ABORT 666 +#define DEFAULT 0 + +/****************************************************************************** +* DEFINE TYPES +*/ + +/* + Internal state codes. Each code represents one of the following internal + states: Idle, Under incoming connection, Under outgoing connection, Under + data transfer, Under incoming disconnection or Under outgoing disconnection. + */ +enum state {IDLE, UICON, UOCON, DATA, UIDCON, UODCON}; +typedef enum state state; + +/* + Abort destination code. Is used to determine where to send an abort. Each + code represents one of the following destinations of the abort : the Peer + entity, the Service user or Both. + */ +enum abortdst {PE, SU, BO}; +typedef enum abortdst abortdst; + +/****************************************************************************** +* DECLARE FUNCTIONS +*/ + +/* See function definitions for documentation. */ + +static int FConnectRequest __P((void)); +static int FConnectIndication __P((void)); +static int FConnectResponse __P((void)); +static int FConnectConfirm __P((void)); +static int FDisconnectRequest __P((void)); +static int FDisconnectIndication __P((void)); +static int FDisconnectResponse __P((void)); +static int FDisconnectConfirm __P((void)); +static int FDataRequest __P((void)); +static int FDataIndication __P((void)); +static int FAbortRequest __P((void)); +static int FAbortIndication __P((void)); +static int FAbort __P((abortdst)); +static int FSystemError __P((void)); +static int FDefault __P((void)); +static void FDbgPESocketEventHandler __P((void_ptr_, int)); +static void FDbgSUSocketEventHandler __P((void_ptr_, int)); +static void CleanUp __P((void)); +static void ErrorHandler __P((string_ptr_)); +static int InitSignalHandler __P((void (*) __P((int)))); +static void SignalHandler __P((int)); +static void MainLoop __P((void)); +static void Server __P((int)); +static void Client __P((int, string_ptr_)); + +/****************************************************************************** +* DEFINE GLOBALS +*/ + +/* Internal state. */ +static state PHYS_STATE = IDLE; + +/* + Socket file descriptors. They can't be of type static since they are used + in other libraries. + */ +static int PE_FD, SU_FD, TMP_FD; + +/* + Probabilities that a byte will get corrupted, that a byte will get delayed + and that a byte will get lost. + */ +static double FAULT_PROBABILITY, DELAY_PROBABILITY, LOSEBYTE_PROBABILITY; + +/* Indicates when a fatal error is in progress. */ +static volatile int FATAL_ERROR_IN_PROGRESS = 0; + +/* Array containing the function associated with a certain signal. */ +static const__ action ALIST[] = { +{ F_DATA_REQUEST , FDataRequest }, +{ INCOMING_DATA , FDataIndication }, +{ F_CONNECT_REQUEST , FConnectRequest }, +{ WANT_CONNECTION , FConnectIndication }, +{ F_CONNECT_RESPONSE , FConnectResponse }, +{ CONNECTION_REQUEST_REPLY , FConnectConfirm }, +{ F_DISCONNECT_REQUEST , FDisconnectRequest }, +{ WANT_DISCONNECTION , FDisconnectIndication }, +{ F_DISCONNECT_RESPONSE , FDisconnectResponse }, +{ DISCONNECTION_REQUEST_REPLY, FDisconnectConfirm }, +{ F_ABORT_REQUEST , FAbortRequest }, +{ ABORT , FAbortIndication }, +{ SYSTEM_FAILURE , FSystemError }, +{ DEFAULT , FDefault }, +}; + +/* + Array containing the error text message associated with a certain status + code. */ +static const__ errmess ERRLIST[] = { +{ 1, "Failed to create Unix client socket\n" }, +{ 2, "Port number out of range \n" }, +{ 3, "System failure \n" }, +{ 4, "Argument out of range \n" }, +{ 5, "Failed to create Inet server socket\n" }, +{ 6, "Failed to accept Inet client socket\n" }, +{ 7, "Failed to create Inet client socket\n" }, +{ 8, "Failed to initialize signal handler\n" }, +{ 9, "Wrong number of arguments \n" }, +{ 10, "Failed to poll sockets \n" }, +{ 0, "Unknown error \n" }, +}; + +/* + Array containing the debug text message associated with a certain debug + code. */ +static const__ dbgmess DBGLIST[] = { +{ 1, "\nGot signal F_CONNECT_REQUEST from service user" }, +{ 2, "\nSending signal WANT_CONNECTION to peer entity\n" }, +{ 3, "\nIn wrong state. Sending signal ABORT to peer entity and signal \ +F_ABORT_INDICATION to service user\n" }, +{ 4, "\nGot signal WANT_CONNECTION from peer entity" }, +{ 5, "\nSending signal F_CONNECT_INDICATION to service user\n" }, +{ 6, "\nGot signal F_CONNECT_RESPONSE from service user" }, +{ 7, "\nSending signal CONNECTION_REQUEST_REPLY to peer entity\n" }, +{ 8, "\nIn state idle. Ignoring signal\n" }, +{ 9, "\nGot signal CONNECTION_REQUEST_REPLY from peer entity" }, +{ 10, "\nSending signal F_CONNECT_CONFIRM to service user\n" }, +{ 11, "\nGot signal F_DISCONNECT_REQUEST from service user" }, +{ 12, "\nSending signal WANT_DISCONNECTION to peer entity\n" }, +{ 13, "\nGot signal WANT_DISCONNECTION from peer entity" }, +{ 14, "\nSending signal F_DISCONNECT_INDICATION to service user\n" }, +{ 15, "\nGot signal F_DISCONNECT_RESPONSE from service user" }, +{ 16, "\nSending signal DISCONNECTION_REQUEST_REPLY to peer entity\n" }, +{ 17, "\nGot signal DISCONNECTION_REQUEST_REPLY from peer entity" }, +{ 18, "\nSending signal F_DISCONNECT_CONFIRM to service user\n" }, +{ 19, "\nGot signal F_DATA_REQUEST from service user and a byte with the \ +ascii value " }, +{ 20, "\nSending signal INCOMING_DATA to peer entity along with the byte\n" }, +{ 21, "\nGot signal INCOMING_DATA from peer entity and a byte with the ascii \ +value " }, +{ 22, "\nSending signal F_DATA_INDICATION to service user along with the \ +byte\n" }, +{ 23, "\nGot signal F_ABORT_REQUEST from service user" }, +{ 24, "\nSending signal ABORT to peer entity\n" }, +{ 25, "\nGot signal ABORT from peer entity" }, +{ 26, "\nSending signal F_ABORT_INDICATION to service user\n" }, +{ 27, "\nGot unknown signal from service user" }, +{ 28, "\nSorry, but the byte of data got lost in cyberspace\n" }, +{ 0, "\nUnknown debug prompt\n" }, +}; + +/****************************************************************************** +* DEFINE FUNCTIONS +*/ + +/****************************************************************************** +* +* FUNCTION: +* +* int FConnectRequest(void) +* +* DESCRIPTION: +* +* Handles a connect request from the service user by sending the signal +* WANT_CONNECTION to the peer entity and setting the internal state to under +* outgoing connection. +* +* PARAMETERS: +* +* void -- None. +* +* RETURNS: +* +* int -- On success 0. +* -- Otherwise, -1. +* +* GLOBALS: +* +* PHYS_STATE specifies the internal state. +* PE_FD references the socket connected to the peer entity. +* DBGLIST contains all debug codes and their respective text messages. +* +* NOTE: +* +* If FConnectRequest() is called and the internal state is not set to idle, it +* will send an abort request to the peer entity and the service user and set +* the internal state to idle. +* +*/ + +#ifdef __STDC__ +int FConnectRequest(void) +#else + int FConnectRequest() +#endif +{ + int retval; + + FDebug(DBGLOG_NAME, 1, DBGLIST, NULL, NULL, 0); + if(PHYS_STATE == IDLE){ + FDebug(DBGLOG_NAME, 2, DBGLIST, NULL, NULL, 0); + retval = WriteSignaltoSocket(PE_FD, WANT_CONNECTION, SIG_LEN); + if(retval < 0){ + return SYSTEM_FAILURE; + } + PHYS_STATE = UOCON; + } + else{ + FDebug(DBGLOG_NAME, 3, DBGLIST, NULL, NULL, 0); + retval = FAbort(BO); + if(retval < 0){ + return SYSTEM_FAILURE; + } + } + + return SUCCESS; +} + +/****************************************************************************** +* +* FUNCTION: +* +* int FConnectIndication(void) +* +* DESCRIPTION: +* +* Handles a connect request from the peer entity by sending the signal +* F_CONNECT_INDICATION to the service user and setting the internal state to +* under incoming connection. +* +* PARAMETERS: +* +* void -- None. +* +* RETURNS: +* +* int -- On success 0. +* -- Otherwise, -1. +* +* GLOBALS: +* +* PHYS_STATE specifies the internal state. +* SU_FD references the socket connected to the service user. +* DBGLIST contains all debug codes and their respective text messages. +* +* NOTE: +* +* If FConnectIndication() is called when the internal state is not set to +* idle, it will send an abort request to the peer entity and the service user +* and set the internal state to idle. +* +*/ + +#ifdef __STDC__ +int FConnectIndication(void) +#else + int FConnectIndication() +#endif +{ + int retval; + + FDebug(DBGLOG_NAME, 4, DBGLIST, NULL, NULL, 0); + if(PHYS_STATE == IDLE){ + FDebug(DBGLOG_NAME, 5, DBGLIST, NULL, NULL, 0); + retval = WriteSignaltoSocket(SU_FD, F_CONNECT_INDICATION, SIG_LEN); + if(retval < 0){ + return SYSTEM_FAILURE; + } + PHYS_STATE = UICON; + } + else{ + FDebug(DBGLOG_NAME, 3, DBGLIST, NULL, NULL, 0); + retval = FAbort(BO); + if(retval < 0){ + return SYSTEM_FAILURE; + } + } + + return SUCCESS; +} + +/****************************************************************************** +* +* FUNCTION: +* +* int FConnectResponse(void) +* +* DESCRIPTION: +* +* Handles a connect response from the service user by sending the signal +* CONNECTION_REQUEST_REPLY to the peer entity and setting the internal state +* to data transfer. +* +* PARAMETERS: +* +* void -- None. +* +* RETURNS: +* +* int -- On success 0. +* -- Otherwise, -1. +* +* GLOBALS: +* +* PHYS_STATE specifies the internal state. +* PE_FD references the socket connected to the peer entity. +* DBGLIST contains all debug codes and their respective text messages. +* +* NOTE: +* +* If FConnectResponse() is called when the internal state is set to idle, it +* will ignore the request. Otherwise, if called when the internal state is not +* set to under incoming connection, it will send an abort request to the peer +* entity and the service user and set the internal state to idle. +* +*/ + +#ifdef __STDC__ +int FConnectResponse(void) +#else + int FConnectResponse() +#endif +{ + int retval; + + FDebug(DBGLOG_NAME, 6, DBGLIST, NULL, NULL, 0); + if(PHYS_STATE == UICON){ + FDebug(DBGLOG_NAME, 7, DBGLIST, NULL, NULL, 0); + retval = WriteSignaltoSocket(PE_FD, CONNECTION_REQUEST_REPLY, SIG_LEN); + if(retval < 0){ + return SYSTEM_FAILURE; + } + PHYS_STATE = DATA; + } + else if(PHYS_STATE == IDLE){ + FDebug(DBGLOG_NAME, 8, DBGLIST, NULL, NULL, 0); + return IGNORE_SIGNAL; + } + else{ + FDebug(DBGLOG_NAME, 3, DBGLIST, NULL, NULL, 0); + retval = FAbort(BO); + if(retval < 0){ + return SYSTEM_FAILURE; + } + } + + return SUCCESS; +} + +/****************************************************************************** +* +* FUNCTION: +* +* int FConnectConfirm(void) +* +* DESCRIPTION: +* +* Handles a connect response from the peer entity by sending the signal +* F_CONNECT_CONFIRM to the service user and setting the internal state to data +* transfer. +* +* PARAMETERS: +* +* void -- None +* +* RETURNS: +* +* int -- On success 0. +* -- Otherwise, -1. +* +* GLOBALS: +* +* PHYS_STATE specifies the internal state. +* SU_FD references the socket connected to the service user. +* DBGLIST contains all debug codes and their respective text messages. +* +* NOTE: +* +* If FConnectConfirm() is called when the internal state is set to idle, it +* will ignore the request. Otherwise, if called when the internal state is not +* set to under outgoing connection, it will send an abort request to the peer +* entity and the service user and set the internal state to idle. +* +*/ + +#ifdef __STDC__ +int FConnectConfirm(void) +#else + int FConnectConfirm() +#endif +{ + int retval; + + FDebug(DBGLOG_NAME, 9, DBGLIST, NULL, NULL, 0); + if(PHYS_STATE == UOCON){ + FDebug(DBGLOG_NAME, 10, DBGLIST, NULL, NULL, 0); + retval = WriteSignaltoSocket(SU_FD, F_CONNECT_CONFIRM, SIG_LEN); + if(retval < 0){ + return SYSTEM_FAILURE; + } + PHYS_STATE = DATA; + } + else if(PHYS_STATE == IDLE){ + FDebug(DBGLOG_NAME, 8, DBGLIST, NULL, NULL, 0); + return IGNORE_SIGNAL; + } + else{ + FDebug(DBGLOG_NAME, 3, DBGLIST, NULL, NULL, 0); + retval = FAbort(BO); + if(retval < 0){ + return SYSTEM_FAILURE; + } + } + + return SUCCESS; +} + +/****************************************************************************** +* +* FUNCTION: +* +* int FDisconnectRequest(void) +* +* DESCRIPTION: +* +* Handles a disconnect request from the service user by sending the signal +* WANT_DISCONNECTION to the peer entity and setting the internal state to +* under outgoing connection. +* +* PARAMETERS: +* +* void -- None. +* +* RETURNS: +* +* int -- On success 0. +* -- Otherwise -1. +* +* GLOBALS: +* +* PHYS_STATE specifies the internal state. +* PE_FD is referencing the socket connected to the peer entity. +* DBGLIST contains all debug codes and their respective text messages. +* +* NOTE: +* +* If FDisconnectRequest() is called when the internal state is set to idle it +* will ignore the request. Otherwise if called when the internal state is not +* set to data transfer it will send an abort request to the peer entity and +* the service user and set the internal state to idle. +* +*/ + +#ifdef __STDC__ +int FDisconnectRequest(void) +#else + int FDisconnectRequest() +#endif +{ + int retval; + + FDebug(DBGLOG_NAME, 11, DBGLIST, NULL, NULL, 0); + if(PHYS_STATE == DATA){ + FDebug(DBGLOG_NAME, 12, DBGLIST, NULL, NULL, 0); + retval = WriteSignaltoSocket(PE_FD, WANT_DISCONNECTION, SIG_LEN); + if(retval < 0){ + return SYSTEM_FAILURE; + } + PHYS_STATE = UODCON; + } + else if(PHYS_STATE == IDLE){ + FDebug(DBGLOG_NAME, 8, DBGLIST, NULL, NULL, 0); + return IGNORE_SIGNAL; + } + else{ + FDebug(DBGLOG_NAME, 3, DBGLIST, NULL, NULL, 0); + retval = FAbort(BO); + if(retval < 0){ + return SYSTEM_FAILURE; + } + } + + return SUCCESS; +} + +/****************************************************************************** +* +* FUNCTION: +* +* int FDisconnectIndication(void) +* +* DESCRIPTION: +* +* Handles a disconnect request from the peer entity by sending the signal +* F_DISCONNECT_INDICATION to the service user and setting the internal state +* to under incoming disconnection. +* +* PARAMETERS: +* +* void -- None. +* +* RETURNS: +* +* int -- On success 0. +* -- Otherwise, -1. +* +* GLOBALS: +* +* PHYS_STATE specifies the internal state. +* SU_FD is referencing the socket connected to the service user. +* DBGLIST contains all debug codes and their respective text messages. +* +* NOTE: +* +* If FDisconnectIndication() is called when the internal state is set to idle, +* it will ignore the request. Otherwise, if called when the internal state is +* not set to data transfer, it will send an abort request to the peer entity +* and the service user and set the internal state to idle. +* +*/ + +#ifdef __STDC__ +int FDisconnectIndication(void) +#else + int FDisconnectIndication() +#endif +{ + int retval; + + FDebug(DBGLOG_NAME, 13, DBGLIST, NULL, NULL, 0); + if(PHYS_STATE == DATA){ + FDebug(DBGLOG_NAME, 14, DBGLIST, NULL, NULL, 0); + retval = WriteSignaltoSocket(SU_FD, F_DISCONNECT_INDICATION, SIG_LEN); + if(retval < 0){ + return SYSTEM_FAILURE; + } + PHYS_STATE = UIDCON; + } + else if(PHYS_STATE == IDLE){ + FDebug(DBGLOG_NAME, 8, DBGLIST, NULL, NULL, 0); + return IGNORE_SIGNAL; + } + else{ + FDebug(DBGLOG_NAME, 3, DBGLIST, NULL, NULL, 0); + retval = FAbort(BO); + if(retval < 0){ + return SYSTEM_FAILURE; + } + } + + return SUCCESS; +} + +/****************************************************************************** +* +* FUNCTION: +* +* int FDisconnectResponse(void) +* +* DESCRIPTION: +* +* Handles a disconnect request response from the service user by sending the +* signal DISCONNECTION_REQUEST_REPLY to the peer entity and setting the +* internal state to idle. +* +* PARAMETERS: +* +* void -- None. +* +* RETURNS: +* +* int -- On success 0. +* -- Otherwise, -1. +* +* GLOBALS: +* +* PHYS_STATE specifies the internal state. +* PE_FD references the socket connected to the peer entity. +* DBGLIST contains all debug codes and their respective text messages. +* +* NOTE: +* +* If FDisconnectResponse() is called when the internal state is set to idle, +* it will ignore the request. Otherwise, if called when the internal state is +* not set to under incoming disconnection, it will send an abort request to +* the peer entity and the service user and set the internal state to idle. +* +*/ + +#ifdef __STDC__ +int FDisconnectResponse(void) +#else + int FDisconnectResponse() +#endif +{ + int retval; + + FDebug(DBGLOG_NAME, 15, DBGLIST, NULL, NULL, 0); + if(PHYS_STATE == UIDCON){ + FDebug(DBGLOG_NAME, 16, DBGLIST, NULL, NULL, 0); + retval = WriteSignaltoSocket(PE_FD, DISCONNECTION_REQUEST_REPLY, \ + SIG_LEN); + if(retval < 0){ + return SYSTEM_FAILURE; + } + PHYS_STATE = IDLE; + } + else if(PHYS_STATE == IDLE){ + FDebug(DBGLOG_NAME, 8, DBGLIST, NULL, NULL, 0); + return IGNORE_SIGNAL; + } + else{ + FDebug(DBGLOG_NAME, 3, DBGLIST, NULL, NULL, 0); + retval = FAbort(BO); + if(retval < 0){ + return SYSTEM_FAILURE; + } + } + + return SUCCESS; +} + +/****************************************************************************** +* +* FUNCTION: +* +* int FDisconnectConfirm(void) +* +* DESCRIPTION: +* +* Handles a disconnect response from the peer entity by sending the signal +* F_DISCONNECT_CONFIRM to the service user and setting the internal state to +* idle. +* +* PARAMETERS: +* +* void -- None. +* +* RETURNS: +* +* int -- On success 0. +* -- Otherwise, -1. +* +* GLOBALS: +* +* PHYS_STATE specifies the internal state. +* SU_FD references the socket connected to the service user. +* DBGLIST contains all debug codes and their respective text messages. +* +* NOTE: +* +* If FDisconnectConfirm() is called and the internal state is set to idle, it +* will ignore the request. Otherwise, if called when the internal state is not +* set to under outgoing disconnection, it will send an abort request to the +* peer entity and the service user and set the internal state to idle. +* +*/ + +#ifdef __STDC__ +int FDisconnectConfirm(void) +#else + int FDisconnectConfirm() +#endif +{ + int retval; + + FDebug(DBGLOG_NAME, 17, DBGLIST, NULL, NULL, 0); + if(PHYS_STATE == UODCON){ + FDebug(DBGLOG_NAME, 18, DBGLIST, NULL, NULL, 0); + retval = WriteSignaltoSocket(SU_FD, F_DISCONNECT_CONFIRM, SIG_LEN); + if(retval < 0){ + return SYSTEM_FAILURE; + } + PHYS_STATE = IDLE; + } + else if(PHYS_STATE == IDLE){ + FDebug(DBGLOG_NAME, 8, DBGLIST, NULL, NULL, 0); + return IGNORE_SIGNAL; + } + else{ + FDebug(DBGLOG_NAME, 3, DBGLIST, NULL, NULL, 0); + retval = FAbort(BO); + if(retval < 0){ + return SYSTEM_FAILURE; + } + } + + return SUCCESS; +} + +/****************************************************************************** +* +* FUNCTION: +* +* int FDataRequest(void) +* +* DESCRIPTION: +* +* Handles a data request from the service user by accepting a byte of data and +* transmitting that byte to the peer entity, using the signal INCOMING_DATA. +* +* PARAMETERS: +* +* void -- None. +* +* RETURNS: +* +* int -- On success 0. +* -- Otherwise, -1. +* +* GLOBALS: +* +* PHYS_STATE specifies the internal state. +* PE_FD is referencing the socket connected to the peer entity. +* SU_FD is referencing the socket connected to the service user. +* FAULT_PROBABILITY specifies the probability that a byte will get corrupted. +* DELAY_PROBABILITY specifies the probability of a transmission delay. +* LOSEBYTE_PROBABILITY specifies the probability of loosing a byte. +* DBGLIST contains all debug codes and their respective text messages. +* +* NOTE: +* +* If FDataRequest() is called when the internal state is set to idle it will +* ignore the request. Otherwise if called when the internal state is not set +* to transfer data it will send an abort request to the peer entity and the +* service user and set the internal state to idle. +* +*/ + +#ifdef __STDC__ +int FDataRequest(void) +#else + int FDataRequest() +#endif +{ + int retval; + char databuf; + + /* + We always read data from the socket to make sure that no pending data + exists in the socket buffer if we start a new session. + */ + retval = ReadDatafromSocket(SU_FD, &databuf, BYTE_LEN); + if(retval < 0){ + return SYSTEM_FAILURE; + } + FDebug(DBGLOG_NAME, 19, DBGLIST, &databuf, INT_FORMAT, BYTE_LEN); + if(PHYS_STATE == DATA){ + /* The byte of data might get lost. */ + retval = LoseByte(LOSEBYTE_PROBABILITY); + if(retval == BYTETRANSMITTED){ + + /* + If the byte is not lost we introduce delays and noice on the line. + */ + CreateNoice(FAULT_PROBABILITY, &databuf); + CreateDelays(DELAY_PROBABILITY, DELAYTIME); + FDebug(DBGLOG_NAME, 20, DBGLIST, NULL, NULL, 0); + retval = WriteSignaltoSocket(PE_FD, INCOMING_DATA, SIG_LEN); + if(retval < 0){ + return SYSTEM_FAILURE; + } + retval = WriteDatatoSocket(PE_FD, &databuf, BYTE_LEN); + fprintf(stderr, "databuf = %d", databuf); + if(retval < 0){ + return SYSTEM_FAILURE; + } + } + else{ + FDebug(DBGLOG_NAME, 28, DBGLIST, NULL, NULL, 0); + } + } + else if(PHYS_STATE == IDLE){ + FDebug(DBGLOG_NAME, 8, DBGLIST, NULL, NULL, 0); + return IGNORE_SIGNAL; + } + else{ + FDebug(DBGLOG_NAME, 3, DBGLIST, NULL, NULL, 0); + retval = FAbort(BO); + if(retval < 0){ + return SYSTEM_FAILURE; + } + } + + return SUCCESS; +} + +/****************************************************************************** +* +* FUNCTION: +* +* int FDataIndication(void) +* +* DESCRIPTION: +* +* Handles a data request from the peer entity by accepting a byte of data and +* transmitting that byte to the service user, using the signal +* F_DATA_INDICATION. +* +* PARAMETERS: +* +* void -- None. +* +* RETURNS: +* +* int -- On success 0. +* -- Otherwise -1. +* +* GLOBALS: +* +* PHYS_STATE specifies the internal state. +* PE_FD references the socket connected to the peer entity. +* SU_FD references the socket connected to the service user. +* DBGLIST contains all debug codes and their respective text messages. +* +* NOTE: +* +* If FDataIndication() is called when the internal state is set to idle it +* will ignore the request. Otherwise if called when the internal state is not +* in state data transfer it will send an abort request to the peer entity and +* the service user and set the internal state to idle. +* +*/ + +#ifdef __STDC__ +int FDataIndication(void) +#else + int FDataIndication() +#endif +{ + int retval; + char databuf; + + /* + We always read data from the socket to make sure that no pending data + exists in the socket buffer if we start a new session. + */ + retval = ReadDatafromSocket(PE_FD, &databuf, BYTE_LEN); + if(retval < 0){ + return SYSTEM_FAILURE; + } + fprintf(stderr, "databuf2 = %d", databuf); + FDebug(DBGLOG_NAME, 21, DBGLIST, &databuf, INT_FORMAT, BYTE_LEN); + if(PHYS_STATE == DATA){ + FDebug(DBGLOG_NAME, 22, DBGLIST, NULL, NULL, 0); + retval = WriteSignaltoSocket(SU_FD, F_DATA_INDICATION, SIG_LEN); + if(retval < 0){ + return SYSTEM_FAILURE; + } + retval = WriteDatatoSocket(SU_FD, &databuf, BYTE_LEN); + fprintf(stderr, "sending data = %d", databuf); + if(retval < 0){ + return SYSTEM_FAILURE; + } + } + else if(PHYS_STATE == IDLE){ + FDebug(DBGLOG_NAME, 8, DBGLIST, NULL, NULL, 0); + return IGNORE_SIGNAL; + } + else{ + FDebug(DBGLOG_NAME, 3, DBGLIST, NULL, NULL, 0); + retval = FAbort(BO); + if(retval < 0){ + return SYSTEM_FAILURE; + } + } + + return SUCCESS; +} + +/****************************************************************************** +* +* FUNCTION: +* +* int FAbortRequest(void) +* +* DESCRIPTION: +* +* Handles an abort request from the service user by sending the signal ABORT +* to the peer entity and setting the internal state to idle. +* +* PARAMETERS: +* +* void -- None. +* +* RETURNS: +* +* int -- On success 0. +* -- Otherwise, -1. +* +* GLOBALS: +* +* PHYS_STATE specifies the internal state. +* PE_FD references the socket connected to the peer entity. +* DBGLIST contains all debug codes and their respective text messages. +* +* NOTE: +* +* If the internal state is set to idle, FAbortRequest() will ignore the +* request. +* +*/ + +#ifdef __STDC__ +int FAbortRequest(void) +#else + int FAbortRequest() +#endif +{ + int retval; + + FDebug(DBGLOG_NAME, 23, DBGLIST, NULL, NULL, 0); + if(PHYS_STATE == IDLE){ + FDebug(DBGLOG_NAME, 8, DBGLIST, NULL, NULL, 0); + return IGNORE_SIGNAL; + } + else{ + FDebug(DBGLOG_NAME, 24, DBGLIST, NULL, NULL, 0); + retval = FAbort(PE); + if(retval < 0){ + return SYSTEM_FAILURE; + } + + return SUCCESS; + } +} + +/****************************************************************************** +* +* FUNCTION: +* +* int FAbortIndication(void) +* +* DESCRIPTION: +* +* Handles an abort request from the peer entity by sending the signal +* F_ABORT_INDICATION to the service user and setting the internal state to +* idle. +* +* PARAMETERS: +* +* void -- None. +* +* RETURNS: +* +* int -- On success 0. +* -- Otherwise, -1. +* +* GLOBALS: +* +* PHYS_STATE specifies the internal state. +* SU_FD is referencing the socket connected to the service user. +* DBGLIST contains all debug codes and their respective text messages. +* +* NOTE: +* +* If the internal state is set to idle FAbortIndication() will ignore the +* request. +* +*/ + +#ifdef __STDC__ +int FAbortIndication(void) +#else + int FAbortIndication() +#endif +{ + int retval; + + FDebug(DBGLOG_NAME, 25, DBGLIST, NULL, NULL, 0); + if(PHYS_STATE == IDLE){ + FDebug(DBGLOG_NAME, 8, DBGLIST, NULL, NULL, 0); + return IGNORE_SIGNAL; + } + else{ + FDebug(DBGLOG_NAME, 26, DBGLIST, NULL, NULL, 0); + retval = FAbort(SU); + if(retval < 0){ + return SYSTEM_FAILURE; + } + } + + return SUCCESS; +} + +/****************************************************************************** +* +* FUNCTION: +* +* int FAbort(abortdst dst) +* +* DESCRIPTION: +* +* Sends an abort request to either the peer entity, the service user or both +* depending on the value specified by the parameter `dst', and sets the +* internal state to idle. +* +* PARAMETERS: +* +* abortdst dst -- The destination of the abort. +* +* RETURNS: +* +* int -- On success 0. +* -- Otherwise, -1. +* +* GLOBALS: +* +* PHYS_STATE specifies the internal state. +* PE_FD references the socket connected to the peer entity. +* SU_FD references the socket connected to the service user. +* +* NOTE: +* +*/ + +#ifdef __STDC__ +int FAbort(abortdst dst) +#else + int FAbort(abortdst) + abortdst dst; +#endif +{ + int retval; + + if((dst == SU) || (dst == BO)){ + retval = WriteSignaltoSocket(SU_FD, F_ABORT_INDICATION, SIG_LEN); + if(retval < 0){ + return SYSTEM_FAILURE; + } + } + if((dst == PE) || (dst == BO)){ + retval = WriteSignaltoSocket(PE_FD, ABORT, SIG_LEN); + if(retval < 0){ + return SYSTEM_FAILURE; + } + } + PHYS_STATE = IDLE; + + return SUCCESS; +} + +/****************************************************************************** +* +* FUNCTION: +* +* int FSystemError(void) +* +* DESCRIPTION: +* +* To be able to catch a system error when finding the correct function +* corresponding to a signal in FindAction(), FSystemError() just returns -1 +* since every signal corresponds to a function and FindAction() has to return +* a pointer to a function a signal can't be returned to the calling +* environment unless its corresponding function does the job. +* +* PARAMETERS: +* +* void -- None. +* +* RETURNS: +* +* int -- Always -1. +* +* NOTE: +* +*/ + +#ifdef __STDC__ +int FSystemError(void) +#else + int FSystemError() +#endif +{ + return SYSTEM_FAILURE; +} + +/****************************************************************************** +* +* FUNCTION: +* +* int FDefault(void) +* +* DESCRIPTION: +* +* The default function used in FindAction() as a break condition to make sure +* FindAction() won't go into an infinite loop. FDefault() is invoked when +* FindAction() encounters an undefined signal and FDefault() sends an abort +* request to the peer entity and the service user. +* +* PARAMETERS: +* +* void -- None. +* +* RETURNS: +* +* int -- On success 0. +* -- Otherwise, -1. +* +* GLOBALS: +* +* DBGLIST contains all debug codes and their respective text messages. +* +* NOTE: +* +*/ + +#ifdef __STDC__ +int FDefault(void) +#else + int FDefault() +#endif +{ + int retval; + + FDebug(DBGLOG_NAME, 27, DBGLIST, NULL, NULL, 0); + if(PHYS_STATE == IDLE){ + FDebug(DBGLOG_NAME, 8, DBGLIST, NULL, NULL, 0); + return IGNORE_SIGNAL; + } + else{ + FDebug(DBGLOG_NAME, 3, DBGLIST, NULL, NULL, 0); + retval = FAbort(BO); + if(retval < 0){ + return SYSTEM_FAILURE; + } + } + + return SUCCESS; +} + +/****************************************************************************** +* +* FUNCTION: +* +* void FDbgPESocketEventHandler(void_ptr_ clientData, int mask) +* +* DESCRIPTION: +* +* This function is passed to SetFDbgSocketEventHandler() together with the +* socket file descriptor PE_FD. When the socket becomes available for reading +* this function will be invoked. +* +* PARAMETERS: +* +* void_ptr_ clientData -- ?. +* int mask -- ?. +* +* RETURNS: +* +* void -- Nothing. +* +* GLOBALS: +* +* PE_FD references the socket connected to the service user. +* ALIST contains all signals and their respective function. +* ERRLIST contains all error codes and their respective text messages. +* +* NOTE: +* +* The function passed to SetFDbgSocketEventHandler() needs two in-parameters. +* The first must be of type void pointer and the second of type int. +* +*/ + +#ifdef __STDC__ +void FDbgPESocketEventHandler(void_ptr_ clientData, int mask) +#else + void FDbgPESocketEventHandler(clientData, mask) + void_ptr_ clientData; + int mask; +#endif +{ + int retval; + + retval = (* FindAction(ReadSignalfromSocket(PollSocket(PE_FD, SU_FD, NULL) \ + - 1 , SIG_LEN), ALIST))(); + if(retval < 0){ + ErrorHandler(FindErrMsgStr(3, ERRLIST)); + return ; + } + + return ; +} + +/****************************************************************************** +* +* FUNCTION: +* +* void FDbgSUSocketEventHandler(void_ptr_ clientData, int mask) +* +* DESCRIPTION: +* +* This function is passed to SetFDbgSocketEventHandler() together with the +* socket file descriptor SU_FD. When the socket becomes available for reading +* this function will be invoked. +* +* PARAMETERS: +* +* void_ptr_ clientData -- ?. +* int mask -- ?. +* +* RETURNS: +* +* void -- Nothing. +* +* GLOBALS: +* +* PE_FD references the socket connected to the service user. +* ALIST contains all signals and their respective function. +* ERRLIST contains all error codes and their respective text messages. +* +* NOTE: +* +* The function passed to SetFDbgSocketEventHandler() needs two in-parameters. +* The first must be of type void pointer and the second of type int. +* +*/ + +#ifdef __STDC__ +void FDbgSUSocketEventHandler(void_ptr_ clientData, int mask) +#else + void FDbgSUSocketEventHandler(clientData, mask) + void_ptr_ clientData; + int mask; +#endif +{ + int retval; + + retval = (* FindAction(ReadSignalfromSocket(SU_FD, SIG_LEN), ALIST))(); + if(retval < 0){ + ErrorHandler(FindErrMsgStr(3, ERRLIST)); + return ; + } + + return ; +} + +/****************************************************************************** +* +* FUNCTION: +* +* void CleanUp(void) +* +* DESCRIPTION: +* +* Closes all global socket file descriptors and removes all related files. +* +* PARAMETERS: +* +* void -- None. +* +* RETURNS: +* +* void -- Nothing. +* +* GLOBALS: +* +* PATH is the file to which the socket connected to the service user, is +* bound. +* TMP_FD references the temporary socket needed when creating a server socket. +* PE_FD references the socket connected to the peer entity. +* SU_FD references the socket connected to the service user. +* +* NOTE: +* +*/ + +#ifdef __STDC__ +void CleanUp(void) +#else + void CleanUp() +#endif +{ + /* + We don't test any return values since this function is called just before + we exit the program so if we fail in closing any file descriptors we hope + that exit() will do it for us. + */ + unlink(F_PATH); + CloseFile(TMP_FD); + CloseFile(PE_FD); + CloseFile(SU_FD); + + return ; +} + +/****************************************************************************** +* +* FUNCTION: +* +* void ErrorHandler(str_ptr_ errormsg) +* +* DESCRIPTION: +* +* Handles system errors. If possible it logs the error specified by the +* character string parameter `errormsg', closes all global socket file +* descriptors, removes all related files and kills all processes in the same +* process group before it exits. +* +* PARAMETERS: +* +* str_ptr_ errormsg -- Pointer to a character string containing the error +* -- message that will be written to the log. +* +* RETURNS: +* +* void -- Nothing. +* +* GLOBALS: +* +* FATAL_ERROR_IN_PROGRESS indicates if a fatal error is in progress or not. +* ERRLIST contains all error codes and their respective text messages. +* +* NOTE: +* +*/ + +#ifdef __STDC__ +void ErrorHandler(string_ptr_ errmsg) +#else + void ErrorHandler(errmsg) + string_ptr_ errmsg; +#endif +{ + /* + FATAL_ERROR_IN_PROGRES works as a semaphore to prevent that a signal + is catched while we are terminating the program. + */ + FATAL_ERROR_IN_PROGRESS = 1; + + /* + We don't test any return values since this function is called just before + we exit the program so there is no need to take care of system failures + at this point. + */ + LogError(ERRLOG_NAME, errmsg); + CleanUp(); + kill(PROCESS_GROUP, SIGINT); + exit(NON_NORMAL_EXIT); + + return ; +} + +/****************************************************************************** +* +* FUNCTION: +* +* int InitSignalHandler(void (* handler)(int)) +* +* DESCRIPTION: +* +* Sets the signals SIGINT, SIGHUP, SIGQUIT and SIGTERM desposition, which is a +* pointer to a function taking an int and returning nothing. +* +* PARAMETERS: +* +* void (* handler)(int) -- Pointer to a function that takes an int and +* -- returns nothing, which is the signal handler +* -- that will be invoked when one of the signals +* -- are raised. +* +* RETURNS: +* +* int -- On success 0. +* -- Otherwise, -1. +* +* NOTE: +* +*/ + +#ifdef __STDC__ +int InitSignalHandler(void (* handler) __P((int))) +#else + int InitSignalHandler(handler) + void (* handler) __P((int)); +#endif +{ + if(SetSignalHandler(SIGINT, handler) < 0){ + return SYSTEM_FAILURE; + } + if(SetSignalHandler(SIGHUP, handler) < 0){ + return SYSTEM_FAILURE; + } + if(SetSignalHandler(SIGTERM, handler) < 0){ + return SYSTEM_FAILURE; + } + if(SetSignalHandler(SIGQUIT, handler) < 0){ + return SYSTEM_FAILURE; + } + + return SUCCESS; +} + +/****************************************************************************** +* +* FUNCTION: +* +* void SignalHandler(int signum) +* +* DESCRIPTION: +* +* Handles system signals. If a signal set by InitSignalHandler() is raised +* SignalHandler() catches that signal and if possible closes all global socket +* file descriptors, removes all related files and kills all processes in the +* same process group before it raises the signal again and lets the system +* handle the exit in it's default manner. +* +* PARAMETERS: +* +* int signum -- The signal that was catched. +* +* RETURNS: +* +* void -- Nothing. +* +* GLOBALS: +* +* FATAL_ERROR_IN_PROGRESS indicates if a fatal error is in progress or not. +* +* NOTE: +* +* `signum' is set to the value of the signal that was catched, automatically +* by the system. +* +*/ + +#ifdef __STDC__ +void SignalHandler(int signum) +#else + void SignalHandler(signum) + int signum; +#endif +{ + /* + FATAL_ERROR_IN_PROGRESS works as a semaphore preventing that several + signals will be catched at the same time. If it is set we just raise + the signal again and continue the termination of the program. + */ + if(FATAL_ERROR_IN_PROGRESS){ + raise(signum); + } + FATAL_ERROR_IN_PROGRESS = 1; + + /* + We don't test any return values since this function is called just before + we exit the program so there is no need to take care of system failures + at this point. + */ + CleanUp(); + + /* Set the signal's desposition to the default signal handler. */ + if(SetSignalHandler(signum, SIG_DFL) < 0){ + exit(NON_NORMAL_EXIT); + } + kill(PROCESS_GROUP, SIGINT); + if(raise(signum) < 0){ + exit(NON_NORMAL_EXIT); + } + + return ; +} + +/****************************************************************************** +* +* FUNCTION: +* +* void MainLoop(void) +* +* DESCRIPTION: +* +* Creates a client socket in the UNIX domain which will connect to the server +* socket bound to the file specified by the character-string parameter `path'. +* Then it will poll the socket connected to the peer entity and the socket +* connected to the service user for signals and take actions depending on the +* value of the signal inside an infinite loop. +* +* PARAMETERS: +* +* void -- None. +* +* RETURNS: +* +* void -- Nothing. +* +* GLOBALS: +* +* PE_FD references the socket connected to the peer entity. +* SU_FD references the socket connected to the service user. +* ALIST contains all signals and their respective function. +* ERRLIST contains all error codes and their respective text messages. +* +* NOTE: +* +*/ + +#ifdef __STDC__ +void MainLoop(void) +#else + void MainLoop() +#endif +{ + int retval; + + SU_FD = CreateUnixClientSocket(F_PATH); + if(SU_FD < 0){ + ErrorHandler(FindErrMsgStr(1, ERRLIST)); + return ; + } + SetFDbgSocketEventHandler(PE_FD, FDbgPESocketEventHandler); + SetFDbgSocketEventHandler(SU_FD, FDbgPESocketEventHandler); + FDbgMainLoop(); + /* + All actions are taken place in an infinite loop (gag) and execution has + to be terminated implicitly by the user by pressing CTRL D. We do this + since we simulate a peer to peer connection and we don't want to break + the socket connections everytime we start a new ( abstract ) connection + with the peer entity and the service user. + */ + do{ + retval = PollSocket(PE_FD, SU_FD, NULL); + if(retval < 0){ + ErrorHandler(FindErrMsgStr(9, ERRLIST)); + return ; + } + /* + We don't test the return value since a system failure will be + caught by FindAction. + */ + retval = ReadSignalfromSocket(retval - 1, SIG_LEN); + retval = (* FindAction(retval, ALIST))(); + if(retval < 0){ + ErrorHandler(FindErrMsgStr(3, ERRLIST)); + return ; + } + }while(retval >= 0); + + return ; +} + +/****************************************************************************** +* +* FUNCTION: +* +* void Server(int port) +* +* DESCRIPTION: +* +* Creates a server socket in the INET domain. The socket will listen for +* incoming connections on the port specified by the parameter `port'. Incoming +* connections are accepted and controll is passed to the main loop. +* +* PARAMETERS: +* +* int port -- Port on which the socket will listen for incoming +* -- connections. +* +* RETURNS: +* +* void -- Nothing. +* +* GLOBALS: +* +* TMP_FD references the temporary socket needed when creating a server socket. +* PE_FD references the socket that will connect to the peer entity. +* ERRLIST contains all error codes and their respective text messages. +* +* NOTE: +* +*/ + +#ifdef __STDC__ +void Server(int port) +#else + void Server(port) + int port; +#endif +{ + TMP_FD = CreateInetServerSocket(port); + if(TMP_FD < 0){ + ErrorHandler(FindErrMsgStr(5, ERRLIST)); + return ; + } + PE_FD = AcceptConnection(TMP_FD); + if(PE_FD < 0){ + ErrorHandler(FindErrMsgStr(6, ERRLIST)); + return ; + } + MainLoop(); + + return ; +} + +/****************************************************************************** +* +* FUNCTION: +* +* void Client(int port, string_ptr_ serv_id) +* +* DESCRIPTION: +* +* Creates a client socket in the INET domain which tries to connect to the +* port specified by the parameter `port' on the host specified by the +* character string parameter `serv_id' and then controll is passed to the main +* loop. +* +* PARAMETERS: +* +* int port -- Port which the socket will connect to. +* string_ptr_ serv_id -- Pointer to a character-string containing the +* -- hosts name or the hosts IP address. +* +* RETURNS: +* +* void -- Nothing. +* +* GLOBALS: +* +* PE_FD references the socket that will connect to the peer entity. +* ERRLIST contains all error codes and their respective text messages. +* +* NOTE: +* +*/ + +#ifdef __STDC__ +void Client(int port, string_ptr_ serv_id) +#else + void Client(port, serv_id) + int port; + string_ptr_ serv_id; +#endif +{ + PE_FD = CreateInetClientSocket(port, serv_id); + if(PE_FD < 0){ + ErrorHandler(FindErrMsgStr(7, ERRLIST)); + return ; + } + MainLoop(); + + return ; +} + +/****************************************************************************** +* +* FUNCTION: +* +* void main(int argc, char *argv[]) +* +* DESCRIPTION: +* +* The main program. Starts as server or client depending on the number +* of arguments given in the command line. +* +* PARAMETERS: +* +* int argc -- The number of arguments. +* char *argv[] -- Array of pointers to character strings. Every string is +* -- associated with one command line argument. +* +* RETURNS: +* +* void -- Nothing. +* +* GLOBALS: +* +* FAULT_PROBABILITY specifies the probability that a byte will get corrupted. +* DELAY_PROBABILITY specifies the probability of a transmission delay. +* LOSEBYTE_PROBABILITY specifies the probability of loosing a byte. +* ERRLIST contains all error codes and their respective text messages. +* +* NOTE: +* +*/ + +#ifdef __STDC__ +void main(int argc, char *argv[]) +#else + void main(argc, argv) + int argc; + char *argv[]; +#endif +{ + int retval, port; + + unlink(ERRLOG_NAME); + unlink(DBGLOG_NAME); + InitFDbg(&argc, argv); + CreateFDbgWindow(); + CreateFDbgHelpDbase(); + CreateFDbgHelpDbaseBrowser(); + if((argc != SERVER) && (argc != CLIENT)){ + ErrorHandler(FindErrMsgStr(9, ERRLIST)); + return ; + } + retval = InitSignalHandler(SignalHandler); + if(retval < 0){ + ErrorHandler(FindErrMsgStr(8, ERRLIST)); + return ; + } + FAULT_PROBABILITY = atof(argv[argc - RELFAULTPOS]); + retval = ValidateProbability(FAULT_PROBABILITY); + if(retval == INVALID){ + ErrorHandler(FindErrMsgStr(4, ERRLIST)); + return ; + } + DELAY_PROBABILITY = atof(argv[argc - RELDELAYPOS]); + retval = ValidateProbability(DELAY_PROBABILITY); + if(retval == INVALID){ + ErrorHandler(FindErrMsgStr(4, ERRLIST)); + return ; + } + LOSEBYTE_PROBABILITY = atof(argv[argc - RELLOSEBYTEPOS]); + retval = ValidateProbability(LOSEBYTE_PROBABILITY); + if(retval == INVALID){ + ErrorHandler(FindErrMsgStr(4, ERRLIST)); + return ; + } + port = atoi(argv[PORTPOS]); + if((port > MAX_PORT) || (port < MIN_PORT)){ + ErrorHandler(FindErrMsgStr(2, ERRLIST)); + return ; + } + if(argc == SERVER){ + Server(port); + } + else if(argc == CLIENT){ + Client(port, argv[HOSTNAMEPOS]); + } + + return; +} + +/****************************************************************************** +* END +*/ + + + + diff --git a/physlayer.h b/physlayer.h new file mode 100644 index 0000000..8c47195 --- /dev/null +++ b/physlayer.h @@ -0,0 +1,96 @@ +/****************************************************************************** +* +* (c) Copyright 1998, University of Karlstad. +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 1, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +* Please report any bugs you find in this code or any improvements to: +* +* Hans Hedbom, Dept. of Computer Science, +* University of Karlstad, Sweden. +* +* Phone: +46 54 838157 +* E-mail: Hans.Hedbom@hks.se +* +* ============================================================================ +* +* FILE: +* +* physlayer.h [ the Data Communication I course programming project ] +* +* AUTHORS: +* +* Jonny Wiederholm +* E-mail: fr7wied@cse.hks.se or +* jonnwied@hks.se +* +* Per-Ola Gustafsson +* E-mail: fr7gust@cse.hks.se +* +* CREATION DATE: +* +* Jan, 08, 1998 +* +* DESCRIPTION: +* +* Includes constants used in the implementation of the Physical Layer, which +* is part of the example implementation of the Data Communication I course +* programming project. +* +* MODIFICATIONS: Date Changes +* ---------------------------------------------------------------------------- +* +*/ + +#ifndef _PHYSLAYER_H /* Avoid multiple copies of this file. */ +#define _PHYSLAYER_H + +#ifdef __cplusplus /* Make this file possible to use in C++ code. */ +extern "C" { +#endif + +/****************************************************************************** +* INCLUDE FILES +*/ + +#include "systems.h" + +/****************************************************************************** +* DEFINE CONSTANTS +*/ + +/* Byte length. */ +#define BYTE_LEN 1 + +/* + Primitives (signals) not visible to the service user. The service user will + only be able to access these primitives via function calls. + */ +#define F_CONNECT_REQUEST 100 +#define F_CONNECT_RESPONSE 104 +#define F_DISCONNECT_REQUEST 108 +#define F_DISCONNECT_RESPONSE 112 +#define F_DATA_REQUEST 116 +#define F_ABORT_REQUEST 188 + +/****************************************************************************** +* END +*/ + +#ifdef __cplusplus +} +#endif + +#endif /* _PHYSLAYER_H */ diff --git a/signal_prim.h b/signal_prim.h new file mode 100644 index 0000000..b28561d --- /dev/null +++ b/signal_prim.h @@ -0,0 +1,48 @@ +#ifndef ___SIGNAL_PRIM___ +#define ___SIGNAL_PRIM___ + +#define L_Con_Req 401 +#define L_Con_Ind 402 +#define L_Con_Resp 403 +#define L_Con_Conf 404 +#define L_Data_Req 405 +#define L_Data_Ind 406 +#define L_Disc_Req 407 +#define L_Disc_Resp 408 +#define L_Disc_Ind 409 +#define L_Disc_Conf 410 +#define L_Abort_Req 411 +#define L_Abort_Ind 412 +#define L_Status 413 + +#define AF_Con_Req 201 +#define AF_Con_Ind 202 +#define AF_Con_Resp 203 +#define AF_Con_Conf 204 +#define AF_Data_Req 205 +#define AF_Data_Ind 206 +#define AF_Disc_Req 207 +#define AF_Disc_Ind 208 +#define AF_Disc_Resp 209 +#define AF_Disc_Conf 210 +#define AF_Rej_Req 211 +#define AF_Rej_Ind 212 +#define AF_Rej_Resp 213 +#define AF_Rej_Conf 214 +#define AF_Abort_Req 215 +#define AF_Abort_Ind 216 + +#define AI_Con_Req 301 +#define AI_Con_Ind 302 +#define AI_Con_Resp 303 +#define AI_Con_Conf 304 +#define AI_Data_Req 305 +#define AI_Data_Ind 306 +#define AI_Disc_Req 307 +#define AI_Disc_Ind 308 +#define AI_Disc_Resp 309 +#define AI_Disc_Conf 310 +#define AI_Abort_Req 311 +#define AI_Abort_Ind 312 + +#endif diff --git a/socketio.h b/socketio.h new file mode 100644 index 0000000..e7f9226 --- /dev/null +++ b/socketio.h @@ -0,0 +1,94 @@ +/****************************************************************************** +* +* (c) Copyright 1998, University of Karlstad. +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 1, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +* Please report any bugs you find in this code or any improvements to: +* +* Hans Hedbom, Dept. of Computer Science, +* University of Karlstad, Sweden. +* +* Phone: +46 54 838157 +* E-mail: Hans.Hedbom@hks.se +* +* ============================================================================ +* +* FILE: +* +* socketio.h [ the Data Communication I course programming project ] +* +* AUTHORS: +* +* Jonny Wiederholm +* E-mail: fr7wied@cse.hks.se or +* jonnwied@hks.se +* +* Per-Ola Gustafsson +* E-mail: fr7gust@cse.hks.se +* +* CREATION DATE: +* +* Jan, 05, 1998 +* +* DESCRIPTION: +* +* Includes declarations of functions needed to handle input and output to +* sockets in the example implementation of the Data Communication I course +* programming project. +* +* MODIFICATIONS: Date Changes +* +* ---------------------------------------------------------------------------- +* +*/ + +#ifndef _SOCKETIO_H /* Avoid multiple copies of this file. */ +#define _SOCKETIO_H + +#ifdef __cplusplus /* Make this file possible to use in C++ code. */ +extern "C" { +#endif + +/****************************************************************************** +* INCLUDE FILES +*/ + +#include "systems.h" +#include "udefs.h" + +/****************************************************************************** +* DECLARE FUNCTIONS +*/ + +/* See function definitions for documentation. */ + +extern int WriteSignaltoSocket __P((int sockfd, u_int_ signal, \ + size_t_ siglen)); +extern int ReadSignalfromSocket __P((int sockfd, size_t_ siglen)); +extern int WriteDatatoSocket __P((int sockfd, c_buf_ptr_ databuf, \ + size_t_ datalen)); +extern int ReadDatafromSocket __P((int sockfd, buf_ptr_ databuf, \ + size_t_ datalen)); + +/****************************************************************************** +* END +*/ + +#ifdef __cplusplus +} +#endif + +#endif /* _SOCKETIO_H */ diff --git a/sockets.h b/sockets.h new file mode 100644 index 0000000..f6e0d68 --- /dev/null +++ b/sockets.h @@ -0,0 +1,132 @@ +/****************************************************************************** +* +* (c) Copyright 1998, University of Karlstad. +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 1, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +* Please report any bugs you find in this code or any improvements to: +* +* Hans Hedbom, Dept. of Computer Science, +* University of Karlstad, Sweden. +* +* Phone: +46 54 838157 +* E-mail: Hans.Hedbom@hks.se +* +* ============================================================================ +* +* FILE: +* +* sockets.h [ the Data Communication I course programming project ] +* +* AUTHORS: +* +* Jonny Wiederholm +* E-mail: fr7wied@cse.hks.se or +* jonnwied@hks.se +* +* Per-Ola Gustafsson +* E-mail: fr7gust@cse.hks.se +* +* CREATION DATE: +* +* Jan, 06, 1998 +* +* DESCRIPTION: +* +* Includes constants, types and declarations of functions needed to create +* and connect sockets in the example implementation of the Data Communication +* I course programming project. +* +* MODIFICATIONS: Date Changes +* ---------------------------------------------------------------------------- +* +*/ + +#ifndef _SOCKETS_H /* Avoid multiple copies of this file. */ +#define _SOCKETS_H + +#ifdef __cplusplus /* Make this file possible to use in C++ code. */ +extern "C" { +#endif + +/****************************************************************************** +* INCLUDE FILES +*/ + +#include "systems.h" +#include "udefs.h" + +/****************************************************************************** +* DEFINE CONSTANTS +*/ + +#if defined (_AIX) || defined (__linux__) + +/* Communication semantics. */ +#define SOCK_STREAM 1 /* Stream socket. */ + +#elif defined (sun) + +#define SOCK_STREAM 2 + +#endif + +/* Communication domains. */ +#define AF_UNIX 1 /* Local to host (pipes, portals). */ +#define AF_INET 2 /* Internetwork: UDP, TCP, etc. */ + +/****************************************************************************** +* DEFINE TYPES +*/ + +#if defined (__linux__) || defined (sun) + +/* Structure used by kernel to store most addresses. */ +struct sockaddr { + unsigned short int sa_family; /* Address family AF_xxx. */ + char sa_data[14]; /* 14 bytes of protocol address. */ +}; + +#elif defined (_AIX) + +struct sockaddr { + unsigned char sa_len; /* Total length. */ + unsigned char sa_family; /* Address family AF_xxx. */ + char sa_data[14]; /* 14 bytes of protocol address. */ +}; + +#endif /* defined (__linux__) || defined (sun) */ + +/***************************************************************************** +* DECLARE FUNCTIONS +*/ + +/* See function definitions for documentation. */ + +extern int CreateSocket __P((int domain, int type, int protocol)); +extern int BindSocket __P((int sockfd, struct sockaddr *name, int namelen)); +extern int ConnectSocket __P((int sockfd, struct sockaddr *name, int namelen)); +extern int ListenforConnection __P((int sockfd, int limit)); +extern int AcceptConnection __P((int sockfd)); + +/****************************************************************************** +* END +*/ + +#ifdef __cplusplus +} +#endif + +#endif /* _SOCKETS_H */ diff --git a/state.h b/state.h new file mode 100644 index 0000000..b1f5cd5 --- /dev/null +++ b/state.h @@ -0,0 +1,12 @@ +#ifndef _state_h_ +#define _state_h_ + +#define IDLE 0 +#define UUUK 1 +#define DATA 2 +#define UUNK 3 +#define UINK 4 +#define UIUK 5 +#define TERR 6 + +#endif diff --git a/student.h b/student.h new file mode 100644 index 0000000..8d62f15 --- /dev/null +++ b/student.h @@ -0,0 +1,145 @@ +/****************************************************************************** +* +* (c) Copyright 1998, University of Karlstad. +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 1, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +* Please report any bugs you find in this code or any improvements to: +* +* Hans Hedbom, Dept. of Computer Science, +* University of Karlstad, Sweden. +* +* Phone: +46 54 838157 +* E-mail: Hans.Hedbom@hks.se +* +* ============================================================================ +* +* FILE: +* +* student.h [ the Data Communication I course programming project ] +* +* AUTHORS: +* +* Jonny Wiederholm +* E-mail: fr7wied@cse.hks.se or +* jonnwied@hks.se +* +* Per-Ola Gustafsson +* E-mail: fr7gust@cse.hks.se +* +* CREATION DATE: +* +* Jan, 08, 1998 +* +* DESCRIPTION: +* +* Includes header files, declaring the functions that are available +* and can be used in the Data Communication I course programming project. +* +* NOTE: +* +* If any system header files needs to be included in the same module as this +* file is included, make sure they are included before this file or otherwise +* it might not be possible to compile due to type redeclaration errors. +* +* MODIFICATIONS: Date Changes +* ---------------------------------------------------------------------------- +* +* 1998-03-16 Added the function FindAction. +* +*/ + +#ifndef _STUDENT_H /* Avoid multiple copies of this file. */ +#define _STUDENT_H + +#ifdef __cplusplus /* Make this file possible to include in C++ code. */ +extern "C" { +#endif + +/****************************************************************************** +* INCLUDE FILES +*/ + +#include "systems.h" +#include "udefs.h" +#include "sockets.h" +#include "socketio.h" +#include "unixsockets.h" +#include "uselect.h" +#include "utimer.h" + +/****************************************************************************** +* +* sockets.h: +* +* int AcceptConnection(int sockfd) +* +* socketio.h: +* +* int WriteSignaltoSocket(int sockfd, unsigned int signal, \ +* unsigned int siglen) +* int ReadSignalfromSocket(int sockfd, unsigned int siglen) +* int WriteDatatoSocket(int sockfd, char* databuf, unsigned int datalen) +* int ReadDatafromSocket(int sockfd, char* databuf, unsigned int datalen) +* +* unixsockets.h: +* +* int CreateUnixClientSocket(char *path) +* int CreateUnixServerSocket(char *path) +* +* uselect.h: +* +* struct timeval *SetPollTimeout(int seconds, int microseconds) +* int PollSocket(int sockfd1, int sockfd2, struct timeval *tv) +* +* utimer.h: +* +* void SetTimer(unsigned int seconds) +* void ResetTimer(void) +* int SetTimeoutHandler(void (*handler)(int)) +* +*/ + +/****************************************************************************** +* DEFINE TYPES +*/ + +/* Pointer to a function that takes nothing and returns an int. */ +typedef int (*psf) __P((void)); + +/* Struct defining the relationship between a signal and a function. */ +typedef struct action{ + int signal; + psf function; +} action; + +/****************************************************************************** +* DECLARE FUNCTIONS +*/ + +/* See function definitions for documentation. */ + +extern psf FindAction __P((int signal, const__ action *list)); + +/****************************************************************************** +* END +*/ + +#ifdef __cplusplus +} +#endif + +#endif /* _STUDENT_H */ + diff --git a/studlib.a b/studlib.a new file mode 100644 index 0000000..2f40c68 Binary files /dev/null and b/studlib.a differ diff --git a/systems.h b/systems.h new file mode 100644 index 0000000..89a5c17 --- /dev/null +++ b/systems.h @@ -0,0 +1,91 @@ +/****************************************************************************** +* +* (c) Copyright 1998, University of Karlstad. +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 1, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +* Please report any bugs you find in this code or any improvements to: +* +* Hans Hedbom, Dept. of Computer Science, +* University of Karlstad, Sweden. +* +* Phone: +46 54 838157 +* E-mail: Hans.Hedbom@hks.se +* +* ============================================================================ +* +* FILE: +* +* systems.h [ the Data Communication I course programming project ] +* +* AUTHORS: +* +* Jonny Wiederholm +* E-mail: fr7wied@cse.hks.se or +* jonnwied@hks.se +* +* Per-Ola Gustafsson +* E-mail: fr7gust@cse.hks.se +* +* CREATION DATE: +* +* Jan, 06, 1998 +* +* DESCRIPTION: +* +* Specifies the systems on which the example implementation of the Data +* Communication I course programming project has been verified to run +* correctly. Attempts to compile the example implementation on a system not +* specified in this file will cause an error message to be printed and the +* compilation to be aborted. +* +* Systems on which the example implementation has been verified to run +* correctly: +* Linux +* AIX +* SunOS Solaris +* +* MODIFICATIONS: Date Changes +* ---------------------------------------------------------------------------- +* +*/ + +#ifndef _SYSTEMS_H /* Avoid multiple copies of this file. */ +#define _SYSTEMS_H + +#ifdef __cplusplus /* Make this file possible to use in C++ code. */ +extern "C" { +#endif + +/****************************************************************************** +* DEFINE CONSTANTS +*/ + +#if ! defined (__linux__) && ! defined (_AIX) && ! defined(sun) + +#error"Sorry, but this program has not been verified to run correctly on your \ +system." + +#endif /* ! defined (__linux__) && ! defined (_AIX) ... */ + +/****************************************************************************** +* END +*/ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYSTEMS_H */ diff --git a/udefs.h b/udefs.h new file mode 100644 index 0000000..ab4d434 --- /dev/null +++ b/udefs.h @@ -0,0 +1,236 @@ +/****************************************************************************** +* +* (c) Copyright 1998, University of Karlstad. +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 1, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +* Please report any bugs you find in this code or any improvements to: +* +* Hans Hedbom, Dept. of Computer Science, +* University of Karlstad, Sweden. +* +* Phone: +46 54 838157 +* E-mail: Hans.Hedbom@hks.se +* +* ============================================================================ +* +* FILE: +* +* udefs.h [ the Data Communication I course programming project ] +* +* AUTHORS: +* +* Jonny Wiederholm +* E-mail: fr7wied@cse.hks.se +* +* Per-Ola Gustafsson +* E-mail: fr7gust@cse.hks.se +* +* CREATION DATE: +* +* Jan, 06, 1998 +* +* DESCRIPTION: +* +* Includes constants used in the example implementation of the Data +* Communication I course programming project. +* +* MODIFICATIONS: Date Changes +* ---------------------------------------------------------------------------- +* +*/ + +#ifndef _UDEFS_H /* Avoid multiple copies of this file. */ +#define _UDEFS_H + +#ifdef __cplusplus /* Make this file possible to use in C++ code. */ +extern "C" { +#endif + +/****************************************************************************** +* INCLUDE FILES +*/ + +#include "systems.h" + +/****************************************************************************** +* DEFINE CONSTANTS +*/ + +/* Null pointer value. */ +#ifndef NULL /* Avoid type redeclaration. */ +#if !defined( __cplusplus) && !defined (sun) + +#define NULL ((void *) 0) + +#else /* !defined( __cplusplus) && !defined (sun) */ + +#define NULL 0 /* C++ definition of NULL. */ + +#endif /* ifndef __cplusplus */ +#endif /* ifndef NULL */ + +/* Normal exit value. */ +#define NORMAL_EXIT 1 + +/* Non normal exit value. */ +#define NON_NORMAL_EXIT -1 + +/* End of string. */ +#define EOS '\0' + +/* Value returned on the occurence of a system failure. */ +#ifndef SYSTEM_FAILURE /* Avoid type redeclaration. */ +#define SYSTEM_FAILURE (-1) +#endif + +/* Value returned on a successful operation. */ +#ifndef SUCCESS /* Avoid type redeclaration. */ +#define SUCCESS 0 +#endif + +/* Allow ANSI C keywords if ANSI C or C++. */ +#if defined (__STDC__) || defined (__cplusplus) + +#define const__ const +#define volatile__ volatile +/* Pointer to void is defined as pointer to char on non ANSI C systems. */ +#define void_ptr_ void * + +#else /* defined (__STDC__) || defined (__cplusplus) */ + +#define const__ /* No ANSI C keywords. */ +#define volatile__ +#define void_ptr_ char * + +#endif /* defined (__STDC__) || defined (__cplusplus) */ + +/****************************************************************************** +* DEFINE TYPES +*/ + +/* + `c_buf_ptr_' is used by functions which take a pointer to a character + buffer as parameter and does not change the contents of the buffer. + */ +#ifndef C_BUF_PTR_ /* Avoid type redeclaration. */ +#define C_BUF_PTR_ +#if defined (__linux__) + +typedef const__ char * c_buf_ptr_; + +#else /* defined (__linux__) */ + +typedef char * c_buf_ptr_; + +#endif /* defined (__linux__) */ +#endif + +/* + `buf_ptr' is used by functions which take a pointer to a character + buffer and does change the value of the buffer. + */ +#ifndef BUF_PTR_ /* Avoid type redeclaration. */ +#define BUF_PTR_ +typedef char * buf_ptr_; +#endif + +/* + `string_ptr_' is used by functions which take a pointer to a character + string as parameter and does not change the contents of the string. +*/ +#ifndef STRING_PTR_ /* Avoid type redeclaration. */ +#define STRING_PTR_ +typedef c_buf_ptr_ string_ptr_; +#endif + +/* + `byte_ptr_' is used by functions which takes a pointer to a character-buffer + which only needs to store one character, or byte. + */ +#ifndef BYTE_PTR_ +#define BYTE_PTR_ +typedef char * byte_ptr_; +#endif + +/* `size_t_' is used as a length parameter for string functions. */ +#ifndef SIZE_T_ /* Avoid type redeclaration. */ +#define SIZE_T_ +typedef unsigned int size_t_; +#endif + +/* + `ssize_t_' is used by functions which return a count of bytes or an error + indication. + */ +#ifndef SSIZE_T_ /* Avoid type redeclaration. */ +#define SSIZE_T_ +typedef signed int ssize_t_; +#endif + +/* + `u_int_' is used by functions which take or return an unsigned int that + is not indicating a length. + */ +#ifndef U_INT_ /* Avoid type redeclaration. */ +#define U_INT_ +typedef unsigned int u_int_; +#endif + +/* + `ul_int_' is used by functions which take or return an unsigned long int + that is not indicating a length. + */ +#ifndef UL_INT_ /* Avoid type redeclaration. */ +#define UL_INT_ +typedef unsigned long int ul_int_; +#endif + +/****************************************************************************** +* DEFINE MACROS +*/ + +/* Allow function prototypes. */ +#if defined (__STDC__) || defined (__cplusplus) + +#ifndef __P /* Avoid type redeclaration. */ +#define __P(args) args +#endif + +#else /* defined (__STDC__) || defined (__cplusplus) */ + +#ifndef __P /* Avoid type redeclaration. */ +#define __P(args) () /* No prototypes. */ +#endif + +#endif /* defined (__STDC__) || defined (__cplusplus) */ + +/****************************************************************************** +* END +*/ + +#ifdef __cplusplus +} +#endif + +#endif /* _UDEFS_H */ + + + + + + + + diff --git a/unixsockets.h b/unixsockets.h new file mode 100644 index 0000000..16b7387 --- /dev/null +++ b/unixsockets.h @@ -0,0 +1,90 @@ +/****************************************************************************** +* +* (c) Copyright 1998, University of Karlstad. +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 1, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +* Please report any bugs you find in this code or any improvements to: +* +* Hans Hedbom, Dept. of Computer Science, +* University of Karlstad, Sweden. +* +* Phone: +46 54 838157 +* E-mail: Hans.Hedbom@hks.se +* +* ============================================================================ +* +* FILE: +* +* unixsockets.h [ the Data Communication I course programming project ] +* +* AUTHORS: +* +* Jonny Wiederholm +* E-mail: fr7wied@cse.hks.se or +* jonnwied@hks.se +* +* Per-Ola Gustafsson +* E-mail: fr7gust@cse.hks.se +* +* CREATION DATE: +* +* Jan, 06, 1998 +* +* DESCRIPTION: +* +* Includes declarations of functions needed to create server/client sockets in +* the AF_UNIX domain in the example implementation of the Data Communication I +* course programming project. +* +* MODIFICATIONS: Date Changes +* ---------------------------------------------------------------------------- +* +*/ + +#ifndef _UNIXSOCKETS_H /* Avoid multiple copies of this file. */ +#define _UNIXSOCKETS_H + +#ifdef __cplusplus /* Make this file possible to use in C++ code. */ +extern "C" { +#endif + +/****************************************************************************** +* INCLUDE FILES +*/ + +#include "systems.h" +#include "udefs.h" + +/****************************************************************************** +* DECLARE FUNCTIONS +*/ + +/* See function definitions for documentation. */ + +extern int CreateUnixClientSocket __P((string_ptr_ path)); +extern int CreateUnixServerSocket __P((string_ptr_ path)); + +/****************************************************************************** +* END +*/ + +#ifdef __cplusplus +} +#endif + +#endif /* _UNIXSOCKETS_H */ + + diff --git a/uselect.h b/uselect.h new file mode 100644 index 0000000..cb4a699 --- /dev/null +++ b/uselect.h @@ -0,0 +1,103 @@ +/****************************************************************************** +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 1, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +* Please report any bugs you find in this code or any improvements to: +* +* Hans Hedbom, Dept. of Computer Science, +* University of Karlstad, Sweden. +* +* Phone: +46 54 838157 +* E-mail: Hans.Hedbom@hks.se +* +* ============================================================================ +* +* FILE: +* +* uselect.h [ the Data Communication I course programming project ] +* +* AUTHORS: +* +* Jonny Wiederholm +* E-mail: fr7wied@cse.hks.se or +* jonnwied@hks.se +* +* Per-Ola Gustafsson +* E-mail: fr7gust@cse.hks.se +* +* CREATION DATE: +* +* Jan, 06, 1998 +* +* DESCRIPTION: +* +* Includes types and declarations of functions needed to poll sockets in the +* example implementation of the Data Communication I course programming +* project. +* +* MODIFICATIONS: Date Changes +* ---------------------------------------------------------------------------- +* +*/ + +#ifndef _USELECT_H /* Avoid multiple copies of this file. */ +#define _USELECT_H + +#ifdef __cplusplus /* Make this file possible to use in C++ code. */ +extern "C" { +#endif + +/****************************************************************************** +* INCLUDE FILES +*/ + +#include "systems.h" + +/****************************************************************************** +* DEFINE TYPES +*/ + +/* Type representing part of a time peroid. */ +#if defined (__linux__) || defined (_AIX) +typedef int time_p_; +#elif defined(sun) +typedef long time_p_; +#endif /* defined (__linux__) || defined (_AIX) */ + +/* Structure representing a timeout time period. */ +struct timeout { + time_p_ tv_sec; /* Seconds. */ + time_p_ tv_usec; /* Microseconds. */ +}; + +/****************************************************************************** +* DECLARE FUNCTIONS +*/ + +/* See function definitions for documentation. */ + +extern struct timeout *SetPollTimeout __P((time_p_ seconds, time_p_ \ + microseconds)); +extern int PollSocket __P((int sockfd1, int sockfd2, struct timeout *to)); + +/****************************************************************************** +* END +*/ + +#ifdef __cplusplus +} +#endif + +#endif /* _USELECT_H */ diff --git a/utimer.h b/utimer.h new file mode 100644 index 0000000..4c24340 --- /dev/null +++ b/utimer.h @@ -0,0 +1,88 @@ +/****************************************************************************** +* +* (c) Copyright 1998, University of Karlstad. +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 1, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +* Please report any bugs you find in this code or any improvements to: +* +* Hans Hedbom, Dept. of Computer Science, +* University of Karlstad, Sweden. +* +* Phone: +46 54 838157 +* E-mail: Hans.Hedbom@hks.se +* +* ============================================================================ +* +* FILE: +* +* utimer.h [ the Data Communication I course programming project ] +* +* AUTHORS: +* +* Jonny Wiederholm +* E-mail: fr7wied@cse.hks.se or +* jonnwied@hks.se +* +* Per-Ola Gustafsson +* E-mail: fr7gust@cse.hks.se +* +* CREATION DATE: +* +* Jan, 06, 1998 +* +* DESCRIPTION: +* +* Includes declarations of functions needed to simulate a timer in the example +* implementation of the Data Communication I course programming project. +* +* MODIFICATIONS: Date Changes +* ---------------------------------------------------------------------------- +* +*/ + +#ifndef _UTIMER_H /* Avoid multiple copies of this file. */ +#define _UTIMER_H + +#ifdef __cplusplus /* Make this file possible to use in C++ code. */ +extern "C" { +#endif + +/****************************************************************************** +* INCLUDE FILES +*/ + +#include "systems.h" +#include "udefs.h" + +/****************************************************************************** +* DECLARE FUNCTIONS +*/ + +/* See function definitions for documentation. */ + +extern void SetTimer __P((u_int_ seconds)); +extern void ResetTimer __P((void)); +extern int SetTimeoutHandler __P((void (*handler) __P((int)))); + +/****************************************************************************** +* END +*/ + +#ifdef __cplusplus +} +#endif + +#endif /* _UTIMER_H */