No Description https://ascii.town
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

server.c 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  1. /* Copyright (C) 2017 Curtis McEnroe <june@causal.agency>
  2. *
  3. * This program is free software: you can redistribute it and/or modify
  4. * it under the terms of the GNU Affero General Public License as published by
  5. * the Free Software Foundation, either version 3 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU Affero General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU Affero General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #include <sys/types.h>
  17. #include <err.h>
  18. #include <errno.h>
  19. #include <fcntl.h>
  20. #include <signal.h>
  21. #include <stdbool.h>
  22. #include <stdint.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <sys/event.h>
  26. #include <sys/mman.h>
  27. #include <sys/socket.h>
  28. #include <sys/time.h>
  29. #include <sys/un.h>
  30. #include <sysexits.h>
  31. #include <time.h>
  32. #include <unistd.h>
  33. #ifdef __FreeBSD__
  34. #include <libutil.h>
  35. #include <sys/capsicum.h>
  36. #endif
  37. #include "torus.h"
  38. static struct Tile *tiles;
  39. static void tilesMap(const char *path) {
  40. int fd = open(path, O_CREAT | O_RDWR, 0644);
  41. if (fd < 0) err(EX_CANTCREAT, "%s", path);
  42. int error = ftruncate(fd, TilesSize);
  43. if (error) err(EX_IOERR, "%s", path);
  44. tiles = mmap(NULL, TilesSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  45. if (tiles == MAP_FAILED) err(EX_OSERR, "mmap");
  46. close(fd);
  47. error = madvise(tiles, TilesSize, MADV_RANDOM);
  48. if (error) err(EX_OSERR, "madvise");
  49. #ifdef MADV_NOCORE
  50. error = madvise(tiles, TilesSize, MADV_NOCORE);
  51. if (error) err(EX_OSERR, "madvise");
  52. #endif
  53. }
  54. static struct Tile *tileGet(uint32_t tileX, uint32_t tileY) {
  55. struct Tile *tile = &tiles[tileY * TileRows + tileX];
  56. if (!tile->meta.createTime) {
  57. memset(tile->cells, ' ', CellsSize);
  58. memset(tile->colors, ColorWhite, CellsSize);
  59. tile->meta.createTime = time(NULL);
  60. }
  61. return tile;
  62. }
  63. static struct Tile *tileAccess(uint32_t tileX, uint32_t tileY) {
  64. struct Tile *tile = tileGet(tileX, tileY);
  65. tile->meta.accessTime = time(NULL);
  66. tile->meta.accessCount++;
  67. return tile;
  68. }
  69. static struct Tile *tileModify(uint32_t tileX, uint32_t tileY) {
  70. struct Tile *tile = tileGet(tileX, tileY);
  71. tile->meta.modifyTime = time(NULL);
  72. tile->meta.modifyCount++;
  73. return tile;
  74. }
  75. static struct Client {
  76. int fd;
  77. uint32_t tileX;
  78. uint32_t tileY;
  79. uint8_t cellX;
  80. uint8_t cellY;
  81. struct Client *prev;
  82. struct Client *next;
  83. } *clientHead;
  84. static struct Client *clientAdd(int fd) {
  85. struct Client *client = malloc(sizeof(*client));
  86. if (!client) err(EX_OSERR, "malloc");
  87. client->fd = fd;
  88. client->tileX = TileInitX;
  89. client->tileY = TileInitY;
  90. client->cellX = CellInitX;
  91. client->cellY = CellInitY;
  92. client->prev = NULL;
  93. if (clientHead) {
  94. clientHead->prev = client;
  95. client->next = clientHead;
  96. } else {
  97. client->next = NULL;
  98. }
  99. clientHead = client;
  100. return client;
  101. }
  102. static bool clientSend(const struct Client *client, struct ServerMessage msg) {
  103. ssize_t size = send(client->fd, &msg, sizeof(msg), 0);
  104. if (size < 0) return false;
  105. if (msg.type == ServerTile) {
  106. struct Tile *tile = tileAccess(client->tileX, client->tileY);
  107. size = send(client->fd, tile, sizeof(*tile), 0);
  108. if (size < 0) return false;
  109. }
  110. return true;
  111. }
  112. static void clientCast(const struct Client *origin, struct ServerMessage msg) {
  113. for (struct Client *client = clientHead; client; client = client->next) {
  114. if (client == origin) continue;
  115. if (client->tileX != origin->tileX) continue;
  116. if (client->tileY != origin->tileY) continue;
  117. clientSend(client, msg);
  118. }
  119. }
  120. static void clientRemove(struct Client *client) {
  121. if (client->prev) client->prev->next = client->next;
  122. if (client->next) client->next->prev = client->prev;
  123. if (clientHead == client) clientHead = client->next;
  124. struct ServerMessage msg = {
  125. .type = ServerCursor,
  126. .cursor = {
  127. .oldCellX = client->cellX, .oldCellY = client->cellY,
  128. .newCellX = CursorNone, .newCellY = CursorNone,
  129. },
  130. };
  131. clientCast(client, msg);
  132. close(client->fd);
  133. free(client);
  134. }
  135. static bool clientCursors(const struct Client *client) {
  136. struct ServerMessage msg = {
  137. .type = ServerCursor,
  138. .cursor = { .oldCellX = CursorNone, .oldCellY = CursorNone },
  139. };
  140. for (struct Client *friend = clientHead; friend; friend = friend->next) {
  141. if (friend == client) continue;
  142. if (friend->tileX != client->tileX) continue;
  143. if (friend->tileY != client->tileY) continue;
  144. msg.cursor.newCellX = friend->cellX;
  145. msg.cursor.newCellY = friend->cellY;
  146. if (!clientSend(client, msg)) return false;
  147. }
  148. return true;
  149. }
  150. static bool clientUpdate(struct Client *client, const struct Client *old) {
  151. struct ServerMessage msg = {
  152. .type = ServerMove,
  153. .move = { .cellX = client->cellX, .cellY = client->cellY },
  154. };
  155. if (!clientSend(client, msg)) return false;
  156. if (client->tileX != old->tileX || client->tileY != old->tileY) {
  157. msg.type = ServerTile;
  158. if (!clientSend(client, msg)) return false;
  159. if (!clientCursors(client)) return false;
  160. msg = (struct ServerMessage) {
  161. .type = ServerCursor,
  162. .cursor = {
  163. .oldCellX = old->cellX, .oldCellY = old->cellY,
  164. .newCellX = CursorNone, .newCellY = CursorNone,
  165. },
  166. };
  167. clientCast(old, msg);
  168. msg = (struct ServerMessage) {
  169. .type = ServerCursor,
  170. .cursor = {
  171. .oldCellX = CursorNone, .oldCellY = CursorNone,
  172. .newCellX = client->cellX, .newCellY = client->cellY,
  173. },
  174. };
  175. clientCast(client, msg);
  176. } else {
  177. msg = (struct ServerMessage) {
  178. .type = ServerCursor,
  179. .cursor = {
  180. .oldCellX = old->cellX, .oldCellY = old->cellY,
  181. .newCellX = client->cellX, .newCellY = client->cellY,
  182. },
  183. };
  184. clientCast(client, msg);
  185. }
  186. return true;
  187. }
  188. static bool clientMove(struct Client *client, int8_t dx, int8_t dy) {
  189. struct Client old = *client;
  190. if (dx > CellCols - client->cellX) dx = CellCols - client->cellX;
  191. if (dx < -client->cellX - 1) dx = -client->cellX - 1;
  192. if (dy > CellRows - client->cellY) dy = CellRows - client->cellY;
  193. if (dy < -client->cellY - 1) dy = -client->cellY - 1;
  194. client->cellX += dx;
  195. client->cellY += dy;
  196. if (client->cellX == CellCols) {
  197. client->tileX++;
  198. client->cellX = 0;
  199. }
  200. if (client->cellX == UINT8_MAX) {
  201. client->tileX--;
  202. client->cellX = CellCols - 1;
  203. }
  204. if (client->cellY == CellRows) {
  205. client->tileY++;
  206. client->cellY = 0;
  207. }
  208. if (client->cellY == UINT8_MAX) {
  209. client->tileY--;
  210. client->cellY = CellRows - 1;
  211. }
  212. if (client->tileX == TileCols) client->tileX = 0;
  213. if (client->tileX == UINT32_MAX) client->tileX = TileCols - 1;
  214. if (client->tileY == TileRows) client->tileY = 0;
  215. if (client->tileY == UINT32_MAX) client->tileY = TileRows - 1;
  216. assert(client->cellX < CellCols);
  217. assert(client->cellY < CellRows);
  218. assert(client->tileX < TileCols);
  219. assert(client->tileY < TileRows);
  220. return clientUpdate(client, &old);
  221. }
  222. static bool clientFlip(struct Client *client) {
  223. struct Client old = *client;
  224. client->tileX = (client->tileX + TileCols / 2) % TileCols;
  225. client->tileY = (client->tileY + TileRows / 2) % TileRows;
  226. return clientUpdate(client, &old);
  227. }
  228. static bool clientPut(const struct Client *client, uint8_t color, uint8_t cell) {
  229. struct Tile *tile = tileModify(client->tileX, client->tileY);
  230. tile->colors[client->cellY][client->cellX] = color;
  231. tile->cells[client->cellY][client->cellX] = cell;
  232. struct ServerMessage msg = {
  233. .type = ServerPut,
  234. .put = {
  235. .cellX = client->cellX,
  236. .cellY = client->cellY,
  237. .color = color,
  238. .cell = cell,
  239. },
  240. };
  241. bool success = clientSend(client, msg);
  242. clientCast(client, msg);
  243. return success;
  244. }
  245. static bool clientMap(const struct Client *client) {
  246. int32_t mapY = (int32_t)client->tileY - MapRows / 2;
  247. int32_t mapX = (int32_t)client->tileX - MapCols / 2;
  248. time_t now = time(NULL);
  249. struct Map map = {
  250. .now = now,
  251. .min = {
  252. .createTime = now,
  253. .modifyTime = now,
  254. .accessTime = now,
  255. .modifyCount = UINT32_MAX,
  256. .accessCount = UINT32_MAX,
  257. },
  258. };
  259. for (int32_t y = 0; y < MapRows; ++y) {
  260. for (int32_t x = 0; x < MapCols; ++x) {
  261. uint32_t tileY = ((mapY + y) % TileRows + TileRows) % TileRows;
  262. uint32_t tileX = ((mapX + x) % TileCols + TileCols) % TileCols;
  263. struct Meta meta = tiles[tileY * TileRows + tileX].meta;
  264. if (meta.createTime) {
  265. if (meta.createTime < map.min.createTime) {
  266. map.min.createTime = meta.createTime;
  267. }
  268. if (meta.createTime > map.max.createTime) {
  269. map.max.createTime = meta.createTime;
  270. }
  271. }
  272. if (meta.modifyTime) {
  273. if (meta.modifyTime < map.min.modifyTime) {
  274. map.min.modifyTime = meta.modifyTime;
  275. }
  276. if (meta.modifyTime > map.max.modifyTime) {
  277. map.max.modifyTime = meta.modifyTime;
  278. }
  279. }
  280. if (meta.accessTime) {
  281. if (meta.accessTime < map.min.accessTime) {
  282. map.min.accessTime = meta.accessTime;
  283. }
  284. if (meta.accessTime > map.max.accessTime) {
  285. map.max.accessTime = meta.accessTime;
  286. }
  287. }
  288. if (meta.modifyCount < map.min.modifyCount) {
  289. map.min.modifyCount = meta.modifyCount;
  290. }
  291. if (meta.modifyCount > map.max.modifyCount) {
  292. map.max.modifyCount = meta.modifyCount;
  293. }
  294. if (meta.accessCount < map.min.accessCount) {
  295. map.min.accessCount = meta.accessCount;
  296. }
  297. if (meta.accessCount > map.max.accessCount) {
  298. map.max.accessCount = meta.accessCount;
  299. }
  300. map.meta[y][x] = meta;
  301. }
  302. }
  303. struct ServerMessage msg = { .type = ServerMap };
  304. if (!clientSend(client, msg)) return false;
  305. if (0 > send(client->fd, &map, sizeof(map), 0)) return false;
  306. return true;
  307. }
  308. int main(int argc, char *argv[]) {
  309. int error;
  310. const char *dataPath = "torus.dat";
  311. const char *sockPath = "torus.sock";
  312. const char *pidPath = NULL;
  313. int opt;
  314. while (0 < (opt = getopt(argc, argv, "d:p:s:"))) {
  315. switch (opt) {
  316. break; case 'd': dataPath = optarg;
  317. break; case 'p': pidPath = optarg;
  318. break; case 's': sockPath = optarg;
  319. break; default: return EX_USAGE;
  320. }
  321. }
  322. #ifdef __FreeBSD__
  323. struct pidfh *pid = NULL;
  324. if (pidPath) {
  325. pid = pidfile_open(pidPath, 0600, NULL);
  326. if (!pid) err(EX_CANTCREAT, "%s", pidPath);
  327. }
  328. #endif
  329. tilesMap(dataPath);
  330. int server = socket(PF_LOCAL, SOCK_STREAM, 0);
  331. if (server < 0) err(EX_OSERR, "socket");
  332. error = unlink(sockPath);
  333. if (error && errno != ENOENT) err(EX_IOERR, "%s", sockPath);
  334. struct sockaddr_un addr = { .sun_family = AF_LOCAL };
  335. strlcpy(addr.sun_path, sockPath, sizeof(addr.sun_path));
  336. error = bind(server, (struct sockaddr *)&addr, SUN_LEN(&addr));
  337. if (error) err(EX_CANTCREAT, "%s", sockPath);
  338. #ifdef __FreeBSD__
  339. error = cap_enter();
  340. if (error) err(EX_OSERR, "cap_enter");
  341. if (pid) {
  342. error = daemon(0, 0);
  343. if (error) err(EX_OSERR, "daemon");
  344. pidfile_write(pid);
  345. }
  346. #endif
  347. error = listen(server, 0);
  348. if (error) err(EX_OSERR, "listen");
  349. int kq = kqueue();
  350. if (kq < 0) err(EX_OSERR, "kqueue");
  351. struct kevent event;
  352. EV_SET(&event, server, EVFILT_READ, EV_ADD, 0, 0, 0);
  353. int nevents = kevent(kq, &event, 1, NULL, 0, NULL);
  354. if (nevents < 0) err(EX_OSERR, "kevent");
  355. for (;;) {
  356. nevents = kevent(kq, NULL, 0, &event, 1, NULL);
  357. if (nevents < 0) err(EX_IOERR, "kevent");
  358. if (!event.udata) {
  359. int fd = accept(server, NULL, NULL);
  360. if (fd < 0) err(EX_IOERR, "accept");
  361. fcntl(fd, F_SETFL, O_NONBLOCK);
  362. int on = 1;
  363. error = setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(on));
  364. if (error) err(EX_IOERR, "setsockopt");
  365. int size = 2 * sizeof(struct Tile);
  366. error = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
  367. if (error) err(EX_IOERR, "setsockopt");
  368. struct Client *client = clientAdd(fd);
  369. EV_SET(&event, fd, EVFILT_READ, EV_ADD, 0, 0, client);
  370. nevents = kevent(kq, &event, 1, NULL, 0, NULL);
  371. if (nevents < 0) err(EX_IOERR, "kevent");
  372. struct ServerMessage msg = { .type = ServerTile };
  373. bool success = clientSend(client, msg)
  374. && clientMove(client, 0, 0)
  375. && clientCursors(client);
  376. if (!success) clientRemove(client);
  377. continue;
  378. }
  379. struct Client *client = (struct Client *)event.udata;
  380. if (event.flags & EV_EOF) {
  381. clientRemove(client);
  382. continue;
  383. }
  384. struct ClientMessage msg;
  385. ssize_t size = recv(client->fd, &msg, sizeof(msg), 0);
  386. if (size != sizeof(msg)) {
  387. clientRemove(client);
  388. continue;
  389. }
  390. bool success = false;
  391. switch (msg.type) {
  392. break; case ClientMove: {
  393. success = clientMove(client, msg.move.dx, msg.move.dy);
  394. }
  395. break; case ClientFlip: {
  396. success = clientFlip(client);
  397. }
  398. break; case ClientPut: {
  399. success = clientPut(client, msg.put.color, msg.put.cell);
  400. }
  401. break; case ClientMap: {
  402. success = clientMap(client);
  403. }
  404. }
  405. if (!success) clientRemove(client);
  406. }
  407. }