#include <stdlib.h> #include <string.h> #include <stdio.h> #include <time.h> #include <syslog.h> #include <mongoose.h> #include <confini.h> #include <router.h> #include <logger.h> #include <config.h> #include <database.h> #include <handlers.h> #include <enums.h> #include <helpers.h> #include <status.h> #include <models/controller.h> static struct mg_mgr mgr; static void terminate(int signum) { LOGGER_INFO("terminating controller (%d)\n", signum); mg_mgr_free(&mgr); sqlite3_close(global_database); router_free(); status_free(); closelog(); exit(signum); } /** * @brief The main function * * @param argc UNUSED * @param argv UNUSED * * @return Statuscode to indicate success (0) or failure (!0) */ int main(int argc, const char** argv) { signal(SIGINT, terminate); signal(SIGABRT, terminate); signal(SIGTERM, terminate); setlogmask(LOG_UPTO(LOG_INFO)); /******************** LOAD CONFIG ********************/ global_config.file = "core.ini"; global_config.discovery_port = 4421; global_config.mqtt_port = 1885; global_config.server_port = 5000; global_config.log_level = LOG_INFO; global_config.log_file = stdout; strcpy(global_config.user, ""); strcpy(global_config.group, ""); strcpy(global_config.content_dir, "."); strcpy(global_config.not_found_file, "404.html"); strcpy(global_config.not_found_file_type, "text/html"); strcpy(global_config.not_found_content, "404 - NOT FOUND"); strcpy(global_config.not_found_content_type, "text/plain"); helper_parse_cli(argc, argv, &global_config); FILE * const ini_file = fopen(global_config.file, "rb"); if(ini_file == NULL) { LOGGER_CRIT("config file '%s' was not found\n", global_config.file); exit(1); } if(load_ini_file( ini_file, INI_DEFAULT_FORMAT, NULL, config_load, &global_config)) { LOGGER_CRIT("unable to parse ini file\n"); exit(1); } fclose(ini_file); memset(&global_config.http_server_opts, 0, sizeof(global_config.http_server_opts)); global_config.http_server_opts.document_root = global_config.content_dir; global_config.http_server_opts.enable_directory_listing = "no"; global_config.http_server_opts.extra_headers = "Access-Control-Allow-Origin: *\r\nAccess-Control-Allow-Headers: *\r\nAccess-Control-Allow-Methods: *"; if(global_config.log_file == NULL) { global_config.log_file = stdout; } openlog("emgauwa-core", 0, LOG_USER); /******************** SETUP CONNECTION ********************/ struct mg_mqtt_broker brk; mg_mgr_init(&mgr, NULL); char address[100]; sprintf(address, "tcp://0.0.0.0:%u", global_config.server_port); struct mg_connection *c_http = mg_bind(&mgr, address, handler_http); if(c_http == NULL) { LOGGER_CRIT("failed to bind http server to port %u\n", global_config.server_port); exit(1); } mg_set_protocol_http_websocket(c_http); sprintf(address, "tcp://0.0.0.0:%u", global_config.mqtt_port); struct mg_connection *c_mqtt = mg_bind(&mgr, address, handler_mqtt); if(c_mqtt == NULL) { LOGGER_CRIT("failed to bind mqtt server to port %u\n", global_config.mqtt_port); exit(1); } mg_mqtt_broker_init(&brk, NULL); c_mqtt->priv_2 = &brk; mg_set_protocol_mqtt(c_mqtt); helper_drop_privileges(); /******************** SETUP DATABASE ********************/ int rc = sqlite3_open(global_config.database, &global_database); if(rc) { LOGGER_CRIT("can't open database: %s\n", sqlite3_errmsg(global_database)); return 1; } if(database_migrate()) { terminate(1); } sqlite3_exec(global_database, "PRAGMA foreign_keys = ON", 0, 0, 0); /******************** INIT COMPONENTS ********************/ router_init(); status_init(); /******************** START MAIN LOOP ********************/ time_t timer = time(NULL); for (;;) { mg_mgr_poll(&mgr, 200); if(time(NULL) - timer >= 10) { status_broadcast(&mgr); timer = time(NULL); } } terminate(0); }