added stats module for neonserv.krypton-bouncer.de stats
authorpk910 <philipp@zoelle1.de>
Thu, 16 Feb 2012 23:40:58 +0000 (00:40 +0100)
committerpk910 <philipp@zoelle1.de>
Thu, 16 Feb 2012 23:47:01 +0000 (00:47 +0100)
13 files changed:
Makefile.am
database.sql
database.upgrade.sql
neonserv.example.conf
src/ClientSocket.c
src/ClientSocket.h
src/IRCParser.c
src/modules.c
src/modules.h
src/modules/module.h
src/modules/stats.mod/module.c [new file with mode: 0644]
src/mysqlConn.c
src/version.h

index 03edbe37c370f4525e693f2a77c97ecf1a881c60..c312545d8e9d18cf6651383aabb8fcf493f5f6d3 100644 (file)
@@ -7,7 +7,7 @@ checkversion:
        cd src && chmod +x version.sh && ./version.sh && cd ..
 
 noinst_PROGRAMS = neonserv
-noinst_LTLIBRARIES = libDummyServ.la libfuncmds.la libglobalcmd.la libNeonHelp.la libNeonServ.la libNeonSpam.la
+noinst_LTLIBRARIES = libDummyServ.la libfuncmds.la libglobalcmd.la libNeonHelp.la libNeonServ.la libNeonSpam.la libstats.la
 
 libDummyServ_la_SOURCES = src/modules/DummyServ.mod/bot_DummyServ.c \
       src/modules/DummyServ.mod/module.c
@@ -142,6 +142,10 @@ libNeonSpam_la_SOURCES = src/modules/NeonSpam.mod/bot_NeonSpam.c \
 libNeonSpam_la_LDFLAGS = -module -rpath /nowhere -avoid-version -no-undefined
 libNeonSpam_la_LIBADD = $(MYSQL_LIBS)
 
+libstats_la_SOURCES = src/modules/stats.mod/module.c
+libstats_la_LDFLAGS = -module -rpath /nowhere -avoid-version -no-undefined
+libstats_la_LIBADD = $(MYSQL_LIBS)
+
 neonserv_SOURCES = src/version.c \
       src/EventLogger.c \
       src/IRCEvents.c \
index fbc3b4048e04d1fab31e215290b7368216303be2..d3d9156e3be87e535b9885b749a47226482dc45c 100644 (file)
@@ -401,3 +401,14 @@ CREATE TABLE IF NOT EXISTS `helpserv_settings` (
   PRIMARY KEY (`helpserv_botid`)
 ) ENGINE=MyISAM DEFAULT CHARSET=latin1;
 
+-- --------------------------------------------------------
+
+--
+-- Tabellenstruktur für Tabelle `settings`
+--
+
+CREATE TABLE IF NOT EXISTS `settings` (
+  `name` varchar(100) NOT NULL,
+  `value` text NOT NULL,
+  PRIMARY KEY (`name`)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;
index cad2b7310784cf5c478b4dc8c9753335534606ef..7d08cd83a6961e598437faaf093626b217d40b51 100644 (file)
@@ -140,3 +140,10 @@ ADD `user_lastcheck` INT( 20 ) NOT NULL;
 
 -- version: 15
 
+CREATE TABLE IF NOT EXISTS `settings` (
+  `name` varchar(100) NOT NULL,
+  `value` text NOT NULL,
+  PRIMARY KEY (`name`)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;
+
+-- version: 16
index 5be3085bb2daa1d7b2c69918de22562b24f4f569..ba99ed7cdfe76df97dc6f798f116c1cac2488486 100644 (file)
         "enabled" = 1;
         "protected" = 0;
     };
+    "libstats" {
+        "enabled" = 1;
+        "protected" = 0;
+        "hide_networkname" = 0;
+        "hide_botnick" = 0;
+        "hide_chancount" = 0;
+        "hide_usercount" = 0;
+    };
 };
 
index 21a191efb4202689f94d3c61c97fb1b2f503237d..d1f80ff8773358a09a9c557b216afbea9c8490c8 100644 (file)
@@ -74,6 +74,7 @@ struct ClientSocket* create_socket(char *host, int port, char *bindto, char *pas
     client->ident = strdup(ident);
     client->realname = strdup(realname);
     client->user = NULL;
+    client->network_name = NULL;
     client->flags = 0;
     client->bufferpos = 0;
     client->traffic_in = 0;
@@ -344,6 +345,8 @@ static void destroy_socket(struct ClientSocket *client, int free_socket) {
             free(client->bind);
         if(client->pass)
             free(client->pass);
+        if(client->network_name)
+            free(client->network_name);
         free(client);
     } else if(client->flags & SOCKET_FLAG_FAST_JUMP) {
         client->flags &= ~SOCKET_FLAG_FAST_JUMP;
@@ -580,6 +583,8 @@ void free_sockets() {
             free(client->bind);
         if(client->pass)
             free(client->pass);
+        if(client->network_name)
+            free(client->network_name);
         free(client);
     }
     free(sockets);
index 40b65bae15488a12ef388cfb70475e1e734fda47..a65dfdfb00edefe2c5681b0db8c0fa05d2f7b9ba 100644 (file)
@@ -55,6 +55,7 @@ struct ClientSocket {
     char *ident;
     char *realname;
     struct UserNode *user;
+    char *network_name;
     unsigned long traffic_in;
     unsigned long traffic_out;
     time_t connection_time;
index da4f434e4cf19f8b2f1e41147e25d87ff1ae720e..220283e1408025789d54c1269c3900bbf8532e46 100644 (file)
@@ -721,10 +721,50 @@ static void client_renamed(struct ClientSocket *client) {
     }
 }
 
+static void raw_005_network(struct ClientSocket *client, char *value) {
+    if(!value) return;
+    //check all other networknames
+    //if they are NOT simular to value throw a warning
+    SYNCHRONIZE(cache_sync); //all bots connect to the same time so there is a higher chance that this code is running on multiple threads at the same time
+    if(client->network_name)
+        free(client->network_name);
+    client->network_name = strdup(value);
+    struct ClientSocket *bot;
+    for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
+        if(bot == client) continue;
+        if(!bot->network_name) continue;
+        if(stricmp(bot->network_name, value)) {
+            putlog(LOGLEVEL_ERROR, "WARNING: Network name '%s' (%s) differs from '%s' (%s)! Connecting to multiple IRC-Networks with one instance is NOT supported!\n", client->network_name, client->nick, bot->network_name, bot->nick);
+            break;
+        }
+    }
+    DESYNCHRONIZE(cache_sync);
+}
+
+static IRC_CMD(raw_005) {
+    char *ptr1 = merge_argv(argv, 1, argc);
+    char *ptr2, *name, *value;
+    do {
+        ptr2 = strchr(ptr1, ' ');
+        if(ptr2)
+            *ptr2 = '\0';
+        name = ptr1;
+        if((value = strchr(ptr1, '='))) {
+            *value = '\0';
+            value++;
+        }
+        if(!stricmp(name, "NETWORK")) raw_005_network(client, value);
+        if(ptr2)
+            ptr1 = ptr2 + 1;
+    } while(ptr2);
+    return 1;
+}
+
 void init_parser() {
     //all the raws we receive...
     register_irc_function("437", raw_437);
     register_irc_function("002", raw_002);
+    register_irc_function("005", raw_005);
     register_irc_function("251", raw_251);
     register_irc_function("254", raw_254);
     register_irc_function("324", raw_324);
index adbe37df4a4cd16432e45ed90e636b67a9401b51..d024c3e186f3abb39bdf80534cf77aa3f16f2d8d 100644 (file)
@@ -44,6 +44,7 @@
 /* 170-180 */ #include "UserNode.h"
 /* 181-183 */ #include "WHOHandler.h"
 /* 184-188 */ #include "version.h"
+/* 189     */ /* modules.h */
 
 #define Function void *
 
@@ -247,7 +248,8 @@ void *global_functions[] = {
 /* 185 */ (Function) get_creation,
 /* 186 */ (Function) get_revision,
 /* 187 */ (Function) get_codelines,
-/* 188 */ (Function) get_patchlevel
+/* 188 */ (Function) get_patchlevel,
+/* 189 */ (Function) get_module_name
 };
 
 static int module_id_counter = 1;
@@ -471,3 +473,13 @@ int module_loaded(int module_id) {
     }
     return 0;
 }
+
+char *get_module_name(int module_id) {
+    if(!module_id) return NULL;
+    struct ModuleInfo *modinfo;
+    for(modinfo = modules; modinfo; modinfo = modinfo->next) {
+        if(modinfo->module_id == module_id)
+            return modinfo->name;
+    }
+    return NULL;
+}
index 5f6ebb6dd2bd8dc859c56764d84012905e5f6eee..cbb496a61d5e2ceb8b643cd1667b64d6394e31d5 100644 (file)
@@ -44,6 +44,8 @@ void loop_modules();
 void stop_modules();
 int module_loaded(int module_id);
 
+/* MODULAR ACCESSIBLE */ char *get_module_name(int module_id);
+
 int ext_load_module(char *name);
 int ext_unload_module(char *name);
 int ext_reload_module(char *name);
index 73e141d546a94fbe04cbfe1557003614c721292e..89bf781a89e3b5bedac202929ac99dd07844e6af 100644 (file)
@@ -218,6 +218,7 @@ extern int module_id;
 /* 186 */ #define get_revision ((const char * (*)(void))global[186])
 /* 187 */ #define get_codelines ((const char * (*)(void))global[187])
 /* 188 */ #define get_patchlevel ((const int (*)(void))global[188])
+/* 189 */ #define get_module_name ((char * (*)(int))global[189])
 
 #define MODULE_HEADER(initfunc,startfunc,loopfunc,stopfunc) \
     void **global = NULL; \
diff --git a/src/modules/stats.mod/module.c b/src/modules/stats.mod/module.c
new file mode 100644 (file)
index 0000000..ee8a20d
--- /dev/null
@@ -0,0 +1,167 @@
+/* module.c - NeonServ v5.4
+ * 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 "../module.h"
+#include "../../timeq.h"
+#include "../../ConfigParser.h"
+#include "../../mysqlConn.h"
+#include "../../ClientSocket.h"
+#include "../../UserNode.h"
+
+#define STATS_UPDATE_SECONDS  1800
+#define STATS_UPDATE_HOST     "neonserv.krypton-bouncer.de"
+#define STATS_UPDATE_PORT     1675
+#define STATS_IDENTIFIER_LEN  10
+#define STATS_IDENTIFIER_POOL "abcdefghijklmnopqrstuvwxyz0123456789#*+-_.:;,!§$%&/()=?[]{}<>|@"
+#define STATS_IDENTIFIER_POOL_SIZE 63
+
+static TIMEQ_CALLBACK(stats_timer_callback);
+
+static int module_initialize() {
+    return 0;
+}
+
+static void module_start(int type) {
+    if(!timeq_name_exists("stats"))
+        timeq_add_name("stats", 60, module_id, stats_timer_callback, NULL);
+}
+
+static void module_loop() {
+    
+}
+
+static void module_stop(int type) {
+    timeq_del_name("stats");
+}
+
+static char *get_identifier() {
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    printf_mysql_query("SELECT `value` FROM `settings` WHERE `name` = 'identifier'");
+    res = mysql_use();
+    if(!(row = mysql_fetch_row(res))) {
+        srand(time(NULL));
+        char identifier[STATS_IDENTIFIER_LEN+1];
+        int i;
+        char *pool = STATS_IDENTIFIER_POOL;
+        for(i = 0; i < STATS_IDENTIFIER_LEN; i++) {
+            identifier[i] = pool[(rand() % STATS_IDENTIFIER_POOL_SIZE)];
+        }
+        identifier[i] = 0;
+        printf_mysql_query("INSERT INTO `settings` (`name`, `value`) VALUES ('identifier', '%s')", escape_string(identifier));
+        printf_mysql_query("SELECT `value` FROM `settings` WHERE `name` = 'identifier'");
+        res = mysql_use();
+        row = mysql_fetch_row(res);
+        if(!row) return NULL;
+    }
+    if(strlen(row[0]) < 10) return NULL;
+    return row[0];
+}
+
+static TIMEQ_CALLBACK(stats_timer_callback) {
+    timeq_add_name("stats", STATS_UPDATE_SECONDS, module_id, stats_timer_callback, NULL);
+    char tmp[200];
+    char pkgbuf[1024];
+    int pkgpos = 0;
+    char *modname = get_module_name(module_id);
+    char *bot_identifier = get_identifier();
+    if(!bot_identifier) return;
+    //build update package
+    pkgpos += sprintf(pkgbuf + pkgpos, "nsupdate\n%s\n%s.%d %s\n", bot_identifier, NEONSERV_VERSION, get_patchlevel(), (strcmp(get_revision(), "") ? get_revision() : "-"));
+    sprintf(tmp, "modules/%s/hide_networkname", modname);
+    if(get_int_field(tmp))
+        pkgpos += sprintf(pkgbuf + pkgpos, "*\n");
+    else {
+        struct ClientSocket *bot;
+        for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
+            if(bot->network_name) break;
+        }
+        if(bot)
+            pkgpos += sprintf(pkgbuf + pkgpos, "%s\n", bot->network_name);
+        else
+            pkgpos += sprintf(pkgbuf + pkgpos, "?\n");
+    }
+    sprintf(tmp, "modules/%s/hide_botnick", modname);
+    if(get_int_field(tmp))
+        pkgpos += sprintf(pkgbuf + pkgpos, "*\n");
+    else {
+        struct ClientSocket *bot, *bot1, *bot2, *bot3;
+        for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
+            if(bot->botid == 1 && (bot->flags & SOCKET_FLAG_PREFERRED))
+                bot1 = bot;
+            else if((bot->flags & SOCKET_FLAG_PREFERRED))
+                bot2 = bot;
+            else
+                bot3 = bot;
+        }
+        if(bot1)
+            bot = bot1;
+        else if(bot2)
+            bot = bot2;
+        else
+            bot = bot3;
+        if(bot) {
+            pkgpos += sprintf(pkgbuf + pkgpos, "%s!%s@%s %d\n", bot->user->nick, bot->user->ident, bot->host, bot->port);
+        } else
+            pkgpos += sprintf(pkgbuf + pkgpos, "?\n");
+    }
+    sprintf(tmp, "modules/%s/hide_chancount", modname);
+    if(get_int_field(tmp))
+        pkgpos += sprintf(pkgbuf + pkgpos, "*\n");
+    else {
+        int channel_count = getChannelCount();
+        pkgpos += sprintf(pkgbuf + pkgpos, "%d\n", channel_count);
+    }
+    sprintf(tmp, "modules/%s/hide_usercount", modname);
+    if(get_int_field(tmp))
+        pkgpos += sprintf(pkgbuf + pkgpos, "*\n");
+    else {
+        int user_count = getUserCount();
+        int chanuser_count = getChanUserCount();
+        pkgpos += sprintf(pkgbuf + pkgpos, "%d %d\n", user_count, chanuser_count);
+    }
+    pkgbuf[pkgpos] = 0;
+    //send package
+    #ifndef WIN32
+    struct sockaddr_in si_other;
+    int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+    if (sock == -1) return;
+    memset((char *) &si_other, 0, sizeof(si_other));
+    si_other.sin_family = AF_INET;
+    si_other.sin_port = htons(STATS_UPDATE_PORT);
+    if (!inet_aton(STATS_UPDATE_HOST, &si_other.sin_addr)) {
+        struct hostent *host = gethostbyname(STATS_UPDATE_HOST);
+        if (!host) return;
+        si_other.sin_addr = *(struct in_addr*)host->h_addr;
+    }
+    #else
+    struct sockaddr_in si_other;
+    int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+    if (sock == -1) return;
+    si_other.sin_family = AF_INET;
+    si_other.sin_port = htons(STATS_UPDATE_PORT);
+    si_other.sin_addr.s_addr = inet_addr(client->host);
+    if (si_other.sin_addr.s_addr == INADDR_NONE) {
+        struct hostent *host = gethostbyname(client->host);
+        if(!host) return;
+        memcpy(&(si_other.sin_addr), host->h_addr_list[0], 4);
+    }
+    #endif
+    sendto(sock, pkgbuf, pkgpos, 0, &si_other, sizeof(si_other));
+    close(sock);
+}
+
+MODULE_HEADER(module_initialize, module_start, module_loop, module_stop);
index a1fb75b6484d9ca98f76efc5f4ca8bad6efe4bb3..163ae12f0f04d3ff5fa6d757fe7a9bc861bce12e 100644 (file)
@@ -16,7 +16,7 @@
  */
 
 #include "mysqlConn.h"
-#define DATABASE_VERSION "15"
+#define DATABASE_VERSION "16"
 
 static void show_mysql_error();
 
index cb1b6fbc3f5485b4e56fdd64688b7a3df9adbe68..85900e200dff8d277196d709ad434a355861c86c 100644 (file)
@@ -19,7 +19,7 @@
 
 #include "main.h"
 
-#define MODULE_VERSION 1
+#define MODULE_VERSION 2
 
 #ifndef DND_FUNCTIONS
 extern const char *compilation;