diff options
Diffstat (limited to 'server.c')
-rw-r--r-- | server.c | 564 |
1 files changed, 282 insertions, 282 deletions
diff --git a/server.c b/server.c index 67aa76c..a5b8855 100644 --- a/server.c +++ b/server.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, Curtis McEnroe <curtis@cmcenroe.me> +/* Copyright (C) 2017 Curtis McEnroe <june@causal.agency> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by @@ -38,337 +38,337 @@ static struct Tile *tiles; static void tilesMap(void) { - int fd = open("torus.dat", O_CREAT | O_RDWR, 0644); - if (fd < 0) err(EX_CANTCREAT, "torus.dat"); + int fd = open("torus.dat", O_CREAT | O_RDWR, 0644); + if (fd < 0) err(EX_CANTCREAT, "torus.dat"); - int error = ftruncate(fd, TILES_SIZE); - if (error) err(EX_IOERR, "ftruncate"); + int error = ftruncate(fd, TILES_SIZE); + if (error) err(EX_IOERR, "ftruncate"); - tiles = mmap(NULL, TILES_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (tiles == MAP_FAILED) err(EX_OSERR, "mmap"); + tiles = mmap(NULL, TILES_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (tiles == MAP_FAILED) err(EX_OSERR, "mmap"); - error = madvise(tiles, TILES_SIZE, MADV_RANDOM); - if (error) err(EX_OSERR, "madvise"); + error = madvise(tiles, TILES_SIZE, MADV_RANDOM); + if (error) err(EX_OSERR, "madvise"); #ifdef MADV_NOCORE - error = madvise(tiles, TILES_SIZE, MADV_NOCORE); - if (error) err(EX_OSERR, "madvise"); + error = madvise(tiles, TILES_SIZE, MADV_NOCORE); + if (error) err(EX_OSERR, "madvise"); #endif } static struct Tile *tileGet(uint32_t tileX, uint32_t tileY) { - struct Tile *tile = &tiles[tileY * TILE_ROWS + tileX]; - if (!tile->createTime) { - memset(tile->cells, ' ', CELLS_SIZE); - memset(tile->colors, COLOR_WHITE, CELLS_SIZE); - tile->createTime = time(NULL); - } - return tile; + struct Tile *tile = &tiles[tileY * TILE_ROWS + tileX]; + if (!tile->createTime) { + memset(tile->cells, ' ', CELLS_SIZE); + memset(tile->colors, COLOR_WHITE, CELLS_SIZE); + tile->createTime = time(NULL); + } + return tile; } static struct Tile *tileAccess(uint32_t tileX, uint32_t tileY) { - struct Tile *tile = tileGet(tileX, tileY); - tile->accessTime = time(NULL); - tile->accessCount++; - return tile; + struct Tile *tile = tileGet(tileX, tileY); + tile->accessTime = time(NULL); + tile->accessCount++; + return tile; } static struct Tile *tileModify(uint32_t tileX, uint32_t tileY) { - struct Tile *tile = tileGet(tileX, tileY); - tile->modifyTime = time(NULL); - tile->modifyCount++; - return tile; + struct Tile *tile = tileGet(tileX, tileY); + tile->modifyTime = time(NULL); + tile->modifyCount++; + return tile; } static struct Client { - int fd; + int fd; - uint32_t tileX; - uint32_t tileY; - uint8_t cellX; - uint8_t cellY; + uint32_t tileX; + uint32_t tileY; + uint8_t cellX; + uint8_t cellY; - struct Client *prev; - struct Client *next; + struct Client *prev; + struct Client *next; } *clientHead; static struct Client *clientAdd(int fd) { - struct Client *client = malloc(sizeof(*client)); - if (!client) err(EX_OSERR, "malloc"); - - client->fd = fd; - client->tileX = TILE_VOID_X; - client->tileY = TILE_VOID_Y; - client->cellX = CELL_INIT_X; - client->cellY = CELL_INIT_Y; - - client->prev = NULL; - if (clientHead) { - clientHead->prev = client; - client->next = clientHead; - } else { - client->next = NULL; - } - clientHead = client; - - return client; + struct Client *client = malloc(sizeof(*client)); + if (!client) err(EX_OSERR, "malloc"); + + client->fd = fd; + client->tileX = TILE_VOID_X; + client->tileY = TILE_VOID_Y; + client->cellX = CELL_INIT_X; + client->cellY = CELL_INIT_Y; + + client->prev = NULL; + if (clientHead) { + clientHead->prev = client; + client->next = clientHead; + } else { + client->next = NULL; + } + clientHead = client; + + return client; } static bool clientSend(const struct Client *client, struct ServerMessage msg) { - ssize_t size = send(client->fd, &msg, sizeof(msg), 0); - if (size < 0) return false; + ssize_t size = send(client->fd, &msg, sizeof(msg), 0); + if (size < 0) return false; - if (msg.type == SERVER_TILE) { - struct Tile *tile = tileAccess(client->tileX, client->tileY); - size = send(client->fd, tile, sizeof(*tile), 0); - if (size < 0) return false; - } + if (msg.type == SERVER_TILE) { + struct Tile *tile = tileAccess(client->tileX, client->tileY); + size = send(client->fd, tile, sizeof(*tile), 0); + if (size < 0) return false; + } - return true; + return true; } static void clientCast(const struct Client *origin, struct ServerMessage msg) { - for (struct Client *client = clientHead; client; client = client->next) { - if (client == origin) continue; - if (client->tileX != origin->tileX) continue; - if (client->tileY != origin->tileY) continue; - clientSend(client, msg); - } + for (struct Client *client = clientHead; client; client = client->next) { + if (client == origin) continue; + if (client->tileX != origin->tileX) continue; + if (client->tileY != origin->tileY) continue; + clientSend(client, msg); + } } static void clientRemove(struct Client *client) { - if (client->prev) client->prev->next = client->next; - if (client->next) client->next->prev = client->prev; - if (clientHead == client) clientHead = client->next; - - struct ServerMessage msg = { - .type = SERVER_CURSOR, - .cursor = { - .oldCellX = client->cellX, .oldCellY = client->cellY, - .newCellX = CURSOR_NONE, .newCellY = CURSOR_NONE, - }, - }; - clientCast(client, msg); - - close(client->fd); - free(client); + if (client->prev) client->prev->next = client->next; + if (client->next) client->next->prev = client->prev; + if (clientHead == client) clientHead = client->next; + + struct ServerMessage msg = { + .type = SERVER_CURSOR, + .cursor = { + .oldCellX = client->cellX, .oldCellY = client->cellY, + .newCellX = CURSOR_NONE, .newCellY = CURSOR_NONE, + }, + }; + clientCast(client, msg); + + close(client->fd); + free(client); } static bool clientCursors(const struct Client *client) { - struct ServerMessage msg = { - .type = SERVER_CURSOR, - .cursor = { .oldCellX = CURSOR_NONE, .oldCellY = CURSOR_NONE }, - }; - - for (struct Client *friend = clientHead; friend; friend = friend->next) { - if (friend == client) continue; - if (friend->tileX != client->tileX) continue; - if (friend->tileY != client->tileY) continue; - - msg.cursor.newCellX = friend->cellX; - msg.cursor.newCellY = friend->cellY; - if (!clientSend(client, msg)) return false; - } - return true; + struct ServerMessage msg = { + .type = SERVER_CURSOR, + .cursor = { .oldCellX = CURSOR_NONE, .oldCellY = CURSOR_NONE }, + }; + + for (struct Client *friend = clientHead; friend; friend = friend->next) { + if (friend == client) continue; + if (friend->tileX != client->tileX) continue; + if (friend->tileY != client->tileY) continue; + + msg.cursor.newCellX = friend->cellX; + msg.cursor.newCellY = friend->cellY; + if (!clientSend(client, msg)) return false; + } + return true; } static bool clientUpdate(const struct Client *client, const struct Client *old) { - struct ServerMessage msg = { - .type = SERVER_MOVE, - .move = { .cellX = client->cellX, .cellY = client->cellY }, - }; - if (!clientSend(client, msg)) return false; - - if (client->tileX != old->tileX || client->tileY != old->tileY) { - msg.type = SERVER_TILE; - if (!clientSend(client, msg)) return false; - - if (!clientCursors(client)) return false; - - msg = (struct ServerMessage) { - .type = SERVER_CURSOR, - .cursor = { - .oldCellX = old->cellX, .oldCellY = old->cellY, - .newCellX = CURSOR_NONE, .newCellY = CURSOR_NONE, - }, - }; - clientCast(old, msg); - - msg = (struct ServerMessage) { - .type = SERVER_CURSOR, - .cursor = { - .oldCellX = CURSOR_NONE, .oldCellY = CURSOR_NONE, - .newCellX = client->cellX, .newCellY = client->cellY, - }, - }; - clientCast(client, msg); - - } else { - msg = (struct ServerMessage) { - .type = SERVER_CURSOR, - .cursor = { - .oldCellX = old->cellX, .oldCellY = old->cellY, - .newCellX = client->cellX, .newCellY = client->cellY, - }, - }; - clientCast(client, msg); - } - - return true; + struct ServerMessage msg = { + .type = SERVER_MOVE, + .move = { .cellX = client->cellX, .cellY = client->cellY }, + }; + if (!clientSend(client, msg)) return false; + + if (client->tileX != old->tileX || client->tileY != old->tileY) { + msg.type = SERVER_TILE; + if (!clientSend(client, msg)) return false; + + if (!clientCursors(client)) return false; + + msg = (struct ServerMessage) { + .type = SERVER_CURSOR, + .cursor = { + .oldCellX = old->cellX, .oldCellY = old->cellY, + .newCellX = CURSOR_NONE, .newCellY = CURSOR_NONE, + }, + }; + clientCast(old, msg); + + msg = (struct ServerMessage) { + .type = SERVER_CURSOR, + .cursor = { + .oldCellX = CURSOR_NONE, .oldCellY = CURSOR_NONE, + .newCellX = client->cellX, .newCellY = client->cellY, + }, + }; + clientCast(client, msg); + + } else { + msg = (struct ServerMessage) { + .type = SERVER_CURSOR, + .cursor = { + .oldCellX = old->cellX, .oldCellY = old->cellY, + .newCellX = client->cellX, .newCellY = client->cellY, + }, + }; + clientCast(client, msg); + } + + return true; } static bool clientSpawn(struct Client *client, uint8_t spawn) { - if (spawn >= SPAWNS_LEN) return false; - struct Client old = *client; - client->tileX = SPAWNS[spawn].tileX; - client->tileY = SPAWNS[spawn].tileY; - client->cellX = CELL_INIT_X; - client->cellY = CELL_INIT_Y; - return clientUpdate(client, &old); + if (spawn >= SPAWNS_LEN) return false; + struct Client old = *client; + client->tileX = SPAWNS[spawn].tileX; + client->tileY = SPAWNS[spawn].tileY; + client->cellX = CELL_INIT_X; + client->cellY = CELL_INIT_Y; + return clientUpdate(client, &old); } static bool clientMove(struct Client *client, int8_t dx, int8_t dy) { - struct Client old = *client; - - if (dx > CELL_COLS - client->cellX) dx = CELL_COLS - client->cellX; - if (dx < -client->cellX - 1) dx = -client->cellX - 1; - if (dy > CELL_ROWS - client->cellY) dy = CELL_ROWS - client->cellY; - if (dy < -client->cellY - 1) dy = -client->cellY - 1; - - client->cellX += dx; - client->cellY += dy; - - if (client->cellX == CELL_COLS) { - client->tileX++; - client->cellX = 0; - } - if (client->cellX == UINT8_MAX) { - client->tileX--; - client->cellX = CELL_COLS - 1; - } - if (client->cellY == CELL_ROWS) { - client->tileY++; - client->cellY = 0; - } - if (client->cellY == UINT8_MAX) { - client->tileY--; - client->cellY = CELL_ROWS - 1; - } - - if (client->tileX == TILE_COLS) client->tileX = 0; - if (client->tileX == UINT32_MAX) client->tileX = TILE_COLS - 1; - if (client->tileY == TILE_ROWS) client->tileY = 0; - if (client->tileY == UINT32_MAX) client->tileY = TILE_ROWS - 1; - - assert(client->cellX < CELL_COLS); - assert(client->cellY < CELL_ROWS); - assert(client->tileX < TILE_COLS); - assert(client->tileY < TILE_ROWS); - - return clientUpdate(client, &old); + struct Client old = *client; + + if (dx > CELL_COLS - client->cellX) dx = CELL_COLS - client->cellX; + if (dx < -client->cellX - 1) dx = -client->cellX - 1; + if (dy > CELL_ROWS - client->cellY) dy = CELL_ROWS - client->cellY; + if (dy < -client->cellY - 1) dy = -client->cellY - 1; + + client->cellX += dx; + client->cellY += dy; + + if (client->cellX == CELL_COLS) { + client->tileX++; + client->cellX = 0; + } + if (client->cellX == UINT8_MAX) { + client->tileX--; + client->cellX = CELL_COLS - 1; + } + if (client->cellY == CELL_ROWS) { + client->tileY++; + client->cellY = 0; + } + if (client->cellY == UINT8_MAX) { + client->tileY--; + client->cellY = CELL_ROWS - 1; + } + + if (client->tileX == TILE_COLS) client->tileX = 0; + if (client->tileX == UINT32_MAX) client->tileX = TILE_COLS - 1; + if (client->tileY == TILE_ROWS) client->tileY = 0; + if (client->tileY == UINT32_MAX) client->tileY = TILE_ROWS - 1; + + assert(client->cellX < CELL_COLS); + assert(client->cellY < CELL_ROWS); + assert(client->tileX < TILE_COLS); + assert(client->tileY < TILE_ROWS); + + return clientUpdate(client, &old); } static bool clientPut(const struct Client *client, uint8_t color, char cell) { - struct Tile *tile = tileModify(client->tileX, client->tileY); - tile->colors[client->cellY][client->cellX] = color; - tile->cells[client->cellY][client->cellX] = cell; - - struct ServerMessage msg = { - .type = SERVER_PUT, - .put = { - .cellX = client->cellX, - .cellY = client->cellY, - .color = color, - .cell = cell, - }, - }; - bool success = clientSend(client, msg); - clientCast(client, msg); - return success; + struct Tile *tile = tileModify(client->tileX, client->tileY); + tile->colors[client->cellY][client->cellX] = color; + tile->cells[client->cellY][client->cellX] = cell; + + struct ServerMessage msg = { + .type = SERVER_PUT, + .put = { + .cellX = client->cellX, + .cellY = client->cellY, + .color = color, + .cell = cell, + }, + }; + bool success = clientSend(client, msg); + clientCast(client, msg); + return success; } int main() { - int error; - - tilesMap(); - - int server = socket(PF_LOCAL, SOCK_STREAM, 0); - if (server < 0) err(EX_OSERR, "socket"); - - error = unlink("torus.sock"); - if (error && errno != ENOENT) err(EX_IOERR, "torus.sock"); - - struct sockaddr_un addr = { - .sun_family = AF_LOCAL, - .sun_path = "torus.sock", - }; - error = bind(server, (struct sockaddr *)&addr, sizeof(addr)); - if (error) err(EX_CANTCREAT, "torus.sock"); - - error = listen(server, 0); - if (error) err(EX_OSERR, "listen"); - - int kq = kqueue(); - if (kq < 0) err(EX_OSERR, "kqueue"); - - struct kevent event = { - .ident = server, - .filter = EVFILT_READ, - .flags = EV_ADD, - }; - int nevents = kevent(kq, &event, 1, NULL, 0, NULL); - if (nevents < 0) err(EX_OSERR, "kevent"); - - for (;;) { - nevents = kevent(kq, NULL, 0, &event, 1, NULL); - if (nevents < 0) err(EX_IOERR, "kevent"); - - if (!event.udata) { - int fd = accept(server, NULL, NULL); - if (fd < 0) err(EX_IOERR, "accept"); - fcntl(fd, F_SETFL, O_NONBLOCK); - - int on = 1; - error = setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(on)); - if (error) err(EX_IOERR, "setsockopt"); - - struct Client *client = clientAdd(fd); - - struct kevent event = { - .ident = fd, - .filter = EVFILT_READ, - .flags = EV_ADD, - .udata = client, - }; - nevents = kevent(kq, &event, 1, NULL, 0, NULL); - if (nevents < 0) err(EX_IOERR, "kevent"); - - if (!clientSpawn(client, 0)) clientRemove(client); - - continue; - } - - struct Client *client = event.udata; - if (event.flags & EV_EOF) { - clientRemove(client); - continue; - } - - struct ClientMessage msg; - ssize_t size = recv(client->fd, &msg, sizeof(msg), 0); - if (size != sizeof(msg)) { - clientRemove(client); - continue; - } - - bool success = false; - if (msg.type == CLIENT_MOVE) { - success = clientMove(client, msg.move.dx, msg.move.dy); - } else if (msg.type == CLIENT_PUT) { - success = clientPut(client, msg.put.color, msg.put.cell); - } else if (msg.type == CLIENT_SPAWN) { - success = clientSpawn(client, msg.spawn); - } - if (!success) clientRemove(client); - } + int error; + + tilesMap(); + + int server = socket(PF_LOCAL, SOCK_STREAM, 0); + if (server < 0) err(EX_OSERR, "socket"); + + error = unlink("torus.sock"); + if (error && errno != ENOENT) err(EX_IOERR, "torus.sock"); + + struct sockaddr_un addr = { + .sun_family = AF_LOCAL, + .sun_path = "torus.sock", + }; + error = bind(server, (struct sockaddr *)&addr, sizeof(addr)); + if (error) err(EX_CANTCREAT, "torus.sock"); + + error = listen(server, 0); + if (error) err(EX_OSERR, "listen"); + + int kq = kqueue(); + if (kq < 0) err(EX_OSERR, "kqueue"); + + struct kevent event = { + .ident = server, + .filter = EVFILT_READ, + .flags = EV_ADD, + }; + int nevents = kevent(kq, &event, 1, NULL, 0, NULL); + if (nevents < 0) err(EX_OSERR, "kevent"); + + for (;;) { + nevents = kevent(kq, NULL, 0, &event, 1, NULL); + if (nevents < 0) err(EX_IOERR, "kevent"); + + if (!event.udata) { + int fd = accept(server, NULL, NULL); + if (fd < 0) err(EX_IOERR, "accept"); + fcntl(fd, F_SETFL, O_NONBLOCK); + + int on = 1; + error = setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(on)); + if (error) err(EX_IOERR, "setsockopt"); + + struct Client *client = clientAdd(fd); + + struct kevent event = { + .ident = fd, + .filter = EVFILT_READ, + .flags = EV_ADD, + .udata = client, + }; + nevents = kevent(kq, &event, 1, NULL, 0, NULL); + if (nevents < 0) err(EX_IOERR, "kevent"); + + if (!clientSpawn(client, 0)) clientRemove(client); + + continue; + } + + struct Client *client = event.udata; + if (event.flags & EV_EOF) { + clientRemove(client); + continue; + } + + struct ClientMessage msg; + ssize_t size = recv(client->fd, &msg, sizeof(msg), 0); + if (size != sizeof(msg)) { + clientRemove(client); + continue; + } + + bool success = false; + if (msg.type == CLIENT_MOVE) { + success = clientMove(client, msg.move.dx, msg.move.dy); + } else if (msg.type == CLIENT_PUT) { + success = clientPut(client, msg.put.color, msg.put.cell); + } else if (msg.type == CLIENT_SPAWN) { + success = clientSpawn(client, msg.spawn); + } + if (!success) clientRemove(client); + } } |