From c2352ee043546b518f69c615a1ece778e942e650 Mon Sep 17 00:00:00 2001 From: Cara Salter Date: Thu, 20 Jan 2022 23:47:53 -0500 Subject: initial commit yay start of a state machine and also learning sockets --- src/data.c | 60 +++++++++++++++++++++++++++++++++++++++++++ src/data.h | 9 +++++++ src/login.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++ src/login.h | 32 +++++++++++++++++++++++ src/main.c | 32 +++++++++++++++++++++++ src/server.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/server.h | 17 ++++++++++++ 7 files changed, 302 insertions(+) create mode 100644 src/data.c create mode 100644 src/data.h create mode 100644 src/login.c create mode 100644 src/login.h create mode 100644 src/main.c create mode 100644 src/server.c create mode 100644 src/server.h (limited to 'src') diff --git a/src/data.c b/src/data.c new file mode 100644 index 0000000..15617e0 --- /dev/null +++ b/src/data.c @@ -0,0 +1,60 @@ +#include +#define _GNU_SOURCE +#include "data.h" +#include "login.h" +#include +#include +#include +#include + +int try_make_data_dirs() { + int err = 0; + err = mkdir("data", S_IRWXU); + err = mkdir("data/players", S_IRWXU); + + return err; +} + +int try_load_plr(char *player_name, playerc_t *plr) { + int err = 0; + err = try_make_data_dirs(); + if (err) { + switch (err) { + // Now the errors that continue will be from I/O, which we can use to figure out if the file exists in login + case EACCES: /* No permissions***************************************/ + printf("No permissions to create directories\n"); + return -1; + default:/* Do nothing because this is fine****************************/ + break; + } + } + + char *fname; + asprintf(&fname, "data/players/%s.plr", player_name); + + FILE *fp = fopen(fname, "rb"); + + fread(&plr, sizeof(playerc_t), 1, fp); + + return err; +} + +int try_write_file(player_t *plr) { + int err = 0; + + err = try_make_data_dirs(); + if (err) { + perror("creating data directories"); + printf("Could not create data/\n"); + return err; + } + + char *fname; + asprintf(&fname, "data/players/%s.plr", *plr->name); + + FILE *fp = fopen(fname, "wb"); + + fwrite(&plr, sizeof(player_t), 1, fp); + + return err; +} diff --git a/src/data.h b/src/data.h new file mode 100644 index 0000000..a030d50 --- /dev/null +++ b/src/data.h @@ -0,0 +1,9 @@ +#ifndef DATA_H +#define DATA_H + +#include "login.h" +int try_load_file(char *player_name); + +int try_write_file(player_t *plr); + +#endif diff --git a/src/login.c b/src/login.c new file mode 100644 index 0000000..c6ab408 --- /dev/null +++ b/src/login.c @@ -0,0 +1,68 @@ +#include +#define _GNU_SOURCE +#include "data.h" +#include "login.h" +#include "server.h" +#include +#include +#include +#include + +void handle_player(int conn_fd) { + playerc_t plrc = {0}; + plrc.state = LoggedOut; + plrc.conn = conn_fd; + player_t plr = {0}; + plrc.plr = plr; + + int err = step_login(&plrc, conn_fd); + if (err) { + err = send_to_fd(conn_fd, "Error in login process, exiting"); + if (err) { + printf("Could not send error message"); + } + close(conn_fd); + return; + } + + close(conn_fd); +} + +int step_login(playerc_t *player, int conn_fd) { + int err = 0; + + for (;;) { + switch (player->state) { + case LoggedOut: /* the player has yet to log in, this is a fresh connection! + */ + send_to_fd(player->conn, + "Welcome! Please enter your **username** below\n"); + char *buf = (char *)malloc(1 << 10); + recv(player->conn, buf, sizeof(buf), 0); + err = try_load_file(buf); + if (err) { + // File doesn't exist, let's create a player! + strcpy(player->plr.name, buf); + send_to_fd(player->conn, "Howdy! Want to introduce yourself? [y|n]\n"); + recv(player->conn, buf, sizeof(buf), 0); + if (buf[0] == 'y') { + player->state = WantMakeAccount; + } else if (buf[0] == 'n') { + send_to_fd(player->conn, + "Awww :(. Oh well, hope to see you again soon!\n"); + return 4; + } + continue; + } else { + player->state = EnterPassword; + continue; + } + case WantMakeAccount: + asprintf(&buf, + "Welcome aboard %s! Why don't you start us off by giving me a " + "password.\n", ) send_to_fd(player->conn, "Welcome aboard! ") + } + } + + return err; +} diff --git a/src/login.h b/src/login.h new file mode 100644 index 0000000..6d4cc3d --- /dev/null +++ b/src/login.h @@ -0,0 +1,32 @@ +#ifndef LOGIN_H +#define LOGIN_H +enum login_state { + LoggedOut, + EnterPassword, + WantMakeAccount, + MakePassword, + MakeConfirmPassword, + Complete +}; + +typedef struct player { + int xp; + int hp; + int max_hp; + int level; + int location_id; + + char *name[]; +} player_t; + +typedef struct player_conn { + int conn; + enum login_state state; + struct player plr; +} playerc_t; + +int step_login(playerc_t *player, int conn_fd); + +void handle_player(int conn_fd); + +#endif diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..4f848ba --- /dev/null +++ b/src/main.c @@ -0,0 +1,32 @@ +/** + * Creates a socket for the server + * */ +#include "server.h" +#include + +/** + * Server entrypoint + * + * sets up everything needed to handle sockets and connections + * */ +int main() { + int err = 0; + server_t server = {0}; + + err = server_listen(&server); + + if (err) { + printf("Failed to listen on address"); + return err; + } + + for (;;) { + err = server_accept(&server); + if (err) { + printf("Failed accepting connection"); + return err; + } + } + + return 0; +} diff --git a/src/server.c b/src/server.c new file mode 100644 index 0000000..bee6153 --- /dev/null +++ b/src/server.c @@ -0,0 +1,84 @@ +#include "server.h" +#include "login.h" +#include +#include +#include +#include +#include +#include + +int server_listen(server_t *server) { + /* + ** + ** The `socket(2)` syscall returns a file descriptor for a socket + ** + ** it takes two arguments that we care about: + ** - domain -- AF_INET for IPv4 + ** - type -- SOCK_STREAM sequenced and reliable + ** + */ + int err = (server->listen_fd = socket(AF_INET, SOCK_STREAM, 0)); + + if (err == -1) { + perror("socket"); + printf("Failed to create socket"); + return err; + } + + struct sockaddr_in server_addr = {0}; + + server_addr.sin_family = AF_INET; + server_addr.sin_addr.s_addr = htonl(INADDR_ANY); + server_addr.sin_port = htons(8000); + + err = bind(server->listen_fd, (struct sockaddr *)&server_addr, + sizeof(server_addr)); + if (err == -1) { + perror("bind"); + printf("Failed to bind socket\n"); + return err; + } + + err = listen(server->listen_fd, 100); + if (err == -1) { + perror("listen"); + printf("Failed to listen on socket\n"); + return err; + } + + return 0; +} + +int server_accept(server_t *server) { + int err = 0; + int conn_fd; + socklen_t client_len; + + struct sockaddr_in client_addr; + + client_len = sizeof(client_addr); + + for (;;) { + err = (conn_fd = accept(server->listen_fd, (struct sockaddr *)&client_addr, + &client_len)); + if (err == -1) { + perror("Accept"); + printf("failed accepting connection\n"); + return err; + } + + if (!fork()) { + handle_player(conn_fd); + } + } + + return err; +} + +int send_to_fd(int fd, char *msg) { + int err = 0; + + err = send(fd, msg, strlen(msg), 0); + + return err; +} diff --git a/src/server.h b/src/server.h new file mode 100644 index 0000000..5392f56 --- /dev/null +++ b/src/server.h @@ -0,0 +1,17 @@ +#ifndef SERVER_H_ +#define SERVER_H_ + +/** + * Yay for storing the server properties + * */ +typedef struct server { + int listen_fd; +} server_t; + +int server_listen(server_t *server); + +int server_accept(server_t *server); + +int send_to_fd(int fd, char *msg); + +#endif // SERVER_H_ -- cgit v1.2.3