#include "IZ_wsserver.h" IZ_ProcedureResult IZ_WSServerCallback( struct lws* wsi, enum lws_callback_reasons reason, void* user, void* in, size_t len ) { switch (reason) { case LWS_CALLBACK_PROTOCOL_INIT: return IZ_WSServerProtocolInitialize(wsi, in); case LWS_CALLBACK_PROTOCOL_DESTROY: IZ_WSServerProtocolTeardown(wsi); break; case LWS_CALLBACK_ESTABLISHED: IZ_WSServerOnOpen(wsi, user); break; case LWS_CALLBACK_CLOSED: IZ_WSServerOnClose(wsi, user); break; case LWS_CALLBACK_SERVER_WRITEABLE: return IZ_WSServerWritable(wsi, user); case LWS_CALLBACK_RECEIVE: return IZ_WSServerOnReceive(wsi, in, len); default: break; } return 0; } void IZ_WSServerLoadConfig(IZ_WSServerState* state, const char* config_path, u8 argc, const char* argv[]) { // TODO unify loading of config from cmdline and config file memcpy_s(state, sizeof(IZ_WSServerState), &IZ_DEFAULT_STATE, sizeof(IZ_WSServerState)); const char *cmdline_buffer; // if ((cmdline_buffer = lws_cmdline_option(argc, argv, "-d"))) { // state->config.log_level = atoi(cmdline_buffer); // } if ((cmdline_buffer = IZ_ConfigGetCommandlineOption(argc, argv, "-p"))) { state->config.port = atoi(cmdline_buffer); } if ((cmdline_buffer = IZ_ConfigGetCommandlineOption(argc, argv, "-n"))) { memcpy_s(state->config.server_name, 64, cmdline_buffer, 64); } } const char* IZ_WSServerTestPath(const char* base_dir, const char* file) { static char test_path[32]; sprintf_s(test_path, 32, "%s/%s", base_dir, file); struct stat stats; stat(test_path, &stats); if (stats.st_mode & S_IREAD) { return file; } return NULL; } IZ_ProcedureResult IZ_WSServerInitialize(IZ_WSServerState* state, void* userdata, const char* config_path, u8 argc, const char* argv[]) { IZ_WSServerLoadConfig(state, config_path, argc, argv); state->userdata = userdata; struct lws_context_creation_info info; memset(&info, 0, sizeof info); info.port = state->config.port; // char server_string[64]; // if (*state->config.server_name) { // sprintf_s(server_string, 64, "%s Dedicated Server [%s]", IZ_APP_NAME, state->config.server_name); // } else { // sprintf_s(server_string, 64, "%s Dedicated Server", IZ_APP_NAME, state->config.server_name); // } // info.server_string = server_string; const char* origin = "./public"; struct stat stats; stat(origin, &stats); if (S_ISDIR(stats.st_mode)) { static struct lws_http_mount mount = { .mount_next = NULL, /* linked-list "next" */ .mountpoint = "/", /* mountpoint URL */ .origin = NULL, /* serve from dir */ .def = "index.htm", /* default filename */ .protocol = "http", .cgienv = NULL, .extra_mimetypes = NULL, .interpret = NULL, .cgi_timeout = 0, .cache_max_age = 0, .auth_mask = 0, .cache_reusable = 0, .cache_revalidate = 0, .cache_intermediaries = 0, .origin_protocol = LWSMPRO_FILE, /* files in a dir */ .mountpoint_len = 1, /* char count */ .basic_auth_login_file = NULL, }; mount.origin = origin; const char* (alt_test_paths[]) = { "index.html", }; const char* default_filename; u8 i; for (i = 0; i < 1; i += 1) { default_filename = IZ_WSServerTestPath(origin, alt_test_paths[i]); } if (default_filename) { mount.def = default_filename; } info.mounts = &mount; } static const struct lws_protocols protocols[] = { { .name = NETWORK_PROTOCOL, .callback = IZ_WSServerCallback, .per_session_data_size = sizeof(IZ_WSServerSessionData), .rx_buffer_size = 0, .id = 0, .user = NULL, .tx_packet_size = 0, }, { .name = "http", .callback = lws_callback_http_dummy, .per_session_data_size = 0, .rx_buffer_size = 0, .id = 0, .user = NULL, .tx_packet_size = 0, }, LWS_PROTOCOL_LIST_TERM, }; info.protocols = protocols; static struct lws_protocol_vhost_options pvo_port = { NULL, NULL, "port", /* pvo name */ NULL /* pvo value */ }; pvo_port.value = (void*) &state->config.port; static struct lws_protocol_vhost_options pvo_app = { &pvo_port, NULL, "app", NULL, }; pvo_app.value = state->userdata; static const struct lws_protocol_vhost_options pvo = { NULL, /* "next" pvo linked-list */ &pvo_app, /* "child" pvo linked-list */ NETWORK_PROTOCOL, /* protocol name we belong to on this vhost */ "" /* ignored */ }; info.pvo = &pvo; info.options = ( LWS_SERVER_OPTION_VALIDATE_UTF8 | LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE ); IZ_WebsocketInitialize(&state->ws); state->ws.context = lws_create_context(&info); if (!state->ws.context) { return -1; } return 0; } IZ_ProcedureResult IZ_WSServerHandle(IZ_WSServerState* state) { return IZ_WebsocketHandle(&state->ws); } void IZ_WSServerTeardown(IZ_WSServerState* state) { IZ_WebsocketTeardown(&state->ws); } void IZ_WSServerCancelService(IZ_WSServerState* state) { IZ_WebsocketCancelService(&state->ws); }