src/cmd_neonserv_halfopall.c \
src/cmd_neonserv_dehalfopall.c \
src/cmd_neonhelp_stats.c \
+ src/cmd_global_meminfo.c \
src/cmd_funcmds.c \
src/ConfigParser.c \
- src/QServer.c
+ src/QServer.c \
+ src/memoryDebug.c
neonserv_LDADD = $(MYSQL_LIBS) $(WINSOCK_LIBS)
],
[])
+AC_ARG_ENABLE([memory-debug],
+ [AS_HELP_STRING([--enable-memory-debug], [run memory debugger])],
+ [
+ AC_DEFINE([ENABLE_MEMORY_DEBUG], 1, [Define if you enable memoryDebug.c])
+ ],
+ [])
+
AC_ARG_ENABLE([debug],
[AS_HELP_STRING([--enable-debug], [debug mode (compile using -O0 -Wall -Wshadow -Werror)])],
[CFLAGS='-g -O0 -Wall -Wshadow -Werror'],
{"NS_MODCMD_HEADER", "$bSettings for command %s:$b"}, /* {ARGS: "access"} */
{"NS_MODCMD_OUTRANKED", "$b%s$b outranks you. (required access: %d)"}, /* {ARGS: "die", 1000} */
{"NS_MODCMD_STATIC_FLAG", "This Flag is added statically. It can't be modified manually."},
+ {"NS_MEMINFO_DISABLED", "Memory Debugger is disabled!"},
+ {"NS_MEMINFO_NAME", "Name"},
+ {"NS_MEMINFO_COUNT", "Count"},
+ {"NS_MEMINFO_SIZE", "Size"},
+ {"NS_MEMINFO_LINE", "Line"},
+ {"NS_MEMINFO_TOTAL", "Total"},
{NULL, NULL}
};
CMD_BIND(global_cmd_die);
CMD_BIND(global_cmd_emote);
CMD_BIND(global_cmd_god);
+CMD_BIND(global_cmd_meminfo);
CMD_BIND(global_cmd_modcmd);
CMD_BIND(global_cmd_motd);
CMD_BIND(global_cmd_netinfo);
--- /dev/null
+/* cmd_global_meminfo.c - NeonServ v5.3
+ * 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 "cmd_global.h"
+#include "memoryInfo.h"
+
+/*
+* no arguments
+*/
+
+CMD_BIND(global_cmd_meminfo) {
+ #ifndef ENABLE_MEMORY_DEBUG
+ reply(getTextBot(), user, "NS_MEMINFO_DISABLED");
+ #else
+ if(argc > 0) {
+ struct Table *table;
+ int elementcount = 0;
+ struct memoryInfoLines *element, *elements;
+ elements = getMemoryInfoLines(argv[0]);
+ for(element = elements; element; element = element->next) {
+ elementcount++;
+ }
+ table = table_init(4, elementcount+2, 0);
+ char *content[4];
+ content[0] = get_language_string(user, "NS_MEMINFO_LINE");
+ content[1] = get_language_string(user, "NS_MEMINFO_COUNT");
+ content[2] = get_language_string(user, "NS_MEMINFO_SIZE");
+ content[3] = get_language_string(user, "NS_MEMINFO_TOTAL");
+ table_add(table, content);
+ char lineBuf[20];
+ char countBuf[20];
+ char sizeBuf[20];
+ char totalBuf[50];
+ unsigned int total_allocations = 0;
+ unsigned int total_allocated = 0;
+ for(element = elements; element; element = element->next) {
+ sprintf(lineBuf, "%u", element->line);
+ content[0] = lineBuf;
+ sprintf(countBuf, "%u", element->allocations);
+ total_allocations += element->allocations;
+ content[1] = countBuf;
+ sprintf(sizeBuf, "%uB", element->allocate);
+ content[2] = sizeBuf;
+ sprintf(totalBuf, "%u (%.2f kB)", (element->allocate * element->allocations), ((float)(element->allocate * element->allocations) / 1024));
+ total_allocated += (element->allocate * element->allocations);
+ content[3] = totalBuf;
+ table_add(table, content);
+ }
+ content[0] = "Total";
+ sprintf(countBuf, "%u", total_allocations);
+ content[1] = countBuf;
+ content[2] = "*";
+ sprintf(sizeBuf, "%u (%.2f kB)", total_allocated, ((float)total_allocated / 1024));
+ content[3] = sizeBuf;
+ table_add(table, content);
+ char **table_lines = table_end(table);
+ int i;
+ for(i = 0; i < table->entrys; i++) {
+ reply(getTextBot(), user, table_lines[i]);
+ }
+ table_free(table);
+ } else {
+ struct Table *table;
+ int elementcount = 0;
+ struct memoryInfoFiles *element, *elements;
+ elements = getMemoryInfoFiles();
+ for(element = elements; element; element = element->next) {
+ elementcount++;
+ }
+ table = table_init(3, elementcount+2, 0);
+ char *content[3];
+ content[0] = get_language_string(user, "NS_MEMINFO_NAME");
+ content[1] = get_language_string(user, "NS_MEMINFO_COUNT");
+ content[2] = get_language_string(user, "NS_MEMINFO_SIZE");
+ table_add(table, content);
+ char countBuf[20];
+ char sizeBuf[50];
+ unsigned int total_allocations = 0;
+ unsigned int total_allocated = 0;
+ for(element = elements; element; element = element->next) {
+ content[0] = element->filename;
+ sprintf(countBuf, "%u", element->allocations);
+ total_allocations += element->allocations;
+ content[1] = countBuf;
+ sprintf(sizeBuf, "%u (%.2f kB)", element->allocated, ((float)element->allocated / 1024));
+ total_allocated += element->allocated;
+ content[2] = sizeBuf;
+ table_add(table, content);
+ }
+ content[0] = "Total";
+ sprintf(countBuf, "%u", total_allocations);
+ content[1] = countBuf;
+ sprintf(sizeBuf, "%u (%.2f kB)", total_allocated, ((float)total_allocated / 1024));
+ content[2] = sizeBuf;
+ table_add(table, content);
+ char **table_lines = table_end(table);
+ int i;
+ for(i = 0; i < table->entrys; i++) {
+ reply(getTextBot(), user, table_lines[i]);
+ }
+ table_free(table);
+ }
+ #endif
+}
\ No newline at end of file
OPER_COMMAND("delbot", global_cmd_delbot, 1, 1000, CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_OPLOG);
OPER_COMMAND("reconnect", global_cmd_reconnect, 0, 1000, CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_OPLOG);
OPER_COMMAND("modcmd", global_cmd_modcmd, 1, 900, CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_OPLOG | CMDFLAG_REQUIRED | CMDFLAG_ESCAPE_ARGS);
+ OPER_COMMAND("meminfo", global_cmd_meminfo, 0, 1000, CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH);
#undef OPER_COMMAND
//NeonServ Commands
signal(SIGSEGV, sighandler);
signal(SIGTERM, sighandler);
+ #ifdef ENABLE_MEMORY_DEBUG
+ initMemoryDebug();
+ #endif
+
start_time = time(0);
#ifdef WIN32
#define COMPILER "Unknown"
#endif
+#ifdef ENABLE_MEMORY_DEBUG
+#include "memoryDebug.h"
+#endif
+
#define SOCKET_SELECT_TIME 1
#define SOCKET_RECONNECT_TIME 20
--- /dev/null
+/* memoryDebug.c - NeonServ v5.3
+ * 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 "main.h"
+#include "memoryDebug.h"
+#include "memoryInfo.h"
+
+#define FILE_NAME_LENGTH 256
+#define OUTPUT_FILE "leak_info.txt"
+
+#undef malloc
+#undef calloc
+#undef strdup
+#undef free
+
+struct MemoryNode {
+void *address;
+unsigned int size;
+char file_name[FILE_NAME_LENGTH];
+unsigned int line;
+};
+
+struct MemoryLeak {
+struct MemoryNode mem_info;
+struct MemoryLeak *next;
+};
+
+#ifdef HAVE_THREADS
+static pthread_mutex_t synchronized;
+#endif
+
+static struct MemoryLeak *ptr_start = NULL;
+
+static void add_mem_info(void * mem_ref, unsigned int size, const char *file, unsigned int line);
+static void remove_mem_info(void * mem_ref);
+
+void *xmalloc(unsigned int size, const char *file, unsigned int line) {
+ void *ptr = malloc(size);
+ if (ptr != NULL) {
+ add_mem_info(ptr, size, file, line);
+ }
+ return ptr;
+}
+
+void *xcalloc(unsigned int elements, unsigned int size, const char *file, unsigned int line) {
+ void *ptr = calloc(elements, size);
+ if(ptr != NULL) {
+ add_mem_info(ptr, (elements * size), file, line);
+ }
+ return ptr;
+}
+
+char *xstrdup(const char *data, const char *file, unsigned int line) {
+ int len = strlen(data)+1;
+ char *ptr = malloc(len);
+ if(ptr != NULL) {
+ strcpy(ptr, data);
+ add_mem_info(ptr, len, file, line);
+ }
+ return ptr;
+}
+
+void xfree(void *mem_ref) {
+ remove_mem_info(mem_ref);
+ free(mem_ref);
+}
+
+
+static void add_mem_info(void *mem_ref, unsigned int size, const char *file, unsigned int line) {
+ SYNCHRONIZE(synchronized);
+ struct MemoryLeak *mem_leak_info = malloc (sizeof(*mem_leak_info));
+ mem_leak_info->mem_info.address = mem_ref;
+ mem_leak_info->mem_info.size = size;
+ strcpy(mem_leak_info->mem_info.file_name, file);
+ mem_leak_info->mem_info.line = line;
+ mem_leak_info->next = ptr_start;
+ ptr_start = mem_leak_info;
+ DESYNCHRONIZE(synchronized);
+}
+
+static void remove_mem_info(void *mem_ref) {
+ SYNCHRONIZE(synchronized);
+ struct MemoryLeak *leak_info, *next, *prev = NULL;
+ for(leak_info = ptr_start; leak_info; leak_info = next) {
+ next = leak_info->next;
+ if (leak_info->mem_info.address == mem_ref) {
+ if(prev)
+ prev->next = next;
+ else
+ ptr_start = next;
+ free(leak_info);
+ break;
+ } else
+ prev = leak_info;
+ }
+ DESYNCHRONIZE(synchronized);
+}
+
+void report_mem_leak() {
+ SYNCHRONIZE(synchronized);
+ struct MemoryLeak *leak_info;
+ FILE *fp_write = fopen(OUTPUT_FILE, "wt");
+ char info[1024];
+
+ if(fp_write != NULL) {
+ sprintf(info, "%s\n", "Memory Leak Summary");
+ fwrite(info, (strlen(info)) , 1, fp_write);
+ sprintf(info, "%s\n", "-----------------------------------");
+ fwrite(info, (strlen(info)) , 1, fp_write);
+
+ for(leak_info = ptr_start; leak_info != NULL; leak_info = leak_info->next) {
+ sprintf(info, "address : %p\n", leak_info->mem_info.address);
+ fwrite(info, (strlen(info)) , 1, fp_write);
+ sprintf(info, "size : %d bytes\n", leak_info->mem_info.size);
+ fwrite(info, (strlen(info)) , 1, fp_write);
+ sprintf(info, "file : %s\n", leak_info->mem_info.file_name);
+ fwrite(info, (strlen(info)) , 1, fp_write);
+ sprintf(info, "line : %d\n", leak_info->mem_info.line);
+ fwrite(info, (strlen(info)) , 1, fp_write);
+ sprintf(info, "%s\n", "-----------------------------------");
+ fwrite(info, (strlen(info)) , 1, fp_write);
+ }
+ }
+ fclose(fp_write);
+ DESYNCHRONIZE(synchronized);
+}
+
+void initMemoryDebug() {
+ THREAD_MUTEX_INIT(synchronized);
+}
+
+struct memoryInfoFiles *getMemoryInfoFiles() {
+ SYNCHRONIZE(synchronized);
+ struct MemoryLeak *leak_info;
+ struct memoryInfoFiles *list = NULL, *element;
+ for(leak_info = ptr_start; leak_info != NULL; leak_info = leak_info->next) {
+ for(element = list; element; element = element->next) {
+ if(!strcmp(leak_info->mem_info.file_name, element->filename)) {
+ break;
+ }
+ }
+ if(!element) {
+ element = malloc(sizeof(*element));
+ element->filename = strdup(leak_info->mem_info.file_name);
+ element->allocations = 0;
+ element->allocated = 0;
+ element->next = list;
+ list = element;
+ }
+ element->allocations += 1;
+ element->allocated += leak_info->mem_info.size;
+ }
+ DESYNCHRONIZE(synchronized);
+ return element;
+}
+
+void freeMemoryInfoFiles(struct memoryInfoFiles *files) {
+ struct memoryInfoFiles *next;
+ for(;files;files = next) {
+ next = files->next;
+ free(files->filename);
+ free(files);
+ }
+}
+
+struct memoryInfoLines *getMemoryInfoLines(const char *filename) {
+ SYNCHRONIZE(synchronized);
+ struct MemoryLeak *leak_info;
+ struct memoryInfoLines *list = NULL, *element;
+ for(leak_info = ptr_start; leak_info != NULL; leak_info = leak_info->next) {
+ if(stricmp(leak_info->mem_info.file_name, filename)) continue;
+ for(element = list; element; element = element->next) {
+ if(element->line == leak_info->mem_info.line && element->allocate == leak_info->mem_info.size) {
+ break;
+ }
+ }
+ if(!element) {
+ element = malloc(sizeof(*element));
+ element->line = leak_info->mem_info.line;
+ element->allocations = 0;
+ element->allocate = leak_info->mem_info.size;
+ element->next = list;
+ list = element;
+ }
+ element->allocations++;
+ }
+ DESYNCHRONIZE(synchronized);
+ return element;
+}
+
+void freeMemoryInfoLines(struct memoryInfoLines *lines) {
+ struct memoryInfoLines *next;
+ for(;lines;lines = next) {
+ next = lines->next;
+ free(lines);
+ }
+}
--- /dev/null
+/* memoryDebug.h - NeonServ v5.3
+ * 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 _memorydebug_h
+#define _memorydebug_h
+
+#define malloc(size) xmalloc (size, __FILE__, __LINE__)
+#define calloc(elements, size) xcalloc (elements, size, __FILE__, __LINE__)
+#define strdup(data) xstrdup (data, __FILE__, __LINE__)
+#define free(mem_ref) xfree(mem_ref)
+
+void *xmalloc(unsigned int size, const char *file, unsigned int line);
+void *xcalloc(unsigned int elements, unsigned int size, const char *file, unsigned int line);
+char *xstrdup(const char *data, const char *file, unsigned int line);
+void xfree(void *mem_ref);
+
+void report_mem_leak();
+void initMemoryDebug();
+
+#endif
--- /dev/null
+/* memoryInfo.h - NeonServ v5.3
+ * 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 _memoryinfo_h
+#define _memoryinfo_h
+
+struct memoryInfoFiles {
+ char *filename;
+ unsigned int allocations;
+ unsigned int allocated;
+ struct memoryInfoFiles *next;
+};
+
+struct memoryInfoFiles *getMemoryInfoFiles();
+void freeMemoryInfoFiles(struct memoryInfoFiles *files);
+
+
+struct memoryInfoLines {
+ unsigned int line;
+ unsigned int allocations;
+ unsigned int allocate;
+ struct memoryInfoLines *next;
+};
+
+struct memoryInfoLines *getMemoryInfoLines(const char *filename);
+void freeMemoryInfoLines(struct memoryInfoLines *lines);
+
+
+#endif