2D Run-and-gun shooter inspired by One Man's Doomsday, Counter-Strike, and Metal Slug.
25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 
 
 
 
 

360 satır
9.5 KiB

  1. #include "IZ_app.h"
  2. static IZ_App* global_app;
  3. void IZ_AppHandleSignal(i32 _signal) {
  4. global_app->net_state.binding.interrupted = true;
  5. IZ_NetServerCancelService(&global_app->net_state);
  6. }
  7. IZ_ProcedureResult IZ_AppInitialize(IZ_App *app, u8 argc, const char **argv) {
  8. global_app = app;
  9. IZ_memset(app, 0, sizeof(IZ_App));
  10. signal(SIGINT, IZ_AppHandleSignal);
  11. IZ_LogInitialize("server", true);
  12. // IZ_LogInterceptWSMessages(app->config.log_level);
  13. IZ_LogInterceptWSMessages(LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE);
  14. const char* cmdline_buffer;
  15. char config_path[128];
  16. // TODO abstract command line args parsing
  17. if ((cmdline_buffer = INI_ConfigGetCommandlineOption(argc, argv, "-c"))) {
  18. IZ_memcpy(config_path, 128, cmdline_buffer, 128);
  19. } else {
  20. IZ_ConfigGetDefaultPath(config_path, 128);
  21. }
  22. if (IZ_NetServerInitialize(&app->net_state, app, config_path, argc, argv)) {
  23. return -1;
  24. }
  25. if (IZ_RepoInitialize(&app->repo_state, config_path, argc, argv)) {
  26. return -1;
  27. }
  28. return 0;
  29. }
  30. void IZ_AppTeardown(IZ_App* app) {
  31. IZ_RepoTeardown(&app->repo_state);
  32. IZ_WSServerTeardown(&app->net_state.binding);
  33. IZ_LogTeardown();
  34. }
  35. void IZ_AppPrintHelpOptions() {
  36. printf("\n");
  37. printf("Options:\n");
  38. printf("\n");
  39. printf(
  40. "\n"
  41. "Options:\n"
  42. "\n"
  43. " -c <path> Specifies the path to the config file. (default: \"./" IZ_CONFIG_SERVER_PATH "\")\n"
  44. " -d <path> Specifies the path to the database. (default: \"./db.sqlite\")\n"
  45. " -h Displays this help screen.\n"
  46. " -m <value> Specifies the message of the day. (default: \"\")\n"
  47. " -n <value> Specifies the name of the server. (default: \"%s\")\n"
  48. " -p <value> Specifies the port where the server runs. (default: 42069)\n",
  49. IZ_APP_NAME
  50. );
  51. }
  52. void IZ_AppPrintHelpUsage() {
  53. printf("\n");
  54. printf("Usage:");
  55. printf(" %s [options]\n", "server.exe");
  56. }
  57. void IZ_AppPrintHelpHeader() {
  58. printf("\n");
  59. printf("%s - %s\n", IZ_APP_NAME, IZ_APP_SERVER_DESCRIPTION);
  60. }
  61. void IZ_AppPrintHelp() {
  62. IZ_AppPrintHelpHeader();
  63. IZ_AppPrintHelpUsage();
  64. IZ_AppPrintHelpOptions();
  65. }
  66. IZ_ProcedureResult IZ_AppRun(IZ_App *app, u8 argc, const char **argv) {
  67. // TODO have a config subsystem that handles these.
  68. if (INI_ConfigGetCommandlineOption(argc, argv, "-h")) {
  69. IZ_AppPrintHelp();
  70. return 0;
  71. }
  72. if (IZ_AppInitialize(app, argc, argv)) {
  73. return -1;
  74. }
  75. if (IZ_WSServerInitialize(&app->net_state.binding, (IZ_WSServerInitializeParams) {
  76. .port = app->net_state.config.port,
  77. })) {
  78. return -1;
  79. }
  80. i32 result = 0;
  81. while (true) {
  82. if (IZ_WSServerHandle(&app->net_state.binding)) {
  83. result = -1;
  84. break;
  85. }
  86. if (app->net_state.binding.interrupted) {
  87. break;
  88. }
  89. }
  90. IZ_AppTeardown(app);
  91. return result;
  92. }
  93. void IZ_WSServerCullLaggingClients(IZ_WSServerVHostData *vhd) {
  94. u32 oldest_tail = lws_ring_get_oldest_tail(vhd->ring);
  95. IZ_WSServerSessionData *old_pss = NULL;
  96. i32 most = 0;
  97. i32 before = (i32) lws_ring_get_count_waiting_elements(vhd->ring, &oldest_tail);
  98. i32 m;
  99. /*
  100. * At least one guy with the oldest tail has lagged too far, filling
  101. * the ringbuffer with stuff waiting for them, while new stuff is
  102. * coming in, and they must close, freeing up ringbuffer entries.
  103. */
  104. lws_start_foreach_llp_safe(
  105. IZ_WSServerSessionData**,
  106. ppss,
  107. vhd->pss_list,
  108. pss_list
  109. ) {
  110. if ((*ppss)->tail == oldest_tail) {
  111. old_pss = *ppss;
  112. lwsl_user("Killing lagging client %p\n", (*ppss)->wsi);
  113. lws_set_timeout((*ppss)->wsi, PENDING_TIMEOUT_LAGGING,
  114. /*
  115. * we may kill the wsi we came in on,
  116. * so the actual close is deferred
  117. */
  118. LWS_TO_KILL_ASYNC);
  119. /*
  120. * We might try to write something before we get a
  121. * chance to close. But this pss is now detached
  122. * from the ring buffer. Mark this pss as culled so we
  123. * don't try to do anything more with it.
  124. */
  125. (*ppss)->culled = true;
  126. /*
  127. * Because we can't kill it synchronously, but we
  128. * know it's closing momentarily and don't want its
  129. * participation any more, remove its pss from the
  130. * vhd pss list early. (This is safe to repeat
  131. * uselessly later in the close flow).
  132. *
  133. * Notice this changes *ppss!
  134. */
  135. lws_ll_fwd_remove(IZ_WSServerSessionData, pss_list, (*ppss), vhd->pss_list);
  136. /* use the changed *ppss so we won't skip anything */
  137. continue;
  138. }
  139. /*
  140. * so this guy is a survivor of the cull. Let's track
  141. * what is the largest number of pending ring elements
  142. * for any survivor.
  143. */
  144. m = (i32) lws_ring_get_count_waiting_elements(vhd->ring, &((*ppss)->tail));
  145. if (m > most) {
  146. most = m;
  147. }
  148. } lws_end_foreach_llp_safe(ppss);
  149. /* it would mean we lost track of oldest... but Coverity insists */
  150. if (!old_pss) {
  151. return;
  152. }
  153. /*
  154. * Let's recover (ie, free up) all the ring slots between the
  155. * original oldest's last one and the "worst" survivor.
  156. */
  157. lws_ring_consume_and_update_oldest_tail(
  158. vhd->ring,
  159. IZ_WSServerSessionData,
  160. &old_pss->tail,
  161. (size_t) (before - most),
  162. vhd->pss_list,
  163. tail,
  164. pss_list
  165. );
  166. lwsl_user("%s: shrunk ring from %d to %d\n", __func__, before, most);
  167. }
  168. /* destroys the message when everyone has had a copy of it */
  169. IZ_ProcedureResult IZ_WSServerProtocolInitialize(struct lws* wsi, void* in) {
  170. const struct lws_protocols* protocols = lws_get_protocol(wsi);
  171. struct lws_vhost* vhost = lws_get_vhost(wsi);
  172. IZ_WSServerVHostData* vhd_instance = (IZ_WSServerVHostData*) lws_protocol_vh_priv_get(vhost, protocols);
  173. IZ_WSServerVHostData** vhd = &vhd_instance;
  174. *vhd = lws_protocol_vh_priv_zalloc(vhost, protocols, sizeof(IZ_WSServerVHostData));
  175. (*vhd)->ring = lws_ring_create(
  176. sizeof(IZ_WebsocketMessage),
  177. RING_COUNT,
  178. IZ_WebsocketDestroyMessage
  179. );
  180. if (!(*vhd)->ring) {
  181. return -1;
  182. }
  183. (*vhd)->context = lws_get_context(wsi);
  184. (*vhd)->protocol = protocols;
  185. (*vhd)->vhost = vhost;
  186. (*vhd)->port = (u16*) lws_pvo_search(
  187. (const struct lws_protocol_vhost_options *)in,
  188. "port"
  189. )->value;
  190. (*vhd)->app = lws_pvo_search(
  191. (const struct lws_protocol_vhost_options *)in,
  192. "app"
  193. )->value;
  194. return 0;
  195. }
  196. void IZ_WSServerProtocolTeardown(struct lws* wsi) {
  197. IZ_WSServerVHostData* vhd = (IZ_WSServerVHostData*) lws_protocol_vh_priv_get(
  198. lws_get_vhost(wsi),
  199. lws_get_protocol(wsi)
  200. );
  201. lws_ring_destroy(vhd->ring);
  202. }
  203. void IZ_WSServerOnOpen(struct lws* wsi, IZ_WSServerSessionData* pss) {
  204. IZ_WSServerVHostData* vhd = (IZ_WSServerVHostData*) lws_protocol_vh_priv_get(
  205. lws_get_vhost(wsi),
  206. lws_get_protocol(wsi)
  207. );
  208. /* add ourselves to the list of live pss held in the vhd */
  209. lwsl_user("LWS_CALLBACK_ESTABLISHED: wsi %p\n", wsi);
  210. lws_ll_fwd_insert(pss, pss_list, vhd->pss_list);
  211. pss->tail = lws_ring_get_oldest_tail(vhd->ring);
  212. pss->wsi = wsi;
  213. }
  214. void IZ_WSServerOnClose(struct lws* wsi, IZ_WSServerSessionData* pss) {
  215. IZ_WSServerVHostData* vhd = (IZ_WSServerVHostData*) lws_protocol_vh_priv_get(
  216. lws_get_vhost(wsi),
  217. lws_get_protocol(wsi)
  218. );
  219. lwsl_user("LWS_CALLBACK_CLOSED: wsi %p\n", wsi);
  220. /* remove our closing pss from the list of live pss */
  221. lws_ll_fwd_remove(IZ_WSServerSessionData, pss_list, pss, vhd->pss_list);
  222. }
  223. IZ_ProcedureResult IZ_WSServerWritable(struct lws* wsi, IZ_WSServerSessionData* pss) {
  224. IZ_WSServerVHostData* vhd = (IZ_WSServerVHostData*) lws_protocol_vh_priv_get(
  225. lws_get_vhost(wsi),
  226. lws_get_protocol(wsi)
  227. );
  228. if (pss->culled) {
  229. return 0;
  230. }
  231. const IZ_WebsocketMessage* pmsg = lws_ring_get_element(vhd->ring, &pss->tail);
  232. if (!pmsg) {
  233. return 0;
  234. }
  235. /* notice we allowed for LWS_PRE in the payload already */
  236. i32 m = lws_write(
  237. wsi,
  238. ((unsigned char*) pmsg->payload) + LWS_PRE,
  239. pmsg->len,
  240. pmsg->binary ? LWS_WRITE_BINARY : LWS_WRITE_TEXT
  241. );
  242. if (m < (i32) pmsg->len) {
  243. lwsl_err("ERROR %d writing to ws socket\n", m);
  244. return -1;
  245. }
  246. lws_ring_consume_and_update_oldest_tail(
  247. vhd->ring, /* lws_ring object */
  248. IZ_WSServerSessionData, /* type of objects with tails */
  249. &pss->tail, /* tail of guy doing the consuming */
  250. 1, /* number of payload objects being consumed */
  251. vhd->pss_list, /* head of list of objects with tails */
  252. tail, /* member name of tail in objects with tails */
  253. pss_list /* member name of next object in objects with tails */
  254. );
  255. /* more to do for us? */
  256. if (lws_ring_get_element(vhd->ring, &pss->tail)) {
  257. /* come back as soon as we can write more */
  258. lws_callback_on_writable(pss->wsi);
  259. }
  260. return 0;
  261. }
  262. IZ_ProcedureResult IZ_WSServerOnReceive(struct lws* wsi, void* in, size_t len) {
  263. IZ_WSServerVHostData* vhd = (IZ_WSServerVHostData*) lws_protocol_vh_priv_get(
  264. lws_get_vhost(wsi),
  265. lws_get_protocol(wsi)
  266. );
  267. i32 n = (i32) lws_ring_get_count_free_elements(vhd->ring);
  268. if (!n) {
  269. /* forcibly make space */
  270. IZ_WSServerCullLaggingClients(vhd);
  271. n = (i32) lws_ring_get_count_free_elements(vhd->ring);
  272. }
  273. if (!n) {
  274. return 0;
  275. }
  276. lwsl_user("LWS_CALLBACK_RECEIVE: free space %d\n", n);
  277. IZ_WebsocketMessage amsg;
  278. const u8 result = (
  279. lws_frame_is_binary(wsi)
  280. ? IZ_WebsocketCreateBinaryMessage(wsi, &amsg, in, len)
  281. : IZ_WebsocketCreateTextMessage(wsi, &amsg, in, len)
  282. );
  283. if (result) {
  284. lwsl_user("OOM: dropping\n");
  285. return 1;
  286. }
  287. if (!lws_ring_insert(vhd->ring, &amsg, 1)) {
  288. IZ_WebsocketDestroyMessage(&amsg);
  289. lwsl_user("dropping!\n");
  290. return 1;
  291. }
  292. /*
  293. * let everybody know we want to write something on them
  294. * as soon as they are ready
  295. */
  296. lws_start_foreach_llp(IZ_WSServerSessionData**, ppss, vhd->pss_list) {
  297. lws_callback_on_writable((*ppss)->wsi);
  298. }
  299. lws_end_foreach_llp(ppss, pss_list);
  300. return 0;
  301. }