From: pk910 Date: Mon, 24 Sep 2012 13:56:52 +0000 (+0200) Subject: tidied up main.c code X-Git-Url: http://git.pk910.de/?p=NeonServV5.git;a=commitdiff_plain;h=e9d8fc51ef743296c6b788dcabba46cbfab05086 tidied up main.c code --- diff --git a/Makefile.am b/Makefile.am index df5f180..fdfb7f1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -211,6 +211,7 @@ neonserv_SOURCES = src/version.c \ src/modules.c \ src/module_commands.c \ src/ModuleFunctions.c \ + src/statistics.c \ src/memoryDebug.c neonserv_LDADD = $(MYSQL_LIBS) $(SYSTEM_LIBS) diff --git a/src/IRCParser.c b/src/IRCParser.c index ff244a0..bcb9f02 100644 --- a/src/IRCParser.c +++ b/src/IRCParser.c @@ -30,6 +30,7 @@ #include "bots.h" #include "timeq.h" #include "ConfigParser.h" +#include "statistics.h" struct irc_cmd *irc_commands = NULL; //static struct UserNode *registering_users = NULL; @@ -645,8 +646,7 @@ static IRC_CMD(raw_privmsg) { if(argv[0][0] == '#') { //Channel message struct ChanNode *chan = getChanByName(argv[0]); if(chan && client == get_first_prefered_bot_in_channel(chan)) { - if(statistics_enabled) - statistics_privmsg++; + statistics_privmsg++; if(argv[1][0] == '\001') { char *cmd = &argv[1][1]; char *text = strstr(cmd, " "); diff --git a/src/main.c b/src/main.c index 5ab1efd..4c7c9f4 100644 --- a/src/main.c +++ b/src/main.c @@ -15,6 +15,10 @@ * along with this program. If not, see . */ +#define DEFAULT_PID_FILE "neonserv.pid" +#define DEFAULT_CONF_FILE "neonserv.conf" +#define DEFAULT_LOG_FILE "neonserv.log" + #include "main.h" #include "signal.h" #include "ClientSocket.h" @@ -41,138 +45,64 @@ #include "module_commands.h" #include "ModuleFunctions.h" #include "IOHandler.h" +#include "statistics.h" + +static struct { + time_t start_time; + int running : 1; + int restart : 1; + int run_as_daemon : 1; + int daemonized : 1; + int loglevel : 8; + int loaded_config : 1; + int running_threads : 8; + + int argc; + char **argv; + + char config[MAXLEN]; + char pidfile[MAXLEN]; +} process_state; -time_t start_time; -static int running, hard_restart; -static int statistics_requested_lusers = 0; -int statistics_enabled; -TIMEQ_CALLBACK(main_statistics); -TIMEQ_CALLBACK(main_checkauths); -static int daemonized = 0; -static int print_loglevel = 0; static FILE *log_fptr = NULL; -static int process_argc; -static char **process_argv; + #ifdef HAVE_THREADS -int running_threads; pthread_mutex_t cache_sync; pthread_mutex_t whohandler_sync, whohandler_mass_sync; static pthread_mutex_t log_sync; +static pthread_t *current_threads = NULL; #endif +static void main_tread(void *empty); +static TIMEQ_CALLBACK(clear_cache); +static TIMEQ_CALLBACK(main_checkauths); static void check_firstrun(); -void cleanup() { - stop_modules(); - free_sockets(); - qserver_free(); - free_parser(); - free_UserNode(); - free_ChanNode(); - free_bind(); - free_modcmd(); - free_whoqueue(); - free_mysql(); - free_handleinfohandler(); - free_lang(); -} - -static int load_mysql_config() { - char *mysql_host, *mysql_user, *mysql_pass, *mysql_base; - int mysql_serverport; - - mysql_host = get_string_field("MySQL.host"); - if(!mysql_host) { - perror("invalid neonserv.conf: missing MySQL.host"); - return 0; - } - mysql_serverport = get_int_field("MySQL.port"); - if(!mysql_serverport) - mysql_serverport = 3306; - mysql_user = get_string_field("MySQL.user"); - if(!mysql_user) { - perror("invalid neonserv.conf: missing MySQL.user"); - return 0; - } - mysql_pass = get_string_field("MySQL.pass"); - if(!mysql_pass) { - perror("invalid neonserv.conf: missing MySQL.pass"); - return 0; - } - mysql_base = get_string_field("MySQL.base"); - if(!mysql_base) { - perror("invalid neonserv.conf: missing MySQL base"); - return 0; - } - init_mysql(mysql_host, mysql_serverport, mysql_user, mysql_pass, mysql_base); - return 1; -} - -static TIMEQ_CALLBACK(clear_cache) { - timeq_add(CLEAR_CACHE_INTERVAL, 0, clear_cache, NULL); - clearTempUsers(); - destroyEvents(); - mysql_free(); -} - -void *thread_main(void *arg) { - while(running) { - iohandler_poll(); - } - return NULL; -} - -#ifdef HAVE_THREADS -pthread_t *current_threads = NULL; -int getCurrentThreadID() { - if(!current_threads) return 0; - int i; - unsigned int my_tid = (unsigned int) pthread_self_tid(); - for(i = 0; i < running_threads; i++) { - #ifdef WIN32 - if((unsigned int) current_threads[i].p == my_tid) - #else - if((unsigned int) current_threads[i] == my_tid) - #endif - return i+1; - } - return 0; -} - -#endif - -void exit_daemon() { - running = 0; - if(daemonized) { - remove(PID_FILE); - } - if(log_fptr) { - fclose(log_fptr); - log_fptr = NULL; - } -} - -int main(int argc, char *argv[]) { - int run_as_daemon = 1; +static void main_parse_arguments() { int c; - process_argv = argv; - process_argc = argc; - printf("NeonServ v%s\n\n", NEONSERV_VERSION); struct option options[] = { {"show", 1, 0, 's'}, {"foreground", 0, 0, 'f'}, + {"config", 1, 0, 'c'}, + {"pid", 1, 0, 'p'}, {"help", 0, 0, 'h'}, {"version", 0, 0, 'v'}, {0, 0, 0, 0} }; - while ((c = getopt_long(argc, argv, "s:fvh", options, NULL)) != -1) { + while ((c = getopt_long(process_state.argc, process_state.argv, "s:fvh", options, NULL)) != -1) { switch (c) { + case 'c': + strncpy(process_state.config, optarg, MAXLEN-1); + break; + case 'p': + strncpy(process_state.pidfile, optarg, MAXLEN-1); + break; case 's': - print_loglevel = atoi(optarg); + process_state.loglevel = atoi(optarg); break; case 'f': - run_as_daemon = 0; + process_state.run_as_daemon = 0; break; case 'v': printf("Version: %s.%d (%s)\n", NEONSERV_VERSION, patchlevel, (strcmp(revision, "") ? revision : "-")); @@ -180,91 +110,74 @@ int main(int argc, char *argv[]) { exit(0); break; case 'h': - printf("Usage: ./neonserv [-s loglevel] [-f] [-h|-v]\n"); - printf(" -s, --show show log lines matching loglevel in stdout.\n"); + printf("Usage: ./neonserv [-c neonserv.conf] [-p neonserv.pid] [-s loglevel] [-f] [-h|-v]\n"); + printf(" -c, --config use this configuration file.\n"); printf(" -f, --foreground run NeonServ in the foreground.\n"); printf(" -h, --help prints this usage message.\n"); + printf(" -p, --pid use this pid file.\n"); + printf(" -s, --show show log lines matching loglevel in stdout.\n"); printf(" -v, --version prints this program's version.\n"); exit(0); break; } } +} + +static void main_daemon_exit() { + remove(process_state.pidfile); +} + +static void main_daemonize() { #ifndef WIN32 - if(geteuid() == 0 || getuid() == 0) { - fprintf(stderr, "NeonServ may not be run with super user privileges.\n"); + /* Attempt to fork into the background if daemon mode is on. */ + pid_t pid = fork(); + if (pid < 0) { + fprintf(stderr, "Unable to fork: %s\n", strerror(errno)); + } else if (pid > 0) { + printf("Forking into the background (pid: %d)...\n", pid); + putlog(LOGLEVEL_INFO, "Forking into the background (pid: %d)...\n", pid); exit(0); } - #endif - #ifdef ENABLE_MEMORY_DEBUG - initMemoryDebug(); - #endif - if(!loadConfig(CONF_FILE)) { - fprintf(stderr, "Unable to load " CONF_FILE "\n"); - exit(0); + setsid(); + process_state.daemonized = 1; + atexit(main_daemon_exit); + FILE *pidfile = fopen(process_state.pidfile, "w"); + if (pidfile == NULL) { + fprintf(stderr, "Unable to create PID file: %s\n", strerror(errno)); + putlog(LOGLEVEL_ERROR, "Unable to create PID file: %s\n", strerror(errno)); + } else { + fprintf(pidfile, "%i\n", (int)getpid()); + fclose(pidfile); } - init_bind(); - event_reload(1); - #if HAVE_THREADS - THREAD_MUTEX_INIT(log_sync); + FILE *retn; + fclose(stdin); retn = fopen("/dev/null", "r"); + fclose(stdout); retn = fopen("/dev/null", "w"); + fclose(stderr); retn = fopen("/dev/null", "w"); #endif - if(!load_mysql_config()) { - fprintf(stderr, "Unable to connect to MySQL\n"); - exit(0); - } - check_firstrun(); - char **modulelist = get_all_fieldnames("modules"); - if(!modulelist || !modulelist[0]) { - fprintf(stderr, "no modules loaded... Please update your configuration!\n"); - exit(0); - } - free(modulelist); - if (run_as_daemon) { - #ifndef WIN32 - /* Attempt to fork into the background if daemon mode is on. */ - pid_t pid = fork(); - if (pid < 0) { - fprintf(stderr, "Unable to fork: %s\n", strerror(errno)); - } else if (pid > 0) { - printf("Forking into the background (pid: %d)...\n", pid); - putlog(LOGLEVEL_INFO, "Forking into the background (pid: %d)...\n", pid); - exit(0); - } - setsid(); - daemonized = 1; - atexit(exit_daemon); - FILE *pidfile = fopen(PID_FILE, "w"); - if (pidfile == NULL) { - fprintf(stderr, "Unable to create PID file: %s\n", strerror(errno)); - putlog(LOGLEVEL_ERROR, "Unable to create PID file: %s\n", strerror(errno)); - } else { - fprintf(pidfile, "%i\n", (int)getpid()); - fclose(pidfile); +} + +static int reload_configuration() { + if(!loadConfig(process_state.config)) + return 1; + if(process_state.loaded_config) { + if(!reload_mysql()) + return 2; + char **modulelist = get_all_fieldnames("modules"); + if(!modulelist || !modulelist[0]) { + free(modulelist); + return 3; } - FILE *retn; - fclose(stdin); retn = fopen("/dev/null", "r"); - fclose(stdout); retn = fopen("/dev/null", "w"); - fclose(stderr); retn = fopen("/dev/null", "w"); - #endif + free(modulelist); } - -main: - signal(SIGABRT, sighandler); - signal(SIGFPE, sighandler); - signal(SIGILL, sighandler); - signal(SIGINT, sighandler); - signal(SIGSEGV, sighandler); - signal(SIGTERM, sighandler); - - start_time = time(0); - - statistics_enabled = get_int_field("statistics.enable"); - - #ifdef HAVE_THREADS - THREAD_MUTEX_INIT(cache_sync); - THREAD_MUTEX_INIT(whohandler_sync); - THREAD_MUTEX_INIT(whohandler_mass_sync); - #endif - + event_reload(!process_state.loaded_config); + process_state.loaded_config = 1; + return 0; +} + + +/* INITIALISATION OF SUBSYSTEMS */ +void initialize_subsystems() { + init_bind(); init_lang(); init_parser(); init_UserNode(); @@ -280,105 +193,218 @@ main: init_bots(); init_DBHelper(); qserver_init(); - load_languages(); - int update_minutes = get_int_field("statistics.frequency"); - if(!update_minutes) update_minutes = 2; - timeq_add(update_minutes * 60 + 10, 0, main_statistics, NULL); - - timeq_add(90, 0, main_checkauths, NULL); - - timeq_add(CLEAR_CACHE_INTERVAL, 0, clear_cache, NULL); - + init_statistics(); +} + +void shutdown_subsystems() { + stop_modules(); + free_sockets(); + qserver_free(); + free_parser(); + free_UserNode(); + free_ChanNode(); + free_bind(); + free_modcmd(); + free_whoqueue(); + free_mysql(); + free_handleinfohandler(); + free_lang(); +} + +/* THREAD CONTROL */ +#ifdef HAVE_THREADS +int getCurrentThreadID() { + if(!current_threads) return 0; + int i; + unsigned int my_tid = (unsigned int) pthread_self_tid(); + for(i = 0; i < process_state.running_threads; i++) { + #ifdef WIN32 + if((unsigned int) current_threads[i].p == my_tid) + #else + if((unsigned int) current_threads[i] == my_tid) + #endif + return i+1; + } + return 0; +} +#endif + +int getRunningThreads() { + #ifdef HAVE_THREADS + return process_state.running_threads; + #else + return 1; + #endif +} + +static void main_start_threads() { + int tid_id = 0; int worker_threads = get_int_field("General.worker_threads"); if(!worker_threads) worker_threads = 1; - running = 1; #ifdef HAVE_THREADS - int tid_id = 0; - current_threads = calloc(worker_threads, sizeof(*current_threads)); - for(tid_id = 0; tid_id < worker_threads; tid_id++) { - running_threads++; - pthread_create(¤t_threads[tid_id], NULL, thread_main, NULL); + { + current_threads = calloc(worker_threads, sizeof(*current_threads)); + for(tid_id = 0; tid_id < worker_threads; tid_id++) { + process_state.running_threads++; + pthread_create(¤t_threads[tid_id], NULL, main_tread, NULL); + } } #endif - thread_main(NULL); + main_tread(NULL); #ifdef HAVE_THREADS - for(tid_id = 0; tid_id < worker_threads; tid_id++) { - pthread_join(current_threads[tid_id], NULL); + { + for(tid_id = 0; tid_id < worker_threads; tid_id++) { + pthread_join(current_threads[tid_id], NULL); + } + process_state.running_threads = 0; } - running_threads = 0; #endif - cleanup(); - if(hard_restart) { - restart_process(); +} + +/* MAIN FUNCTION(S) */ + +static void main_tread(void *empty) { + while(process_state.running) { + iohandler_poll(); } - goto main; } -void restart_process() { +static void main_restart_process() { /* Append a NULL to the end of argv[]. */ - char **restart_argv = (char **)alloca((process_argc + 1) * sizeof(char *)); - memcpy(restart_argv, process_argv, process_argc * sizeof(char *)); - restart_argv[process_argc] = NULL; + char **restart_argv = (char **)alloca((process_state.argc + 1) * sizeof(char *)); + memcpy(restart_argv, process_state.argv, process_state.argc * sizeof(char *)); + restart_argv[process_state.argc] = NULL; #ifdef WIN32 - execv(process_argv[0], (const char * const*)restart_argv); + execv(process_state.argv[0], (const char * const*)restart_argv); #else - execv(process_argv[0], restart_argv); + execv(process_state.argv[0], restart_argv); #endif } -int stricmp (const char *s1, const char *s2) -{ - if (s1 == NULL) return s2 == NULL ? 0 : -(*s2); - if (s2 == NULL) return *s1; - char c1, c2; - while ((c1 = tolower (*s1)) == (c2 = tolower (*s2))) - { - if (*s1 == '\0') break; - ++s1; ++s2; - } - return c1 - c2; +int main(int argc, char *argv[]) { + memset(&process_state, 0, sizeof(process_state)); + printf("NeonServ v%s\n\n", NEONSERV_VERSION); + + process_state.argv = argv; + process_state.argc = argc; + process_state.run_as_daemon = 1; + strcpy(process_state.config, DEFAULT_CONF_FILE); + strcpy(process_state.pidfile, DEFAULT_PID_FILE); + + //parse argv + main_parse_arguments(); + + //initialize memory debugger BEFORE allocating memory + #ifdef ENABLE_MEMORY_DEBUG + initMemoryDebug(); + #endif + + //deny root startup + #ifndef WIN32 + if(geteuid() == 0 || getuid() == 0) { + fprintf(stderr, "NeonServ may not be run with super user privileges.\n"); + exit(0); + } + #endif + + //load configuration + int errid; + if(errid = reload_configuration()) { + fprintf(stderr, "Unable to load configuration file `%s`. (errid: %d)\n", process_state.config, errid); + exit(0); + } + + //check mysql configuration + if(!reload_mysql()) { + fprintf(stderr, "Unable to load MySQL configuration.\n"); + exit(0); + } + + //check module configuration + char **modulelist = get_all_fieldnames("modules"); + if(!modulelist || !modulelist[0]) { + fprintf(stderr, "Unable to load Module configuration.\n"); + exit(0); + } + free(modulelist); + + #if HAVE_THREADS + THREAD_MUTEX_INIT(log_sync); + THREAD_MUTEX_INIT(cache_sync); + THREAD_MUTEX_INIT(whohandler_sync); + THREAD_MUTEX_INIT(whohandler_mass_sync); + #endif + + //connect to mysql and check if it's the frst bot startup + init_mysql(); + check_firstrun(); + + //deamonize if wanted + if(process_state.run_as_daemon) + main_daemonize(); + + //set signal handlers + signal(SIGABRT, sighandler); + signal(SIGFPE, sighandler); + signal(SIGILL, sighandler); + signal(SIGINT, sighandler); + signal(SIGSEGV, sighandler); + signal(SIGTERM, sighandler); + + //set start time and initialize other code parts + process_state.running = 1; + process_state.start_time = time(0); + initialize_subsystems(); + + //start timers + timeq_add(CLEAR_CACHE_INTERVAL, 0, clear_cache, NULL); + timeq_add(90, 0, main_checkauths, NULL); + + //start worker threads + main_start_threads(); //BLOCKING + + //shutdown sequence... + shutdown_subsystems(); + if(process_state.restart) + main_restart_process(); //terminates the current process on success + + //eop (end of program :P) + //trust me, thats the end! + exit(0); } -int stricmplen (const char *s1, const char *s2, int len) -{ - if (s1 == NULL) return s2 == NULL ? 0 : -(*s2); - if (s2 == NULL) return *s1; - char c1, c2; - int i = 0; - while ((c1 = tolower (*s1)) == (c2 = tolower (*s2))) - { - i++; - if (*s1 == '\0') break; - ++s1; ++s2; - if(i == len) break; - } - return c1 - c2; +/* BOT INFORMATION */ +time_t getStartTime() { + return process_state.start_time; } -void restart_bot(int do_hard_restart) { - hard_restart = do_hard_restart; - running = 0; +/* BOT CONTROL */ +void restart_bot(int crash) { + if(crash) { + main_daemon_exit(); + main_restart_process(); + } else { + process_state.restart = 1; + process_state.running = 0; + } } void stop_bot() { - cleanup(); - exit(0); + process_state.running = 0; } void reload_config() { - loadConfig(CONF_FILE); - event_reload(0); + reload_configuration(); } -static int getCurrentSecondsOfDay() { - time_t now = time(0); - struct tm *timeofday = localtime(&now); - int seconds = 0; - seconds += timeofday->tm_hour * 3600; - seconds += timeofday->tm_min * 60; - seconds += timeofday->tm_sec; - return seconds; +/* TIMER FUNCTIONS */ + +static TIMEQ_CALLBACK(clear_cache) { + timeq_add(CLEAR_CACHE_INTERVAL, 0, clear_cache, NULL); + clearTempUsers(); + destroyEvents(); + mysql_free(); } static AUTHLOOKUP_CALLBACK(main_checkauths_callback) { @@ -416,7 +442,7 @@ static AUTHLOOKUP_CALLBACK(main_checkauths_callback) { } } -TIMEQ_CALLBACK(main_checkauths) { +static TIMEQ_CALLBACK(main_checkauths) { int next_call = 600; if(get_int_field("General.CheckAuths.enabled")) { int check_start_time = get_int_field("General.CheckAuths.start_time") * 3600; @@ -456,72 +482,18 @@ TIMEQ_CALLBACK(main_checkauths) { timeq_add(next_call, 0, main_checkauths, NULL); } -TIMEQ_CALLBACK(main_statistics) { - int update_minutes = get_int_field("statistics.frequency"); - if(!update_minutes) update_minutes = 2; - timeq_add(update_minutes * 60, 0, main_statistics, NULL); - if(get_int_field("statistics.enable")) { - statistics_enabled = 1; - statistics_requested_lusers = 1; - if(get_int_field("statistics.include_lusers")) { - struct ClientSocket *bot, *lusersbot = NULL; - for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) { - if(bot->flags & SOCKET_FLAG_PREFERRED) - lusersbot = bot; - } - bot = lusersbot; - if(bot == NULL) bot = getBots(SOCKET_FLAG_READY, NULL); - putsock(bot, "LUSERS"); - } else { - statistics_update(); - } - } else - statistics_enabled = 0; -} - -int statistics_update() { - if(get_int_field("statistics.enable") && statistics_requested_lusers && get_string_field("statistics.execute")) { - statistics_requested_lusers = 0; - char command[MAXLEN]; - /* parameters: - - visible users - - visible chanusers - - visible channels - - privmsg per minute - - commands per minute - - network users - - network channels - */ - sprintf(command, "%s %d %d %d %d %d %d %d", get_string_field("statistics.execute"), getUserCount(), getChanUserCount(), getChannelCount(), statistics_privmsg, statistics_commands, statistics_network_users, statistics_network_channels); - statistics_privmsg = 0; - statistics_commands = 0; - return system(command); - } - return -1; -} - -time_t getStartTime() { - return start_time; -} - -int getRunningThreads() { - #ifdef HAVE_THREADS - return running_threads; - #else - return 1; - #endif -} +/* LOG BACKEND */ void write_log(int loglevel, const char *line, int len) { SYNCHRONIZE(log_sync); - if(!daemonized && (print_loglevel & loglevel)) { + if(!process_state.daemonized && (process_state.loglevel & loglevel)) { printf("%s", line); - } else if(!daemonized && loglevel == LOGLEVEL_ERROR) { + } else if(!process_state.daemonized && loglevel == LOGLEVEL_ERROR) { fprintf(stderr, "%s", line); } if(get_int_field("log.loglevel") & loglevel) { if(!log_fptr) { - log_fptr = fopen(LOG_FILE, "a"); + log_fptr = fopen(DEFAULT_LOG_FILE, "a"); if(!log_fptr) goto write_log_end; } time_t rawtime; @@ -550,6 +522,8 @@ void putlog(int loglevel, const char *text, ...) { write_log(loglevel, logBuf, pos); } +/* INSTALLATION SCRIPT */ + static void check_firstrun() { MYSQL_RES *res; MYSQL_ROW row; diff --git a/src/main.h b/src/main.h index 26f4319..f429b67 100644 --- a/src/main.h +++ b/src/main.h @@ -19,10 +19,8 @@ #include "overall.h" #ifndef DND_FUNCTIONS -extern time_t start_time; -extern int statistics_enabled; + #ifdef HAVE_THREADS -extern int running_threads; extern pthread_mutex_t cache_sync; extern pthread_mutex_t whohandler_sync, whohandler_mass_sync; @@ -32,19 +30,10 @@ extern pthread_mutex_t whohandler_sync, whohandler_mass_sync; /* MODULAR ACCESSIBLE */ time_t getStartTime(); /* MODULAR ACCESSIBLE */ int getRunningThreads(); -void exit_daemon(); - -/* MODULAR ACCESSIBLE */ int stricmp (const char *s1, const char *s2); -/* MODULAR ACCESSIBLE */ int stricmplen (const char *s1, const char *s2, int len); - -/* MODULAR ACCESSIBLE */ void restart_process(); -/* MODULAR ACCESSIBLE */ void cleanup(); -/* MODULAR ACCESSIBLE */ void restart_bot(int do_hard_restart); +/* MODULAR ACCESSIBLE */ void restart_bot(int crash); /* MODULAR ACCESSIBLE */ void stop_bot(); /* MODULAR ACCESSIBLE */ void reload_config(); -int statistics_update(); - /* MODULAR ACCESSIBLE */ void putlog(int loglevel, const char *text, ...) PRINTF_LIKE(2, 3); #endif #endif \ No newline at end of file diff --git a/src/modcmd.c b/src/modcmd.c index e19d261..5837d33 100644 --- a/src/modcmd.c +++ b/src/modcmd.c @@ -237,8 +237,7 @@ static void handle_command(struct ClientSocket *client, struct UserNode *user, s if(cbind == NULL) break; } else if(cbind->flags & CMDFLAG_SUB_LINKER) cbind = modcmd_sub_linker_command(client, textclient, user, cbind, bind_index, &args); - if(statistics_enabled) - statistics_commands++; + statistics_commands++; total_triggered++; cbind->triggered++; if((BIND_FLAGS(cbind) & CMDFLAG_FUNCMD)) { diff --git a/src/modules.c b/src/modules.c index 0de4505..7310c88 100644 --- a/src/modules.c +++ b/src/modules.c @@ -19,7 +19,10 @@ #include #endif -/* 000-011 */ #include "main.h" +/* 000-001 */ #include "main.h" +/* 002-004 */ #include "tools.h" +/* 005-006 */ /* deprecated */ +/* 007-011 */ /* main.h */ /* 012 */ #include "BanNode.h" /* 013-019 */ #include "bots.h" /* 020-025 */ #include "ChanNode.h" @@ -40,7 +43,7 @@ /* 126-136 */ #include "ModeNode.h" /* 137-142 */ #include "mysqlConn.h" /* 143-149 */ #include "timeq.h" -/* 150-169 */ #include "tools.h" +/* 150-169 */ /* tools.h */ /* 170-180 */ #include "UserNode.h" /* 181-183 */ #include "WHOHandler.h" /* 184-188 */ #include "version.h" @@ -56,11 +59,11 @@ void *global_functions[] = { /* 000 */ (Function) getStartTime, /* 001 */ (Function) getRunningThreads, -/* 002 */ (Function) exit_daemon, +/* 002 */ (Function) getCurrentSecondsOfDay, /* 003 */ (Function) stricmp, /* 004 */ (Function) stricmplen, -/* 005 */ (Function) restart_process, -/* 006 */ (Function) cleanup, +/* 005 */ (Function) NULL, /* deprecated */ +/* 006 */ (Function) NULL, /* deprecated */ /* 007 */ (Function) restart_bot, /* 008 */ (Function) stop_bot, /* 009 */ (Function) reload_config, diff --git a/src/modules/global.mod/cmd_global_restart.c b/src/modules/global.mod/cmd_global_restart.c index 64ef5a5..80f4403 100644 --- a/src/modules/global.mod/cmd_global_restart.c +++ b/src/modules/global.mod/cmd_global_restart.c @@ -22,7 +22,5 @@ */ CMD_BIND(global_cmd_restart) { - int hard_restart = 1; - if(argc > 0 && !stricmp(argv[0], "soft")) hard_restart = 0; - restart_bot(hard_restart); + restart_bot(0); } diff --git a/src/modules/module.h b/src/modules/module.h index 071c148..25a7676 100644 --- a/src/modules/module.h +++ b/src/modules/module.h @@ -27,11 +27,11 @@ extern int module_id; /**** global function list ****/ /* 000 */ #define getStartTime ((time_t (*)(void))global[0]) /* 001 */ #define getRunningThreads ((int (*)(void))global[1]) -/* 002 */ #define exit_daemon ((int (*)(void))global[2]) +/* 002 */ #define getCurrentSecondsOfDay ((int (*)(void))global[2]) /* 003 */ #define stricmp ((int (*)(const char *, const char *))global[3]) /* 004 */ #define stricmplen ((int (*)(const char *, const char *, int))global[4]) -/* 005 */ #define restart_process ((void (*)(void))global[5]) -/* 006 */ #define cleanup ((void (*)(void))global[6]) +/* 005 */ /* deprecated */ +/* 006 */ /* deprecated */ /* 007 */ #define restart_bot ((void (*)(int))global[7]) /* 008 */ #define stop_bot ((void (*)(void))global[8]) /* 009 */ #define reload_config ((void (*)(void))global[9]) diff --git a/src/mysqlConn.c b/src/mysqlConn.c index 79c82e9..867af65 100644 --- a/src/mysqlConn.c +++ b/src/mysqlConn.c @@ -16,6 +16,7 @@ */ #include "mysqlConn.h" +#include "ConfigParser.h" #define DATABASE_VERSION "20" static void show_mysql_error(); @@ -96,14 +97,39 @@ void mysql_free() { mysql_conn->escaped_strings = NULL; } -void init_mysql(char *host, int port, char *user, char *pass, char *base) { - THREAD_MUTEX_INIT(synchronized); - mysql_host = strdup(host); - mysql_serverport = port; - mysql_user = strdup(user); - mysql_pass = strdup(pass); - mysql_base = strdup(base); +int reload_mysql() { + char *new_mysql_host = get_string_field("MySQL.host"); + char *new_mysql_user = get_string_field("MySQL.user"); + char *new_mysql_pass = get_string_field("MySQL.pass"); + char *new_mysql_base = get_string_field("MySQL.base"); + if(!(new_mysql_host && new_mysql_user && new_mysql_pass && new_mysql_base)) + return 0; + + //replace login data + if(mysql_host) + free(mysql_host); + mysql_host = strdup(new_mysql_host); + + if(mysql_user) + free(mysql_user); + mysql_user = strdup(new_mysql_user); + + if(mysql_pass) + free(mysql_pass); + mysql_pass = strdup(new_mysql_pass); + if(mysql_base) + free(mysql_base); + mysql_base = strdup(new_mysql_base); + + mysql_serverport = get_int_field("MySQL.port"); + if(!mysql_serverport) + mysql_serverport = 3306; + return 1; +} + +void init_mysql() { + THREAD_MUTEX_INIT(synchronized); MYSQL *mysql_conn = get_mysql_conn(); diff --git a/src/mysqlConn.h b/src/mysqlConn.h index 660e2cb..e85832f 100644 --- a/src/mysqlConn.h +++ b/src/mysqlConn.h @@ -30,7 +30,8 @@ #ifndef DND_FUNCTIONS /* MODULAR ACCESSIBLE */ MYSQL_RES *mysql_use(); /* MODULAR ACCESSIBLE */ void mysql_free(); -void init_mysql(char *host, int port, char *user, char *pass, char *base); +int reload_mysql(); +void init_mysql(); void free_mysql(); /* MODULAR ACCESSIBLE */ void printf_mysql_query(const char *text, ...) PRINTF_LIKE(1, 2); /* MODULAR ACCESSIBLE */ void printf_long_mysql_query(int len, const char *text, ...) PRINTF_LIKE(2, 3); diff --git a/src/overall.h b/src/overall.h index caf062d..26ff10e 100644 --- a/src/overall.h +++ b/src/overall.h @@ -120,10 +120,6 @@ #include "memoryDebug.h" #endif -#define PID_FILE "neonserv.pid" -#define CONF_FILE "neonserv.conf" -#define LOG_FILE "neonserv.log" - #define SOCKET_SELECT_TIME 1 #define SOCKET_RECONNECT_TIME 20 diff --git a/src/signal.c b/src/signal.c index 24e399d..bc44446 100644 --- a/src/signal.c +++ b/src/signal.c @@ -92,15 +92,12 @@ static void sigcrash(int signum) { } } putlog(LOGLEVEL_INFO, "hard shutdown...\n"); - exit_daemon(); usleep(2000000); //hard restart - restart_process(); + restart_bot(1); exit(0); } static void sigexit(int signum) { - cleanup(); - exit_daemon(); - exit(0); + stop_bot(); } diff --git a/src/statistics.c b/src/statistics.c new file mode 100644 index 0000000..5d102ca --- /dev/null +++ b/src/statistics.c @@ -0,0 +1,78 @@ +/* statistics.c - NeonServ v5.6 + * Copyright (C) 2011-2012 Philipp Kreil (pk910) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "statistics.h" +#include "timeq.h" +#include "ConfigParser.h" +#include "ClientSocket.h" +#include "bots.h" +#include "UserNode.h" +#include "ChanNode.h" +#include "ChanUser.h" +#include "IRCParser.h" +#include "modcmd.h" + +int statistics_requested_lusers = 0; + +static TIMEQ_CALLBACK(main_statistics) { + int update_minutes = get_int_field("statistics.frequency"); + if(!update_minutes) update_minutes = 2; + timeq_add(update_minutes * 60, 0, main_statistics, NULL); + if(get_int_field("statistics.enable")) { + statistics_requested_lusers = 1; + if(get_int_field("statistics.include_lusers")) { + struct ClientSocket *bot, *lusersbot = NULL; + for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) { + if(bot->flags & SOCKET_FLAG_PREFERRED) + lusersbot = bot; + } + bot = lusersbot; + if(bot == NULL) bot = getBots(SOCKET_FLAG_READY, NULL); + putsock(bot, "LUSERS"); + } else + statistics_update(); + } else { + statistics_privmsg = 0; + statistics_commands = 0; + } +} + +int statistics_update() { + if(get_int_field("statistics.enable") && statistics_requested_lusers && get_string_field("statistics.execute")) { + statistics_requested_lusers = 0; + char command[MAXLEN]; + /* parameters: + - visible users + - visible chanusers + - visible channels + - privmsg per minute + - commands per minute + - network users + - network channels + */ + sprintf(command, "%s %d %d %d %d %d %d %d", get_string_field("statistics.execute"), getUserCount(), getChanUserCount(), getChannelCount(), statistics_privmsg, statistics_commands, statistics_network_users, statistics_network_channels); + statistics_privmsg = 0; + statistics_commands = 0; + return system(command); + } + return -1; +} + +void init_statistics() { + int update_minutes = get_int_field("statistics.frequency"); + if(!update_minutes) update_minutes = 2; + timeq_add(update_minutes * 60 + 10, 0, main_statistics, NULL); +} diff --git a/src/statistics.h b/src/statistics.h new file mode 100644 index 0000000..79f7f4d --- /dev/null +++ b/src/statistics.h @@ -0,0 +1,25 @@ +/* statistics.h - NeonServ v5.6 + * Copyright (C) 2011-2012 Philipp Kreil (pk910) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef _statistics_h +#define _statistics_h + +#include "main.h" + +int statistics_update(); +void init_statistics(); + +#endif diff --git a/src/tools.c b/src/tools.c index daedcd0..5447232 100644 --- a/src/tools.c +++ b/src/tools.c @@ -375,6 +375,16 @@ int strToTime(struct UserNode *user, char *str) { return total_time; } +int getCurrentSecondsOfDay() { + time_t now = time(0); + struct tm *timeofday = localtime(&now); + int seconds = 0; + seconds += timeofday->tm_hour * 3600; + seconds += timeofday->tm_min * 60; + seconds += timeofday->tm_sec; + return seconds; +} + struct ModeBuffer* initModeBuffer(struct ClientSocket *client, struct ChanNode *chan) { struct ModeBuffer *modeBuf = malloc(sizeof(*modeBuf)); if(!modeBuf) { @@ -576,6 +586,28 @@ unsigned long crc32(const char *text) { return (crc^0xFFFFFFFF); } +int stricmp (const char *s1, const char *s2) { + return stricmplen(s1, s2, -1); +} + +int stricmplen(const char *s1, const char *s2, int len) { + if (s1 == NULL) + return (s2 == NULL ? 0 : -(*s2)); + if (s2 == NULL) + return *s1; + char c1, c2; + int i = 0; + while ((c1 = tolower(*s1)) == (c2 = tolower(*s2))) { + if (*s1 == '\0') + break; + i++; + s1++; + s2++; + if(len != -1 && i == len) break; + } + return c1 - c2; +} + void init_tools() { register_default_language_table(msgtab); crc32_init(); diff --git a/src/tools.h b/src/tools.h index 320cb79..bab14cb 100644 --- a/src/tools.h +++ b/src/tools.h @@ -75,6 +75,7 @@ struct ModeBuffer { /* MODULAR ACCESSIBLE */ char* timeToStr(struct UserNode *user, int seconds, int items, char *buf); /* MODULAR ACCESSIBLE */ int strToTime(struct UserNode *user, char *str); +/* MODULAR ACCESSIBLE */ int getCurrentSecondsOfDay(); /* MODULAR ACCESSIBLE */ struct ModeBuffer* initModeBuffer(struct ClientSocket *client, struct ChanNode *chan); /* MODULAR ACCESSIBLE */ void modeBufferSet(struct ModeBuffer *modeBuf, int add, char mode, char *param); @@ -91,6 +92,9 @@ struct ModeBuffer { /* MODULAR ACCESSIBLE */ unsigned long crc32(const char *text); +/* MODULAR ACCESSIBLE */ int stricmp (const char *s1, const char *s2); +/* MODULAR ACCESSIBLE */ int stricmplen (const char *s1, const char *s2, int len); + void init_tools(); #endif