diff options
| author | Cara Salter <cara@devcara.com> | 2022-01-20 23:47:53 -0500 | 
|---|---|---|
| committer | Cara Salter <cara@devcara.com> | 2022-01-20 23:47:53 -0500 | 
| commit | c2352ee043546b518f69c615a1ece778e942e650 (patch) | |
| tree | 6efe18199f0fe2810c879c9251db2897a3244604 | |
| download | cmud-c2352ee043546b518f69c615a1ece778e942e650.tar.gz cmud-c2352ee043546b518f69c615a1ece778e942e650.zip  | |
initial commit
yay start of a state machine and also learning sockets
| -rw-r--r-- | .gitignore | 111 | ||||
| -rw-r--r-- | Makefile | 22 | ||||
| -rw-r--r-- | src/data.c | 60 | ||||
| -rw-r--r-- | src/data.h | 9 | ||||
| -rw-r--r-- | src/login.c | 68 | ||||
| -rw-r--r-- | src/login.h | 32 | ||||
| -rw-r--r-- | src/main.c | 32 | ||||
| -rw-r--r-- | src/server.c | 84 | ||||
| -rw-r--r-- | src/server.h | 17 | 
9 files changed, 435 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a426513 --- /dev/null +++ b/.gitignore @@ -0,0 +1,111 @@ + +# Created by https://www.toptal.com/developers/gitignore/api/c,emacs +# Edit at https://www.toptal.com/developers/gitignore?templates=c,emacs + +### C ### +# Prerequisites +*.d + +# Object files +*.o +*.ko +*.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf + +### Emacs ### +# -*- mode: gitignore; -*- +*~ +\#*\# +/.emacs.desktop +/.emacs.desktop.lock +*.elc +auto-save-list +tramp +.\#* + +# Org-mode +.org-id-locations +*_archive + +# flymake-mode +*_flymake.* + +# eshell files +/eshell/history +/eshell/lastdir + +# elpa packages +/elpa/ + +# reftex files +*.rel + +# AUCTeX auto folder +/auto/ + +# cask packages +.cask/ +dist/ + +# Flycheck +flycheck_*.el + +# server auth directory +/server/ + +# projectiles files +.projectile + +# directory configuration +.dir-locals.el + +# network security +/network-security.data + + +# End of https://www.toptal.com/developers/gitignore/api/c,emacs +cmud* diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1b79565 --- /dev/null +++ b/Makefile @@ -0,0 +1,22 @@ +CC=gcc +CFLAGS=-I. -static +SRCS=src/main.c src/login.c src/server.c src/data.c +BIN=cmud + +%.o: %.c +	$(CC) -c -o $@ $< $(CFLAGS) + +dev: $(SRCS) +	$(CC) -o $(BIN)-devel $(SRCS) $(LFLAGS) -g + +main: $(SRCS) +	$(CC) -o $(BIN) $(SRCS) $(LFLAGS) $(CFLAGS) + +dist: main +	tar czvf $(BIN).tar.gz $(BIN) + +clean: +	rm $(BIN)* + +run: dev +	./cmud-devel 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 <asm-generic/errno-base.h> +#define _GNU_SOURCE +#include "data.h" +#include "login.h" +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <sys/stat.h> + +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 <string.h> +#define _GNU_SOURCE +#include "data.h" +#include "login.h" +#include "server.h" +#include <stdio.h> +#include <stdlib.h> +#include <sys/socket.h> +#include <unistd.h> + +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 <stdio.h> + +/** + * 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 <netinet/in.h> +#include <stdio.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <unistd.h> + +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_  | 
