From efd17b030ea1c046fed48eba2580c9fe7d0ea159 Mon Sep 17 00:00:00 2001 From: Warwick Date: Thu, 20 Jul 2023 17:42:07 +0100 Subject: [PATCH] Initial basic messaging server. --- .gitignore | 8 ++++ CMakeLists.txt | 28 +++++++++++++ src/client/main.c | 79 ++++++++++++++++++++++++++++++++++++ src/server/main.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 216 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 src/client/main.c create mode 100644 src/server/main.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6faf0c4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +.cache +CMakeCache.txt +CMakeFiles +cmake_install.cmake +compile_commands.json +.dir-locals.el +Makefile +Urchin-* diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..3224f2c --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,28 @@ +cmake_minimum_required(VERSION 3.16) +project(Urchin + VERSION 0 + DESCRIPTION "Simple Mud Experiment in C" + HOMEPAGE_URL "https://git.warwick-new.co.uk/" + LANGUAGES C) + +set(CMAKE_C_STANDARD 90) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +set(CMAKE_C_CLANG_TIDY) + +# Compile Server +file(GLOB_RECURSE SERVER_SOURCE_FILES + ${CMAKE_SOURCE_DIR}/src/server/*.c) + +file(GLOB_RECURSE SERVER_HEADER_FILES + ${CMAKE_SOURCE_DIR}/src/server/*.h) + +add_executable(${PROJECT_NAME}-server ${SERVER_HEADER_FILES} ${SERVER_SOURCE_FILES}) + +# Compile Client +file(GLOB_RECURSE CLIENT_SOURCE_FILES + ${CMAKE_SOURCE_DIR}/src/client/*.c) + +file(GLOB_RECURSE CLIENT_HEADER_FILES + ${CMAKE_SOURCE_DIR}/src/client/*.h) + +add_executable(${PROJECT_NAME}-client ${CLIENT_HEADER_FILES} ${CLIENT_SOURCE_FILES}) diff --git a/src/client/main.c b/src/client/main.c new file mode 100644 index 0000000..046dd65 --- /dev/null +++ b/src/client/main.c @@ -0,0 +1,79 @@ +// Sorry in advance for all the comments. This project is also a way for me to +// learn C. + +#include // Contains host structure +#include //sockaddr_in +#include +#include // Keeping for conversion functions +#include +#include +#include // sockaddr +#include + +void error_crash(const char *msg) { + fprintf(stderr, "error crash: %s\n", msg); + exit(EXIT_FAILURE); +} + +void error_warn(const char *msg) { fprintf(stderr, "warning: %s\n", msg); } + +// TODO: Save the logs somewhere +void error_log(const char *msg) { fprintf(stderr, "log: %s\n", msg); } + +int main(int argc, char *argv[]) { + // Set up containers for file descriptor id's + int sockfd, portno, errflag; + struct sockaddr_in serv_addr; + bzero((char *)&serv_addr, sizeof(serv_addr)); + struct hostent *server; + char msgbuffer[255]; + + if (argc < 2) { + error_crash("Not enough server info has been provided"); + } + + if (argc > 2) { + portno = atoi(argv[2]); + } else { + portno = 3940; + } + + // Create socket + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd < 0) + error_crash("Can't open socket."); + + server = gethostbyname(argv[1]); + if (server == NULL) + error_crash("No such host exists :("); + + serv_addr.sin_family = AF_INET; + bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, + server->h_length); + serv_addr.sin_port = htons(portno); + errflag = connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)); + if (errflag < 0) + error_crash("Failed to connect to host"); + + while (1) { + bzero(msgbuffer, sizeof msgbuffer); + fgets(msgbuffer, sizeof msgbuffer, stdin); + errflag = write(sockfd, msgbuffer, strlen(msgbuffer)); + if (errflag < 0) + error_crash("Failed to write message"); + + bzero(msgbuffer, sizeof msgbuffer); + errflag = read(sockfd, msgbuffer, sizeof msgbuffer); + if (errflag < 0) + error_crash("Failed to read message"); + + printf("Server: %s", msgbuffer); + + int cmp = strncmp("Bye", msgbuffer, 3); + if (cmp == 0) + break; + } + + close(sockfd); + return EXIT_SUCCESS; +} diff --git a/src/server/main.c b/src/server/main.c new file mode 100644 index 0000000..79eaef8 --- /dev/null +++ b/src/server/main.c @@ -0,0 +1,101 @@ +// Sorry in advance for all the comments. This project is also a way for me to +// learn C. + +#include //sockaddr_in +#include +#include // Keeping for conversion functions +#include +#include +#include // sockaddr +#include + +void error_crash(const char *msg) { + fprintf(stderr, "error crash: %s\n", msg); + exit(EXIT_FAILURE); +} + +void error_warn(const char *msg) { fprintf(stderr, "warning: %s\n", msg); } + +// TODO: Save the logs somewhere +void error_log(const char *msg) { fprintf(stderr, "log: %s\n", msg); } + +int main(int argc, char *argv[]) { + // Set up containers for file descriptor id's + int sockfd, clientsockfd, portno, errflag; + char msgbuffer[255]; + + // Set port number. + if (argc > 1) { + portno = atoi(argv[1]); + } else { + portno = 3940; + } + + // Socket address info + struct sockaddr_in serv_addr, cli_addr; + socklen_t clilen = sizeof cli_addr; // We can do this here as cli_addr isn't + // touched until it's used + + // Create socket + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd < 0) { + error_crash("Can't open socket."); + } + + // Make sure there is no junk data in serve_addr + bzero((char *)&serv_addr, sizeof serv_addr); + + // Tell the connection to use ipv4 and port number + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = INADDR_ANY; + serv_addr.sin_port = htons(portno); + + // Bind Socket + errflag = bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)); + if (errflag < 0) { + error_crash("Can't bind socket"); + } + + errflag = listen(sockfd, 5); + if (errflag < 0) { + error_crash("Can't listen for connections"); + } + + char portstr[5]; // Buffer to store string version of port + snprintf(portstr, sizeof portstr, "%d", portno); + printf("Server Listening on port: %s\n", portstr); + + clientsockfd = accept(sockfd, (struct sockaddr *)&cli_addr, &clilen); + if (clientsockfd < 0) { + error_crash("Can't accept connection"); + } + + while (1) { + // Empty message buffer + bzero(msgbuffer, sizeof msgbuffer); + + errflag = read(clientsockfd, msgbuffer, sizeof msgbuffer); + if (errflag < 0) { + error_crash("Didn't recieve message from connection"); + } + printf("Client: %s\n", msgbuffer); + + // clear buffer for writing + bzero(msgbuffer, sizeof msgbuffer); + fgets(msgbuffer, sizeof msgbuffer, stdin); + + errflag = write(clientsockfd, msgbuffer, strlen(msgbuffer)); + if (errflag < 0) { + error_crash("Couldn't write response message"); + } + + int cmp = strncmp("Bye", msgbuffer, 3); + if (cmp == 0) + break; + } + + close(clientsockfd); + close(sockfd); + + return EXIT_SUCCESS; +}