COMMON = array.o binsearch.o list.o map.o signal.o util.o types.o
SERVER = $(COMMON) server.o servercommands.o
-CLIENT = $(COMMON) client.o clientcommands.o mesh.o
+CLIENT = $(COMMON) client.o clientcommands.o mesh.o scene.o
LIBRARIES = -lpthread -lm
CLIENT_LIBRARIES = -lGL -lGLEW -lglfw
FLAGS = -g
{
if (array->siz > array->cap) {
array->cap = array->siz + ARRAY_REALLOC_EXTRA;
- array->ptr = realloc(array->ptr, array->cap * sizeof(void *));
+ array->ptr = realloc(array->ptr, array->cap * array->membsiz);
}
}
size_t oldsiz = array->siz;
array_alloc(array, 1);
- void **iptr = array->ptr + idx;
- memmove(iptr + 1, iptr, (oldsiz - idx) * sizeof(void *));
- *iptr = elem;
+ char *iptr = (char *) array->ptr + idx * array->membsiz;
+ memmove(iptr + array->membsiz, iptr, (oldsiz - idx) * array->membsiz);
+ memcpy(iptr, elem, array->membsiz);
}
void array_append(Array *array, void *elem)
size_t oldsiz = array->siz;
array_alloc(array, 1);
- array->ptr[oldsiz] = elem;
+ memcpy((char *) array->ptr + oldsiz * array->membsiz, elem, array->membsiz);
}
-Array array_create()
+Array array_create(size_t membsiz)
{
- return (Array) {0, 0, NULL};
+ return (Array) {
+ .membsiz = membsiz,
+ .siz = 0,
+ .cap = 0,
+ .ptr = NULL,
+ };
}
typedef struct
{
+ size_t membsiz;
size_t siz, cap;
- void **ptr;
+ void *ptr;
} Array;
void array_insert(Array *array, void *elem, size_t idx);
void array_append(Array *array, void *elem);
-Array array_create();
+Array array_create(size_t membsiz);
#endif
#include <unistd.h>
#include <errno.h>
#include <netdb.h>
-#include <GLFW/glfw3.h>
#include <GL/glew.h>
#include <GL/gl.h>
+#include <GLFW/glfw3.h>
#include "client.h"
-#include "mesh.h"
#include "signal.h"
#include "util.h"
-void client_create_mesh(Client *client, Mesh *mesh);
-{
- pthread_mutex_lock(client->meshlist_mtx);
- list_put(&client->meshlist, mesh, NULL);
- pthread_mutex_unlock(client->meshlist_mtx);
-}
+Client client;
-void client_remove_mesh(Client *client, Mesh *mesh);
+void client_disconnect(bool send, const char *detail)
{
- pthread_mutex_lock(client->meshlist_mtx);
- list_delete(&client->meshlist, mesh);
- pthread_mutex_unlock(client->meshlist_mtx);
- delete_mesh(mesh);
-}
-
-void client_mapblock_changed(Client *client, v3s32 pos)
-{
- v3s32 *posptr = malloc(sizeof(v3s32));
- *posptr = pos;
- pthread_mutex_lock(client->mapblock_meshgen_mtx);
- if (! list_put(&client->mapblock_meshgen_queue, posptr, NULL))
- free(posptr);
- pthread_mutex_unlock(client->mapblock_meshgen_mtx);
-}
-
-void client_disconnect(Client *client, bool send, const char *detail)
-{
- pthread_mutex_lock(client->write_mtx);
- if (client->state != CS_DISCONNECTED) {
+ pthread_mutex_lock(&client.mtx);
+ if (client.state != CS_DISCONNECTED) {
if (send)
- write_u32(client->fd, SC_DISCONNECT);
+ write_u32(client.fd, SC_DISCONNECT);
- client->state = CS_DISCONNECTED;
+ client.state = CS_DISCONNECTED;
printf("Disconnected %s%s%s\n", INBRACES(detail));
- close(client->fd);
+ close(client.fd);
}
- pthread_mutex_unlock(client->write_mtx);
+ pthread_mutex_unlock(&client.mtx);
}
#include "network.c"
-static void *reciever_thread(void *cliptr)
+static void *reciever_thread(void *unused)
{
- Client *client = cliptr;
-
- handle_packets(client);
+ (void) unused;
- if (errno == EINTR)
- client_disconnect(client, true, NULL);
- else
- client_disconnect(client, false, "network error");
+ handle_packets(&client);
- if (client->name)
- free(client->name);
+ if (errno != EINTR)
+ client_disconnect(false, "network error");
- pthread_mutex_lock(client->meshlist_mtx);
- ITERATE_LIST(&client->meshes, pair) delete_mesh(pair->value);
- list_clear(&client->meshes);
- pthread_mutex_unlock(client->meshlist_mtx);
-
- for (int i = 0; i < CLIENT_MTX_COUNT; i++)
- pthread_mutex_destroy(&client.mutexes[i]);
-
- exit(EXIT_SUCCESS);
return NULL;
}
-static void *mapblock_meshgen_thread(void *cliptr)
-{
- Client *client = cliptr;
-
- for ever {
- ListPair **lptr = &client->mapblock_meshgen_queue.first;
- if (*lptr) {
- MapBlock *block = map_get_block(client->map, *(v3s32 *)(*lptr)->key, false);
- Array vertices(sizeof(GLfloat));
-
- // ToDo: Actual vertices generation code
-
- client_create_mesh(client, create_mesh(vertices.ptr, vertices.siz));
- pthread_mutex_lock(client->mapblock_meshgen_mtx);
- *lptr = (*lptr)->next;
- pthread_mutex_unlock(client->mapblock_meshgen_mtx);
- } else {
- sched_yield();
- }
- }
-}
-
-static void client_loop(Client *client)
+static void client_loop()
{
if(! glfwInit()) {
printf("Failed to initialize GLFW\n");
return;
}
- while (! glfwWindowShouldClose(window) && client->state != CS_DISCONNECTED && ! interrupted) {
+ int shader_program = 0;
+
+ while (! glfwWindowShouldClose(window) && client.state != CS_DISCONNECTED && ! interrupted) {
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(0.52941176470588, 0.8078431372549, 0.92156862745098, 1.0);
+ mat4x4 view, proj;
+
+ scene_render(client.scene, shader_program, view, proj);
+
glfwSwapBuffers(window);
glfwPollEvents();
}
}
-static bool client_name_prompt(Client *client)
+static bool client_name_prompt()
{
printf("Enter name: ");
fflush(stdout);
char name[NAME_MAX];
if (scanf("%s", name) == EOF)
return false;
- client->name = strdup(name);
- pthread_mutex_lock(client->write_mtx);
- if (write_u32(client->fd, SC_AUTH) && write(client->fd, client->name, strlen(name) + 1)) {
- client->state = CS_AUTH;
+ client.name = strdup(name);
+ pthread_mutex_lock(&client.mtx);
+ if (write_u32(client.fd, SC_AUTH) && write(client.fd, client.name, strlen(client.name) + 1)) {
+ client.state = CS_AUTH;
printf("Authenticating...\n");
}
- pthread_mutex_unlock(client->write_mtx);
+ pthread_mutex_unlock(&client.mtx);
return true;
}
-static bool client_authenticate(Client *client)
+static bool client_authenticate()
{
for ever {
- switch (client->state) {
+ switch (client.state) {
case CS_CREATED:
- if (client_name_prompt(client))
+ if (client_name_prompt())
break;
else
return false;
return false;
}
-static bool compare_positions(void *p1, void *p2)
+static void client_start(int fd)
{
- v3s32 *pos1 = p1;
- v3s32 *pos2 = p2;
- return pos1->x == pos2->x && pos1->y == pos2->y && pos->z == pos2->z;
+ client.fd = fd;
+ pthread_mutex_init(&client.mtx, NULL);
+ client.state = CS_CREATED;
+ client.name = NULL;
+ client.map = map_create();
+ client.scene = scene_create();
+ //client.mapblock_meshgen = mapblock_meshgen_create();
+
+ pthread_t recv_thread;
+ pthread_create(&recv_thread, NULL, &reciever_thread, NULL);
+
+ if (client_authenticate())
+ client_loop();
+
+ if (client.state != CS_DISCONNECTED)
+ client_disconnect(true, NULL);
+
+ if (client.name)
+ free(client.name);
+
+ map_delete(client.map);
+ scene_delete(client.scene);
+ //mapblock_meshgen_delete(client.mapblock_meshgen);
+
+ pthread_mutex_destroy(&client.mtx);
}
int main(int argc, char **argv)
internal_error("missing address or port");
struct addrinfo hints = {
- .ai_family = AF_UNSPEC, // support both IPv4 and IPv6
+ .ai_family = AF_UNSPEC,
.ai_socktype = SOCK_STREAM,
.ai_protocol = 0,
.ai_flags = AI_NUMERICSERV,
if (gai_state != 0)
internal_error(gai_strerror(gai_state));
- Client client = {
- .fd = -1,
- .map = NULL,
- .name = NULL,
- .state = CS_CREATED,
- .meshlist = list_create(NULL),
- .mapblock_meshgen_queue = list_create(&compare_positions),
- };
-
- for (int i = 0; i < CLIENT_MTX_COUNT; i++)
- pthread_mutex_init(&client.mutexes[i], NULL);
-
- client.write_mtx = &client.mutexes[0];
- client.meshlist_mtx = &client.mutexes[1];
- client.mapblock_meshgen_mtx = &client.mutexes[2];
+ int fd = socket(info->ai_family, info->ai_socktype, info->ai_protocol);
- client.fd = socket(info->ai_family, info->ai_socktype, info->ai_protocol);
-
- if (client.fd == -1)
+ if (fd == -1)
syscall_error("socket");
- if (connect(client.fd, info->ai_addr, info->ai_addrlen) == -1)
+ if (connect(fd, info->ai_addr, info->ai_addrlen) == -1)
syscall_error("connect");
char *addrstr = address_string((struct sockaddr_in6 *) info->ai_addr);
freeaddrinfo(info);
init_signal_handlers();
+ client_start(fd);
- client.map = map_create();
-
- pthread_t recv_thread;
- pthread_t mmg_thread;
- pthread_create(&recv_thread, NULL, &reciever_thread, &client);
- pthread_create(&mmg_thread, NULL, &mapblock_meshgen_thread, &client);
-
- if (client_authenticate(&client))
- client_loop(&client);
-
- client_disconnect(&client, true, NULL);
-
- pthread_join(recv_thread, NULL);
+ return EXIT_SUCCESS;
}
#include "servercommands.h"
#include "clientcommands.h"
#include "network.h"
-#include "list.h"
#include "map.h"
-
-#define CLIENT_MTX_COUNT 3
+//#include "mapblock_meshgen.h"
+#include "scene.h"
typedef struct Client
{
int fd;
+ pthread_mutex_t mtx;
+ ClientState state;
char *name;
Map *map;
- ClientState state;
- pthread_mutex_t *write_mtx;
- pthread_mutex_t *meshlist_mtx;
- pthread_mutex_t *mapblock_meshgen_mtx;
- pthread_mutex_t mutexes[CLIENT_MTX_COUNT];
- List meshlist;
- List mapblock_meshgen_queue;
+ Scene *scene;
+ //MapblockMeshgen *mapblock_meshgen;
} Client;
-void client_add_mesh(Client *client, Mesh *mesh);
-void client_remove_mesh(Client *client, Mesh *mesh);
-void client_mapblock_changed(Client *client, v3s32 pos);
-void client_disconnect(Client *client, bool send, const char *detail);
+void client_disconnect(bool send, const char *detail);
#endif
static bool disconnect_handler(Client *client, bool good)
{
+ (void) client;
+
if (good)
- client_disconnect(client, false, NULL);
+ client_disconnect(false, NULL);
return true;
}
return false;
if (good) {
- client_mapblock_changed(client, block->pos);
+ //mapblock_meshgen_enqueue(client->mapblock_meshgen, block->pos);
map_add_block(client->map, block);
} else {
map_free_block(block);
#include <stdlib.h>
#include <string.h>
-#include "List.h"
+#include "list.h"
-int list_compare_default(void *v1, void *v2)
+bool list_compare_default(void *v1, void *v2)
{
return v1 == v2;
}
-int list_compare_string(void *v1, void *v2)
+bool list_compare_string(void *v1, void *v2)
{
return strcmp(v1, v2) == 0;
}
List list_create(ListComparator cmp)
{
return (List) {
- .cmp = cmp ? cmp : list_compare_default;
+ .cmp = cmp ? cmp : list_compare_default,
.first = NULL,
};
}
#include "map.h"
#include "util.h"
+Map *map_create()
+{
+ Map *map = malloc(sizeof(Map));
+ map->sectors = array_create(sizeof(MapSector *));
+ return map;
+}
+
+static MapBlock **get_block_ptr(MapSector *sector, size_t idx)
+{
+ return (MapBlock **) sector->blocks.ptr + idx;
+}
+
+static MapSector **get_sector_ptr(Map *map, size_t idx)
+{
+ return (MapSector **) map->sectors.ptr + idx;
+}
+
+void map_delete(Map *map)
+{
+ for (size_t s = 0; s < map->sectors.siz; s++) {
+ MapSector *sector = *get_sector_ptr(map, s);
+ for (size_t b = 0; b < sector->blocks.siz; b++)
+ map_free_block(*get_block_ptr(sector, b));
+ if (sector->blocks.ptr)
+ free(sector->blocks.ptr);
+ free(sector);
+ }
+ if (map->sectors.ptr)
+ free(map->sectors.ptr);
+ free(map);
+}
+
#define CMPBOUNDS(x) x == 0 ? 0 : x > 0 ? 1 : -1
static s8 sector_compare(void *hash, void *sector)
BinsearchResult res = binsearch(&hash, map->sectors.ptr, map->sectors.siz, §or_compare);
if (res.success)
- return map->sectors.ptr[res.index];
+ return *get_sector_ptr(map, res.index);
if (! create)
return NULL;
MapSector *sector = malloc(sizeof(MapSector));
sector->pos = pos;
sector->hash = hash;
- sector->blocks = array_create();
+ sector->blocks = array_create(sizeof(MapBlock *));
- array_insert(&map->sectors, sector, res.index);
+ array_insert(&map->sectors, §or, res.index);
return sector;
}
return CMPBOUNDS(d);
}
-static void allocate_block(v3s23 pos)
+static MapBlock *allocate_block(v3s32 pos)
{
MapBlock *block = malloc(sizeof(MapBlock));
block->pos = pos;
BinsearchResult res = binsearch(&pos.y, sector->blocks.ptr, sector->blocks.siz, &block_compare);
if (res.success)
- return sector->blocks.ptr[res.index];
+ return *get_block_ptr(sector, res.index);
if (! create)
return NULL;
MapNode air = map_node_create(NODE_AIR);
ITERATE_MAPBLOCK block->data[x][y][z] = air;
- array_insert(§or->blocks, block, res.index);
+ array_insert(§or->blocks, &block, res.index);
return block;
}
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) {
- map_free_block(sector->blocks.ptr[res.index]);
- sector->blocks.ptr[res.index] = block;
+ MapBlock **ptr = get_block_ptr(sector, res.index);
+ map_free_block(*ptr);
+ *ptr = block;
} else {
- array_insert(§or->blocks, block, res.index);
+ array_insert(§or->blocks, &block, res.index);
}
}
bool map_serialize(int fd, Map *map)
{
for (size_t s = 0; s < map->sectors.siz; s++) {
- MapSector *sector = map->sectors.ptr[s];
+ MapSector *sector = *get_sector_ptr(map, s);
for (size_t b = 0; b < sector->blocks.siz; b++)
- if (! map_serialize_block(fd, sector->blocks.ptr[b]))
+ if (! map_serialize_block(fd, *get_block_ptr(sector, b)))
return false;
}
return true;
{
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++)
- map_free_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);
-}
#include <stdbool.h>
#include "array.h"
-#include "linkedlist.h"
+#include "list.h"
#include "node.h"
#include "types.h"
typedef struct
{
Node type;
- LinkedList meta;
+ List meta;
} MapNode;
typedef struct
Array sectors;
} Map;
+Map *map_create();
+void map_delete(Map *map);
+
MapSector *map_get_sector(Map *map, v2s32 pos, bool create);
MapBlock *map_get_block(Map *map, v3s32 pos, bool create);
MapNode map_node_create(Node type);
void map_node_clear(MapNode *node);
-Map *map_create();
-void map_delete(Map *map);
-
#endif
--- /dev/null
+static bool compare_positions(void *p1, void *p2)
+{
+ v3s32 *pos1 = p1;
+ v3s32 *pos2 = p2;
+ return pos1->x == pos2->x && pos1->y == pos2->y && pos->z == pos2->z;
+}
+
+static void *mapblock_meshgen_thread(void *cliptr)
+{
+ Client *client = cliptr;
+
+ for ever {
+ ListPair **lptr = &client->mapblock_meshgen_queue.first;
+ if (*lptr) {
+ MapBlock *block = map_get_block(client->map, *(v3s32 *)(*lptr)->key, false);
+ Array vertices(sizeof(GLfloat));
+
+ ITERATE_MAPBLOCK {
+ MapNode node = block->data[x][y][z];
+ BlockDef *def = block->getDef();
+ if (! def->drawable)
+ continue;
+ ivec3 bpos(x, y, z);
+ vec3 pos_from_mesh_origin = vec3(bpos) - vec3(SIZE / 2 + 0.5);
+ for (int facenr = 0; facenr < 6; facenr++) {
+ ivec3 npos = bpos + face_dir[facenr];
+ const Block *neighbor_own, *neighbor;
+ neighbor_own = neighbor = getBlockNoEx(npos);
+ if (! neighbor)
+ neighbor = map->getBlock(pos * SIZE + npos);
+ if (neighbor && ! neighbor->getDef()->drawable)
+ any_drawable_block = true;
+ if (! mesh_created_before)
+ neighbor = neighbor_own;
+ if (! mesh_created_before && ! neighbor || neighbor && ! neighbor->getDef()->drawable) {
+ textures.push_back(def->tile_def.get(facenr));
+ for (int vertex_index = 0; vertex_index < 6; vertex_index++) {
+ for (int attribute_index = 0; attribute_index < 5; attribute_index++) {
+ GLdouble value = box_vertices[facenr][vertex_index][attribute_index];
+ switch (attribute_index) {
+ case 0:
+ value += pos_from_mesh_origin.x;
+ break;
+ case 1:
+ value += pos_from_mesh_origin.y;
+ break;
+ case 2:
+ value += pos_from_mesh_origin.z;
+ break;
+ }
+ vertices.push_back(value);
+ }
+ }
+ }
+ }
+ }
+
+ client_create_mesh(client, create_mesh(vertices.ptr, vertices.siz));
+ pthread_mutex_lock(client->mapblock_meshgen_mtx);
+ *lptr = (*lptr)->next;
+ pthread_mutex_unlock(client->mapblock_meshgen_mtx);
+ } else {
+ sched_yield();
+ }
+ }
+}
+
+void client_mapblock_changed(Client *client, v3s32 pos)
+{
+ v3s32 *posptr = malloc(sizeof(v3s32));
+ *posptr = pos;
+ pthread_mutex_lock(client->mapblock_meshgen_mtx);
+ if (! list_put(&client->mapblock_meshgen_queue, posptr, NULL))
+ free(posptr);
+ pthread_mutex_unlock(client->mapblock_meshgen_mtx);
+}
--- /dev/null
+#ifndef _MAPBLOCK_MESHGEN_H_
+#define _MAPBLOCK_MESHGEN_H_
+
+typedef struct
+{
+ pthread_mutex_t mtx;
+} MapblockMeshgen;
+
+
+
+#endif
GLuint VAO, VBO;
} Mesh;
-Mesh *create_mesh(const GLvoid *vertices, GLsizei size);
-void delete_mesh(Mesh *mesh);
+Mesh *mesh_create(const GLvoid *vertices, GLsizei size);
+void mesh_delete(Mesh *mesh);
#endif
bool send_command(Client *client, RemoteCommand cmd)
{
- pthread_mutex_lock(client->write_mtx);
+ pthread_mutex_lock(&client->mtx);
bool ret = write_u32(client->fd, cmd);
- pthread_mutex_unlock(client->write_mtx);
+ pthread_mutex_unlock(&client->mtx);
return ret;
}
static void handle_packets(Client *client) {
- while (client->state != CS_DISCONNECTED) {
+ while (client->state != CS_DISCONNECTED || ! interrupted) {
struct pollfd pfd = {
.fd = client->fd,
.events = POLLIN,
return;
}
- if (client->state == CS_DISCONNECTED)
- return;
-
- if (pstate == 0)
+ if (pstate == 0) {
+ sched_yield();
continue;
+ }
if (! (pfd.revents & POLLIN))
return;
--- /dev/null
+#include <stdlib.h>
+#include "scene.h"
+
+Scene *scene_create()
+{
+ Scene *scene = malloc(sizeof(Scene));
+ scene->meshes = list_create(NULL),
+ pthread_mutex_init(&scene->mtx, NULL);
+
+ return scene;
+}
+
+void scene_delete(Scene *scene)
+{
+ ITERATE_LIST(&scene->meshes, pair) mesh_delete(pair->value);
+ list_clear(&scene->meshes);
+ pthread_mutex_destroy(&scene->mtx);
+ free(scene);
+}
+
+void scene_add_mesh(Scene *scene, Mesh *mesh)
+{
+ list_put(&scene->meshes, mesh, NULL);
+}
+
+void scene_remove_mesh(Scene *scene, Mesh *mesh)
+{
+ pthread_mutex_lock(&scene->mtx);
+ list_delete(&scene->meshes, mesh);
+ pthread_mutex_unlock(&scene->mtx);
+ mesh_delete(mesh);
+}
+
--- /dev/null
+#ifndef _SCENE_H_
+#define _SCENE_H_
+
+#include <pthread.h>
+#include "list.h"
+#include "mesh.h"
+
+typedef struct
+{
+ List meshes;
+ pthread_mutex_t mtx;
+} Scene;
+
+Scene *scene_create();
+void scene_delete(Scene *scene);
+
+void scene_add_mesh(Scene *scene, Mesh *mesh);
+void scene_remove_mesh(Scene *scene, Mesh *mesh);
+void scene_render(Scene *scene, int prog, mat4x4 view, mat4x4 proj); // ToDo
+
+#endif
#include <unistd.h>
#include <errno.h>
#include <netdb.h>
-#include <fcntl.h>
#include "server.h"
#include "signal.h"
#include "util.h"
+Server server;
+
void server_disconnect_client(Client *client, int flags, const char *detail)
{
client->state = CS_DISCONNECTED;
if (client->name && ! (flags & DISCO_NO_REMOVE))
- list_delete(&client->server->clients, client->name);
+ list_delete(&server.clients, client->name);
if (! (flags & DISCO_NO_MESSAGE))
printf("Disconnected %s %s%s%s\n", client->name, INBRACES(detail));
if (! (flags & DISCO_NO_SEND))
send_command(client, CC_DISCONNECT);
- pthread_mutex_lock(client->write_mtx);
+ pthread_mutex_lock(&client->mtx);
close(client->fd);
- pthread_mutex_unlock(client->write_mtx);
-}
-
-void server_shutdown(Server *srv)
-{
- printf("Shutting down\n");
-
- ITERATE_LIST(&srv->clients, pair) server_disconnect_client(pair->value, DISCO_NO_REMOVE | DISCO_NO_MESSAGE, "");
- list_clear(&srv->clients);
-
- shutdown(srv->sockfd, SHUT_RDWR);
- close(srv->sockfd);
-
- FILE *mapfile = fopen("map", "w");
- if (mapfile) {
- if (map_serialize(fileno(mapfile), srv->map))
- printf("Saved map\n");
- else
- perror("map_serialize");
- fclose(mapfile);
- } else {
- perror("fopen");
- }
-
- map_delete(srv->map);
-
- exit(EXIT_SUCCESS);
+ pthread_mutex_unlock(&client->mtx);
}
#include "network.c"
-static void *reciever_thread(void *clientptr)
+static void *server_reciever_thread(void *clientptr)
{
Client *client = clientptr;
free(client->address);
- pthread_mutex_destroy(client->write_mtx);
+ pthread_mutex_destroy(&client->mtx);
+
free(client);
return NULL;
}
-static void accept_client(Server *srv)
+static void server_accept_client()
{
struct sockaddr_storage client_address = {0};
socklen_t client_addrlen = sizeof(client_address);
- int fd = accept(srv->sockfd, (struct sockaddr *) &client_address, &client_addrlen);
+ int fd = accept(server.sockfd, (struct sockaddr *) &client_address, &client_addrlen);
if (fd == -1) {
- if (errno == EINTR)
- server_shutdown(srv);
- else
- syscall_error("accept");
+ if (errno != EINTR)
+ perror("accept");
+ return;
}
Client *client = malloc(sizeof(Client));
- client->server = srv;
- client->state = CS_CREATED;
client->fd = fd;
+ pthread_mutex_init(&client->mtx, NULL);
+ client->state = CS_CREATED;
client->address = address_string((struct sockaddr_in6 *) &client_address);
client->name = client->address;
+ client->server = &server;
+ pthread_create(&client->thread, NULL, &server_reciever_thread, client);
printf("Connected %s\n", client->address);
+}
+
+void server_start(int fd)
+{
+ server.sockfd = fd;
+ server.map = map_create(NULL);
+ server.clients = list_create(&list_compare_string);
+
+ FILE *mapfile = fopen("map", "r");
+ if (mapfile) {
+ map_deserialize(fileno(mapfile), server.map);
+ fclose(mapfile);
+ } else if (errno != ENOENT) {
+ perror("fopen");
+ }
+
+ while (! interrupted)
+ server_accept_client();
+
+ printf("Shutting down\n");
+
+ ITERATE_LIST(&server.clients, pair) server_disconnect_client(pair->value, DISCO_NO_REMOVE | DISCO_NO_MESSAGE, "");
+ list_clear(&server.clients);
- client->write_mtx = &client->mutex;
- pthread_mutex_init(client->write_mtx, NULL);
+ shutdown(server.sockfd, SHUT_RDWR);
+ close(server.sockfd);
- pthread_t thread;
- pthread_create(&thread, NULL, &reciever_thread, client);
+ mapfile = fopen("map", "w");
+ if (mapfile) {
+ if (map_serialize(fileno(mapfile), server.map))
+ printf("Saved map\n");
+ else
+ perror("map_serialize");
+ fclose(mapfile);
+ } else {
+ perror("fopen");
+ }
+
+ map_delete(server.map);
+
+ exit(EXIT_SUCCESS);
}
int main(int argc, char **argv)
if (gai_state != 0)
internal_error(gai_strerror(gai_state));
- Server server = {
- .sockfd = -1,
- .map = NULL,
- .clients = list_create(&list_compare_string),
- };
-
- server.sockfd = socket(info->ai_family, info->ai_socktype, 0);
+ int fd = socket(info->ai_family, info->ai_socktype, 0);
- if (server.sockfd == -1)
+ if (fd == -1)
syscall_error("socket");
int flag = 1;
- if (setsockopt(server.sockfd, SOL_SOCKET, SO_REUSEADDR, &flag, 4) == -1)
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)) == -1)
syscall_error("setsockopt");
- if (bind(server.sockfd, info->ai_addr, info->ai_addrlen) == -1)
+ if (bind(fd, info->ai_addr, info->ai_addrlen) == -1)
syscall_error("bind");
- if (listen(server.sockfd, 3) == -1)
+ if (listen(fd, 3) == -1)
syscall_error("listen");
char *addrstr = address_string((struct sockaddr_in6 *) info->ai_addr);
freeaddrinfo(info);
init_signal_handlers();
+ server_start(fd);
- server.map = map_create(NULL);
-
- FILE *mapfile = fopen("map", "r");
- if (mapfile) {
- map_deserialize(fileno(mapfile), server.map);
- fclose(mapfile);
- } else if (errno != ENOENT) {
- perror("fopen");
- }
-
- for ever accept_client(&server);
+ return EXIT_SUCCESS;
}
typedef struct
{
int sockfd;
- Map *map;
List clients;
+ Map *map;
} Server;
typedef struct Client
{
int fd;
- char *name;
+ pthread_mutex_t mtx;
+ ClientState state;
char *address;
+ char *name;
Server *server;
- ClientState state;
- pthread_mutex_t *write_mtx;
- pthread_mutex_t mutex;
+ pthread_t thread;
} Client;
typedef enum
} DiscoFlag;
void server_disconnect_client(Client *client, int flags, const char *detail);
-void server_shutdown(Server *srv);
+void server_shutdown();
#endif
free(name);
}
- pthread_mutex_lock(client->write_mtx);
+ pthread_mutex_lock(&client->mtx);
bool ret = write_u32(client->fd, CC_AUTH) && write_u8(client->fd, success);
- pthread_mutex_unlock(client->write_mtx);
+ pthread_mutex_unlock(&client->mtx);
return ret;
}
MapBlock *block = map_get_block(client->server->map, pos, false);
if (block) {
- pthread_mutex_lock(client->write_mtx);
+ pthread_mutex_lock(&client->mtx);
bool ret = write_u32(client->fd, CC_BLOCK) && map_serialize_block(client->fd, block);
- pthread_mutex_unlock(client->write_mtx);
+ pthread_mutex_unlock(&client->mtx);
return ret;
}