From fd04d44e1225adfdce446a340ad74b2424de2564 Mon Sep 17 00:00:00 2001 From: Christian Ohlsson Date: Thu, 5 Mar 2026 13:35:06 +0100 Subject: [PATCH] Startpunkten --- c_app.c | 45 ++++++++++ c_stub.c | 259 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ c_stub.o | Bin 0 -> 30272 bytes header.h | 63 ++++++++++++++ read_me | 15 ++++ s_stub.c | 213 +++++++++++++++++++++++++++++++++++++++++++++ s_stub.o | Bin 0 -> 28244 bytes 7 files changed, 595 insertions(+) create mode 100644 c_app.c create mode 100644 c_stub.c create mode 100644 c_stub.o create mode 100644 header.h create mode 100644 read_me create mode 100644 s_stub.c create mode 100644 s_stub.o diff --git a/c_app.c b/c_app.c new file mode 100644 index 0000000..63f2149 --- /dev/null +++ b/c_app.c @@ -0,0 +1,45 @@ +/* ***************************************** */ +/* Laboration 2 i Datakommunikation 2 */ +/* RPC-lib */ +/* ***************************************** */ +/* c_app.c */ +/* Ber användaren mata in vilken typ */ +/* av operation denne vill göra */ +/* ***************************************** */ +/* Christian Ohlsson, di7chro@cse.kau.se */ +/* Stefan Sonesson, di7stes@cse.kau.se */ +/* ***************************************** */ +#include "header.h" + +/* ============================================== + menu() + Skriver ut menyn på skärmen + ============================================== */ +int menu() { + char choice[5]; + int ret_val = TRUE; + system("clear"); + puts("Welcome to RPC"); + puts("================"); + puts("1 - Open file"); + puts("2 - Read file"); + puts("3 - Write to file"); + puts("4 - Delete file"); + puts("5 - Close file"); + puts("6 - Exit"); + + printf("\nEnter your choice: "); + fgets(choice, sizeof(choice), stdin); + + switch(choice[0]){ + case '1': ret_val = in_open(); break; + case '2': ret_val = in_read(); break; + case '3': ret_val = in_write(); break; + case '4': ret_val = in_delete(); break; + case '5': ret_val = in_close(); break; + case '6': ret_val = in_quit(); break; + default : puts("Try again 1-5 or 6");break; + } + return ret_val; +} + diff --git a/c_stub.c b/c_stub.c new file mode 100644 index 0000000..48506ba --- /dev/null +++ b/c_stub.c @@ -0,0 +1,259 @@ +/* ***************************************** */ +/* Laboration 2 i Datakommunikation 2 */ +/* RPC-lib */ +/* ***************************************** */ +/* c_stub.c */ +/* Klientapplikation som skickar */ +/* kommandon till servern */ +/* ***************************************** */ +/* Christian Ohlsson, di7chro@cse.kau.se */ +/* Stefan Sonesson, di7stes@cse.kau.se */ +/* ***************************************** */ + +#include "header.h" + +/* Globala variabler */ +int fd=-1, sock; /* fd kommer ihåg om någon fil är öppen */ +msg myMsg; /* Meddelandet som funktionerna fyller i */ + +/* ============================================== + in_connect() + Gör en uppkoppling mot en server + ============================================== */ +void in_connect() { + char *remhost; + u_short remport; + struct sockaddr_in remote; + struct hostent *h; + /* Skapa en socket att skicka data på */ + if((sock = socket(AF_INET, SOCK_STREAM, 0 )) < 0 ) { + perror("client:socket"); + exit(1); + } + remport = 8704; + /* Nolla ut structen */ + bzero((char *) &remote, sizeof(remote)); + remote.sin_family = AF_INET; + /* Fyll i hostent structen */ + if((h = gethostbyname(myMsg.machine)) == NULL) { + perror("client:gethostbyname"); + exit(1); + } + bcopy((char *)h->h_addr, (char *)&remote.sin_addr, h->h_length); + remote.sin_port = htons(remport); + /* Begär uppkoppling mot servern */ + if(connect(sock, (struct sockaddr *)&remote, sizeof(remote)) < 0) { + perror("client:connect"); + exit(1); + } +} + +/* ============================================== + in_open() + Letar fram server och fil att öppna + ============================================== */ +int in_open() { + int i,j,k=0; + char this_machine[BUFSIZE], this_path[BUFSIZE], filename[BUFSIZE]; + if(fd<0) { + printf("Enter filename: "); + fgets(filename, sizeof(filename), stdin); + for(i = 0; i < BUFSIZE; i++) { + if(filename[i] != '/') + this_machine[i] = filename[i]; + else { + this_machine[i] = 0; + break; + } + } + for(; i < BUFSIZE ; i++) { + if(filename[i] != 10) { + this_path[k] = filename[i]; + k++; + } + else { + this_path[k] = 0; + break; + } + } + myMsg.op = OP; + if(filename[0] == '/') /* Lokal fil */ + strcpy(this_machine, "localhost"); + strcpy(myMsg.machine, this_machine); + strcpy(myMsg.path, this_path); + in_connect(myMsg); + } + else { + puts("A file is already open!"); + sleep(SLEEPTIME); + return FALSE; + } + return TRUE; +} + +/* ============================================== + in_read() + Sätter operatorn till READ + ============================================== */ +int in_read() { + if(fd > 0) + myMsg.op = RD; + else { + puts("No file is open!"); + sleep(SLEEPTIME); + return FALSE; + } + return TRUE; +} + +/* ============================================== + in_write() + Frågar hur mycket som skall skrivas och + sätter operatorn + ============================================== */ +int in_write() { + char buf[BUFSIZE]; + int length = 0; + if(fd>0) { + printf("How many bytes do you wish to write: "); + gets(buf); + length = atoi(buf); + printf("Enter text: "); + if((myMsg.data = (char*)malloc(length)) < 0) { + perror("Malloc fel, byt minnesskretsarna, eller skaffa fler\n"); + return FALSE; + } + myMsg.length = length; + gets(myMsg.data); + myMsg.op = WR; + } + else { + puts("No file is open!"); + sleep(SLEEPTIME); + return FALSE; + } + return TRUE; +} + +/* ============================================== + in_delete() + Sätter operatorn till DELETE + ============================================== */ +int in_delete() { + if(fd > 0) + myMsg.op = DEL; + else { + puts("No file is open!"); + sleep(SLEEPTIME); + return FALSE; + } + return TRUE; +} + +/* ============================================== + + in_close() + Sätter operatorn till CLOSE + ============================================== */ +int in_close() { + if(fd > 0) + myMsg.op = CL; + else { + puts("No file is open!"); + sleep(SLEEPTIME); + return FALSE; + } + return TRUE; +} + +/* ============================================== + showFile() + Om data finns i filen skrivs detta ut + ============================================== */ +void showFile(char *data) { + if(myMsg.length > 0) + printf("Data:%s\n",data); + else + puts("File contains no data."); + sleep(SLEEPTIME); +} + +/* ============================================== + in_quit() + Stänger socketen och avslutar + ============================================== */ +int in_quit() { + if(fd > 0) { + puts("Close file first."); + sleep(SLEEPTIME); + return FALSE; + } + else { + puts("QUIT"); + close(sock); + exit(0); + } +} +void in_exit() { + close(sock); + puts("Application error, probably due to underpaid programmers"); + exit(0); +} + +/* ============================================== + main() + Anropar funktioner beroende på menyval + ============================================== */ +main() { + char *data; + signal(SIGCHLD, SIG_IGN); + signal(SIGINT, SIG_IGN); + + while(TRUE) { + if(menu(myMsg)) { + if((write(sock, &myMsg, sizeof(myMsg))) < 0) + {puts("1");in_exit();} + write(sock, myMsg.data, myMsg.length); + if((read(sock, &myMsg, sizeof(myMsg))) < 0) /*lyssna efter svar från servern*/ + {puts("3");in_exit();} + switch(myMsg.op) { + case OPN: /* Öppning misslyckades */ + puts("Could not open file."); + sleep(SLEEPTIME); break; + case OPP: /* Öppning gick bra */ + printf("File: %s is open", myMsg.path);fflush(stdout); + fd = myMsg.fd;sleep(SLEEPTIME); break; + case RDN: /* Läsning misslyckades */ + puts("Could not read from file."); + sleep(SLEEPTIME); break; + case RDP: /* Läsning gick bra */ + if((data = (char*)malloc(myMsg.length)) == NULL) { + puts("Could not read from file.");break;} + if((read(sock, data, myMsg.length)) < 0) { + puts("Could not read from file");break;} + showFile(data);break; + case WRN: /* Skrivning misslyckades */ + puts("Could not write to file."); + sleep(SLEEPTIME);break; + case WRP: /* Skrivning gick bra */ + printf("%d bytes written.\n", myMsg.length); + sleep(SLEEPTIME);break; + case DLN: /* Borttagning misslyckades */ + puts("Could not delete file."); + sleep(SLEEPTIME);break; + case DLP: /* Borttagning gick bra */ + printf("File %s deleted\n", myMsg.path); + fd=-1; sleep(SLEEPTIME);break; + case CLN: /* Stängning misslyckades */ + puts("Could not close file."); + sleep(SLEEPTIME);break; + case CLP: /* Stängning gick bra */ + printf("File: %s is closed\n", myMsg.path); + fd=-1;sleep(SLEEPTIME);close(sock);break; + default: puts(".");sleep(SLEEPTIME);break; + } + } + } + /*close(sock);*/ +} + diff --git a/c_stub.o b/c_stub.o new file mode 100644 index 0000000000000000000000000000000000000000..e96bb1d4e6aba2de403fd76f01303c8ce21df9fc GIT binary patch literal 30272 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 +#include +#include +#include +#include +#include +#include +#include +#include + +/* Meddelande som skickas över */ +typedef struct msg{ + int op; /* Typ av kommando */ + int fd; /* Fildeskriptor */ + long length; /* Storlek på data */ + char machine[50]; /* Maskin vi vill koppla upp mot */ + char path[50]; /* Sökväg på maskinen */ + char *data; /* Datafält */ +}msg; + +typedef msg *msgPtr; + +#endif + diff --git a/read_me b/read_me new file mode 100644 index 0000000..17ee7e7 --- /dev/null +++ b/read_me @@ -0,0 +1,15 @@ +Readmefil för Laboration i +Datakommunikation II +================================= + + RPC-lib + + Kompilera genom att köra + makefilen (make) + .SDR filerna i Doc/ katalogen + är skapade med SmartDraw + Labben är provkörd och klar. + +================================ + Christian.Ohlsson@cs.kau.se + diff --git a/s_stub.c b/s_stub.c new file mode 100644 index 0000000..b4fcd20 --- /dev/null +++ b/s_stub.c @@ -0,0 +1,213 @@ +/* ***************************************** */ +/* Laboration 2 i Datakommunikation 2 */ +/* RPC-lib */ +/* ***************************************** */ +/* s_stub.c */ +/* Ansvarar för att operationer utförs */ +/* utförs på rätt sätt i servern */ +/* ***************************************** */ +/* Christian Ohlsson, di7chro@cse.kau.se */ +/* Stefan Sonesson, di7stes@cse.kau.se */ +/* ***************************************** */ + +#include "header.h" + +/* Globala variabler */ +int data_sockfd; /* Den socket som data färdas på */ +msg myMsg; /* Meddelandet som funktionerna fyller i */ + +/* ============================================== + printsin() + Skriver ut information om klienten + ============================================== */ +printsin(struct sockaddr_in *sin, char *m1, char *m2 ) { + struct hostent *gethostbyaddr(), *h; + printf ("%s %s\n", m1, m2); + printf ("Family %d addr %x port %d\n", sin -> sin_family, + ntohl(sin -> sin_addr.s_addr), ntohs(sin -> sin_port)); + h = gethostbyaddr((char *)&sin->sin_addr, sizeof(int), AF_INET); + printf ("Symbolic host name <%s>\n",h->h_name); +} + +/* ============================================== + rem_open() + Öppnar en fil och fyller i data såsom + längd och fildeskriptor i strukten. + ============================================== */ +void rem_open() { + int fd; + struct stat st; + if((fd = open(myMsg.path, O_CREAT|O_RDWR|O_APPEND, PERMS)) < 0) { + myMsg.op = OPN; /* Skicka fel till klient */ + return; + } + fstat(fd, &st); + myMsg.length = st.st_size; + myMsg.op = OPP; /* Operationen gick bra */ + myMsg.fd = fd; +} + +/* ============================================== + rem_read() + Läser data ur en fil tills EOF tecknet nås och + dessa tecken stoppas i en buffer, som slutligen + returneras + ============================================== */ +char *rem_read() { + char *buf; + int fd; + lseek(myMsg.fd, 0, SEEK_SET); + buf = (char*)malloc(myMsg.length); + + if((read(myMsg.fd, buf, myMsg.length)) < 0) + myMsg.op = RDN; /* Skicka fel till klient */ + else + myMsg.op = RDP; /* Operationen gick bra */ + return buf; +} + +/* ============================================== + rem_write() + Skriver tecken till fil + ============================================== */ +void rem_write() { + if((write(myMsg.fd, myMsg.data, myMsg.length)) < 0) + myMsg.op = WRN; /* Skicka fel till klient */ + else + myMsg.op = WRP; /* Operationen gick bra */ +} +/* ============================================== + rem_delete() + Tar bort en fil mha unlink, som egentligen + räknar ner antalet länkar till en fil + ============================================== */ +int rem_delete() { + if((unlink(myMsg.path)) < 0) { + myMsg.op = DLN; /* Skicka fel till klient */ + return 0; + } + else { + myMsg.op = DLP; /* Operationen gick bra */ + return 1; + } +} + +/* ============================================== + rem_close() + Stänger en fil. + Returnerar svar om hur det gick + ============================================== */ +int rem_close() { + if((close(myMsg.fd)) < 0) { + myMsg.op = CLN; /* Skicka fel till klient */ + return 0; + } + else { + myMsg.op = CLP; /* Operationen gick bra */ + return 1; + } +} +/* ============================================== + rem_exit() + Stänger datasocketen vid fel. + Avslutar programmet + ============================================== */ +void rem_exit() { + puts("Quitting"); + close(data_sockfd); + exit(0); +} +/* ============================================== + main() + Sköter uppkoppling och lyssnar efter klienter + ============================================== */ +main() { + int listener, client_length, length, val, again; + char *bytes; + struct sockaddr_in srvr_addr, client_addr; + signal(SIGCHLD, SIG_IGN); + signal(SIGINT, rem_exit); + + /* Skapa en socket som lyssnar efter uppkopplingar */ + if((listener = socket( AF_INET, SOCK_STREAM, 0 )) < 0 ) { + perror("server: can't open stream socket"); + exit(0); + } + /* Nolla ut strukten */ + bzero((char *) &srvr_addr, sizeof(srvr_addr)); + srvr_addr.sin_family = AF_INET; + srvr_addr.sin_addr.s_addr = htons(INADDR_ANY); + srvr_addr.sin_port = PORT; + /* Bind ett namn till socketen */ + if(bind(listener, (struct sockaddr *)&srvr_addr, sizeof(srvr_addr)) < 0) { + perror("server: can't bind local address"); + exit(0); + } + length = sizeof(srvr_addr); + while(TRUE) { + /* Hämta namnet på socketen */ + if(getsockname(listener, (struct sockaddr *)&srvr_addr, &length) < 0) { + perror("server: can't get sockname"); + exit(0); + } + printf("Port number %d\n", ntohs(srvr_addr.sin_port)); + /* Lyssna efter uppkopplingar */ + listen(listener, MAXCONNECTED); + + client_length = sizeof(client_addr); + /* Acceptera den nya uppkopplingen */ + if ((data_sockfd=accept(listener, + (struct sockaddr *)&client_addr, &length)) < 0) { + perror("server: accept error"); + exit(0); + } + /*printsin(&client_addr,"\nRSTREAM", "accepted connection from");*/ + again=1; + while(again) { + /* Läs data från socketen */ + if((read(data_sockfd, &myMsg, sizeof(myMsg))) < 0) + rem_exit(); + + switch(myMsg.op) { + case OP: /* Klienten vill öppna en fil */ + rem_open(); + if((write(data_sockfd, &myMsg, sizeof(myMsg))) < 0) + rem_exit(); + break; + case RD: /* Klienten vill läsa från en fil */ + bytes = rem_read(); + if((write(data_sockfd, &myMsg, sizeof(myMsg))) < 0) + rem_exit(); + if((write(data_sockfd, bytes, myMsg.length)) < 0) + rem_exit(); + break; + case WR: /* Klienten vill skriva till en fil */ + if((myMsg.data = (char*)malloc(myMsg.length)) == NULL) { + myMsg.op = WRN; /* Om minne inte kunde allokeras */ + if((write(data_sockfd, &myMsg, sizeof(myMsg))) < 0) + rem_exit(); + } + if((read(data_sockfd, myMsg.data, myMsg.length)) < 0) + rem_exit(); + rem_write(); + if((write(data_sockfd, &myMsg, sizeof(myMsg))) < 0) + rem_exit(); + free(myMsg.data); + break; + case DEL:/* Klienten vill ta bort en fil */ + val = rem_delete(); + if((write(data_sockfd, &myMsg, sizeof(myMsg))) < 0) + rem_exit(); + if(val == 1) { close(data_sockfd); again=0; } + break; + case CL: /* Klienten vill stänga en fil */ + val = rem_close(); + if((write(data_sockfd, &myMsg, sizeof(myMsg))) < 0) + rem_exit(); + if(val == 1) { close(data_sockfd); again=0; } + break; + default: break; + } + } + } +} diff --git a/s_stub.o b/s_stub.o new file mode 100644 index 0000000000000000000000000000000000000000..6c1c029d14dfbef05a13e5c377d1f8f479e4e588 GIT binary patch literal 28244 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 literal 0 HcmV?d00001