From 1eb51a665ab799fbdae784d6fee913c6e37f8ff9 Mon Sep 17 00:00:00 2001 From: Skylar Scorca <64870579+skylarscorca@users.noreply.github.com> Date: Wed, 22 Mar 2023 12:47:53 -0400 Subject: [PATCH 1/8] update readme --- README.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/README.md b/README.md index 47d612fe..dda79ae8 100644 --- a/README.md +++ b/README.md @@ -24,3 +24,29 @@ style CLI. Kilo was written by Salvatore Sanfilippo aka antirez and is released under the BSD 2 clause license. + +# cpd-term-project +Term Project for COP5570 +Concurrent Text File Editing (Google Docs redev) + +Contributers: +Skylar Scorca, +Tony Drouillard, +Jack Dewey + +Project Objectives (intended features) +- Allow users to update a single text file simultaneously +- Allow users to view the updates of other users in real-time +- Handle the movement of a user’s cursor after an update is made +- Handle transactions quickly and efficiently + +Optional Objectives: (if time allows) +- Allow users to create and delete text files in a greater system of files +- Allow users to modify the tree structure of the greater system of files +- Allow users to view the updates to the file system in real-time + +Due date countdown: +https://www.timeanddate.com/countdown/generic?iso=20230428T2359&p0=856&msg=cpd+term+project+due+date&font=cursive&csz=1 + +Google Drive Folder: +https://drive.google.com/drive/folders/1sZ5ulUizpBA6Rq9KOYdHxhaF4QC_5UAi?usp=share_link From d9eef172a2bf891176b6143aa869d947a35af249 Mon Sep 17 00:00:00 2001 From: Skylar Scorca Date: Wed, 22 Mar 2023 13:07:20 -0400 Subject: [PATCH 2/8] deleted TODO, changed makefile --- Makefile | 2 +- TODO | 10 ---------- 2 files changed, 1 insertion(+), 11 deletions(-) delete mode 100644 TODO diff --git a/Makefile b/Makefile index 13620cc1..1a4102b8 100644 --- a/Makefile +++ b/Makefile @@ -4,4 +4,4 @@ kilo: kilo.c $(CC) -o kilo kilo.c -Wall -W -pedantic -std=c99 clean: - rm kilo + rm -f kilo diff --git a/TODO b/TODO deleted file mode 100644 index 95ae28b9..00000000 --- a/TODO +++ /dev/null @@ -1,10 +0,0 @@ -IMPORTANT -=== - -* Testing and stability to reach "usable" level. - -MAYBE -=== - -* Send alternate screen sequences if TERM=xterm: "\033[?1049h" and "\033[?1049l" -* Improve internals to be more understandable. From 8909ab9612d0c5bd8186fb1caea3a4a381b286f8 Mon Sep 17 00:00:00 2001 From: Skylar Scorca Date: Wed, 22 Mar 2023 13:09:46 -0400 Subject: [PATCH 3/8] change makefile --- Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 1a4102b8..2e46ffe2 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,9 @@ +CC = gcc -g -Wall -W -ansi -pedantic -std=c99 -o + all: kilo kilo: kilo.c - $(CC) -o kilo kilo.c -Wall -W -pedantic -std=c99 + $(CC) kilo kilo.c clean: rm -f kilo From dc8334a6de46c0259a589584bf056b84867c2061 Mon Sep 17 00:00:00 2001 From: Skylar Scorca Date: Fri, 21 Apr 2023 18:39:06 -0400 Subject: [PATCH 4/8] fixed comments and added a few notes in the commends --- kilo.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/kilo.c b/kilo.c index 406eb7be..1be9e7b1 100644 --- a/kilo.c +++ b/kilo.c @@ -109,6 +109,8 @@ struct editorConfig { struct editorSyntax *syntax; /* Current syntax highlight, or NULL. */ }; +//Note: we may want to add a few fields to the erow and editorConfig structs + static struct editorConfig E; enum KEY_ACTION{ @@ -198,6 +200,7 @@ struct editorSyntax HLDB[] = { #define HLDB_ENTRIES (sizeof(HLDB)/sizeof(HLDB[0])) /* ======================= Low level terminal handling ====================== */ +//Note: probably don't need to edit these static struct termios orig_termios; /* In order to restore at exit.*/ @@ -214,7 +217,7 @@ void editorAtExit(void) { disableRawMode(STDIN_FILENO); } -/* Raw mode: 1960 magic shit. */ +/* Raw mode: 1960 magic*/ int enableRawMode(int fd) { struct termios raw; @@ -362,6 +365,7 @@ int getWindowSize(int ifd, int ofd, int *rows, int *cols) { } /* ====================== Syntax highlight color scheme ==================== */ +//Note: probably don't need to edit these int is_separator(int c) { return c == '\0' || isspace(c) || strchr(",.()+-/*=~%[];",c) != NULL; @@ -551,6 +555,10 @@ void editorSelectSyntaxHighlight(char *filename) { } /* ======================= Editor rows implementation ======================= */ +//Note: probably want to edit these. perhaps at the end of an update function, we call another +// function to send an update message to the server. +//Note: we can copy the logic from these functions to allow for editing after receuving an +// update message from the server. /* Update the rendered version and the syntax highlight of a row. */ void editorUpdateRow(erow *row) { @@ -616,7 +624,7 @@ void editorFreeRow(erow *row) { free(row->hl); } -/* Remove the row at the specified position, shifting the remainign on the +/* Remove the row at the specified position, shifting the remaining on the * top. */ void editorDelRow(int at) { erow *row; @@ -852,6 +860,7 @@ int editorSave(void) { } /* ============================= Terminal update ============================ */ +//Note: probably don't need to edit these /* We define a very simple "append buffer" structure, that is an heap * allocated string where we can append to. This is useful in order to @@ -1008,6 +1017,7 @@ void editorSetStatusMessage(const char *fmt, ...) { } /* =============================== Find mode ================================ */ +//Note: probably don't need to edit these #define KILO_QUERY_LEN 256 @@ -1107,6 +1117,7 @@ void editorFind(int fd) { } /* ========================= Editor events handling ======================== */ +//Note: we probably don't need to edit these /* Handle cursor position change because arrow keys were pressed. */ void editorMoveCursor(int key) { @@ -1288,7 +1299,10 @@ void initEditor(void) { signal(SIGWINCH, handleSigWinCh); } +//main program of text-editor client int main(int argc, char **argv) { + + //need to change this to be server ip instead if (argc != 2) { fprintf(stderr,"Usage: kilo \n"); exit(1); From 4c08df6d8b8467efffb7a3cfc7dc948c39929239 Mon Sep 17 00:00:00 2001 From: jdewey2023 Date: Fri, 21 Apr 2023 23:09:44 -0400 Subject: [PATCH 5/8] Initial server & client set up | Transfer a file between server and client --- Makefile | 10 +++-- kilo.c | 66 ++++++++++++++++++++++++++---- server.cpp | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 181 insertions(+), 10 deletions(-) create mode 100755 server.cpp diff --git a/Makefile b/Makefile index 2e46ffe2..a32a9303 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,13 @@ -CC = gcc -g -Wall -W -ansi -pedantic -std=c99 -o +CC = gcc -g -Wall -W -ansi -pedantic -std=c99 -pthread -o +C+ = g++ -g -Wall -pthread -o -all: kilo +all: clean kilo server kilo: kilo.c $(CC) kilo kilo.c +server: server.cpp + $(C+) server server.cpp + clean: - rm -f kilo + rm -f kilo kilo.exe server server.exe diff --git a/kilo.c b/kilo.c index 1be9e7b1..24f457c6 100644 --- a/kilo.c +++ b/kilo.c @@ -53,6 +53,7 @@ #include #include #include +#include /* Syntax highlight types */ #define HL_NORMAL 0 @@ -1299,17 +1300,68 @@ void initEditor(void) { signal(SIGWINCH, handleSigWinCh); } +void receiveFile(int fd){ + ssize_t n; + FILE *file = fopen("transfer", "w"); + char buffer[1024]; + n = read(fd, buffer, 1024); + buffer[n] = '\0'; + while (1){ + if ((n = read(fd, buffer, 1024)) > 0){ + // printf("Line: %s\n", buffer); + buffer[n] = '\0'; + if (!strcmp(buffer, "End Transfer")){ + // printf("Closing\n"); + fclose(file); + return; + } + fprintf(file, "%s\n", buffer); + send(fd, "ACK", 1024, 0); + } + } + //editorOpen("test"); +} + //main program of text-editor client int main(int argc, char **argv) { - - //need to change this to be server ip instead - if (argc != 2) { - fprintf(stderr,"Usage: kilo \n"); + //need to change this to be server ip instead + if (argc != 3) { + fprintf(stderr,"Usage: kilo \n"); exit(1); } - - initEditor(); - editorSelectSyntaxHighlight(argv[1]); + struct addrinfo hints, *res, *traverser; + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + int r = getaddrinfo(argv[1], argv[2], &hints, &res); + if (r != 0){ + fprintf(stderr,"Error: Can't find server.\n"); + return 1; + } + // Try addresses until one is successful + int serverFd; + for (traverser = res; traverser; traverser = traverser->ai_next){ + if ((serverFd = socket(traverser->ai_family, traverser->ai_socktype, traverser->ai_protocol)) != -1){ + if ((connect(serverFd, traverser->ai_addr, traverser->ai_addrlen)) == 0){ + break; + } + } + } + printf("Connected\n"); + char buffer[1024]; + while (fgets(buffer, 1024, stdin)){ + buffer[strcspn(buffer, "\r\n")] = 0; + if (!strcmp(buffer, "get")){ + // printf("Get Received\n"); + send(serverFd, "get", 1024, 0); + receiveFile(serverFd); + } + // printf("%s\n", buffer); + } + close(serverFd); + // exit(0); + initEditor(); + editorSelectSyntaxHighlight("transfer"); editorOpen(argv[1]); enableRawMode(STDIN_FILENO); editorSetStatusMessage( diff --git a/server.cpp b/server.cpp new file mode 100755 index 00000000..a7f88dfc --- /dev/null +++ b/server.cpp @@ -0,0 +1,115 @@ +// C Headers +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +// C++ Headers +#include +#include +#include +#include +#include +#include +using namespace std; + +vector readFile(){ + string line; + vector lines; + ifstream file("test"); + while (getline(file, line)){ + lines.push_back(line); + } + return lines; +} + +void sendFile(int fd, vector lines){ + vector::iterator i; + send(fd, (void*)"Start Transfer", 1024, 0); + for (i = lines.begin(); i != lines.end(); i++){ + char buffer[1024]; + string msg = *i; + // cout << "Line: " << msg << endl; + send(fd, msg.c_str(), msg.length(), 0); + read(fd, buffer, 1024); + } + send(fd, (void*)"End Transfer", 1024, 0); +} + +void *threadFunc(void *args){ + ssize_t n; + int clientFd = *(int*)args; + char buffer[1024]; + pthread_detach(pthread_self()); + // Read until disconnection + while ((n = read(clientFd, buffer, 1024)) > 0){ + string line(buffer); + if (line == "exit"){ + close(clientFd); + } + if (line == "get"){ + // cout << "Get Received" << endl; + sendFile(clientFd, readFile()); + } + } + return NULL; +} + +void handleSigInt(int unused __attribute__((unused))){ + exit(0); +} + +int main(void){ + signal(SIGINT, handleSigInt); + // Create server socket + int serverFd; + if ((serverFd = socket(AF_INET, SOCK_STREAM, 0)) < 0){ + std::cerr << "Error: Can't create socket." << std::endl; + return 1; + } + // Set options for socket + int val; + if (setsockopt(serverFd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(int))){ + std::cerr << "Error: Can't reuse socket." << std::endl; + return 2; + } + // Configure addr and bind + struct sockaddr_in serverAddr; + serverAddr.sin_family = AF_INET; + serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); + serverAddr.sin_port = htons(10001); + if (bind(serverFd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) == -1){ + cerr << "Error: Can't bind socket to port." << endl; + return 3; + } + // Listen for client connections + if (listen(serverFd, 20) < 0){ + cerr << "Error: Can't listen for clients." << endl; + return 4; + } + // Get name and port assigned to server + char *name = new char[1024]; + struct sockaddr_in infoAddr; + socklen_t len = sizeof(infoAddr); + gethostname(name, 1024); + getsockname(serverFd, (struct sockaddr *)&infoAddr, &len); + // Report name and port + cout << name << ":" << ntohs(serverAddr.sin_port)<< endl; + delete name; + // Connect a client + struct sockaddr_in cliAddr; + len = sizeof(cliAddr); + while (true){ + int clientFd = accept(serverFd, (struct sockaddr *)&serverAddr, &len); + // Create thread to deal with client + pthread_t thread; + pthread_create(&thread, NULL, threadFunc, (void *)&clientFd); + } + return 0; +} \ No newline at end of file From ccd310672a026e1fa89b7b1b2e6d4eb3b48c1d83 Mon Sep 17 00:00:00 2001 From: Skylar Scorca Date: Sat, 22 Apr 2023 17:42:55 -0400 Subject: [PATCH 6/8] cleaned up code --- kilo.c | 9 ++++++++- server.cpp | 15 +++++++++++++++ transfer | 0 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 transfer diff --git a/kilo.c b/kilo.c index 24f457c6..0c0bc6d6 100644 --- a/kilo.c +++ b/kilo.c @@ -1324,11 +1324,13 @@ void receiveFile(int fd){ //main program of text-editor client int main(int argc, char **argv) { - //need to change this to be server ip instead + //check command-line args if (argc != 3) { fprintf(stderr,"Usage: kilo \n"); exit(1); } + + //setup struct addrinfo hints, *res, *traverser; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; @@ -1338,6 +1340,7 @@ int main(int argc, char **argv) { fprintf(stderr,"Error: Can't find server.\n"); return 1; } + // Try addresses until one is successful int serverFd; for (traverser = res; traverser; traverser = traverser->ai_next){ @@ -1348,6 +1351,7 @@ int main(int argc, char **argv) { } } printf("Connected\n"); + char buffer[1024]; while (fgets(buffer, 1024, stdin)){ buffer[strcspn(buffer, "\r\n")] = 0; @@ -1358,8 +1362,11 @@ int main(int argc, char **argv) { } // printf("%s\n", buffer); } + close(serverFd); // exit(0); + + //start editor initEditor(); editorSelectSyntaxHighlight("transfer"); editorOpen(argv[1]); diff --git a/server.cpp b/server.cpp index a7f88dfc..f6c5a04a 100755 --- a/server.cpp +++ b/server.cpp @@ -19,6 +19,7 @@ #include using namespace std; +//readFile - reads lines in file into the data structure lines vector readFile(){ string line; vector lines; @@ -29,6 +30,7 @@ vector readFile(){ return lines; } +//sendFile - send file line-by-line to a client at fd void sendFile(int fd, vector lines){ vector::iterator i; send(fd, (void*)"Start Transfer", 1024, 0); @@ -42,6 +44,7 @@ void sendFile(int fd, vector lines){ send(fd, (void*)"End Transfer", 1024, 0); } +//threadFunc - thread function to read any messages from a client void *threadFunc(void *args){ ssize_t n; int clientFd = *(int*)args; @@ -61,24 +64,31 @@ void *threadFunc(void *args){ return NULL; } +//handleSigInt - action performed when user types ctrl-C void handleSigInt(int unused __attribute__((unused))){ exit(0); } +//main server program int main(void){ + + //setup SIGINT signal handler signal(SIGINT, handleSigInt); + // Create server socket int serverFd; if ((serverFd = socket(AF_INET, SOCK_STREAM, 0)) < 0){ std::cerr << "Error: Can't create socket." << std::endl; return 1; } + // Set options for socket int val; if (setsockopt(serverFd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(int))){ std::cerr << "Error: Can't reuse socket." << std::endl; return 2; } + // Configure addr and bind struct sockaddr_in serverAddr; serverAddr.sin_family = AF_INET; @@ -88,25 +98,30 @@ int main(void){ cerr << "Error: Can't bind socket to port." << endl; return 3; } + // Listen for client connections if (listen(serverFd, 20) < 0){ cerr << "Error: Can't listen for clients." << endl; return 4; } + // Get name and port assigned to server char *name = new char[1024]; struct sockaddr_in infoAddr; socklen_t len = sizeof(infoAddr); gethostname(name, 1024); getsockname(serverFd, (struct sockaddr *)&infoAddr, &len); + // Report name and port cout << name << ":" << ntohs(serverAddr.sin_port)<< endl; delete name; + // Connect a client struct sockaddr_in cliAddr; len = sizeof(cliAddr); while (true){ int clientFd = accept(serverFd, (struct sockaddr *)&serverAddr, &len); + // Create thread to deal with client pthread_t thread; pthread_create(&thread, NULL, threadFunc, (void *)&clientFd); diff --git a/transfer b/transfer new file mode 100644 index 00000000..e69de29b From 312aa8c3340a8596989b7fe54ed724ff30ca4838 Mon Sep 17 00:00:00 2001 From: Skylar Scorca Date: Sat, 22 Apr 2023 17:50:03 -0400 Subject: [PATCH 7/8] added comments --- kilo.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kilo.c b/kilo.c index 0c0bc6d6..d17632bf 100644 --- a/kilo.c +++ b/kilo.c @@ -1300,6 +1300,8 @@ void initEditor(void) { signal(SIGWINCH, handleSigWinCh); } +/* ========================= Communication with Server ======================== */ + void receiveFile(int fd){ ssize_t n; FILE *file = fopen("transfer", "w"); @@ -1322,6 +1324,8 @@ void receiveFile(int fd){ //editorOpen("test"); } +/* ============================= Main Program ================================== */ + //main program of text-editor client int main(int argc, char **argv) { //check command-line args From 69eaef48a2413a985f8d1179ed18c95c3fd9f641 Mon Sep 17 00:00:00 2001 From: Skylar Scorca Date: Sat, 22 Apr 2023 18:26:37 -0400 Subject: [PATCH 8/8] fixed makefile and readme, copies test to transfer using get command --- Makefile | 6 +++--- README.md | 5 ++++- kilo.c | 6 ++++-- server.cpp | 21 +++++++++++++++++---- test | 4 ++++ 5 files changed, 32 insertions(+), 10 deletions(-) create mode 100644 test diff --git a/Makefile b/Makefile index a32a9303..e4b644fc 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ CC = gcc -g -Wall -W -ansi -pedantic -std=c99 -pthread -o -C+ = g++ -g -Wall -pthread -o +C+ = g++ -g -Wall -pthread -std=c++11 -o -all: clean kilo server +all: kilo server kilo: kilo.c $(CC) kilo kilo.c @@ -10,4 +10,4 @@ server: server.cpp $(C+) server server.cpp clean: - rm -f kilo kilo.exe server server.exe + rm -f kilo server transfer diff --git a/README.md b/README.md index dda79ae8..72998646 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,11 @@ Kilo is a small text editor in less than 1K lines of code (counted with cloc). A screencast is available here: https://asciinema.org/a/90r2i9bq8po03nazhqtsifksb Usage: kilo `` +New Usage: kilo -Keys: +'get' to copy file from server + +Editor Keys: CTRL-S: Save CTRL-Q: Quit diff --git a/kilo.c b/kilo.c index d17632bf..02e5faf4 100644 --- a/kilo.c +++ b/kilo.c @@ -1306,8 +1306,10 @@ void receiveFile(int fd){ ssize_t n; FILE *file = fopen("transfer", "w"); char buffer[1024]; + n = read(fd, buffer, 1024); buffer[n] = '\0'; + while (1){ if ((n = read(fd, buffer, 1024)) > 0){ // printf("Line: %s\n", buffer); @@ -1318,7 +1320,7 @@ void receiveFile(int fd){ return; } fprintf(file, "%s\n", buffer); - send(fd, "ACK", 1024, 0); + send(fd, "ACK", 1024, 0); //why are we sending this? } } //editorOpen("test"); @@ -1360,7 +1362,7 @@ int main(int argc, char **argv) { while (fgets(buffer, 1024, stdin)){ buffer[strcspn(buffer, "\r\n")] = 0; if (!strcmp(buffer, "get")){ - // printf("Get Received\n"); + printf("sending get\n"); send(serverFd, "get", 1024, 0); receiveFile(serverFd); } diff --git a/server.cpp b/server.cpp index f6c5a04a..50f16ad2 100755 --- a/server.cpp +++ b/server.cpp @@ -33,14 +33,25 @@ vector readFile(){ //sendFile - send file line-by-line to a client at fd void sendFile(int fd, vector lines){ vector::iterator i; + send(fd, (void*)"Start Transfer", 1024, 0); - for (i = lines.begin(); i != lines.end(); i++){ + +/* for (i = lines.begin(); i != lines.end(); i++){ char buffer[1024]; string msg = *i; // cout << "Line: " << msg << endl; + send(fd, msg.c_str(), msg.length(), 0); + read(fd, buffer, 1024); + } */ + + //this is the same as the loop that is commented out + for(string msg : lines){ + char buffer[1024]; + send(fd, msg.c_str(), msg.length(), 0); read(fd, buffer, 1024); } + send(fd, (void*)"End Transfer", 1024, 0); } @@ -50,14 +61,16 @@ void *threadFunc(void *args){ int clientFd = *(int*)args; char buffer[1024]; pthread_detach(pthread_self()); + // Read until disconnection while ((n = read(clientFd, buffer, 1024)) > 0){ string line(buffer); + if (line == "exit"){ close(clientFd); } - if (line == "get"){ - // cout << "Get Received" << endl; + else if (line == "get"){ + cout << "Get Received" << endl; sendFile(clientFd, readFile()); } } @@ -121,7 +134,7 @@ int main(void){ len = sizeof(cliAddr); while (true){ int clientFd = accept(serverFd, (struct sockaddr *)&serverAddr, &len); - + // Create thread to deal with client pthread_t thread; pthread_create(&thread, NULL, threadFunc, (void *)&clientFd); diff --git a/test b/test new file mode 100644 index 00000000..57a9c9f5 --- /dev/null +++ b/test @@ -0,0 +1,4 @@ +this is a test file +these are some words +these are some more +bye!