]> git.lizzy.rs Git - dragonblocks_alpha.git/commitdiff
Move code to src/
authorElias Fleckenstein <eliasfleckenstein@web.de>
Wed, 24 Mar 2021 10:57:29 +0000 (11:57 +0100)
committerElias Fleckenstein <eliasfleckenstein@web.de>
Wed, 24 Mar 2021 10:57:29 +0000 (11:57 +0100)
53 files changed:
BUILDING.md
Makefile [deleted file]
array.c [deleted file]
array.h [deleted file]
binsearch.c [deleted file]
binsearch.h [deleted file]
client.c [deleted file]
client.h [deleted file]
clientcommands.c [deleted file]
clientcommands.h [deleted file]
linkedlist.c [deleted file]
linkedlist.h [deleted file]
map.c [deleted file]
map.h [deleted file]
network.c [deleted file]
network.h [deleted file]
node.h [deleted file]
server.c [deleted file]
server.h [deleted file]
servercommands.c [deleted file]
servercommands.h [deleted file]
signal.c [deleted file]
signal.h [deleted file]
src/Makefile [new file with mode: 0644]
src/array.c [new file with mode: 0644]
src/array.h [new file with mode: 0644]
src/binsearch.c [new file with mode: 0644]
src/binsearch.h [new file with mode: 0644]
src/client.c [new file with mode: 0644]
src/client.h [new file with mode: 0644]
src/clientcommands.c [new file with mode: 0644]
src/clientcommands.h [new file with mode: 0644]
src/linkedlist.c [new file with mode: 0644]
src/linkedlist.h [new file with mode: 0644]
src/map.c [new file with mode: 0644]
src/map.h [new file with mode: 0644]
src/network.c [new file with mode: 0644]
src/network.h [new file with mode: 0644]
src/node.h [new file with mode: 0644]
src/server.c [new file with mode: 0644]
src/server.h [new file with mode: 0644]
src/servercommands.c [new file with mode: 0644]
src/servercommands.h [new file with mode: 0644]
src/signal.c [new file with mode: 0644]
src/signal.h [new file with mode: 0644]
src/types.c [new file with mode: 0644]
src/types.h [new file with mode: 0644]
src/util.c [new file with mode: 0644]
src/util.h [new file with mode: 0644]
types.c [deleted file]
types.h [deleted file]
util.c [deleted file]
util.h [deleted file]

index 6bf62f500b2a422495ef6194d1f350c60534b936..0f257a124ee0ac238c455515b445bc9bf50e861c 100644 (file)
@@ -1,5 +1,7 @@
 # Building instructions
 
+The code and the Makefile are located in the src/ directory
+
 ## Available targets
 - `all` (default)
 - `Dragonblocks`
diff --git a/Makefile b/Makefile
deleted file mode 100644 (file)
index 98ea2a2..0000000
--- a/Makefile
+++ /dev/null
@@ -1,26 +0,0 @@
-COMMON = array.o binsearch.o linkedlist.o map.o signal.o util.o types.o
-SERVER = $(COMMON) server.o servercommands.o
-CLIENT = $(COMMON) client.o clientcommands.o
-LIBRARIES = -lpthread -lm
-FLAGS = -g
-
-ifdef RELEASE
-FLAGS = -O3
-endif
-
-all: Dragonblocks DragonblocksServer
-
-Dragonblocks: $(CLIENT)
-       cc $(FLAGS) -o Dragonblocks $(CLIENT) $(LIBRARIES)
-
-DragonblocksServer: $(SERVER)
-       cc $(FLAGS) -o DragonblocksServer $(SERVER) $(LIBRARIES)
-
-%.o: %.c
-       cc $(FLAGS) -o $@ -c -Wall -Wextra -Wpedantic -Werror $<
-
-clean:
-       rm -rf *.o
-
-clobber: clean
-       rm -rf Dragonblocks DragonblocksServer
diff --git a/array.c b/array.c
deleted file mode 100644 (file)
index de7733b..0000000
--- a/array.c
+++ /dev/null
@@ -1,40 +0,0 @@
-#include <string.h>
-#include <stdlib.h>
-#include "array.h"
-
-static void array_realloc(Array *array)
-{
-       if (array->siz > array->cap) {
-               array->cap = array->siz + ARRAY_REALLOC_EXTRA;
-               array->ptr = realloc(array->ptr, array->cap * sizeof(void *));
-       }
-}
-
-static void array_alloc(Array *array, size_t siz)
-{
-       array->siz += siz;
-       array_realloc(array);
-}
-
-void array_insert(Array *array, void *elem, size_t idx)
-{
-       size_t oldsiz = array->siz;
-       array_alloc(array, 1);
-
-       void **iptr = array->ptr + idx;
-       memmove(iptr + 1, iptr, (oldsiz - idx) * sizeof(void *));
-       *iptr = elem;
-}
-
-void array_append(Array *array, void *elem)
-{
-       size_t oldsiz = array->siz;
-       array_alloc(array, 1);
-
-       array->ptr[oldsiz] = elem;
-}
-
-Array array_create()
-{
-       return (Array) {0, 0, NULL};
-}
diff --git a/array.h b/array.h
deleted file mode 100644 (file)
index c0b42b5..0000000
--- a/array.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef _ARRAY_H_
-#define _ARRAY_H_
-
-#define ARRAY_REALLOC_EXTRA 25
-
-#include <stddef.h>
-
-typedef struct
-{
-       size_t siz, cap;
-       void **ptr;
-} Array;
-
-void array_insert(Array *array, void *elem, size_t idx);
-void array_append(Array *array, void *elem);
-Array array_create();
-
-#endif
diff --git a/binsearch.c b/binsearch.c
deleted file mode 100644 (file)
index d6b1362..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-#include "binsearch.h"
-
-BinsearchResult binsearch(void *search, void **array, size_t size, BinsearchComparator cmp)
-{
-       size_t min, max, index;
-
-       min = index = 0;
-       max = size;
-
-       while (min < max) {
-               index = min;
-
-               size_t mid = (max + min) / 2;
-               s8 state = cmp(search, array[mid]);
-
-               if (state == 0)
-                       return (BinsearchResult) {true, mid};
-               else if (state > 0)
-                       max = mid;
-               else
-                       min = mid;
-       }
-
-       return (BinsearchResult) {false, index};
-}
diff --git a/binsearch.h b/binsearch.h
deleted file mode 100644 (file)
index f6337a2..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef _BINSEARCH_H_
-#define _BINSEARCH_H_
-
-#include <stddef.h>
-#include <stdbool.h>
-#include "types.h"
-
-typedef s8 (*BinsearchComparator)(void *search, void *element);
-
-typedef struct {
-       bool success;
-       size_t index;
-} BinsearchResult;
-
-BinsearchResult binsearch(void *search, void **array, size_t size, BinsearchComparator cmp);
-
-#endif
diff --git a/client.c b/client.c
deleted file mode 100644 (file)
index 62afbda..0000000
--- a/client.c
+++ /dev/null
@@ -1,195 +0,0 @@
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <arpa/inet.h>
-#include <unistd.h>
-#include <errno.h>
-#include <netdb.h>
-#include "client.h"
-#include "signal.h"
-#include "util.h"
-
-#include "network.c"
-
-void client_disconnect(Client *client, bool send, const char *detail)
-{
-       pthread_mutex_lock(&client->mtx);
-       if (client->state != CS_DISCONNECTED) {
-               if (send)
-                       write_u32(client->fd, SC_DISCONNECT);
-
-               client->state = CS_DISCONNECTED;
-               printf("Disconnected %s%s%s\n", INBRACES(detail));
-               close(client->fd);
-       }
-       pthread_mutex_unlock(&client->mtx);
-}
-
-static void *reciever_thread(void *cliptr)
-{
-       Client *client = cliptr;
-
-       handle_packets(client);
-
-       if (errno == EINTR)
-               client_disconnect(client, true, NULL);
-       else
-               client_disconnect(client, false, "network error");
-
-       if (client->name)
-               free(client->name);
-
-       pthread_mutex_destroy(&client->mtx);
-
-       exit(EXIT_SUCCESS);
-       return NULL;
-}
-
-static void client_loop(Client *client)
-{
-       while (client->state != CS_DISCONNECTED) {
-               if (client->state == CS_CREATED) {
-                       printf("Enter name: ");
-                       fflush(stdout);
-                       char name[NAME_MAX];
-                       if (scanf("%s", name) == EOF)
-                               return;
-                       client->name = strdup(name);
-                       pthread_mutex_lock(&client->mtx);
-                       if (write_u32(client->fd, SC_AUTH) && write(client->fd, client->name, strlen(name) + 1)) {
-                               client->state = CS_AUTH;
-                               printf("Authenticating...\n");
-                       }
-                       pthread_mutex_unlock(&client->mtx);
-               } else if (client->state == CS_ACTIVE) {
-                       printf("%s: ", client->name);
-                       fflush(stdout);
-                       char buffer[BUFSIZ] = {0};
-                       if (scanf("%s", buffer) == EOF)
-                               return;
-                       if (strcmp(buffer, "disconnect") == 0) {
-                               return;
-                       } else if (strcmp(buffer, "setnode") == 0) {
-                               v3s32 pos;
-                               char node[BUFSIZ] = {0};
-                               if (scanf("%d %d %d %s", &pos.x, &pos.y, &pos.z, node) == EOF)
-                                       return;
-                               Node node_type = NODE_INVALID;
-                               if (strcmp(node, "air") == 0)
-                                       node_type = NODE_AIR;
-                               else if (strcmp(node, "grass") == 0)
-                                       node_type = NODE_GRASS;
-                               else if (strcmp(node, "dirt") == 0)
-                                       node_type = NODE_DIRT;
-                               else if (strcmp(node, "stone") == 0)
-                                       node_type = NODE_STONE;
-                               if (node_type == NODE_INVALID) {
-                                       printf("Invalid node\n");
-                               } else {
-                                       pthread_mutex_lock(&client->mtx);
-                                       (void) (write_u32(client->fd, SC_SETNODE) && write_v3s32(client->fd, pos) && write_u32(client->fd, node_type));
-                                       pthread_mutex_unlock(&client->mtx);
-                               }
-                       } else if (strcmp(buffer, "getnode") == 0) {
-                               v3s32 pos;
-                               if (scanf("%d %d %d", &pos.x, &pos.y, &pos.z) == EOF)
-                                       return;
-                               pthread_mutex_lock(&client->mtx);
-                               (void) (write_u32(client->fd, SC_GETBLOCK) && write_v3s32(client->fd, map_node_to_block_pos(pos, NULL)));
-                               pthread_mutex_unlock(&client->mtx);
-                       } else if (strcmp(buffer, "printnode") == 0) {
-                               v3s32 pos;
-                               if (scanf("%d %d %d", &pos.x, &pos.y, &pos.z) == EOF)
-                                       return;
-                               MapNode node = map_get_node(client->map, pos);
-                               const char *nodename;
-                               switch (node.type) {
-                                       case NODE_UNLOADED:
-                                               nodename = "unloaded";
-                                               break;
-                                       case NODE_AIR:
-                                               nodename = "air";
-                                               break;
-                                       case NODE_GRASS:
-                                               nodename = "grass";
-                                               break;
-                                       case NODE_DIRT:
-                                               nodename = "dirt";
-                                               break;
-                                       case NODE_STONE:
-                                               nodename = "stone";
-                                               break;
-                                       case NODE_INVALID:
-                                               nodename = "invalid";
-                                               break;
-                               }
-                               printf("%s\n", nodename);
-                       } else if (strcmp(buffer, "kick") == 0) {
-                               char target_name[NAME_MAX];
-                               if (scanf("%s", target_name) == EOF)
-                                       return;
-                               pthread_mutex_lock(&client->mtx);
-                               (void) (write_u32(client->fd, SC_KICK) && write(client->fd, target_name, strlen(target_name) + 1) != -1);
-                               pthread_mutex_unlock(&client->mtx);
-                       } else {
-                               printf("Invalid command: %s\n", buffer);
-                       }
-               } else {
-                       sched_yield();
-               }
-       }
-}
-
-int main(int argc, char **argv)
-{
-       program_name = argv[0];
-
-       if (argc < 3)
-               internal_error("missing address or port");
-
-       struct addrinfo hints = {
-               .ai_family = AF_UNSPEC,                 // support both IPv4 and IPv6
-               .ai_socktype = SOCK_STREAM,
-               .ai_protocol = 0,
-               .ai_flags = AI_NUMERICSERV,
-       };
-
-       struct addrinfo *info = NULL;
-
-       int gai_state = getaddrinfo(argv[1], argv[2], &hints, &info);
-
-       if (gai_state != 0)
-               internal_error(gai_strerror(gai_state));
-
-       Client client = {
-               .fd = -1,
-               .map = NULL,
-               .name = NULL,
-               .state = CS_CREATED,
-       };
-
-       pthread_mutex_init(&client.mtx, NULL);
-
-       client.fd = socket(info->ai_family, info->ai_socktype, info->ai_protocol);
-
-       if (client.fd == -1)
-               syscall_error("socket");
-
-       if (connect(client.fd, info->ai_addr, info->ai_addrlen) == -1)
-               syscall_error("connect");
-
-       freeaddrinfo(info);
-
-       init_signal_handlers();
-
-       client.map = map_create();
-
-       pthread_t recv_thread;
-       pthread_create(&recv_thread, NULL, &reciever_thread, &client);
-
-       client_loop(&client);
-
-       client_disconnect(&client, true, NULL);
-
-       pthread_join(recv_thread, NULL);
-}
diff --git a/client.h b/client.h
deleted file mode 100644 (file)
index 2b8c431..0000000
--- a/client.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef _CLIENT_H_
-#define _CLIENT_H_
-
-#include <stdbool.h>
-#include <pthread.h>
-#include "servercommands.h"
-#include "clientcommands.h"
-#include "network.h"
-#include "map.h"
-
-typedef struct Client
-{
-       int fd;
-       char *name;
-       Map *map;
-       ClientState state;
-       pthread_mutex_t mtx;
-} Client;
-
-void client_disconnect(Client *client, bool send, const char *detail);
-
-#endif
diff --git a/clientcommands.c b/clientcommands.c
deleted file mode 100644 (file)
index f158a71..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-#include <stdio.h>
-#include "client.h"
-#include "types.h"
-
-static bool disconnect_handler(Client *client, bool good)
-{
-       if (good)
-               client_disconnect(client, false, NULL);
-       return true;
-}
-
-static bool auth_handler(Client *client, bool good)
-{
-       u8 success;
-       if (! read_u8(client->fd, &success))
-               return false;
-
-       if (! good)
-               return true;
-
-       if (success) {
-               printf("Authenticated successfully\n");
-               client->state = CS_ACTIVE;
-       } else {
-               printf("Authentication failed, please try again\n");
-               client->state = CS_CREATED;
-       }
-
-       return true;
-}
-
-static bool block_handler(Client *client, bool good)
-{
-       if (good)
-               return map_deserialize_block(client->fd, client->map);
-       return true;
-}
-
-CommandHandler command_handlers[CLIENT_COMMAND_COUNT] = {
-       {0},
-       {&disconnect_handler, "DISCONNECT", CS_CREATED | CS_AUTH | CS_ACTIVE},
-       {&auth_handler, "AUTH", CS_AUTH},
-       {&block_handler, "BLOCK", CS_ACTIVE},
-};
diff --git a/clientcommands.h b/clientcommands.h
deleted file mode 100644 (file)
index 3249ae2..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef _CLIENT_COMMAND_H_
-#define _CLIENT_COMMAND_H_
-
-typedef enum
-{
-       CLIENT_COMMAND_NULL,
-       CC_DISCONNECT,
-       CC_AUTH,
-       CC_BLOCK,
-       CLIENT_COMMAND_COUNT
-} ClientCommand;
-
-#ifdef _SERVER_H_
-typedef ClientCommand RemoteCommand;
-#endif
-
-#ifdef _CLIENT_H_
-typedef ClientCommand HostCommand;
-#define HOST_COMMAND_COUNT CLIENT_COMMAND_COUNT
-#endif
-
-#endif
diff --git a/linkedlist.c b/linkedlist.c
deleted file mode 100644 (file)
index 5618c65..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-#include <stdlib.h>
-#include <string.h>
-#include "linkedlist.h"
-
-LinkedList linked_list_create()
-{
-       return (LinkedList) {NULL};
-}
-
-void linked_list_clear(LinkedList *list)
-{
-       for (LinkedListPair *pair = list->first; pair != NULL;) {
-               LinkedListPair *next = pair->next;
-               free(pair);
-               pair = next;
-       }
-       list->first = NULL;
-}
-
-static LinkedListPair *make_pair(const char *key, void *value)
-{
-       LinkedListPair *pair = malloc(sizeof(LinkedListPair));
-       pair->key = key;
-       pair->value = value;
-       pair->next = NULL;
-       return pair;
-}
-
-bool linked_list_put(LinkedList *list, const char *key, void *value)
-{
-       LinkedListPair **pairptr;
-       for (pairptr = &list->first; *pairptr != NULL; pairptr = &(*pairptr)->next) {
-               if (strcmp((*pairptr)->key, key) == 0)
-                       return false;
-       }
-       *pairptr = make_pair(key, value);
-       return true;
-}
-
-void linked_list_set(LinkedList *list, const char *key, void *value)
-{
-       LinkedListPair **pairptr;
-       for (pairptr = &list->first; *pairptr != NULL; pairptr = &(*pairptr)->next) {
-               if (strcmp((*pairptr)->key, key) == 0)
-                       break;
-       }
-       *pairptr = make_pair(key, value);
-}
-
-void linked_list_delete(LinkedList *list, const char *key)
-{
-       for (LinkedListPair **pairptr = &list->first; *pairptr != NULL; pairptr = &(*pairptr)->next) {
-               if (strcmp((*pairptr)->key, key) == 0) {
-                       LinkedListPair *pair = *pairptr;
-                       *pairptr = pair->next;
-                       free(pair);
-                       return;
-               }
-       }
-}
-
-void *linked_list_get(LinkedList *list, const char *key)
-{
-       for (LinkedListPair *pair = list->first; pair != NULL; pair = pair->next)
-               if (strcmp(pair->key, key) == 0)
-                       return pair->value;
-       return NULL;
-}
diff --git a/linkedlist.h b/linkedlist.h
deleted file mode 100644 (file)
index a3604c2..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef _LINKEDLIST_H_
-#define _LINKEDLIST_H_
-
-#include <stdbool.h>
-
-#define ITERATE_LINKEDLIST(list, pair) for (LinkedListPair *pair = (list)->first; pair != NULL; pair = pair->next)
-
-typedef struct LinkedListPair
-{
-       struct LinkedListPair *next;
-       const char *key;
-       void *value;
-} LinkedListPair;
-
-typedef struct
-{
-       LinkedListPair *first;
-} LinkedList;
-
-LinkedList linked_list_create();
-void linked_list_clear(LinkedList *list);
-
-bool linked_list_put(LinkedList *list, const char *key, void *value);
-void linked_list_set(LinkedList *list, const char *key, void *value);
-void *linked_list_get(LinkedList *list, const char *key);
-void linked_list_delete(LinkedList *list, const char *key);
-
-void linked_list_serialize(int fd); // ToDo
-void linked_list_deserialize(int fd, LinkedList *); // ToDo
-
-#endif
diff --git a/map.c b/map.c
deleted file mode 100644 (file)
index d85455c..0000000
--- a/map.c
+++ /dev/null
@@ -1,185 +0,0 @@
-#include <stdlib.h>
-#include <stdbool.h>
-#include <math.h>
-#include "binsearch.h"
-#include "map.h"
-#include "util.h"
-
-#define CMPBOUNDS(x) x == 0 ? 0 : x > 0 ? 1 : -1
-
-static void raw_delete_block(MapBlock *block)
-{
-       ITERATE_MAPBLOCK map_node_clear(&block->data[x][y][z]);
-       free(block);
-}
-
-static s8 sector_compare(void *hash, void *sector)
-{
-       s64 d = *((u64 *) hash) - ((MapSector *) sector)->hash;
-       return CMPBOUNDS(d);
-}
-
-MapSector *map_get_sector(Map *map, v2s32 pos, bool create)
-{
-       u64 hash = ((u64) pos.x << 32) + (u64) pos.y;
-       BinsearchResult res = binsearch(&hash, map->sectors.ptr, map->sectors.siz, &sector_compare);
-
-       if (res.success)
-               return map->sectors.ptr[res.index];
-       if (! create)
-               return NULL;
-
-       MapSector *sector = malloc(sizeof(MapSector));
-       sector->pos = pos;
-       sector->hash = hash;
-       sector->blocks = array_create();
-
-       array_insert(&map->sectors, sector, res.index);
-
-       return sector;
-}
-
-static s8 block_compare(void *level, void *block)
-{
-       s32 d = *((s32 *) level) - ((MapBlock *) block)->pos.y;
-       return CMPBOUNDS(d);
-}
-
-MapBlock *map_get_block(Map *map, v3s32 pos, bool create)
-{
-       MapSector *sector = map_get_sector(map, (v2s32) {pos.x, pos.z}, create);
-       if (! sector)
-               return NULL;
-
-       BinsearchResult res = binsearch(&pos.y, sector->blocks.ptr, sector->blocks.siz, &block_compare);
-
-       if (res.success)
-               return sector->blocks.ptr[res.index];
-       if (! create)
-               return NULL;
-
-       MapBlock *block = malloc(sizeof(MapBlock));
-       block->pos = pos;
-
-       MapNode air = map_node_create(NODE_AIR);
-       ITERATE_MAPBLOCK block->data[x][y][z] = air;
-
-       array_insert(&sector->blocks, block, res.index);
-
-       return block;
-}
-
-bool map_deserialize_node(int fd, MapNode *node)
-{
-       Node type;
-
-       if (! read_u32(fd, &type))
-               return false;
-
-       if (type > NODE_INVALID)
-               type = NODE_INVALID;
-
-       *node = map_node_create(type);
-
-       return true;
-}
-
-bool map_serialize_block(int fd, MapBlock *block)
-{
-       if (! write_v3s32(fd, block->pos))
-               return false;
-
-       ITERATE_MAPBLOCK {
-               if (! write_u32(fd, block->data[x][y][z].type))
-                       return false;
-       }
-
-       return true;
-}
-
-bool map_deserialize_block(int fd, Map *map)
-{
-       MapBlock *block = malloc(sizeof(MapBlock));
-
-       if (! read_v3s32(fd, &block->pos))
-               return false;
-
-       ITERATE_MAPBLOCK {
-               if (! map_deserialize_node(fd, &block->data[x][y][z])) {
-                       free(block);
-                       return false;
-               }
-       }
-
-       MapSector *sector = map_get_sector(map, (v2s32) {block->pos.x, block->pos.z}, true);
-       BinsearchResult res = binsearch(&block->pos.y, sector->blocks.ptr, sector->blocks.siz, &block_compare);
-       if (res.success) {
-               raw_delete_block(sector->blocks.ptr[res.index]);
-               sector->blocks.ptr[res.index] = block;
-       } else {
-               array_insert(&sector->blocks, block, res.index);
-       }
-
-       return true;
-}
-
-
-v3s32 map_node_to_block_pos(v3s32 pos, v3u8 *offset)
-{
-       if (offset)
-               *offset = (v3u8) {(u32) pos.x % 16, (u32) pos.y % 16, (u32) pos.z % 16};
-       return (v3s32) {floor((double) pos.x / 16), floor((double) pos.y / 16), floor((double) pos.z / 16)};
-}
-
-
-MapNode map_get_node(Map *map, v3s32 pos)
-{
-       v3u8 offset;
-       v3s32 blockpos = map_node_to_block_pos(pos, &offset);
-       MapBlock *block = map_get_block(map, blockpos, false);
-       if (! block)
-               return map_node_create(NODE_UNLOADED);
-       return block->data[offset.x][offset.y][offset.z];
-}
-
-void map_set_node(Map *map, v3s32 pos, MapNode node)
-{
-       v3u8 offset;
-       MapBlock *block = map_get_block(map, map_node_to_block_pos(pos, &offset), true);
-       MapNode *current_node = &block->data[offset.x][offset.y][offset.z];
-       map_node_clear(current_node);
-       *current_node = node;
-}
-
-MapNode map_node_create(Node type)
-{
-       return (MapNode) {type, linked_list_create()};
-}
-
-void map_node_clear(MapNode *node)
-{
-       linked_list_clear(&node->meta);
-}
-
-Map *map_create()
-{
-       Map *map = malloc(sizeof(Map));
-       map->sectors = array_create();
-
-       return map;
-}
-
-void map_delete(Map *map)
-{
-       for (size_t s = 0; s < map->sectors.siz; s++) {
-               MapSector *sector = map->sectors.ptr[s];
-               for (size_t b = 0; b < sector->blocks.siz; b++)
-                       raw_delete_block(sector->blocks.ptr[b]);
-               if (sector->blocks.ptr)
-                       free(sector->blocks.ptr);
-               free(sector);
-       }
-       if (map->sectors.ptr)
-               free(map->sectors.ptr);
-       free(map);
-}
diff --git a/map.h b/map.h
deleted file mode 100644 (file)
index 398cf30..0000000
--- a/map.h
+++ /dev/null
@@ -1,56 +0,0 @@
-#ifndef _MAP_H_
-#define _MAP_H_
-
-#include <stdbool.h>
-#include "array.h"
-#include "linkedlist.h"
-#include "node.h"
-#include "types.h"
-
-#define ITERATE_MAPBLOCK for (u8 x = 0; x < 16; x++) for (u8 y = 0; y < 16; y++) for (u8 z = 0; z < 16; z++)
-
-typedef struct
-{
-       Node type;
-       LinkedList meta;
-} MapNode;
-
-typedef struct
-{
-       MapNode data[16][16][16];
-       v3s32 pos;
-} MapBlock;
-
-typedef struct
-{
-       Array blocks;
-       v2s32 pos;
-       u64 hash;
-} MapSector;
-
-typedef struct
-{
-       Array sectors;
-} Map;
-
-MapSector *map_get_sector(Map *map, v2s32 pos, bool create);
-MapBlock *map_get_block(Map *map, v3s32 pos, bool create);
-
-bool map_deserialize_node(int fd, MapNode *buf);
-bool map_serialize_block(int fd, MapBlock *block);
-bool map_deserialize_block(int fd, Map *map);
-
-void map_delete_block(MapBlock *); // ToDo
-void map_unload_block(MapBlock *); // ToDo
-
-v3s32 map_node_to_block_pos(v3s32 pos, v3u8 *offset);
-
-MapNode map_get_node(Map *map, v3s32 pos);
-void map_set_node(Map *map, v3s32 pos, MapNode node);
-MapNode map_node_create(Node type);
-void map_node_clear(MapNode *node);
-
-Map *map_create();
-void map_delete(Map *map);
-
-#endif
diff --git a/network.c b/network.c
deleted file mode 100644 (file)
index 27bc5ed..0000000
--- a/network.c
+++ /dev/null
@@ -1,54 +0,0 @@
-#include <poll.h>
-
-bool send_command(Client *client, RemoteCommand cmd)
-{
-       pthread_mutex_lock(&client->mtx);
-       bool ret = write_u32(client->fd, cmd);
-       pthread_mutex_unlock(&client->mtx);
-       return ret;
-}
-
-static void handle_packets(Client *client) {
-       while (client->state != CS_DISCONNECTED) {
-               struct pollfd pfd = {
-                       .fd = client->fd,
-                       .events = POLLIN,
-                       .revents = 0,
-               };
-
-               int pstate = poll(&pfd, 1, 0);
-
-               if (pstate == -1) {
-                       perror("poll");
-                       return;
-               }
-
-               if (client->state == CS_DISCONNECTED)
-                       return;
-
-               if (pstate == 0)
-                       continue;
-
-               if (! (pfd.revents & POLLIN))
-                       return;
-
-               HostCommand command;
-               if (! read_u32(client->fd, &command))
-                       return;
-
-               CommandHandler *handler = NULL;
-
-               if (command < HOST_COMMAND_COUNT)
-                       handler = &command_handlers[command];
-
-               if (handler && handler->func) {
-                       bool good = client->state & handler->state_flags;
-                       if (! good)
-                               printf("Recieved %s command, but client is in invalid state: %d\n", handler->name, client->state);
-                       if (! handler->func(client, good))
-                               return;
-               } else {
-                       printf("Recieved invalid command %d\n", command);
-               }
-       }
-}
diff --git a/network.h b/network.h
deleted file mode 100644 (file)
index f21ecbe..0000000
--- a/network.h
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef _NETWORK_H_
-#define _NETWORK_H_
-
-#include <stdbool.h>
-#define NAME_MAX 64
-
-typedef enum
-{
-       CS_CREATED = 0x01,
-       CS_AUTH = 0x02,
-       CS_ACTIVE = 0x04,
-       CS_DISCONNECTED = 0x08,
-} ClientState;
-
-struct Client;
-
-typedef struct {
-       bool (*func)(struct Client *client, bool good);
-       const char *name;
-       int state_flags;
-} CommandHandler;
-
-extern CommandHandler command_handlers[];
-
-bool send_command(struct Client *client, RemoteCommand cmd);
-
-#endif
diff --git a/node.h b/node.h
deleted file mode 100644 (file)
index 3d96e71..0000000
--- a/node.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef _NODE_H_
-#define _NODE_H_
-
-typedef enum
-{
-       NODE_UNLOADED,          // Used for nodes in unloaded blocks
-       NODE_AIR,
-       NODE_GRASS,
-       NODE_DIRT,
-       NODE_STONE,
-       NODE_INVALID,           // Used for invalid nodes received from server (caused by outdated clients)
-} Node;
-
-#endif
diff --git a/server.c b/server.c
deleted file mode 100644 (file)
index 94364d2..0000000
--- a/server.c
+++ /dev/null
@@ -1,149 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <netdb.h>
-#include "server.h"
-#include "signal.h"
-#include "util.h"
-
-#include "network.c"
-
-char *server_get_client_name(Client *client)
-{
-       return client->name ? client->name : client->address;
-}
-
-void server_disconnect_client(Client *client, int flags, const char *detail)
-{
-       client->state = CS_DISCONNECTED;
-
-       if (client->name && ! (flags & DISCO_NO_REMOVE))
-               linked_list_delete(&client->server->clients, client->name);
-
-       if (! (flags & DISCO_NO_MESSAGE))
-               printf("Disconnected %s %s%s%s\n", server_get_client_name(client), INBRACES(detail));
-
-       if (! (flags & DISCO_NO_SEND))
-               send_command(client, CC_DISCONNECT);
-
-       pthread_mutex_lock(&client->mtx);
-       close(client->fd);
-       pthread_mutex_unlock(&client->mtx);
-}
-
-void server_shutdown(Server *srv)
-{
-       printf("Shutting down\n");
-
-       ITERATE_LINKEDLIST(&srv->clients, pair) server_disconnect_client(pair->value, DISCO_NO_REMOVE | DISCO_NO_MESSAGE, "");
-       linked_list_clear(&srv->clients);
-
-       shutdown(srv->sockfd, SHUT_RDWR);
-       close(srv->sockfd);
-
-       map_delete(srv->map);
-
-       exit(EXIT_SUCCESS);
-}
-
-static void *reciever_thread(void *clientptr)
-{
-       Client *client = clientptr;
-
-       handle_packets(client);
-
-       if (client->state != CS_DISCONNECTED)
-               server_disconnect_client(client, DISCO_NO_SEND, "network error");
-
-       if (client->name)
-               free(client->name);
-
-       free(client->address);
-
-       pthread_mutex_destroy(&client->mtx);
-       free(client);
-
-       return NULL;
-}
-
-static void accept_client(Server *srv)
-{
-       struct sockaddr_storage client_address = {0};
-       socklen_t client_addrlen = sizeof(client_address);
-
-       int fd = accept(srv->sockfd, (struct sockaddr *)&client_address, &client_addrlen);
-
-       if (fd == -1) {
-               if (errno == EINTR)
-                       server_shutdown(srv);
-               else
-                       syscall_error("accept");
-       }
-
-       Client *client = malloc(sizeof(Client));
-       client->server = srv;
-       client->state = CS_CREATED;
-       client->fd = fd;
-       client->name = NULL;
-       client->address = address_string((struct sockaddr_in6 *) &client_address);
-
-       printf("Connected %s\n", client->address);
-
-       pthread_mutex_init(&client->mtx, NULL);
-
-       pthread_t thread;
-       pthread_create(&thread, NULL, &reciever_thread, client);
-}
-
-int main(int argc, char **argv)
-{
-       program_name = argv[0];
-
-       if (argc < 2)
-               internal_error("missing port");
-
-       struct addrinfo hints = {
-               .ai_family = AF_INET6,
-               .ai_socktype = SOCK_STREAM,
-               .ai_protocol = 0,
-               .ai_flags = AI_NUMERICSERV | AI_PASSIVE,
-       };
-
-       struct addrinfo *info = NULL;
-
-       int gai_state = getaddrinfo(NULL, argv[1], &hints, &info);
-
-       if (gai_state != 0)
-               internal_error(gai_strerror(gai_state));
-
-       Server server = {
-               .sockfd = -1,
-               .map = NULL,
-               .clients = linked_list_create(),
-       };
-
-       server.sockfd = socket(info->ai_family, info->ai_socktype, 0);
-
-       if (server.sockfd == -1)
-               syscall_error("socket");
-
-       int flag = 1;
-
-       if (setsockopt(server.sockfd, SOL_SOCKET, SO_REUSEADDR, &flag, 4) == -1)
-               syscall_error("setsockopt");
-
-       if (bind(server.sockfd, info->ai_addr, info->ai_addrlen) == -1)
-               syscall_error("bind");
-
-       if (listen(server.sockfd, 3) == -1)
-               syscall_error("listen");
-
-       freeaddrinfo(info);
-
-       init_signal_handlers();
-
-       server.map = map_create(NULL);
-
-       for ever accept_client(&server);
-}
diff --git a/server.h b/server.h
deleted file mode 100644 (file)
index cee2383..0000000
--- a/server.h
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef _SERVER_H_
-#define _SERVER_H_
-
-#include <pthread.h>
-#include <netinet/in.h>
-#include "clientcommands.h"
-#include "servercommands.h"
-#include "linkedlist.h"
-#include "map.h"
-#include "network.h"
-
-typedef struct
-{
-       int sockfd;
-       Map *map;
-       LinkedList clients;
-} Server;
-
-typedef struct Client
-{
-       int fd;
-       char *name;
-       char *address;
-       Server *server;
-       ClientState state;
-       pthread_mutex_t mtx;
-} Client;
-
-typedef enum
-{
-       DISCO_NO_REMOVE = 0x01,
-       DISCO_NO_SEND = 0x02,
-       DISCO_NO_MESSAGE = 0x04,
-} DiscoFlag;
-
-char *server_get_client_name(Client *client);
-void server_disconnect_client(Client *client, int flags, const char *detail);
-void server_shutdown(Server *srv);
-
-#endif
diff --git a/servercommands.c b/servercommands.c
deleted file mode 100644 (file)
index 89742db..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include "server.h"
-#include "util.h"
-
-static bool disconnect_handler(Client *client, bool good)
-{
-       if (good)
-               server_disconnect_client(client, DISCO_NO_SEND, NULL);
-       return true;
-}
-
-static bool auth_handler(Client *client, bool good)
-{
-       char *name = read_string(client->fd, NAME_MAX);
-
-       if (! name)
-               return false;
-
-       if (! good) {
-               free(name);
-               return true;
-       }
-
-       u8 success = linked_list_put(&client->server->clients, name, client);
-
-       printf("Authentication %s: %s -> %s\n", success ? "success" : "failure", client->address, name);
-
-       if (success) {
-               client->name = name;
-               client->state = CS_ACTIVE;
-       } else {
-               free(name);
-       }
-
-       pthread_mutex_lock(&client->mtx);
-       bool ret = write_u32(client->fd, CC_AUTH) && write_u8(client->fd, success);
-       pthread_mutex_unlock(&client->mtx);
-
-       return ret;
-}
-
-static bool getblock_handler(Client *client, bool good)
-{
-       v3s32 pos;
-
-       if (! read_v3s32(client->fd, &pos))
-               return false;
-
-       if (! good)
-               return true;
-
-       MapBlock *block = map_get_block(client->server->map, pos, false);
-       if (block) {
-               pthread_mutex_lock(&client->mtx);
-               bool ret = write_u32(client->fd, CC_BLOCK) && map_serialize_block(client->fd, block);
-               pthread_mutex_unlock(&client->mtx);
-
-               return ret;
-       }
-
-       return true;
-}
-
-static bool setnode_handler(Client *client, bool good)
-{
-       v3s32 pos;
-
-       if (! read_v3s32(client->fd, &pos))
-               return false;
-
-       MapNode node;
-
-       if (! map_deserialize_node(client->fd, &node))
-               return false;
-
-       if (good)
-               map_set_node(client->server->map, pos, node);
-
-       return true;
-}
-
-static bool kick_handler(Client *client, bool good)
-{
-       char *target_name = read_string(client->fd, NAME_MAX);
-
-       if (! target_name)
-               return false;
-
-       if (good) {
-               Client *target = linked_list_get(&client->server->clients, target_name);
-               if (target)
-                       server_disconnect_client(target, 0, "kicked");
-       }
-
-       free(target_name);
-       return true;
-}
-
-CommandHandler command_handlers[SERVER_COMMAND_COUNT] = {
-       {0},
-       {&disconnect_handler, "DISCONNECT", CS_CREATED | CS_ACTIVE},
-       {&auth_handler, "AUTH", CS_CREATED},
-       {&getblock_handler, "GETBLOCK", CS_ACTIVE},
-       {&setnode_handler, "SETNODE", CS_ACTIVE},
-       {&kick_handler, "KICK", CS_ACTIVE},
-};
diff --git a/servercommands.h b/servercommands.h
deleted file mode 100644 (file)
index 4e306fa..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef _SERVER_COMMAND_H_
-#define _SERVER_COMMAND_H_
-
-typedef enum
-{
-       SERVER_COMMAND_NULL,
-       SC_DISCONNECT,
-       SC_AUTH,
-       SC_GETBLOCK,
-       SC_SETNODE,
-       SC_KICK,
-       SERVER_COMMAND_COUNT,
-} ServerCommand;
-
-#ifdef _CLIENT_H_
-typedef ServerCommand RemoteCommand;
-#endif
-
-#ifdef _SERVER_H_
-typedef ServerCommand HostCommand;
-#define HOST_COMMAND_COUNT SERVER_COMMAND_COUNT
-#endif
-
-#endif
diff --git a/signal.c b/signal.c
deleted file mode 100644 (file)
index e5ac22c..0000000
--- a/signal.c
+++ /dev/null
@@ -1,26 +0,0 @@
-#include <signal.h>
-#include <stdio.h>
-#include <string.h>
-
-static void interrupt_handler(int sig)
-{
-       fprintf(stderr, "%s\n", strsignal(sig));
-}
-
-static void silent_handler(int sig)
-{
-       (void) sig;
-}
-
-static struct sigaction sigact_interrupt = {0};
-static struct sigaction sigact_silent = {0};
-
-void init_signal_handlers()
-{
-       sigact_interrupt.sa_handler = &interrupt_handler;
-       sigaction(SIGINT, &sigact_interrupt, NULL);
-       sigaction(SIGTERM, &sigact_interrupt, NULL);
-
-       sigact_silent.sa_handler = &silent_handler;
-       sigaction(SIGPIPE, &sigact_silent, NULL);
-}
diff --git a/signal.h b/signal.h
deleted file mode 100644 (file)
index e927ae1..0000000
--- a/signal.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _SIGNAL_H_
-#define _SIGNAL_H_
-
-void init_signal_handlers();
-
-#endif
diff --git a/src/Makefile b/src/Makefile
new file mode 100644 (file)
index 0000000..98ea2a2
--- /dev/null
@@ -0,0 +1,26 @@
+COMMON = array.o binsearch.o linkedlist.o map.o signal.o util.o types.o
+SERVER = $(COMMON) server.o servercommands.o
+CLIENT = $(COMMON) client.o clientcommands.o
+LIBRARIES = -lpthread -lm
+FLAGS = -g
+
+ifdef RELEASE
+FLAGS = -O3
+endif
+
+all: Dragonblocks DragonblocksServer
+
+Dragonblocks: $(CLIENT)
+       cc $(FLAGS) -o Dragonblocks $(CLIENT) $(LIBRARIES)
+
+DragonblocksServer: $(SERVER)
+       cc $(FLAGS) -o DragonblocksServer $(SERVER) $(LIBRARIES)
+
+%.o: %.c
+       cc $(FLAGS) -o $@ -c -Wall -Wextra -Wpedantic -Werror $<
+
+clean:
+       rm -rf *.o
+
+clobber: clean
+       rm -rf Dragonblocks DragonblocksServer
diff --git a/src/array.c b/src/array.c
new file mode 100644 (file)
index 0000000..de7733b
--- /dev/null
@@ -0,0 +1,40 @@
+#include <string.h>
+#include <stdlib.h>
+#include "array.h"
+
+static void array_realloc(Array *array)
+{
+       if (array->siz > array->cap) {
+               array->cap = array->siz + ARRAY_REALLOC_EXTRA;
+               array->ptr = realloc(array->ptr, array->cap * sizeof(void *));
+       }
+}
+
+static void array_alloc(Array *array, size_t siz)
+{
+       array->siz += siz;
+       array_realloc(array);
+}
+
+void array_insert(Array *array, void *elem, size_t idx)
+{
+       size_t oldsiz = array->siz;
+       array_alloc(array, 1);
+
+       void **iptr = array->ptr + idx;
+       memmove(iptr + 1, iptr, (oldsiz - idx) * sizeof(void *));
+       *iptr = elem;
+}
+
+void array_append(Array *array, void *elem)
+{
+       size_t oldsiz = array->siz;
+       array_alloc(array, 1);
+
+       array->ptr[oldsiz] = elem;
+}
+
+Array array_create()
+{
+       return (Array) {0, 0, NULL};
+}
diff --git a/src/array.h b/src/array.h
new file mode 100644 (file)
index 0000000..c0b42b5
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef _ARRAY_H_
+#define _ARRAY_H_
+
+#define ARRAY_REALLOC_EXTRA 25
+
+#include <stddef.h>
+
+typedef struct
+{
+       size_t siz, cap;
+       void **ptr;
+} Array;
+
+void array_insert(Array *array, void *elem, size_t idx);
+void array_append(Array *array, void *elem);
+Array array_create();
+
+#endif
diff --git a/src/binsearch.c b/src/binsearch.c
new file mode 100644 (file)
index 0000000..d6b1362
--- /dev/null
@@ -0,0 +1,25 @@
+#include "binsearch.h"
+
+BinsearchResult binsearch(void *search, void **array, size_t size, BinsearchComparator cmp)
+{
+       size_t min, max, index;
+
+       min = index = 0;
+       max = size;
+
+       while (min < max) {
+               index = min;
+
+               size_t mid = (max + min) / 2;
+               s8 state = cmp(search, array[mid]);
+
+               if (state == 0)
+                       return (BinsearchResult) {true, mid};
+               else if (state > 0)
+                       max = mid;
+               else
+                       min = mid;
+       }
+
+       return (BinsearchResult) {false, index};
+}
diff --git a/src/binsearch.h b/src/binsearch.h
new file mode 100644 (file)
index 0000000..f6337a2
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef _BINSEARCH_H_
+#define _BINSEARCH_H_
+
+#include <stddef.h>
+#include <stdbool.h>
+#include "types.h"
+
+typedef s8 (*BinsearchComparator)(void *search, void *element);
+
+typedef struct {
+       bool success;
+       size_t index;
+} BinsearchResult;
+
+BinsearchResult binsearch(void *search, void **array, size_t size, BinsearchComparator cmp);
+
+#endif
diff --git a/src/client.c b/src/client.c
new file mode 100644 (file)
index 0000000..62afbda
--- /dev/null
@@ -0,0 +1,195 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <errno.h>
+#include <netdb.h>
+#include "client.h"
+#include "signal.h"
+#include "util.h"
+
+#include "network.c"
+
+void client_disconnect(Client *client, bool send, const char *detail)
+{
+       pthread_mutex_lock(&client->mtx);
+       if (client->state != CS_DISCONNECTED) {
+               if (send)
+                       write_u32(client->fd, SC_DISCONNECT);
+
+               client->state = CS_DISCONNECTED;
+               printf("Disconnected %s%s%s\n", INBRACES(detail));
+               close(client->fd);
+       }
+       pthread_mutex_unlock(&client->mtx);
+}
+
+static void *reciever_thread(void *cliptr)
+{
+       Client *client = cliptr;
+
+       handle_packets(client);
+
+       if (errno == EINTR)
+               client_disconnect(client, true, NULL);
+       else
+               client_disconnect(client, false, "network error");
+
+       if (client->name)
+               free(client->name);
+
+       pthread_mutex_destroy(&client->mtx);
+
+       exit(EXIT_SUCCESS);
+       return NULL;
+}
+
+static void client_loop(Client *client)
+{
+       while (client->state != CS_DISCONNECTED) {
+               if (client->state == CS_CREATED) {
+                       printf("Enter name: ");
+                       fflush(stdout);
+                       char name[NAME_MAX];
+                       if (scanf("%s", name) == EOF)
+                               return;
+                       client->name = strdup(name);
+                       pthread_mutex_lock(&client->mtx);
+                       if (write_u32(client->fd, SC_AUTH) && write(client->fd, client->name, strlen(name) + 1)) {
+                               client->state = CS_AUTH;
+                               printf("Authenticating...\n");
+                       }
+                       pthread_mutex_unlock(&client->mtx);
+               } else if (client->state == CS_ACTIVE) {
+                       printf("%s: ", client->name);
+                       fflush(stdout);
+                       char buffer[BUFSIZ] = {0};
+                       if (scanf("%s", buffer) == EOF)
+                               return;
+                       if (strcmp(buffer, "disconnect") == 0) {
+                               return;
+                       } else if (strcmp(buffer, "setnode") == 0) {
+                               v3s32 pos;
+                               char node[BUFSIZ] = {0};
+                               if (scanf("%d %d %d %s", &pos.x, &pos.y, &pos.z, node) == EOF)
+                                       return;
+                               Node node_type = NODE_INVALID;
+                               if (strcmp(node, "air") == 0)
+                                       node_type = NODE_AIR;
+                               else if (strcmp(node, "grass") == 0)
+                                       node_type = NODE_GRASS;
+                               else if (strcmp(node, "dirt") == 0)
+                                       node_type = NODE_DIRT;
+                               else if (strcmp(node, "stone") == 0)
+                                       node_type = NODE_STONE;
+                               if (node_type == NODE_INVALID) {
+                                       printf("Invalid node\n");
+                               } else {
+                                       pthread_mutex_lock(&client->mtx);
+                                       (void) (write_u32(client->fd, SC_SETNODE) && write_v3s32(client->fd, pos) && write_u32(client->fd, node_type));
+                                       pthread_mutex_unlock(&client->mtx);
+                               }
+                       } else if (strcmp(buffer, "getnode") == 0) {
+                               v3s32 pos;
+                               if (scanf("%d %d %d", &pos.x, &pos.y, &pos.z) == EOF)
+                                       return;
+                               pthread_mutex_lock(&client->mtx);
+                               (void) (write_u32(client->fd, SC_GETBLOCK) && write_v3s32(client->fd, map_node_to_block_pos(pos, NULL)));
+                               pthread_mutex_unlock(&client->mtx);
+                       } else if (strcmp(buffer, "printnode") == 0) {
+                               v3s32 pos;
+                               if (scanf("%d %d %d", &pos.x, &pos.y, &pos.z) == EOF)
+                                       return;
+                               MapNode node = map_get_node(client->map, pos);
+                               const char *nodename;
+                               switch (node.type) {
+                                       case NODE_UNLOADED:
+                                               nodename = "unloaded";
+                                               break;
+                                       case NODE_AIR:
+                                               nodename = "air";
+                                               break;
+                                       case NODE_GRASS:
+                                               nodename = "grass";
+                                               break;
+                                       case NODE_DIRT:
+                                               nodename = "dirt";
+                                               break;
+                                       case NODE_STONE:
+                                               nodename = "stone";
+                                               break;
+                                       case NODE_INVALID:
+                                               nodename = "invalid";
+                                               break;
+                               }
+                               printf("%s\n", nodename);
+                       } else if (strcmp(buffer, "kick") == 0) {
+                               char target_name[NAME_MAX];
+                               if (scanf("%s", target_name) == EOF)
+                                       return;
+                               pthread_mutex_lock(&client->mtx);
+                               (void) (write_u32(client->fd, SC_KICK) && write(client->fd, target_name, strlen(target_name) + 1) != -1);
+                               pthread_mutex_unlock(&client->mtx);
+                       } else {
+                               printf("Invalid command: %s\n", buffer);
+                       }
+               } else {
+                       sched_yield();
+               }
+       }
+}
+
+int main(int argc, char **argv)
+{
+       program_name = argv[0];
+
+       if (argc < 3)
+               internal_error("missing address or port");
+
+       struct addrinfo hints = {
+               .ai_family = AF_UNSPEC,                 // support both IPv4 and IPv6
+               .ai_socktype = SOCK_STREAM,
+               .ai_protocol = 0,
+               .ai_flags = AI_NUMERICSERV,
+       };
+
+       struct addrinfo *info = NULL;
+
+       int gai_state = getaddrinfo(argv[1], argv[2], &hints, &info);
+
+       if (gai_state != 0)
+               internal_error(gai_strerror(gai_state));
+
+       Client client = {
+               .fd = -1,
+               .map = NULL,
+               .name = NULL,
+               .state = CS_CREATED,
+       };
+
+       pthread_mutex_init(&client.mtx, NULL);
+
+       client.fd = socket(info->ai_family, info->ai_socktype, info->ai_protocol);
+
+       if (client.fd == -1)
+               syscall_error("socket");
+
+       if (connect(client.fd, info->ai_addr, info->ai_addrlen) == -1)
+               syscall_error("connect");
+
+       freeaddrinfo(info);
+
+       init_signal_handlers();
+
+       client.map = map_create();
+
+       pthread_t recv_thread;
+       pthread_create(&recv_thread, NULL, &reciever_thread, &client);
+
+       client_loop(&client);
+
+       client_disconnect(&client, true, NULL);
+
+       pthread_join(recv_thread, NULL);
+}
diff --git a/src/client.h b/src/client.h
new file mode 100644 (file)
index 0000000..2b8c431
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef _CLIENT_H_
+#define _CLIENT_H_
+
+#include <stdbool.h>
+#include <pthread.h>
+#include "servercommands.h"
+#include "clientcommands.h"
+#include "network.h"
+#include "map.h"
+
+typedef struct Client
+{
+       int fd;
+       char *name;
+       Map *map;
+       ClientState state;
+       pthread_mutex_t mtx;
+} Client;
+
+void client_disconnect(Client *client, bool send, const char *detail);
+
+#endif
diff --git a/src/clientcommands.c b/src/clientcommands.c
new file mode 100644 (file)
index 0000000..f158a71
--- /dev/null
@@ -0,0 +1,44 @@
+#include <stdio.h>
+#include "client.h"
+#include "types.h"
+
+static bool disconnect_handler(Client *client, bool good)
+{
+       if (good)
+               client_disconnect(client, false, NULL);
+       return true;
+}
+
+static bool auth_handler(Client *client, bool good)
+{
+       u8 success;
+       if (! read_u8(client->fd, &success))
+               return false;
+
+       if (! good)
+               return true;
+
+       if (success) {
+               printf("Authenticated successfully\n");
+               client->state = CS_ACTIVE;
+       } else {
+               printf("Authentication failed, please try again\n");
+               client->state = CS_CREATED;
+       }
+
+       return true;
+}
+
+static bool block_handler(Client *client, bool good)
+{
+       if (good)
+               return map_deserialize_block(client->fd, client->map);
+       return true;
+}
+
+CommandHandler command_handlers[CLIENT_COMMAND_COUNT] = {
+       {0},
+       {&disconnect_handler, "DISCONNECT", CS_CREATED | CS_AUTH | CS_ACTIVE},
+       {&auth_handler, "AUTH", CS_AUTH},
+       {&block_handler, "BLOCK", CS_ACTIVE},
+};
diff --git a/src/clientcommands.h b/src/clientcommands.h
new file mode 100644 (file)
index 0000000..3249ae2
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef _CLIENT_COMMAND_H_
+#define _CLIENT_COMMAND_H_
+
+typedef enum
+{
+       CLIENT_COMMAND_NULL,
+       CC_DISCONNECT,
+       CC_AUTH,
+       CC_BLOCK,
+       CLIENT_COMMAND_COUNT
+} ClientCommand;
+
+#ifdef _SERVER_H_
+typedef ClientCommand RemoteCommand;
+#endif
+
+#ifdef _CLIENT_H_
+typedef ClientCommand HostCommand;
+#define HOST_COMMAND_COUNT CLIENT_COMMAND_COUNT
+#endif
+
+#endif
diff --git a/src/linkedlist.c b/src/linkedlist.c
new file mode 100644 (file)
index 0000000..5618c65
--- /dev/null
@@ -0,0 +1,68 @@
+#include <stdlib.h>
+#include <string.h>
+#include "linkedlist.h"
+
+LinkedList linked_list_create()
+{
+       return (LinkedList) {NULL};
+}
+
+void linked_list_clear(LinkedList *list)
+{
+       for (LinkedListPair *pair = list->first; pair != NULL;) {
+               LinkedListPair *next = pair->next;
+               free(pair);
+               pair = next;
+       }
+       list->first = NULL;
+}
+
+static LinkedListPair *make_pair(const char *key, void *value)
+{
+       LinkedListPair *pair = malloc(sizeof(LinkedListPair));
+       pair->key = key;
+       pair->value = value;
+       pair->next = NULL;
+       return pair;
+}
+
+bool linked_list_put(LinkedList *list, const char *key, void *value)
+{
+       LinkedListPair **pairptr;
+       for (pairptr = &list->first; *pairptr != NULL; pairptr = &(*pairptr)->next) {
+               if (strcmp((*pairptr)->key, key) == 0)
+                       return false;
+       }
+       *pairptr = make_pair(key, value);
+       return true;
+}
+
+void linked_list_set(LinkedList *list, const char *key, void *value)
+{
+       LinkedListPair **pairptr;
+       for (pairptr = &list->first; *pairptr != NULL; pairptr = &(*pairptr)->next) {
+               if (strcmp((*pairptr)->key, key) == 0)
+                       break;
+       }
+       *pairptr = make_pair(key, value);
+}
+
+void linked_list_delete(LinkedList *list, const char *key)
+{
+       for (LinkedListPair **pairptr = &list->first; *pairptr != NULL; pairptr = &(*pairptr)->next) {
+               if (strcmp((*pairptr)->key, key) == 0) {
+                       LinkedListPair *pair = *pairptr;
+                       *pairptr = pair->next;
+                       free(pair);
+                       return;
+               }
+       }
+}
+
+void *linked_list_get(LinkedList *list, const char *key)
+{
+       for (LinkedListPair *pair = list->first; pair != NULL; pair = pair->next)
+               if (strcmp(pair->key, key) == 0)
+                       return pair->value;
+       return NULL;
+}
diff --git a/src/linkedlist.h b/src/linkedlist.h
new file mode 100644 (file)
index 0000000..a3604c2
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef _LINKEDLIST_H_
+#define _LINKEDLIST_H_
+
+#include <stdbool.h>
+
+#define ITERATE_LINKEDLIST(list, pair) for (LinkedListPair *pair = (list)->first; pair != NULL; pair = pair->next)
+
+typedef struct LinkedListPair
+{
+       struct LinkedListPair *next;
+       const char *key;
+       void *value;
+} LinkedListPair;
+
+typedef struct
+{
+       LinkedListPair *first;
+} LinkedList;
+
+LinkedList linked_list_create();
+void linked_list_clear(LinkedList *list);
+
+bool linked_list_put(LinkedList *list, const char *key, void *value);
+void linked_list_set(LinkedList *list, const char *key, void *value);
+void *linked_list_get(LinkedList *list, const char *key);
+void linked_list_delete(LinkedList *list, const char *key);
+
+void linked_list_serialize(int fd); // ToDo
+void linked_list_deserialize(int fd, LinkedList *); // ToDo
+
+#endif
diff --git a/src/map.c b/src/map.c
new file mode 100644 (file)
index 0000000..d85455c
--- /dev/null
+++ b/src/map.c
@@ -0,0 +1,185 @@
+#include <stdlib.h>
+#include <stdbool.h>
+#include <math.h>
+#include "binsearch.h"
+#include "map.h"
+#include "util.h"
+
+#define CMPBOUNDS(x) x == 0 ? 0 : x > 0 ? 1 : -1
+
+static void raw_delete_block(MapBlock *block)
+{
+       ITERATE_MAPBLOCK map_node_clear(&block->data[x][y][z]);
+       free(block);
+}
+
+static s8 sector_compare(void *hash, void *sector)
+{
+       s64 d = *((u64 *) hash) - ((MapSector *) sector)->hash;
+       return CMPBOUNDS(d);
+}
+
+MapSector *map_get_sector(Map *map, v2s32 pos, bool create)
+{
+       u64 hash = ((u64) pos.x << 32) + (u64) pos.y;
+       BinsearchResult res = binsearch(&hash, map->sectors.ptr, map->sectors.siz, &sector_compare);
+
+       if (res.success)
+               return map->sectors.ptr[res.index];
+       if (! create)
+               return NULL;
+
+       MapSector *sector = malloc(sizeof(MapSector));
+       sector->pos = pos;
+       sector->hash = hash;
+       sector->blocks = array_create();
+
+       array_insert(&map->sectors, sector, res.index);
+
+       return sector;
+}
+
+static s8 block_compare(void *level, void *block)
+{
+       s32 d = *((s32 *) level) - ((MapBlock *) block)->pos.y;
+       return CMPBOUNDS(d);
+}
+
+MapBlock *map_get_block(Map *map, v3s32 pos, bool create)
+{
+       MapSector *sector = map_get_sector(map, (v2s32) {pos.x, pos.z}, create);
+       if (! sector)
+               return NULL;
+
+       BinsearchResult res = binsearch(&pos.y, sector->blocks.ptr, sector->blocks.siz, &block_compare);
+
+       if (res.success)
+               return sector->blocks.ptr[res.index];
+       if (! create)
+               return NULL;
+
+       MapBlock *block = malloc(sizeof(MapBlock));
+       block->pos = pos;
+
+       MapNode air = map_node_create(NODE_AIR);
+       ITERATE_MAPBLOCK block->data[x][y][z] = air;
+
+       array_insert(&sector->blocks, block, res.index);
+
+       return block;
+}
+
+bool map_deserialize_node(int fd, MapNode *node)
+{
+       Node type;
+
+       if (! read_u32(fd, &type))
+               return false;
+
+       if (type > NODE_INVALID)
+               type = NODE_INVALID;
+
+       *node = map_node_create(type);
+
+       return true;
+}
+
+bool map_serialize_block(int fd, MapBlock *block)
+{
+       if (! write_v3s32(fd, block->pos))
+               return false;
+
+       ITERATE_MAPBLOCK {
+               if (! write_u32(fd, block->data[x][y][z].type))
+                       return false;
+       }
+
+       return true;
+}
+
+bool map_deserialize_block(int fd, Map *map)
+{
+       MapBlock *block = malloc(sizeof(MapBlock));
+
+       if (! read_v3s32(fd, &block->pos))
+               return false;
+
+       ITERATE_MAPBLOCK {
+               if (! map_deserialize_node(fd, &block->data[x][y][z])) {
+                       free(block);
+                       return false;
+               }
+       }
+
+       MapSector *sector = map_get_sector(map, (v2s32) {block->pos.x, block->pos.z}, true);
+       BinsearchResult res = binsearch(&block->pos.y, sector->blocks.ptr, sector->blocks.siz, &block_compare);
+       if (res.success) {
+               raw_delete_block(sector->blocks.ptr[res.index]);
+               sector->blocks.ptr[res.index] = block;
+       } else {
+               array_insert(&sector->blocks, block, res.index);
+       }
+
+       return true;
+}
+
+
+v3s32 map_node_to_block_pos(v3s32 pos, v3u8 *offset)
+{
+       if (offset)
+               *offset = (v3u8) {(u32) pos.x % 16, (u32) pos.y % 16, (u32) pos.z % 16};
+       return (v3s32) {floor((double) pos.x / 16), floor((double) pos.y / 16), floor((double) pos.z / 16)};
+}
+
+
+MapNode map_get_node(Map *map, v3s32 pos)
+{
+       v3u8 offset;
+       v3s32 blockpos = map_node_to_block_pos(pos, &offset);
+       MapBlock *block = map_get_block(map, blockpos, false);
+       if (! block)
+               return map_node_create(NODE_UNLOADED);
+       return block->data[offset.x][offset.y][offset.z];
+}
+
+void map_set_node(Map *map, v3s32 pos, MapNode node)
+{
+       v3u8 offset;
+       MapBlock *block = map_get_block(map, map_node_to_block_pos(pos, &offset), true);
+       MapNode *current_node = &block->data[offset.x][offset.y][offset.z];
+       map_node_clear(current_node);
+       *current_node = node;
+}
+
+MapNode map_node_create(Node type)
+{
+       return (MapNode) {type, linked_list_create()};
+}
+
+void map_node_clear(MapNode *node)
+{
+       linked_list_clear(&node->meta);
+}
+
+Map *map_create()
+{
+       Map *map = malloc(sizeof(Map));
+       map->sectors = array_create();
+
+       return map;
+}
+
+void map_delete(Map *map)
+{
+       for (size_t s = 0; s < map->sectors.siz; s++) {
+               MapSector *sector = map->sectors.ptr[s];
+               for (size_t b = 0; b < sector->blocks.siz; b++)
+                       raw_delete_block(sector->blocks.ptr[b]);
+               if (sector->blocks.ptr)
+                       free(sector->blocks.ptr);
+               free(sector);
+       }
+       if (map->sectors.ptr)
+               free(map->sectors.ptr);
+       free(map);
+}
diff --git a/src/map.h b/src/map.h
new file mode 100644 (file)
index 0000000..398cf30
--- /dev/null
+++ b/src/map.h
@@ -0,0 +1,56 @@
+#ifndef _MAP_H_
+#define _MAP_H_
+
+#include <stdbool.h>
+#include "array.h"
+#include "linkedlist.h"
+#include "node.h"
+#include "types.h"
+
+#define ITERATE_MAPBLOCK for (u8 x = 0; x < 16; x++) for (u8 y = 0; y < 16; y++) for (u8 z = 0; z < 16; z++)
+
+typedef struct
+{
+       Node type;
+       LinkedList meta;
+} MapNode;
+
+typedef struct
+{
+       MapNode data[16][16][16];
+       v3s32 pos;
+} MapBlock;
+
+typedef struct
+{
+       Array blocks;
+       v2s32 pos;
+       u64 hash;
+} MapSector;
+
+typedef struct
+{
+       Array sectors;
+} Map;
+
+MapSector *map_get_sector(Map *map, v2s32 pos, bool create);
+MapBlock *map_get_block(Map *map, v3s32 pos, bool create);
+
+bool map_deserialize_node(int fd, MapNode *buf);
+bool map_serialize_block(int fd, MapBlock *block);
+bool map_deserialize_block(int fd, Map *map);
+
+void map_delete_block(MapBlock *); // ToDo
+void map_unload_block(MapBlock *); // ToDo
+
+v3s32 map_node_to_block_pos(v3s32 pos, v3u8 *offset);
+
+MapNode map_get_node(Map *map, v3s32 pos);
+void map_set_node(Map *map, v3s32 pos, MapNode node);
+MapNode map_node_create(Node type);
+void map_node_clear(MapNode *node);
+
+Map *map_create();
+void map_delete(Map *map);
+
+#endif
diff --git a/src/network.c b/src/network.c
new file mode 100644 (file)
index 0000000..27bc5ed
--- /dev/null
@@ -0,0 +1,54 @@
+#include <poll.h>
+
+bool send_command(Client *client, RemoteCommand cmd)
+{
+       pthread_mutex_lock(&client->mtx);
+       bool ret = write_u32(client->fd, cmd);
+       pthread_mutex_unlock(&client->mtx);
+       return ret;
+}
+
+static void handle_packets(Client *client) {
+       while (client->state != CS_DISCONNECTED) {
+               struct pollfd pfd = {
+                       .fd = client->fd,
+                       .events = POLLIN,
+                       .revents = 0,
+               };
+
+               int pstate = poll(&pfd, 1, 0);
+
+               if (pstate == -1) {
+                       perror("poll");
+                       return;
+               }
+
+               if (client->state == CS_DISCONNECTED)
+                       return;
+
+               if (pstate == 0)
+                       continue;
+
+               if (! (pfd.revents & POLLIN))
+                       return;
+
+               HostCommand command;
+               if (! read_u32(client->fd, &command))
+                       return;
+
+               CommandHandler *handler = NULL;
+
+               if (command < HOST_COMMAND_COUNT)
+                       handler = &command_handlers[command];
+
+               if (handler && handler->func) {
+                       bool good = client->state & handler->state_flags;
+                       if (! good)
+                               printf("Recieved %s command, but client is in invalid state: %d\n", handler->name, client->state);
+                       if (! handler->func(client, good))
+                               return;
+               } else {
+                       printf("Recieved invalid command %d\n", command);
+               }
+       }
+}
diff --git a/src/network.h b/src/network.h
new file mode 100644 (file)
index 0000000..f21ecbe
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef _NETWORK_H_
+#define _NETWORK_H_
+
+#include <stdbool.h>
+#define NAME_MAX 64
+
+typedef enum
+{
+       CS_CREATED = 0x01,
+       CS_AUTH = 0x02,
+       CS_ACTIVE = 0x04,
+       CS_DISCONNECTED = 0x08,
+} ClientState;
+
+struct Client;
+
+typedef struct {
+       bool (*func)(struct Client *client, bool good);
+       const char *name;
+       int state_flags;
+} CommandHandler;
+
+extern CommandHandler command_handlers[];
+
+bool send_command(struct Client *client, RemoteCommand cmd);
+
+#endif
diff --git a/src/node.h b/src/node.h
new file mode 100644 (file)
index 0000000..3d96e71
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef _NODE_H_
+#define _NODE_H_
+
+typedef enum
+{
+       NODE_UNLOADED,          // Used for nodes in unloaded blocks
+       NODE_AIR,
+       NODE_GRASS,
+       NODE_DIRT,
+       NODE_STONE,
+       NODE_INVALID,           // Used for invalid nodes received from server (caused by outdated clients)
+} Node;
+
+#endif
diff --git a/src/server.c b/src/server.c
new file mode 100644 (file)
index 0000000..94364d2
--- /dev/null
@@ -0,0 +1,149 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <netdb.h>
+#include "server.h"
+#include "signal.h"
+#include "util.h"
+
+#include "network.c"
+
+char *server_get_client_name(Client *client)
+{
+       return client->name ? client->name : client->address;
+}
+
+void server_disconnect_client(Client *client, int flags, const char *detail)
+{
+       client->state = CS_DISCONNECTED;
+
+       if (client->name && ! (flags & DISCO_NO_REMOVE))
+               linked_list_delete(&client->server->clients, client->name);
+
+       if (! (flags & DISCO_NO_MESSAGE))
+               printf("Disconnected %s %s%s%s\n", server_get_client_name(client), INBRACES(detail));
+
+       if (! (flags & DISCO_NO_SEND))
+               send_command(client, CC_DISCONNECT);
+
+       pthread_mutex_lock(&client->mtx);
+       close(client->fd);
+       pthread_mutex_unlock(&client->mtx);
+}
+
+void server_shutdown(Server *srv)
+{
+       printf("Shutting down\n");
+
+       ITERATE_LINKEDLIST(&srv->clients, pair) server_disconnect_client(pair->value, DISCO_NO_REMOVE | DISCO_NO_MESSAGE, "");
+       linked_list_clear(&srv->clients);
+
+       shutdown(srv->sockfd, SHUT_RDWR);
+       close(srv->sockfd);
+
+       map_delete(srv->map);
+
+       exit(EXIT_SUCCESS);
+}
+
+static void *reciever_thread(void *clientptr)
+{
+       Client *client = clientptr;
+
+       handle_packets(client);
+
+       if (client->state != CS_DISCONNECTED)
+               server_disconnect_client(client, DISCO_NO_SEND, "network error");
+
+       if (client->name)
+               free(client->name);
+
+       free(client->address);
+
+       pthread_mutex_destroy(&client->mtx);
+       free(client);
+
+       return NULL;
+}
+
+static void accept_client(Server *srv)
+{
+       struct sockaddr_storage client_address = {0};
+       socklen_t client_addrlen = sizeof(client_address);
+
+       int fd = accept(srv->sockfd, (struct sockaddr *)&client_address, &client_addrlen);
+
+       if (fd == -1) {
+               if (errno == EINTR)
+                       server_shutdown(srv);
+               else
+                       syscall_error("accept");
+       }
+
+       Client *client = malloc(sizeof(Client));
+       client->server = srv;
+       client->state = CS_CREATED;
+       client->fd = fd;
+       client->name = NULL;
+       client->address = address_string((struct sockaddr_in6 *) &client_address);
+
+       printf("Connected %s\n", client->address);
+
+       pthread_mutex_init(&client->mtx, NULL);
+
+       pthread_t thread;
+       pthread_create(&thread, NULL, &reciever_thread, client);
+}
+
+int main(int argc, char **argv)
+{
+       program_name = argv[0];
+
+       if (argc < 2)
+               internal_error("missing port");
+
+       struct addrinfo hints = {
+               .ai_family = AF_INET6,
+               .ai_socktype = SOCK_STREAM,
+               .ai_protocol = 0,
+               .ai_flags = AI_NUMERICSERV | AI_PASSIVE,
+       };
+
+       struct addrinfo *info = NULL;
+
+       int gai_state = getaddrinfo(NULL, argv[1], &hints, &info);
+
+       if (gai_state != 0)
+               internal_error(gai_strerror(gai_state));
+
+       Server server = {
+               .sockfd = -1,
+               .map = NULL,
+               .clients = linked_list_create(),
+       };
+
+       server.sockfd = socket(info->ai_family, info->ai_socktype, 0);
+
+       if (server.sockfd == -1)
+               syscall_error("socket");
+
+       int flag = 1;
+
+       if (setsockopt(server.sockfd, SOL_SOCKET, SO_REUSEADDR, &flag, 4) == -1)
+               syscall_error("setsockopt");
+
+       if (bind(server.sockfd, info->ai_addr, info->ai_addrlen) == -1)
+               syscall_error("bind");
+
+       if (listen(server.sockfd, 3) == -1)
+               syscall_error("listen");
+
+       freeaddrinfo(info);
+
+       init_signal_handlers();
+
+       server.map = map_create(NULL);
+
+       for ever accept_client(&server);
+}
diff --git a/src/server.h b/src/server.h
new file mode 100644 (file)
index 0000000..cee2383
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef _SERVER_H_
+#define _SERVER_H_
+
+#include <pthread.h>
+#include <netinet/in.h>
+#include "clientcommands.h"
+#include "servercommands.h"
+#include "linkedlist.h"
+#include "map.h"
+#include "network.h"
+
+typedef struct
+{
+       int sockfd;
+       Map *map;
+       LinkedList clients;
+} Server;
+
+typedef struct Client
+{
+       int fd;
+       char *name;
+       char *address;
+       Server *server;
+       ClientState state;
+       pthread_mutex_t mtx;
+} Client;
+
+typedef enum
+{
+       DISCO_NO_REMOVE = 0x01,
+       DISCO_NO_SEND = 0x02,
+       DISCO_NO_MESSAGE = 0x04,
+} DiscoFlag;
+
+char *server_get_client_name(Client *client);
+void server_disconnect_client(Client *client, int flags, const char *detail);
+void server_shutdown(Server *srv);
+
+#endif
diff --git a/src/servercommands.c b/src/servercommands.c
new file mode 100644 (file)
index 0000000..89742db
--- /dev/null
@@ -0,0 +1,107 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "server.h"
+#include "util.h"
+
+static bool disconnect_handler(Client *client, bool good)
+{
+       if (good)
+               server_disconnect_client(client, DISCO_NO_SEND, NULL);
+       return true;
+}
+
+static bool auth_handler(Client *client, bool good)
+{
+       char *name = read_string(client->fd, NAME_MAX);
+
+       if (! name)
+               return false;
+
+       if (! good) {
+               free(name);
+               return true;
+       }
+
+       u8 success = linked_list_put(&client->server->clients, name, client);
+
+       printf("Authentication %s: %s -> %s\n", success ? "success" : "failure", client->address, name);
+
+       if (success) {
+               client->name = name;
+               client->state = CS_ACTIVE;
+       } else {
+               free(name);
+       }
+
+       pthread_mutex_lock(&client->mtx);
+       bool ret = write_u32(client->fd, CC_AUTH) && write_u8(client->fd, success);
+       pthread_mutex_unlock(&client->mtx);
+
+       return ret;
+}
+
+static bool getblock_handler(Client *client, bool good)
+{
+       v3s32 pos;
+
+       if (! read_v3s32(client->fd, &pos))
+               return false;
+
+       if (! good)
+               return true;
+
+       MapBlock *block = map_get_block(client->server->map, pos, false);
+       if (block) {
+               pthread_mutex_lock(&client->mtx);
+               bool ret = write_u32(client->fd, CC_BLOCK) && map_serialize_block(client->fd, block);
+               pthread_mutex_unlock(&client->mtx);
+
+               return ret;
+       }
+
+       return true;
+}
+
+static bool setnode_handler(Client *client, bool good)
+{
+       v3s32 pos;
+
+       if (! read_v3s32(client->fd, &pos))
+               return false;
+
+       MapNode node;
+
+       if (! map_deserialize_node(client->fd, &node))
+               return false;
+
+       if (good)
+               map_set_node(client->server->map, pos, node);
+
+       return true;
+}
+
+static bool kick_handler(Client *client, bool good)
+{
+       char *target_name = read_string(client->fd, NAME_MAX);
+
+       if (! target_name)
+               return false;
+
+       if (good) {
+               Client *target = linked_list_get(&client->server->clients, target_name);
+               if (target)
+                       server_disconnect_client(target, 0, "kicked");
+       }
+
+       free(target_name);
+       return true;
+}
+
+CommandHandler command_handlers[SERVER_COMMAND_COUNT] = {
+       {0},
+       {&disconnect_handler, "DISCONNECT", CS_CREATED | CS_ACTIVE},
+       {&auth_handler, "AUTH", CS_CREATED},
+       {&getblock_handler, "GETBLOCK", CS_ACTIVE},
+       {&setnode_handler, "SETNODE", CS_ACTIVE},
+       {&kick_handler, "KICK", CS_ACTIVE},
+};
diff --git a/src/servercommands.h b/src/servercommands.h
new file mode 100644 (file)
index 0000000..4e306fa
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef _SERVER_COMMAND_H_
+#define _SERVER_COMMAND_H_
+
+typedef enum
+{
+       SERVER_COMMAND_NULL,
+       SC_DISCONNECT,
+       SC_AUTH,
+       SC_GETBLOCK,
+       SC_SETNODE,
+       SC_KICK,
+       SERVER_COMMAND_COUNT,
+} ServerCommand;
+
+#ifdef _CLIENT_H_
+typedef ServerCommand RemoteCommand;
+#endif
+
+#ifdef _SERVER_H_
+typedef ServerCommand HostCommand;
+#define HOST_COMMAND_COUNT SERVER_COMMAND_COUNT
+#endif
+
+#endif
diff --git a/src/signal.c b/src/signal.c
new file mode 100644 (file)
index 0000000..e5ac22c
--- /dev/null
@@ -0,0 +1,26 @@
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+
+static void interrupt_handler(int sig)
+{
+       fprintf(stderr, "%s\n", strsignal(sig));
+}
+
+static void silent_handler(int sig)
+{
+       (void) sig;
+}
+
+static struct sigaction sigact_interrupt = {0};
+static struct sigaction sigact_silent = {0};
+
+void init_signal_handlers()
+{
+       sigact_interrupt.sa_handler = &interrupt_handler;
+       sigaction(SIGINT, &sigact_interrupt, NULL);
+       sigaction(SIGTERM, &sigact_interrupt, NULL);
+
+       sigact_silent.sa_handler = &silent_handler;
+       sigaction(SIGPIPE, &sigact_silent, NULL);
+}
diff --git a/src/signal.h b/src/signal.h
new file mode 100644 (file)
index 0000000..e927ae1
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _SIGNAL_H_
+#define _SIGNAL_H_
+
+void init_signal_handlers();
+
+#endif
diff --git a/src/types.c b/src/types.c
new file mode 100644 (file)
index 0000000..3b59714
--- /dev/null
@@ -0,0 +1,82 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <endian.h>
+#include <poll.h>
+#include "types.h"
+
+#define htobe8(x) x
+#define be8toh(x) x
+
+#define READVEC(type, n) \
+       type buf[n]; \
+       for (int i = 0; i < n; i++) { \
+               if (! read_ ## type(fd, &buf[i])) \
+                       return false; \
+       }
+
+#define WRITEVEC(type, n) \
+       for (int i = 0; i < n; i++) { \
+               if (! write_ ## type(fd, vec[i])) \
+                       return false; \
+       } \
+       return true;
+
+#define DEFVEC(type) \
+       bool read_v2 ## type(int fd, v2 ## type *ptr) \
+       { \
+               READVEC(type, 2) \
+               ptr->x = buf[0]; \
+               ptr->y = buf[1]; \
+               return true; \
+       } \
+       bool write_v2 ## type(int fd, v2 ## type val) \
+       { \
+               type vec[2] = {val.x, val.y}; \
+               WRITEVEC(type, 2) \
+       } \
+       bool read_v3 ## type(int fd, v3 ## type *ptr) \
+       { \
+               READVEC(type, 3) \
+               ptr->x = buf[0]; \
+               ptr->y = buf[1]; \
+               ptr->z = buf[2]; \
+               return true; \
+       } \
+       bool write_v3 ## type(int fd, v3 ## type val) \
+       { \
+               type vec[3] = {val.x, val.y, val.z}; \
+               WRITEVEC(type, 3) \
+       }
+
+#define DEFTYP(type, bits) \
+       bool read_ ## type(int fd, type *buf) \
+       { \
+               u ## bits encoded; \
+               int n_read; \
+               if ((n_read = read(fd, &encoded, sizeof(encoded))) != sizeof(encoded)) { \
+                       if (n_read == -1) \
+                               perror("read"); \
+                       return false; \
+               } \
+               *buf = be ## bits ## toh(encoded); \
+               return true; \
+       } \
+       bool write_ ## type(int fd, type val) \
+       { \
+               u ## bits encoded = htobe ## bits(val); \
+               if (write(fd, &encoded, sizeof(encoded)) == -1) { \
+                       perror("write"); \
+                       return false; \
+               } \
+               return true; \
+       } \
+       DEFVEC(type)
+
+#define DEFTYPES(bits) \
+       DEFTYP(s ## bits, bits) \
+       DEFTYP(u ## bits, bits)
+
+DEFTYPES(8)
+DEFTYPES(16)
+DEFTYPES(32)
+DEFTYPES(64)
diff --git a/src/types.h b/src/types.h
new file mode 100644 (file)
index 0000000..cbf9baa
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef _TYPES_H_
+#define _TYPES_H_
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#define DEFRW(type) \
+       bool read_ ## type(int fd, type *ptr); \
+       bool write_ ## type(int fd, type val);
+
+#define DEFVEC(type) \
+       typedef struct {type x, y;} v2 ## type; \
+       DEFRW(v2 ## type) \
+       typedef struct {type x, y, z;} v3 ## type; \
+       DEFRW(v3 ## type)
+
+#define DEFTYP(from, to) \
+       typedef from to; \
+       DEFRW(to) \
+       DEFVEC(to)
+
+#define DEFTYPES(bits) \
+       DEFTYP(int ## bits ## _t, s ## bits) \
+       DEFTYP(uint ## bits ## _t, u ## bits)
+
+DEFTYPES(8)
+DEFTYPES(16)
+DEFTYPES(32)
+DEFTYPES(64)
+
+typedef float f32;
+typedef double f64;
+
+DEFVEC(f32)
+DEFVEC(f64)
+
+typedef v2f32 v2f;
+typedef v3f32 v3f;
+
+#undef DEFRW
+#undef DEFVEC
+#undef DEFTYP
+#undef DEFTYPES
+
+#endif
diff --git a/src/util.c b/src/util.c
new file mode 100644 (file)
index 0000000..e8c9e3a
--- /dev/null
@@ -0,0 +1,51 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include "util.h"
+
+const char *program_name;
+
+void syscall_error(const char *err)
+{
+       perror(err);
+       exit(EXIT_FAILURE);
+}
+
+void internal_error(const char *err)
+{
+       fprintf(stderr, "%s: %s\n", program_name, err);
+       exit(EXIT_FAILURE);
+}
+
+char *read_string(int fd, size_t bufsiz)
+{
+       char buf[bufsiz + 1];
+       buf[bufsiz] = 0;
+       for (size_t i = 0;; i++) {
+               char c;
+               if (read(fd, &c, 1) == -1) {
+                       perror("read");
+                       return NULL;
+               }
+               if (i < bufsiz)
+                       buf[i] = c;
+               if (c == EOF || c == 0)
+                       break;
+       }
+       return strdup(buf);
+}
+
+char *address_string(struct sockaddr_in6 *addr)
+{
+       char address[INET6_ADDRSTRLEN] = {0};
+       char port[6] = {0};
+
+       if (inet_ntop(addr->sin6_family, &addr->sin6_addr, address, INET6_ADDRSTRLEN) == NULL)
+               perror("inet_ntop");
+       sprintf(port, "%d", ntohs(addr->sin6_port));
+
+       char *result = malloc(strlen(address) + 1 + strlen(port) + 1);
+       sprintf(result, "%s:%s", address, port);
+       return result;
+}
diff --git a/src/util.h b/src/util.h
new file mode 100644 (file)
index 0000000..ed53816
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef _UTIL_H_
+#define _UTIL_H_
+
+#include <arpa/inet.h>
+#include "types.h"
+
+#define ever (;;)
+#define INBRACES(str) str ? "(" : "", str ? str : "", str ? ")" : ""
+
+extern const char *program_name;
+
+void syscall_error(const char *err);
+void internal_error(const char *err);
+char *read_string(int fd, size_t bufsiz);
+char *address_string(struct sockaddr_in6 *addr);
+
+#endif
diff --git a/types.c b/types.c
deleted file mode 100644 (file)
index 3b59714..0000000
--- a/types.c
+++ /dev/null
@@ -1,82 +0,0 @@
-#include <stdio.h>
-#include <unistd.h>
-#include <endian.h>
-#include <poll.h>
-#include "types.h"
-
-#define htobe8(x) x
-#define be8toh(x) x
-
-#define READVEC(type, n) \
-       type buf[n]; \
-       for (int i = 0; i < n; i++) { \
-               if (! read_ ## type(fd, &buf[i])) \
-                       return false; \
-       }
-
-#define WRITEVEC(type, n) \
-       for (int i = 0; i < n; i++) { \
-               if (! write_ ## type(fd, vec[i])) \
-                       return false; \
-       } \
-       return true;
-
-#define DEFVEC(type) \
-       bool read_v2 ## type(int fd, v2 ## type *ptr) \
-       { \
-               READVEC(type, 2) \
-               ptr->x = buf[0]; \
-               ptr->y = buf[1]; \
-               return true; \
-       } \
-       bool write_v2 ## type(int fd, v2 ## type val) \
-       { \
-               type vec[2] = {val.x, val.y}; \
-               WRITEVEC(type, 2) \
-       } \
-       bool read_v3 ## type(int fd, v3 ## type *ptr) \
-       { \
-               READVEC(type, 3) \
-               ptr->x = buf[0]; \
-               ptr->y = buf[1]; \
-               ptr->z = buf[2]; \
-               return true; \
-       } \
-       bool write_v3 ## type(int fd, v3 ## type val) \
-       { \
-               type vec[3] = {val.x, val.y, val.z}; \
-               WRITEVEC(type, 3) \
-       }
-
-#define DEFTYP(type, bits) \
-       bool read_ ## type(int fd, type *buf) \
-       { \
-               u ## bits encoded; \
-               int n_read; \
-               if ((n_read = read(fd, &encoded, sizeof(encoded))) != sizeof(encoded)) { \
-                       if (n_read == -1) \
-                               perror("read"); \
-                       return false; \
-               } \
-               *buf = be ## bits ## toh(encoded); \
-               return true; \
-       } \
-       bool write_ ## type(int fd, type val) \
-       { \
-               u ## bits encoded = htobe ## bits(val); \
-               if (write(fd, &encoded, sizeof(encoded)) == -1) { \
-                       perror("write"); \
-                       return false; \
-               } \
-               return true; \
-       } \
-       DEFVEC(type)
-
-#define DEFTYPES(bits) \
-       DEFTYP(s ## bits, bits) \
-       DEFTYP(u ## bits, bits)
-
-DEFTYPES(8)
-DEFTYPES(16)
-DEFTYPES(32)
-DEFTYPES(64)
diff --git a/types.h b/types.h
deleted file mode 100644 (file)
index cbf9baa..0000000
--- a/types.h
+++ /dev/null
@@ -1,45 +0,0 @@
-#ifndef _TYPES_H_
-#define _TYPES_H_
-
-#include <stdint.h>
-#include <stdbool.h>
-
-#define DEFRW(type) \
-       bool read_ ## type(int fd, type *ptr); \
-       bool write_ ## type(int fd, type val);
-
-#define DEFVEC(type) \
-       typedef struct {type x, y;} v2 ## type; \
-       DEFRW(v2 ## type) \
-       typedef struct {type x, y, z;} v3 ## type; \
-       DEFRW(v3 ## type)
-
-#define DEFTYP(from, to) \
-       typedef from to; \
-       DEFRW(to) \
-       DEFVEC(to)
-
-#define DEFTYPES(bits) \
-       DEFTYP(int ## bits ## _t, s ## bits) \
-       DEFTYP(uint ## bits ## _t, u ## bits)
-
-DEFTYPES(8)
-DEFTYPES(16)
-DEFTYPES(32)
-DEFTYPES(64)
-
-typedef float f32;
-typedef double f64;
-
-DEFVEC(f32)
-DEFVEC(f64)
-
-typedef v2f32 v2f;
-typedef v3f32 v3f;
-
-#undef DEFRW
-#undef DEFVEC
-#undef DEFTYP
-#undef DEFTYPES
-
-#endif
diff --git a/util.c b/util.c
deleted file mode 100644 (file)
index e8c9e3a..0000000
--- a/util.c
+++ /dev/null
@@ -1,51 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include "util.h"
-
-const char *program_name;
-
-void syscall_error(const char *err)
-{
-       perror(err);
-       exit(EXIT_FAILURE);
-}
-
-void internal_error(const char *err)
-{
-       fprintf(stderr, "%s: %s\n", program_name, err);
-       exit(EXIT_FAILURE);
-}
-
-char *read_string(int fd, size_t bufsiz)
-{
-       char buf[bufsiz + 1];
-       buf[bufsiz] = 0;
-       for (size_t i = 0;; i++) {
-               char c;
-               if (read(fd, &c, 1) == -1) {
-                       perror("read");
-                       return NULL;
-               }
-               if (i < bufsiz)
-                       buf[i] = c;
-               if (c == EOF || c == 0)
-                       break;
-       }
-       return strdup(buf);
-}
-
-char *address_string(struct sockaddr_in6 *addr)
-{
-       char address[INET6_ADDRSTRLEN] = {0};
-       char port[6] = {0};
-
-       if (inet_ntop(addr->sin6_family, &addr->sin6_addr, address, INET6_ADDRSTRLEN) == NULL)
-               perror("inet_ntop");
-       sprintf(port, "%d", ntohs(addr->sin6_port));
-
-       char *result = malloc(strlen(address) + 1 + strlen(port) + 1);
-       sprintf(result, "%s:%s", address, port);
-       return result;
-}
diff --git a/util.h b/util.h
deleted file mode 100644 (file)
index ed53816..0000000
--- a/util.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef _UTIL_H_
-#define _UTIL_H_
-
-#include <arpa/inet.h>
-#include "types.h"
-
-#define ever (;;)
-#define INBRACES(str) str ? "(" : "", str ? str : "", str ? ")" : ""
-
-extern const char *program_name;
-
-void syscall_error(const char *err);
-void internal_error(const char *err);
-char *read_string(int fd, size_t bufsiz);
-char *address_string(struct sockaddr_in6 *addr);
-
-#endif