tidied up main.c code
authorpk910 <philipp@zoelle1.de>
Mon, 24 Sep 2012 13:56:52 +0000 (15:56 +0200)
committerpk910 <philipp@zoelle1.de>
Mon, 24 Sep 2012 14:05:55 +0000 (16:05 +0200)
16 files changed:
Makefile.am
src/IRCParser.c
src/main.c
src/main.h
src/modcmd.c
src/modules.c
src/modules/global.mod/cmd_global_restart.c
src/modules/module.h
src/mysqlConn.c
src/mysqlConn.h
src/overall.h
src/signal.c
src/statistics.c [new file with mode: 0644]
src/statistics.h [new file with mode: 0644]
src/tools.c
src/tools.h

index df5f18017770bcfffee2a7ac08a4ab5d122ce124..fdfb7f1304091e8e1464c837d349f553b0752983 100644 (file)
@@ -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)
index ff244a05043c98384c978b0dca68e8bca1a01be2..bcb9f026897a838cc34cc392d903b4bba8820a2a 100644 (file)
@@ -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, " ");
index 5ab1efd0bd5f93ccce05657783bcdda7f8722484..4c7c9f48f4b1d1ba5d3037fa0a4fc9c41fc496e7 100644 (file)
  * along with this program. If not, see <http://www.gnu.org/licenses/>. 
  */
 
+#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"
 #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(&current_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(&current_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;
index 26f4319379e5d8c3f22b37b139034858f0f5bcbd..f429b67da41b3b02d7676c19be16ecaa175df9d5 100644 (file)
 #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
index e19d261318cd71f169f894bee1efc2a1ea5259c8..5837d33983eeab109d08289330cd6ccccd30265b 100644 (file)
@@ -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)) {
index 0de4505ea9df74c1474f0c7ce95298e0360d59fc..7310c88465152f21f1dc0351869489867d1346e4 100644 (file)
 #include <dlfcn.h>
 #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"
 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,
index 64ef5a52d4d78089cb5cfd37b3903a452fc61c95..80f4403520302900c4fc24281ac8a29540847800 100644 (file)
@@ -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);
 }
index 071c1483afd35462ec8f25db331a36a20bc122d4..25a767690264df5fd68ae73cd943169478f273d4 100644 (file)
@@ -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])
index 79c82e9d4194f49514cf14aa8202d4461fc63312..867af65dccf8014afa546c88f43077d9094ce116 100644 (file)
@@ -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();
     
index 660e2cb32c2c74f8c5ef817d9af97f19f71dcc6d..e85832f6272796160ed84b5b4439d80fb10d9f18 100644 (file)
@@ -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);
index caf062de7161598fa76e3ccc485ab790160c22a8..26ff10ebe0d54466b92ea6f6a371ef40116c5488 100644 (file)
 #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
 
index 24e399d6490ade57b73a94ac9573944e6ce7b3a7..bc444465089f1b2faa2f5d3ce03366c3ae3c041a 100644 (file)
@@ -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 (file)
index 0000000..5d102ca
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>. 
+ */
+#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 (file)
index 0000000..79f7f4d
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>. 
+ */
+#ifndef _statistics_h
+#define _statistics_h
+
+#include "main.h"
+
+int statistics_update();
+void init_statistics();
+
+#endif
index daedcd095ae19d28097f8814c1ef7fc362b7e433..5447232a347f391f5881ff7a4cdf6244aa24e000 100644 (file)
@@ -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();
index 320cb797665b426d5114b506126e3c851044b164..bab14cb658f3771c1612be726a21f7b38341f976 100644 (file)
@@ -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