From a2c45a8db6d724b98ab41fe9e75e1f7ea7523d5d Mon Sep 17 00:00:00 2001 From: shennetsind Date: Thu, 2 May 2013 17:14:01 -0300 Subject: Introducing Hercules Plugin Mananger http://hercules.ws/board/topic/549-introducing-hercules-plugin-manager/ Signed-off-by: shennetsind --- src/common/CMakeLists.txt | 3 + src/common/HPM.c | 348 ++++++++++++++++++++++++++++++++++++++++++++++ src/common/HPM.h | 83 +++++++++++ src/common/HPMi.h | 67 +++++++++ src/common/Makefile.in | 2 +- src/common/console.c | 223 ++++++++++++++++++++++++++++- src/common/console.h | 24 ++++ src/common/core.c | 16 ++- src/common/core.h | 17 +-- src/common/db.c | 20 ++- src/common/ers.c | 9 +- src/common/netbuffer.c | 8 +- src/common/showmsg.c | 17 +-- src/common/showmsg.h | 32 +++-- 14 files changed, 811 insertions(+), 58 deletions(-) create mode 100644 src/common/HPM.c create mode 100644 src/common/HPM.h create mode 100644 src/common/HPMi.h (limited to 'src/common') diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 508154c00..dbc30734c 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -68,6 +68,8 @@ set( COMMON_BASE_HEADERS "${COMMON_SOURCE_DIR}/des.h" "${COMMON_SOURCE_DIR}/ers.h" "${COMMON_SOURCE_DIR}/grfio.h" + "${COMMON_SOURCE_DIR}/HPM.h" + "${COMMON_SOURCE_DIR}/HPMi.h" "${COMMON_SOURCE_DIR}/malloc.h" "${COMMON_SOURCE_DIR}/mapindex.h" "${COMMON_SOURCE_DIR}/md5calc.h" @@ -94,6 +96,7 @@ set( COMMON_BASE_SOURCES "${COMMON_SOURCE_DIR}/des.c" "${COMMON_SOURCE_DIR}/ers.c" "${COMMON_SOURCE_DIR}/grfio.c" + "${COMMON_SOURCE_DIR}/HPM.c" "${COMMON_SOURCE_DIR}/malloc.c" "${COMMON_SOURCE_DIR}/mapindex.c" "${COMMON_SOURCE_DIR}/md5calc.c" diff --git a/src/common/HPM.c b/src/common/HPM.c new file mode 100644 index 000000000..ec5ba888e --- /dev/null +++ b/src/common/HPM.c @@ -0,0 +1,348 @@ +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file + +#include "../common/cbasetypes.h" +#include "../common/mmo.h" +#include "../common/core.h" +#include "../common/malloc.h" +#include "../common/showmsg.h" +#include "../common/socket.h" +#include "../common/timer.h" +#include "../common/conf.h" +#include "../common/utils.h" +#include "../common/console.h" +#include "HPM.h" + +#include +#include +#include +#ifndef WIN32 +#include +#endif + +void hplugin_trigger_event(enum hp_event_types type) { + unsigned int i; + for( i = 0; i < HPM->plugin_count; i++ ) { + if( HPM->plugins[i]->hpi->event[type] != NULL ) + (HPM->plugins[i]->hpi->event[type])(); + } +} + +void hplugin_export_symbol(void *var, char *name) { + RECREATE(HPM->symbols, struct hpm_symbol *, ++HPM->symbol_count); + CREATE(HPM->symbols[HPM->symbol_count - 1] ,struct hpm_symbol, 1); + HPM->symbols[HPM->symbol_count - 1]->name = name; + HPM->symbols[HPM->symbol_count - 1]->ptr = var; +} + +void *hplugin_import_symbol(char *name) { + unsigned int i; + + for( i = 0; i < HPM->symbol_count; i++ ) { + if( strcmp(HPM->symbols[i]->name,name) == 0 ) + return HPM->symbols[i]->ptr; + } + + ShowError("HPM:get_symbol: '"CL_WHITE"%s"CL_RESET"' not found!\n",name); + return NULL; +} + +bool hplugin_iscompatible(char* version) { + unsigned int req_major = 0, req_minor = 0; + + if( version == NULL ) + return false; + + sscanf(version, "%d.%d", &req_major, &req_minor); + + return ( req_major == HPM->version[0] && req_minor <= HPM->version[1] ) ? true : false; +} + +bool hplugin_exists(const char *filename) { + unsigned int i; + for(i = 0; i < HPM->plugin_count; i++) { + if( strcmpi(HPM->plugins[i]->filename,filename) == 0 ) + return true; + } + return false; +} +struct hplugin *hplugin_create(void) { + RECREATE(HPM->plugins, struct hplugin *, ++HPM->plugin_count); + CREATE(HPM->plugins[HPM->plugin_count - 1], struct hplugin, 1); + HPM->plugins[HPM->plugin_count - 1]->idx = HPM->plugin_count - 1; + HPM->plugins[HPM->plugin_count - 1]->filename = NULL; + return HPM->plugins[HPM->plugin_count - 1]; +} +bool hplugin_showmsg_populate(struct hplugin *plugin, const char *filename) { + void **ShowSub; + const char* ShowSubNames[9] = { + "ShowMessage", + "ShowStatus", + "ShowSQL", + "ShowInfo", + "ShowNotice", + "ShowWarning", + "ShowDebug", + "ShowError", + "ShowFatalError", + }; + void* ShowSubRef[9] = { + ShowMessage, + ShowStatus, + ShowSQL, + ShowInfo, + ShowNotice, + ShowWarning, + ShowDebug, + ShowError, + ShowFatalError, + }; + int i; + for(i = 0; i < 9; i++) { + if( !( ShowSub = plugin_import(plugin->dll, ShowSubNames[i],void **) ) ) { + ShowWarning("HPM:plugin_load: failed to retrieve '%s' for '"CL_WHITE"%s"CL_RESET"', skipping...\n", ShowSubNames[i], filename); + HPM->unload(plugin); + return false; + } + *ShowSub = ShowSubRef[i]; + } + return true; +} +void hplugin_load(const char* filename) { + struct hplugin *plugin; + struct hplugin_info *info; + struct HPMi_interface **HPMi; + bool anyEvent = false; + void **import_symbol_ref; + + if( HPM->exists(filename) ) { + ShowWarning("HPM:plugin_load: attempting to load duplicate '"CL_WHITE"%s"CL_RESET"', skipping...\n", filename); + return; + } + + plugin = HPM->create(); + + if( !( plugin->dll = plugin_open(filename) ) ){ + ShowWarning("HPM:plugin_load: failed to load '"CL_WHITE"%s"CL_RESET"', skipping...\n", filename); + HPM->unload(plugin); + return; + } + + if( !( info = plugin_import(plugin->dll, "pinfo",struct hplugin_info*) ) ) { + ShowDebug("HPM:plugin_load: failed to retrieve 'plugin_info' for '"CL_WHITE"%s"CL_RESET"', skipping...\n", filename); + HPM->unload(plugin); + return; + } + + if( !(info->type & SERVER_TYPE) ) { + HPM->unload(plugin); + return; + } + + if( !HPM->iscompatible(info->req_version) ) { + ShowWarning("HPM:plugin_load: '"CL_WHITE"%s"CL_RESET"' incompatible version '%s' -> '%s', skipping...\n", filename, info->req_version, HPM_VERSION); + HPM->unload(plugin); + return; + } + + if( !( import_symbol_ref = plugin_import(plugin->dll, "import_symbol",void **) ) ) { + ShowWarning("HPM:plugin_load: failed to retrieve 'import_symbol' for '"CL_WHITE"%s"CL_RESET"', skipping...\n", filename); + HPM->unload(plugin); + return; + } + + *import_symbol_ref = HPM->import_symbol; + + if( !( HPMi = plugin_import(plugin->dll, "HPMi",struct HPMi_interface **) ) ) { + ShowWarning("HPM:plugin_load: failed to retrieve 'HPMi' for '"CL_WHITE"%s"CL_RESET"', skipping...\n", filename); + HPM->unload(plugin); + return; + } + + if( !( *HPMi = plugin_import(plugin->dll, "HPMi_s",struct HPMi_interface *) ) ) { + ShowWarning("HPM:plugin_load: failed to retrieve 'HPMi_s' for '"CL_WHITE"%s"CL_RESET"', skipping...\n", filename); + HPM->unload(plugin); + return; + } + plugin->hpi = *HPMi; + + if( ( plugin->hpi->event[HPET_INIT] = plugin_import(plugin->dll, "plugin_init",void (*)(void)) ) ) + anyEvent = true; + + if( ( plugin->hpi->event[HPET_FINAL] = plugin_import(plugin->dll, "plugin_final",void (*)(void)) ) ) + anyEvent = true; + + if( ( plugin->hpi->event[HPET_READY] = plugin_import(plugin->dll, "server_online",void (*)(void)) ) ) + anyEvent = true; + + if( !anyEvent ) { + ShowWarning("HPM:plugin_load: no events found for '"CL_WHITE"%s"CL_RESET"', skipping...\n", filename); + HPM->unload(plugin); + return; + } + + if( !HPM->showmsg_pop(plugin,filename) ) + return; + + if( SERVER_TYPE == SERVER_TYPE_MAP ) { + plugin->hpi->addCommand = HPM->import_symbol("addCommand"); + plugin->hpi->addScript = HPM->import_symbol("addScript"); + plugin->hpi->addCPCommand = HPM->import_symbol("addCPCommand"); + } + + plugin->info = info; + plugin->filename = aStrdup(filename); + + return; +} + +void hplugin_unload(struct hplugin* plugin) { + unsigned int i = plugin->idx, cursor = 0; + + if( plugin->filename ) + aFree(plugin->filename); + if( plugin->dll ) + plugin_close(plugin->dll); + + aFree(plugin); + if( !HPM->off ) { + HPM->plugins[i] = NULL; + for(i = 0; i < HPM->plugin_count; i++) { + if( HPM->plugins[i] == NULL ) + continue; + if( cursor != i ) + HPM->plugins[cursor] = HPM->plugins[i]; + cursor++; + } + if( !(HPM->plugin_count = cursor) ) { + aFree(HPM->plugins); + HPM->plugins = NULL; + } + } +} + +void hplugins_config_read(void) { + config_t plugins_conf; + config_setting_t *plist = NULL; + const char *config_filename = "conf/plugins.conf"; // FIXME hardcoded name + + if (conf_read_file(&plugins_conf, config_filename)) + return; + + if( HPM->symbol_defaults_sub ) + HPM->symbol_defaults_sub(); + + plist = config_lookup(&plugins_conf, "plugins_list"); + + if (plist != NULL) { + int length = config_setting_length(plist), i; + char filename[60]; + for(i = 0; i < length; i++) { + snprintf(filename, 60, "plugins/%s%s", config_setting_get_string_elem(plist,i), DLL_EXT); + HPM->load(filename); + } + config_destroy(&plugins_conf); + } + + if( HPM->plugin_count ) + ShowStatus("HPM: There are '"CL_WHITE"%d"CL_RESET"' plugins loaded, type '"CL_WHITE"plugins"CL_RESET"' to list them\n", HPM->plugin_count); +} +void hplugins_share_defaults(void) { + /* console */ + HPM->share(console->addCommand,"addCPCommand"); + /* core */ + HPM->share(&runflag,"runflag"); + HPM->share(arg_v,"arg_v"); + HPM->share(&arg_c,"arg_c"); + HPM->share(SERVER_NAME,"SERVER_NAME"); + HPM->share(&SERVER_TYPE,"SERVER_TYPE"); + HPM->share((void*)get_svn_revision,"get_svn_revision"); + HPM->share((void*)get_git_hash,"get_git_hash"); + /* socket */ + HPM->share(RFIFOSKIP,"RFIFOSKIP"); + HPM->share(WFIFOSET,"WFIFOSET"); + HPM->share(do_close,"do_close"); + HPM->share(make_connection,"make_connection"); + HPM->share(session,"session"); + HPM->share(&fd_max,"fd_max"); + HPM->share(addr_,"addr"); + /* timer */ + HPM->share(gettick,"gettick"); + HPM->share(add_timer,"add_timer"); + HPM->share(add_timer_interval,"add_timer_interval"); + HPM->share(add_timer_func_list,"add_timer_func_list"); + HPM->share(delete_timer,"delete_timer"); + HPM->share(get_uptime,"get_uptime"); +} +CPCMD(plugins) { + if( HPM->plugin_count == 0 ) { + ShowInfo("HPC: there are no plugins loaded\n"); + } else { + unsigned int i; + + ShowInfo("HPC: There are '"CL_WHITE"%d"CL_RESET"' plugins loaded\n",HPM->plugin_count); + + for(i = 0; i < HPM->plugin_count; i++) { + ShowInfo("HPC: - '"CL_WHITE"%s"CL_RESET"' (%s)\n",HPM->plugins[i]->info->name,HPM->plugins[i]->filename); + } + } +} +void hpm_init(void) { + HPM->symbols = NULL; + HPM->plugins = NULL; + HPM->plugin_count = HPM->symbol_count = 0; + HPM->off = false; + + sscanf(HPM_VERSION, "%d.%d", &HPM->version[0], &HPM->version[1]); + + if( HPM->version[0] == 0 && HPM->version[1] == 0 ) { + ShowError("HPM:init:failed to retrieve HPM version!!\n"); + return; + } + HPM->symbol_defaults(); + + console->addCommand("plugins",CPCMD_A(plugins)); + + return; +} + +void hpm_final(void) { + unsigned int i; + + HPM->off = true; + + for( i = 0; i < HPM->plugin_count; i++ ) { + HPM->unload(HPM->plugins[i]); + } + + if( HPM->plugins ) + aFree(HPM->plugins); + + for( i = 0; i < HPM->symbol_count; i++ ) { + aFree(HPM->symbols[i]); + } + + if( HPM->symbols ) + aFree(HPM->symbols); + + return; +} +void hpm_defaults(void) { + HPM = &HPM_s; + + HPM->init = hpm_init; + HPM->final = hpm_final; + + HPM->create = hplugin_create; + HPM->load = hplugin_load; + HPM->unload = hplugin_unload; + HPM->event = hplugin_trigger_event; + HPM->exists = hplugin_exists; + HPM->iscompatible = hplugin_iscompatible; + HPM->import_symbol = hplugin_import_symbol; + HPM->share = hplugin_export_symbol; + HPM->symbol_defaults = hplugins_share_defaults; + HPM->config_read = hplugins_config_read; + HPM->showmsg_pop = hplugin_showmsg_populate; + HPM->symbol_defaults_sub = NULL; +} \ No newline at end of file diff --git a/src/common/HPM.h b/src/common/HPM.h new file mode 100644 index 000000000..ac2c4050f --- /dev/null +++ b/src/common/HPM.h @@ -0,0 +1,83 @@ +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file + +#ifndef _HPM_H_ +#define _HPM_H_ + +#include "../common/cbasetypes.h" +#include "../common/HPMi.h" + +#ifdef WIN32 + #ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN + #endif + #include + #define plugin_open(x) LoadLibraryA(x) + #define plugin_import(x,y,z) (z)GetProcAddress(x,y) + #define plugin_close(x) FreeLibrary(x) + + #define DLL_EXT ".dll" + #define DLL HINSTANCE +#else + #include + #define plugin_open(x) dlopen(x,RTLD_NOW) + #define plugin_import(x,y,z) (z)dlsym(x,y) + #define plugin_close(x) dlclose(x) + + #ifdef CYGWIN + #define DLL_EXT ".dll" + #else + #define DLL_EXT ".so" + #endif + + #define DLL void * + + #include // size_t + +#endif + +struct hplugin { + DLL dll; + unsigned int idx; + char *filename; + struct hplugin_info *info; + struct HPMi_interface *hpi; +}; + +struct hpm_symbol { + char *name; + void *ptr; +}; + +/* Hercules Plugin Manager Interface */ +struct HPM_interface { + /* vars */ + unsigned int version[2]; + bool off; + /* data */ + struct hplugin **plugins; + unsigned int plugin_count; + struct hpm_symbol **symbols; + unsigned int symbol_count; + /* funcs */ + void (*init) (void); + void (*final) (void); + struct hplugin * (*create) (void); + void (*load) (const char* filename); + void (*unload) (struct hplugin* plugin); + bool (*exists) (const char *filename); + bool (*iscompatible) (char* version); + void (*event) (enum hp_event_types type); + void *(*import_symbol) (char *); + void (*share) (void *, char *); + void (*symbol_defaults) (void); + void (*config_read) (void); + bool (*showmsg_pop) (struct hplugin *plugin,const char *filename); + void (*symbol_defaults_sub) (void); +} HPM_s; + +struct HPM_interface *HPM; + +void hpm_defaults(void); + +#endif /* _HPM_H_ */ \ No newline at end of file diff --git a/src/common/HPMi.h b/src/common/HPMi.h new file mode 100644 index 000000000..517d9125d --- /dev/null +++ b/src/common/HPMi.h @@ -0,0 +1,67 @@ +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file + +#ifndef _HPMi_H_ +#define _HPMi_H_ + +#include "../common/cbasetypes.h" +#include "../common/core.h" +#include "../common/console.h" + +struct script_state; +struct AtCommandInfo; + +#ifdef WIN32 + #define HPExport __declspec(dllexport) +#else + #define HPExport +#endif + +#ifndef _SHOWMSG_H_ + HPExport void (*ShowMessage) (const char *, ...); + HPExport void (*ShowStatus) (const char *, ...); + HPExport void (*ShowSQL) (const char *, ...); + HPExport void (*ShowInfo) (const char *, ...); + HPExport void (*ShowNotice) (const char *, ...); + HPExport void (*ShowWarning) (const char *, ...); + HPExport void (*ShowDebug) (const char *, ...); + HPExport void (*ShowError) (const char *, ...); + HPExport void (*ShowFatalError) (const char *, ...); +#endif + +/* after */ +#include "../common/showmsg.h" + +#define HPM_VERSION "0.1" + +struct hplugin_info { + char* name; + enum server_types type; + char* version; + char* req_version; +}; + +HPExport void *(*import_symbol) (char *name); +#define GET_SYMBOL(n) import_symbol(n) + +#define SERVER_TYPE_ALL SERVER_TYPE_LOGIN|SERVER_TYPE_CHAR|SERVER_TYPE_MAP + +enum hp_event_types { + HPET_INIT,/* server starts */ + HPET_FINAL,/* server is shutting down */ + HPET_READY,/* server is ready (online) */ + HPET_MAX, +}; + +/* Hercules Plugin Mananger Include Interface */ +struct HPMi_interface { + void (*event[HPET_MAX]) (void); + bool (*addCommand) (char *name, bool (*func)(const int fd, struct map_session_data* sd, const char* command, const char* message,struct AtCommandInfo *info)); + bool (*addScript) (char *name, char *args, bool (*func)(struct script_state *st)); + void (*addCPCommand) (char *name, CParseFunc func); +} HPMi_s; +#ifndef _HPM_H_ + struct HPMi_interface *HPMi; +#endif + +#endif /* _HPMi_H_ */ \ No newline at end of file diff --git a/src/common/Makefile.in b/src/common/Makefile.in index 26cae3e51..279f82e5f 100644 --- a/src/common/Makefile.in +++ b/src/common/Makefile.in @@ -1,5 +1,5 @@ -COMMON_OBJ = obj_all/core.o obj_all/socket.o obj_all/timer.o obj_all/db.o \ +COMMON_OBJ = obj_all/core.o obj_all/socket.o obj_all/timer.o obj_all/db.o obj_all/HPM.o \ obj_all/nullpo.o obj_all/malloc.o obj_all/showmsg.o obj_all/strlib.o obj_all/utils.o \ obj_all/grfio.o obj_all/mapindex.o obj_all/ers.o obj_all/md5calc.o \ obj_all/minicore.o obj_all/minisocket.o obj_all/minimalloc.o obj_all/random.o obj_all/des.o \ diff --git a/src/common/console.c b/src/common/console.c index 67897ee81..db914db98 100644 --- a/src/common/console.c +++ b/src/common/console.c @@ -8,6 +8,8 @@ #include "console.h" #ifndef MINICORE + #include "../common/ers.h" + #include "../common/malloc.h" #include "../common/atomic.h" #include "../common/spinlock.h" #include "../common/thread.h" @@ -77,7 +79,212 @@ int console_parse_key_pressed(void) { return FD_ISSET(STDIN_FILENO, &fds); } #endif /* _WIN32 */ +CPCMD(exit) { + runflag = 0; +} +CPCMD(ers_report) { + ers_report(); +} +CPCMD(help) { + unsigned int i = 0; + for ( i = 0; i < console->cmd_list_count; i++ ) { + if( console->cmd_list[i]->next_count ) { + ShowInfo("- '"CL_WHITE"%s"CL_RESET"' subs\n",console->cmd_list[i]->cmd); + console->parse_list_subs(console->cmd_list[i],2); + } else { + ShowInfo("- '"CL_WHITE"%s"CL_RESET"'\n",console->cmd_list[i]->cmd); + } + } +} +/* [Ind/Hercules] */ +CPCMD(malloc_usage) { + unsigned int val = (unsigned int)malloc_usage(); + ShowInfo("malloc_usage: %.2f MB\n",(double)(val)/1024); +} +#define CP_DEF_C(x) { #x , NULL , NULL, NULL } +#define CP_DEF_C2(x,y) { #x , NULL , #y, NULL } +#define CP_DEF_S(x,y) { #x , console_parse_ ## x , #y, NULL } +#define CP_DEF(x) { #x , console_parse_ ## x , NULL, NULL } +void console_load_defaults(void) { + struct { + char *name; + CParseFunc func; + char *connect; + struct CParseEntry *self; + } default_list[] = { + CP_DEF(help), + CP_DEF_C(server), + CP_DEF_S(ers_report,server), + CP_DEF_S(malloc_usage,server), + CP_DEF_S(exit,server), + }; + unsigned int i, len = ARRAYLENGTH(default_list); + struct CParseEntry *cmd; + + RECREATE(console->cmds,struct CParseEntry *, len); + + for(i = 0; i < len; i++) { + CREATE(cmd, struct CParseEntry, 1); + + safestrncpy(cmd->cmd, default_list[i].name, CP_CMD_LENGTH); + + if( default_list[i].func ) + cmd->u.func = default_list[i].func; + else + cmd->u.next = NULL; + + cmd->next_count = 0; + + console->cmd_count++; + console->cmds[i] = cmd; + default_list[i].self = cmd; + if( !default_list[i].connect ) { + RECREATE(console->cmd_list,struct CParseEntry *, ++console->cmd_list_count); + console->cmd_list[console->cmd_list_count - 1] = cmd; + } + } + + for(i = 0; i < len; i++) { + unsigned int k; + if( !default_list[i].connect ) + continue; + for(k = 0; k < console->cmd_count; k++) { + if( strcmpi(default_list[i].connect,console->cmds[k]->cmd) == 0 ) { + cmd = default_list[i].self; + RECREATE(console->cmds[k]->u.next, struct CParseEntry *, ++console->cmds[k]->next_count); + console->cmds[k]->u.next[console->cmds[k]->next_count - 1] = cmd; + break; + } + } + } +} +void console_parse_create(char *name, CParseFunc func) { + unsigned int i; + char *tok; + char sublist[CP_CMD_LENGTH * 5]; + struct CParseEntry *cmd; + + safestrncpy(sublist, name, CP_CMD_LENGTH * 5); + tok = strtok(sublist,":"); + + for ( i = 0; i < console->cmd_list_count; i++ ) { + if( strcmpi(tok,console->cmd_list[i]->cmd) == 0 ) + break; + } + if( i == console->cmd_list_count ) { + RECREATE(console->cmds,struct CParseEntry *, ++console->cmd_count); + CREATE(cmd, struct CParseEntry, 1); + safestrncpy(cmd->cmd, tok, CP_CMD_LENGTH); + cmd->next_count = 0; + console->cmds[console->cmd_count - 1] = cmd; + RECREATE(console->cmd_list,struct CParseEntry *, ++console->cmd_list_count); + console->cmd_list[console->cmd_list_count - 1] = cmd; + i = console->cmd_list_count - 1; + } + + cmd = console->cmd_list[i]; + while( ( tok = strtok(NULL, ":") ) != NULL ) { + + for(i = 0; i < cmd->next_count; i++) { + if( strcmpi(cmd->u.next[i]->cmd,tok) == 0 ) + break; + } + + if ( i == cmd->next_count ) { + RECREATE(console->cmds,struct CParseEntry *, ++console->cmd_count); + CREATE(console->cmds[console->cmd_count-1], struct CParseEntry, 1); + safestrncpy(console->cmds[console->cmd_count-1]->cmd, tok, CP_CMD_LENGTH); + console->cmds[console->cmd_count-1]->next_count = 0; + RECREATE(cmd->u.next, struct CParseEntry *, ++cmd->next_count); + cmd->u.next[cmd->next_count - 1] = console->cmds[console->cmd_count-1]; + cmd = console->cmds[console->cmd_count-1]; + continue; + } + + } + cmd->u.func = func; +} +void console_parse_list_subs(struct CParseEntry *cmd, unsigned char depth) { + unsigned int i; + char msg[CP_CMD_LENGTH * 2]; + for( i = 0; i < cmd->next_count; i++ ) { + if( cmd->u.next[i]->next_count ) { + memset(msg, '-', depth); + snprintf(msg + depth,CP_CMD_LENGTH * 2, " '"CL_WHITE"%s"CL_RESET"'",cmd->u.next[i]->cmd); + ShowInfo("%s subs\n",msg); + console->parse_list_subs(cmd->u.next[i],depth + 1); + } else { + memset(msg, '-', depth); + snprintf(msg + depth,CP_CMD_LENGTH * 2, " %s",cmd->u.next[i]->cmd); + ShowInfo("%s\n",msg); + } + } +} +void console_parse_sub(char *line) { + struct CParseEntry *cmd; + char bline[200]; + char *tok; + char sublist[CP_CMD_LENGTH * 5]; + unsigned int i, len = 0; + memcpy(bline, line, 200); + tok = strtok(line, " "); + for ( i = 0; i < console->cmd_list_count; i++ ) { + if( strcmpi(tok,console->cmd_list[i]->cmd) == 0 ) + break; + } + + if( i == console->cmd_list_count ) { + ShowError("'"CL_WHITE"%s"CL_RESET"' is not a known command, type '"CL_WHITE"help"CL_RESET"' to list all commands\n",line); + return; + } + + cmd = console->cmd_list[i]; + + len += snprintf(sublist,CP_CMD_LENGTH * 5,"%s", cmd->cmd) + 1; + + if( cmd->next_count == 0 && console->cmd_list[i]->u.func ) { + char *r = NULL; + if( (tok = strtok(NULL, " ")) ) { + r = bline; + r += len + 1; + } + cmd->u.func(r); + } else { + while( ( tok = strtok(NULL, " ") ) != NULL ) { + for( i = 0; i < cmd->next_count; i++ ) { + if( strcmpi(cmd->u.next[i]->cmd,tok) == 0 ) + break; + } + if( i == cmd->next_count ) { + if( strcmpi("help",tok) == 0 ) { + if( cmd->next_count ) { + ShowInfo("- '"CL_WHITE"%s"CL_RESET"' subs\n",sublist); + console->parse_list_subs(cmd,2); + } else { + ShowError("'"CL_WHITE"%s"CL_RESET"' doesn't possess any subcommands\n",sublist); + } + return; + } + ShowError("'"CL_WHITE"%s"CL_RESET"' is not a known subcommand of '"CL_WHITE"%s"CL_RESET"'\n",tok,cmd->cmd); + ShowError("type '"CL_WHITE"%s help"CL_RESET"' to list its subcommands\n",sublist); + return; + } + if( cmd->u.next[i]->next_count == 0 && cmd->u.next[i]->u.func ) { + char *r = NULL; + if( (tok = strtok(NULL, " ")) ) { + r = bline; + r += len + strlen(cmd->u.next[i]->cmd) + 1; + } + cmd->u.next[i]->u.func(r); + return; + } else + cmd = cmd->u.next[i]; + len += snprintf(sublist + len,CP_CMD_LENGTH * 5,":%s", cmd->cmd); + } + ShowError("it is only a category, type '"CL_WHITE"%s help"CL_RESET"' to list its subcommands\n",sublist); + } +} void console_parse(char* line) { int c, i = 0, len = MAX_CONSOLE_INPUT - 1;/* we leave room for the \0 :P */ @@ -122,7 +329,7 @@ int console_parse_timer(int tid, unsigned int tick, int id, intptr_t data) { int i; EnterSpinLock(&console->ptlock); for(i = 0; i < cinput.count; i++) { - parse_console(cinput.queue[i]); + console->parse_sub(cinput.queue[i]); } cinput.count = 0; LeaveSpinLock(&console->ptlock); @@ -163,12 +370,22 @@ void console_parse_init(void) { void console_init (void) { #ifdef CONSOLE_INPUT + console->cmd_count = console->cmd_list_count = 0; + console->load_defaults(); console->parse_init(); #endif } void console_final(void) { #ifdef CONSOLE_INPUT + int i; console->parse_final(); + for( i = 0; i < console->cmd_count; i++ ) { + if( console->cmds[i]->next_count ) + aFree(console->cmds[i]->u.next); + aFree(console->cmds[i]); + } + aFree(console->cmds); + aFree(console->cmd_list); #endif } void console_defaults(void) { @@ -182,6 +399,10 @@ void console_defaults(void) { console->parse_timer = console_parse_timer; console->pthread_main = cThread_main; console->parse = console_parse; + console->parse_sub = console_parse_sub; console->key_pressed = console_parse_key_pressed; + console->load_defaults = console_load_defaults; + console->parse_list_subs = console_parse_list_subs; + console->addCommand = console_parse_create; #endif } diff --git a/src/common/console.h b/src/common/console.h index 7f1490084..ebce013f7 100644 --- a/src/common/console.h +++ b/src/common/console.h @@ -14,6 +14,21 @@ * why is there a limit, why not make it dynamic? - I'm playing it safe, I'd rather not play with memory management between threads **/ #define CONSOLE_PARSE_SIZE 10 + +typedef void (*CParseFunc)(char *line); +#define CPCMD(x) void console_parse_ ##x (char *line) +#define CPCMD_A(x) console_parse_ ##x + +#define CP_CMD_LENGTH 20 +struct CParseEntry { + char cmd[CP_CMD_LENGTH]; + union { + CParseFunc func; + struct CParseEntry **next; + } u; + unsigned short next_count; +}; + struct { char queue[CONSOLE_PARSE_SIZE][MAX_CONSOLE_INPUT]; unsigned short count; @@ -31,12 +46,21 @@ struct console_interface { ramutex ptmutex;/* parse thread mutex */ racond ptcond;/* parse thread cond */ /* */ + struct CParseEntry **cmd_list; + struct CParseEntry **cmds; + unsigned int cmd_count; + unsigned int cmd_list_count; + /* */ void (*parse_init) (void); void (*parse_final) (void); int (*parse_timer) (int tid, unsigned int tick, int id, intptr_t data); void *(*pthread_main) (void *x); void (*parse) (char* line); + void (*parse_sub) (char* line); int (*key_pressed) (void); + void (*load_defaults) (void); + void (*parse_list_subs) (struct CParseEntry *cmd, unsigned char depth); + void (*addCommand) (char *name, CParseFunc func); #endif }; diff --git a/src/common/core.c b/src/common/core.c index da4e4ccf9..9fd9747aa 100644 --- a/src/common/core.c +++ b/src/common/core.c @@ -17,6 +17,7 @@ #include "../common/sql.h" #include "../config/core.h" #include "../common/strlib.h" + #include "../common/HPM.h" #endif #include @@ -37,7 +38,6 @@ int arg_c = 0; char **arg_v = NULL; char *SERVER_NAME = NULL; -char SERVER_TYPE = ATHENA_SERVER_NONE; #ifndef MINICORE // minimalist Core // Added by Gabuzomeu @@ -295,6 +295,9 @@ int main (int argc, char **argv) arg_c = argc; arg_v = argv; } +#ifndef MINICORE + hpm_defaults(); +#endif console_defaults(); malloc_init();// needed for Show* in display_title() [FlavioJS] @@ -320,13 +323,16 @@ int main (int argc, char **argv) #endif timer_init(); - + console->init(); + +#ifndef MINICORE + HPM->init(); +#endif socket_init(); do_init(argc,argv); - {// Main runtime cycle int next; while (runflag != CORE_ST_STOP) { @@ -338,7 +344,9 @@ int main (int argc, char **argv) console->final(); do_final(); - +#ifndef MINICORE + HPM->final(); +#endif timer_final(); socket_final(); db_final(); diff --git a/src/common/core.h b/src/common/core.h index 21da18938..8fdcdcfc3 100644 --- a/src/common/core.h +++ b/src/common/core.h @@ -23,17 +23,15 @@ extern char **arg_v; extern int runflag; extern char *SERVER_NAME; -enum { - ATHENA_SERVER_NONE = 0, // not defined - ATHENA_SERVER_LOGIN = 1, // login server - ATHENA_SERVER_CHAR = 2, // char server - ATHENA_SERVER_INTER = 4, // inter server - ATHENA_SERVER_MAP = 8, // map server +enum server_types { + SERVER_TYPE_UNKNOWN = 0x0, + SERVER_TYPE_LOGIN = 0x1, + SERVER_TYPE_CHAR = 0x2, + SERVER_TYPE_MAP = 0x4, }; -extern char SERVER_TYPE; +enum server_types SERVER_TYPE; -extern int parse_console(const char* buf); const char *get_svn_revision(void); const char *get_git_hash (void); extern int do_init(int,char**); @@ -42,8 +40,7 @@ extern void do_abort(void); extern void do_final(void); /// The main loop continues until runflag is CORE_ST_STOP -enum E_CORE_ST -{ +enum E_CORE_ST { CORE_ST_STOP = 0, CORE_ST_RUN, CORE_ST_LAST diff --git a/src/common/db.c b/src/common/db.c index 204c6d2ea..7ac9b2dc7 100644 --- a/src/common/db.c +++ b/src/common/db.c @@ -47,6 +47,7 @@ * - create a db that organizes itself by splaying * * HISTORY: + * 2013/04/27 - Added ERS to speed up iterator memory allocation [Ind/Hercules] * 2012/03/09 - Added enum for data types (int, uint, void*) * 2008/02/19 - Fixed db_obj_get not handling deleted entries correctly. * 2007/11/09 - Added an iterator to the database. @@ -319,6 +320,10 @@ static struct db_stats { #define DB_COUNTSTAT(token) #endif /* !defined(DB_ENABLE_STATS) */ +/* [Ind/Hercules] */ +struct eri *db_iterator_ers; +struct eri *db_alloc_ers; + /*****************************************************************************\ * (2) Section of private functions used by the database system. * * db_rotate_left - Rotate a tree node to the left. * @@ -1366,7 +1371,7 @@ void dbit_obj_destroy(DBIterator* self) // unlock the database db_free_unlock(it->db); // free iterator - aFree(self); + ers_free(db_iterator_ers,self); } /** @@ -1384,7 +1389,7 @@ static DBIterator* db_obj_iterator(DBMap* self) DBIterator_impl* it; DB_COUNTSTAT(db_iterator); - CREATE(it, struct DBIterator_impl, 1); + it = ers_alloc(db_iterator_ers, struct DBIterator_impl); /* Interface of the iterator **/ it->vtable.first = dbit_obj_first; it->vtable.last = dbit_obj_last; @@ -2127,7 +2132,7 @@ static int db_obj_vdestroy(DBMap* self, DBApply func, va_list args) db->free_max = 0; ers_destroy(db->nodes); db_free_unlock(db); - aFree(db); + ers_free(db_alloc_ers, db); return sum; } @@ -2409,7 +2414,7 @@ DBMap* db_alloc(const char *file, int line, DBType type, DBOptions options, unsi case DB_ISTRING: DB_COUNTSTAT(db_istring_alloc); break; } #endif /* DB_ENABLE_STATS */ - CREATE(db, struct DBMap_impl, 1); + db = ers_alloc(db_alloc_ers, struct DBMap_impl); options = db_fix_options(type, options); /* Interface of the database */ @@ -2602,8 +2607,9 @@ void* db_data2ptr(DBData *data) * @public * @see #db_final(void) */ -void db_init(void) -{ +void db_init(void) { + db_iterator_ers = ers_new(sizeof(struct DBIterator_impl),"db.c::db_iterator_ers",ERS_OPT_NONE); + db_alloc_ers = ers_new(sizeof(struct DBMap_impl),"db.c::db_alloc_ers",ERS_OPT_NONE); DB_COUNTSTAT(db_init); } @@ -2696,6 +2702,8 @@ void db_final(void) stats.db_data2ui, stats.db_data2ptr, stats.db_init, stats.db_final); #endif /* DB_ENABLE_STATS */ + ers_destroy(db_iterator_ers); + ers_destroy(db_alloc_ers); } // Link DB System - jAthena diff --git a/src/common/ers.c b/src/common/ers.c index 3b354166e..13e54b393 100644 --- a/src/common/ers.c +++ b/src/common/ers.c @@ -1,7 +1,7 @@ +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams /*****************************************************************************\ - * Copyright (c) Athena Dev Teams - Licensed under GNU GPL * - * For more information, see LICENCE in the main folder * - * * *

Entry Reusage System

* * * * There are several root entry managers, each with a different entry size. * @@ -48,8 +48,7 @@ #ifndef DISABLE_ERS -#define ERS_ROOT_SIZE 256 -#define ERS_BLOCK_ENTRIES 4096 +#define ERS_BLOCK_ENTRIES 2048 struct ers_list { diff --git a/src/common/netbuffer.c b/src/common/netbuffer.c index 57742d612..60a299aa9 100644 --- a/src/common/netbuffer.c +++ b/src/common/netbuffer.c @@ -52,10 +52,10 @@ void netbuffer_init(){ // Set localsection name according to running serverype. switch(SERVER_TYPE){ - case ATHENA_SERVER_LOGIN: strcpy(localsection, "login-netbuffer"); break; - case ATHENA_SERVER_CHAR: strcpy(localsection, "char-netbuffer"); break; - case ATHENA_SERVER_INTER: strcpy(localsection, "inter-netbuffer"); break; - case ATHENA_SERVER_MAP: strcpy(localsection, "map-netbuffer"); break; + case SERVER_TYPE_LOGIN: strcpy(localsection, "login-netbuffer"); break; + case SERVER_TYPE_CHAR: strcpy(localsection, "char-netbuffer"); break; + //case ATHENA_SERVER_INTER: strcpy(localsection, "inter-netbuffer"); break; + case SERVER_TYPE_MAP: strcpy(localsection, "map-netbuffer"); break; default: strcpy(localsection, "unsupported_type"); break; } diff --git a/src/common/showmsg.c b/src/common/showmsg.c index 609ae3c50..50fa972f0 100644 --- a/src/common/showmsg.c +++ b/src/common/showmsg.c @@ -1,5 +1,6 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams #include "../common/cbasetypes.h" #include "../common/strlib.h" // StringBuf @@ -687,22 +688,12 @@ int _vShowMessage(enum msg_type flag, const char *string, va_list ap) ShowError("Empty string passed to _vShowMessage().\n"); return 1; } - /** - * For the buildbot, these result in a EXIT_FAILURE from core.c when done reading the params. - **/ -#if defined(BUILDBOT) - if( flag == MSG_WARNING || - flag == MSG_ERROR || - flag == MSG_SQL ) { - buildbotflag = 1; - } -#endif if( ( flag == MSG_WARNING && console_msg_log&1 ) || ( ( flag == MSG_ERROR || flag == MSG_SQL ) && console_msg_log&2 ) || ( flag == MSG_DEBUG && console_msg_log&4 ) ) {//[Ind] FILE *log = NULL; - if( (log = fopen(SERVER_TYPE == ATHENA_SERVER_MAP ? "./log/map-msg_log.log" : "./log/unknown.log","a+")) ) { + if( (log = fopen(SERVER_TYPE == SERVER_TYPE_MAP ? "./log/map-msg_log.log" : "./log/unknown.log","a+")) ) { char timestring[255]; time_t curtime; time(&curtime); diff --git a/src/common/showmsg.h b/src/common/showmsg.h index 0d6cb5c9f..a88985770 100644 --- a/src/common/showmsg.h +++ b/src/common/showmsg.h @@ -1,11 +1,13 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams #ifndef _SHOWMSG_H_ #define _SHOWMSG_H_ -#include "libconfig.h" - +#ifndef _HPMi_H_ + #include "libconfig.h" +#endif // for help with the console colors look here: // http://www.edoceo.com/liberum/?doc=printf-with-color // some code explanation (used here): @@ -85,15 +87,17 @@ enum msg_type { }; extern void ClearScreen(void); -extern void ShowMessage(const char *, ...); -extern void ShowStatus(const char *, ...); -extern void ShowSQL(const char *, ...); -extern void ShowInfo(const char *, ...); -extern void ShowNotice(const char *, ...); -extern void ShowWarning(const char *, ...); -extern void ShowDebug(const char *, ...); -extern void ShowError(const char *, ...); -extern void ShowFatalError(const char *, ...); -extern void ShowConfigWarning(config_setting_t *config, const char *string, ...); +#ifndef _HPMi_H_ + extern void ShowMessage(const char *, ...); + extern void ShowStatus(const char *, ...); + extern void ShowSQL(const char *, ...); + extern void ShowInfo(const char *, ...); + extern void ShowNotice(const char *, ...); + extern void ShowWarning(const char *, ...); + extern void ShowDebug(const char *, ...); + extern void ShowError(const char *, ...); + extern void ShowFatalError(const char *, ...); + extern void ShowConfigWarning(config_setting_t *config, const char *string, ...); +#endif #endif /* _SHOWMSG_H_ */ -- cgit v1.2.3-70-g09d2