diff --git a/Makefile b/Makefile index 13620cc1..e4b644fc 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,13 @@ -all: kilo +CC = gcc -g -Wall -W -ansi -pedantic -std=c99 -pthread -o +C+ = g++ -g -Wall -pthread -std=c++11 -o + +all: kilo server kilo: kilo.c - $(CC) -o kilo kilo.c -Wall -W -pedantic -std=c99 + $(CC) kilo kilo.c + +server: server.cpp + $(C+) server server.cpp clean: - rm kilo + rm -f kilo server transfer diff --git a/README.md b/README.md index 47d612fe..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 @@ -24,3 +27,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 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. diff --git a/kilo.c b/kilo.c index 406eb7be..02e5faf4 100644 --- a/kilo.c +++ b/kilo.c @@ -53,6 +53,7 @@ #include #include #include +#include /* Syntax highlight types */ #define HL_NORMAL 0 @@ -109,6 +110,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 +201,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 +218,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 +366,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 +556,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 +625,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 +861,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 +1018,7 @@ void editorSetStatusMessage(const char *fmt, ...) { } /* =============================== Find mode ================================ */ +//Note: probably don't need to edit these #define KILO_QUERY_LEN 256 @@ -1107,6 +1118,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,14 +1300,81 @@ void initEditor(void) { signal(SIGWINCH, handleSigWinCh); } +/* ========================= Communication with Server ======================== */ + +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); //why are we sending this? + } + } + //editorOpen("test"); +} + +/* ============================= Main Program ================================== */ + +//main program of text-editor client int main(int argc, char **argv) { - if (argc != 2) { - fprintf(stderr,"Usage: kilo \n"); + //check command-line args + if (argc != 3) { + fprintf(stderr,"Usage: kilo \n"); exit(1); } - initEditor(); - editorSelectSyntaxHighlight(argv[1]); + //setup + 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("sending get\n"); + send(serverFd, "get", 1024, 0); + receiveFile(serverFd); + } + // printf("%s\n", buffer); + } + + close(serverFd); + // exit(0); + + //start editor + initEditor(); + editorSelectSyntaxHighlight("transfer"); editorOpen(argv[1]); enableRawMode(STDIN_FILENO); editorSetStatusMessage( diff --git a/server.cpp b/server.cpp new file mode 100755 index 00000000..50f16ad2 --- /dev/null +++ b/server.cpp @@ -0,0 +1,143 @@ +// C Headers +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +// C++ Headers +#include +#include +#include +#include +#include +#include +using namespace std; + +//readFile - reads lines in file into the data structure lines +vector readFile(){ + string line; + vector lines; + ifstream file("test"); + while (getline(file, line)){ + lines.push_back(line); + } + 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); + +/* 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); +} + +//threadFunc - thread function to read any messages from a client +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); + } + else if (line == "get"){ + cout << "Get Received" << endl; + sendFile(clientFd, readFile()); + } + } + 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; + 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 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! diff --git a/transfer b/transfer new file mode 100644 index 00000000..e69de29b