diff options
-rw-r--r-- | Changelog-Trunk.txt | 7 | ||||
-rw-r--r-- | conf-tmpl/Changelog.txt | 2 | ||||
-rw-r--r-- | conf-tmpl/plugin_athena.conf | 5 | ||||
-rw-r--r-- | src/char/char.c | 46 | ||||
-rw-r--r-- | src/char_sql/char.c | 46 | ||||
-rw-r--r-- | src/common/core.c | 4 | ||||
-rw-r--r-- | src/common/core.h | 1 | ||||
-rw-r--r-- | src/common/plugin.h | 59 | ||||
-rw-r--r-- | src/common/plugins.c | 358 | ||||
-rw-r--r-- | src/common/plugins.h | 33 | ||||
-rw-r--r-- | src/common/socket.c | 20 | ||||
-rw-r--r-- | src/login/login.c | 15 | ||||
-rw-r--r-- | src/login_sql/login.c | 44 | ||||
-rw-r--r-- | src/map/map.c | 44 | ||||
-rw-r--r-- | src/plugins/console.c | 226 | ||||
-rw-r--r-- | vcproj-8/plugin.def | 4 |
16 files changed, 640 insertions, 274 deletions
diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt index 54da5ccc4..0137b69e6 100644 --- a/Changelog-Trunk.txt +++ b/Changelog-Trunk.txt @@ -3,6 +3,13 @@ Date Added AS OF SVN REV. 5091, WE ARE NOW USING TRUNK. ALL UNTESTED BUGFIXES/FEATURES GO INTO TRUNK. IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK. +2007/01/08 + * Added a precompiler error when the shutdown defines are not found. + * Added parse_console to the plugin API. + * Added plugin for parsing the console. (working with cygwin) + * Copied the parse_console code form login txt to login sql and char. + * Added propper plugin version compatibility tests. + * Better output when a plugin fails to load. [FlavioJS] 2007/01/07 * Fixed the sleep timers not being removed when the an npc was being unloaded and when reloading scripts. [FlavioJS] diff --git a/conf-tmpl/Changelog.txt b/conf-tmpl/Changelog.txt index d9910db55..fc194dca4 100644 --- a/conf-tmpl/Changelog.txt +++ b/conf-tmpl/Changelog.txt @@ -1,5 +1,7 @@ Date Added +2007/01/08 + * Added the console plugin to plugin_athena.conf commented out. [FlavioJS] 2007/01/05 * Updated noicewall mapflags (to allow them in cities), thanks to Au{R}oN 2007/01/03 diff --git a/conf-tmpl/plugin_athena.conf b/conf-tmpl/plugin_athena.conf index c4b889da8..306fddf71 100644 --- a/conf-tmpl/plugin_athena.conf +++ b/conf-tmpl/plugin_athena.conf @@ -26,4 +26,7 @@ plugin: upnp //plugin: pid // Built-in webserver -//plugin: httpd
\ No newline at end of file +//plugin: httpd + +// Console parser +//plugin: console diff --git a/src/char/char.c b/src/char/char.c index 262adb86f..a7a199f12 100644 --- a/src/char/char.c +++ b/src/char/char.c @@ -3856,27 +3856,33 @@ int parse_char(int fd) { } // Console Command Parser [Wizputer] -int parse_console(char *buf) { - char *type,*command; - - type = (char *)aCalloc(64,1); - command = (char *)aCalloc(64,1); - -// memset(type,0,64); -// memset(command,0,64); - - ShowStatus("Console: %s\n",buf); - - if ( sscanf(buf, "%[^:]:%[^\n]", type , command ) < 2 ) - sscanf(buf,"%[^\n]",type); - - ShowDebug("Type of command: %s || Command: %s \n",type,command); - - if(buf) aFree(buf); - if(type) aFree(type); - if(command) aFree(command); +int parse_console(char* buf) +{ + char command[256]; + + memset(command, 0, sizeof(command)); + + sscanf(buf, "%[^\n]", command); + + //login_log("Console command :%s" RETCODE, command); + + if( strcmpi("shutdown", command) == 0 || + strcmpi("exit", command) == 0 || + strcmpi("quit", command) == 0 || + strcmpi("end", command) == 0 ) + runflag = 0; + else if( strcmpi("alive", command) == 0 || + strcmpi("status", command) == 0 ) + ShowInfo(CL_CYAN"Console: "CL_BOLD"I'm Alive."CL_RESET"\n"); + else if( strcmpi("help", command) == 0 ){ + printf(CL_BOLD"Help of commands:"CL_RESET"\n"); + printf(" To shutdown the server:\n"); + printf(" 'shutdown|exit|qui|end'\n"); + printf(" To know if server is alive:\n"); + printf(" 'alive|status'\n"); + } - return 0; + return 0; } // 全てのMAPサーバーにデータ送信(送信したmap鯖の数を返す) diff --git a/src/char_sql/char.c b/src/char_sql/char.c index 4851fbaca..2cf237317 100644 --- a/src/char_sql/char.c +++ b/src/char_sql/char.c @@ -3648,27 +3648,33 @@ int parse_char(int fd) { } // Console Command Parser [Wizputer] -int parse_console(char *buf) { - char *type,*command; - - type = (char *)aMalloc(64); - command = (char *)aMalloc(64); - - memset(type,0,64); - memset(command,0,64); - - ShowNotice("Console: %s\n",buf); - - if ( sscanf(buf, "%[^:]:%[^\n]", type , command ) < 2 ) - sscanf(buf,"%[^\n]",type); - - ShowNotice("Type of command: %s || Command: %s \n",type,command); - - if(buf) aFree(buf); - if(type) aFree(type); - if(command) aFree(command); +int parse_console(char* buf) +{ + char command[256]; + + memset(command, 0, sizeof(command)); + + sscanf(buf, "%[^\n]", command); + + //login_log("Console command :%s" RETCODE, command); + + if( strcmpi("shutdown", command) == 0 || + strcmpi("exit", command) == 0 || + strcmpi("quit", command) == 0 || + strcmpi("end", command) == 0 ) + runflag = 0; + else if( strcmpi("alive", command) == 0 || + strcmpi("status", command) == 0 ) + ShowInfo(CL_CYAN"Console: "CL_BOLD"I'm Alive."CL_RESET"\n"); + else if( strcmpi("help", command) == 0 ){ + printf(CL_BOLD"Help of commands:"CL_RESET"\n"); + printf(" To shutdown the server:\n"); + printf(" 'shutdown|exit|qui|end'\n"); + printf(" To know if server is alive:\n"); + printf(" 'alive|status'\n"); + } - return 0; + return 0; } // MAP send all diff --git a/src/common/core.c b/src/common/core.c index e8fd48923..b5db552e6 100644 --- a/src/common/core.c +++ b/src/common/core.c @@ -259,7 +259,7 @@ int main (int argc, char **argv) do_init(argc,argv); graph_init(); - plugin_event_trigger("Athena_Init"); + plugin_event_trigger(EVENT_ATHENA_INIT); {// Main runtime cycle int next; @@ -272,7 +272,7 @@ int main (int argc, char **argv) } } - plugin_event_trigger("Athena_Final"); + plugin_event_trigger(EVENT_ATHENA_FINAL); graph_final(); do_final(); diff --git a/src/common/core.h b/src/common/core.h index fffd44028..06ce86448 100644 --- a/src/common/core.h +++ b/src/common/core.h @@ -13,6 +13,7 @@ extern int runflag; extern char *SERVER_NAME; extern char SERVER_TYPE; +extern int parse_console(char* buf); extern const char *get_svn_revision(void); extern int do_init(int,char**); extern void set_server_type(void); diff --git a/src/common/plugin.h b/src/common/plugin.h index 402636b1d..f30a15e5e 100644 --- a/src/common/plugin.h +++ b/src/common/plugin.h @@ -4,23 +4,44 @@ #ifndef _PLUGIN_H_ #define _PLUGIN_H_ +#include "cbasetypes.h" + ////// Plugin functions /////////////// -#define PLUGIN_VERSION "1.02" +// Plugin version <major version>.<minor version> +// * <major version> is increased and <minor version> reset when at least one +// export of the previous version becomes incompatible +// * <minor version> is increased if the previous version remains compatible +// +// Compatible plugins have: +// - equal major version +// - lower or equal minor version +#define PLUGIN_VERSION "1.03" typedef struct _Plugin_Info { - char *name; + char* name; char type; - char *version; - char *req_version; - char *description; + char* version; + char* req_version; + char* description; } Plugin_Info; typedef struct _Plugin_Event_Table { - char *func_name; - char *event_name; + char* func_name; + char* event_name; } Plugin_Event_Table; +// Format of the test function +typedef int Plugin_Test_Func(void); +#define EVENT_PLUGIN_INIT "Plugin_Init" // Initialize the plugin +#define EVENT_PLUGIN_FINAL "Plugin_Final" // Finalize the plugin +#define EVENT_ATHENA_INIT "Athena_Init" // Server started +#define EVENT_ATHENA_FINAL "Athena_Final" // Server ended + +// Format of event functions +typedef void Plugin_Event_Func(void); +#define EVENT_PLUGIN_TEST "Plugin_Test" // Test the plugin for compatibility + ////// Plugin Export functions ///////////// #define PLUGIN_ALL 0 @@ -31,10 +52,32 @@ typedef struct _Plugin_Event_Table { #define IMPORT_SYMBOL(s,n) (s) = plugin_call_table[n] +#define SYMBOL_SERVER_TYPE 0 +#define SYMBOL_SERVER_NAME 1 +#define SYMBOL_ARG_C 2 +#define SYMBOL_ARG_V 3 +#define SYMBOL_RUNFLAG 4 +#define SYMBOL_GETTICK 5 +#define SYMBOL_GET_SVN_REVISION 6 +#define SYMBOL_ADD_TIMER 7 +#define SYMBOL_ADD_TIMER_INTERVAL 8 +#define SYMBOL_ADD_TIMER_FUNC_LIST 9 +#define SYMBOL_DELETE_TIMER 10 +#define SYMBOL_GET_UPTIME 11 +#define SYMBOL_ADDR 12 +#define SYMBOL_FD_MAX 13 +#define SYMBOL_SESSION 14 +#define SYMBOL_DELETE_SESSION 15 +#define SYMBOL_WFIFOSET 16 +#define SYMBOL_RFIFOSKIP 17 +#define SYMBOL_FUNC_PARSE_TABLE 18 +// 1.03 +#define SYMBOL_PARSE_CONSOLE 19 + ////// Global Plugin variables ///////////// #define PLUGIN_INFO struct _Plugin_Info plugin_info #define PLUGIN_EVENTS_TABLE struct _Plugin_Event_Table plugin_event_table[] -void **plugin_call_table; +void** plugin_call_table; #endif // _PLUGIN_H_ diff --git a/src/common/plugins.c b/src/common/plugins.c index 3dcddcb3d..4d3849330 100644 --- a/src/common/plugins.c +++ b/src/common/plugins.c @@ -1,14 +1,6 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#ifndef _WIN32 -#include <unistd.h> -#endif - -#include "plugin.h" #include "plugins.h" #include "../common/mmo.h" #include "../common/core.h" @@ -19,99 +11,109 @@ #include "../common/version.h" #include "../common/showmsg.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#ifndef WIN32 +#include <unistd.h> +#endif + ////////////////////////////////////////////// typedef struct _Plugin_Event { - void (*func)(void); - struct _Plugin_Event *next; + struct _Plugin_Event* next; + Plugin_Event_Func* func; } Plugin_Event; typedef struct _Plugin_Event_List { - char *name; - struct _Plugin_Event_List *next; - struct _Plugin_Event *events; + struct _Plugin_Event_List* next; + char* name; + struct _Plugin_Event* events; } Plugin_Event_List; -static int auto_search = 1; +static int auto_search = 0; static int load_priority = 0; -Plugin_Event_List *event_head = NULL; -Plugin *plugin_head = NULL; +Plugin_Event_List* event_head = NULL; +Plugin* plugin_head = NULL; -Plugin_Info default_info = { "Unknown", PLUGIN_ALL, "0", PLUGIN_VERSION, "Unknown" }; +static Plugin_Info default_info = { "Unknown", PLUGIN_ALL, "0", PLUGIN_VERSION, "Unknown" }; static size_t call_table_size = 0; static size_t max_call_table = 0; ////// Plugin Events Functions ////////////////// -int register_plugin_func (char *name) +int register_plugin_func(char* name) { - Plugin_Event_List *evl; - if (name) { - evl = (Plugin_Event_List *) aMalloc(sizeof(Plugin_Event_List)); - evl->name = (char *) aMalloc (strlen(name) + 1); - + Plugin_Event_List* evl; + if( name ){ + //ShowDebug("register_plugin_func(%s)\n", name); + CREATE(evl, Plugin_Event_List, 1); evl->next = event_head; - strcpy(evl->name, name); + evl->name = aStrdup(name); evl->events = NULL; event_head = evl; } return 0; } -Plugin_Event_List *search_plugin_func (char *name) +static Plugin_Event_List* search_plugin_func(char* name) { - Plugin_Event_List *evl = event_head; - while (evl) { - if (strcmpi(evl->name, name) == 0) + Plugin_Event_List* evl = event_head; + while( evl ){ + if( strcmpi(evl->name,name) == 0 ) return evl; evl = evl->next; } return NULL; } -int register_plugin_event (void (*func)(void), char* name) +int register_plugin_event(Plugin_Event_Func* func, char* name) { - Plugin_Event_List *evl = search_plugin_func(name); - if (!evl) { - // register event if it doesn't exist already + Plugin_Event_List* evl = search_plugin_func(name); + //ShowDebug("register_plugin_event(0x%x, %s)\n", func, name); + if( !evl ) + {// event does not exist, register register_plugin_func(name); - // relocate the new event list + // get the new event list evl = search_plugin_func(name); } - if (evl) { - Plugin_Event *ev; + if( evl ){ + Plugin_Event* ev; - ev = (Plugin_Event *) aMalloc(sizeof(Plugin_Event)); + CREATE(ev, Plugin_Event, 1); ev->func = func; ev->next = NULL; - if (evl->events == NULL) + // insert event at the end of the linked list + if( evl->events == NULL ) evl->events = ev; else { - Plugin_Event *ev2 = evl->events; - while (ev2) { - if (ev2->next == NULL) { - ev2->next = ev; + Plugin_Event* last_ev = evl->events; + while( last_ev ){ + if( last_ev->next == NULL ){ + last_ev->next = ev; break; } - ev2 = ev2->next; + last_ev = last_ev->next; } } } return 0; } -int plugin_event_trigger (char *name) +int plugin_event_trigger(char* name) { int c = 0; - Plugin_Event_List *evl = search_plugin_func(name); - if (evl) { - Plugin_Event *ev = evl->events; - while (ev) { + Plugin_Event_List* evl = search_plugin_func(name); + //ShowDebug("plugin_event_trigger(%s)\n", name); + if( evl ){ + Plugin_Event* ev = evl->events; + while( ev ){ ev->func(); + //ShowDebug("plugin_event_trigger: Executing function 0x%x.\n", ev->func); ev = ev->next; - c++; + ++c; } } return c; @@ -119,27 +121,27 @@ int plugin_event_trigger (char *name) ////// Plugins Call Table Functions ///////// -int export_symbol (void *var, int offset) +int export_symbol(void* var, size_t offset) { - //printf ("0x%x\n", var); - + ShowDebug("export_symbol(0x%x,%d)\n", var,offset); + // add to the end of the list - if (offset < 0) + if( offset < 0 ) offset = call_table_size; - - // realloc if not large enough - if ((size_t)offset >= max_call_table) { + + if( offset >= max_call_table ) + {// realloc if not large enough max_call_table = 1 + offset; - plugin_call_table = (void**)aRealloc(plugin_call_table, max_call_table*sizeof(void*)); - + RECREATE(plugin_call_table, void*, max_call_table); + // clear the new alloced block memset(plugin_call_table + call_table_size, 0, (max_call_table-call_table_size)*sizeof(void*)); } // the new table size is delimited by the new element at the end - if ((size_t)offset >= call_table_size) + if( offset >= call_table_size ) call_table_size = offset+1; - + // put the pointer at the selected place plugin_call_table[offset] = var; return 0; @@ -147,106 +149,139 @@ int export_symbol (void *var, int offset) ////// Plugins Core ///////////////////////// -Plugin *plugin_open (const char *filename) +static int plugin_iscompatible(char* version) +{ + int req_major = 0; + int req_minor = 0; + int major = 0; + int minor = 0; + + if( version == NULL ) + return 0; + sscanf(version, "%d.%d", &req_major, &req_minor); + sscanf(version, "%d.%d", &major, &minor); + return ( req_major == major || req_minor <= minor ); +} + +Plugin* plugin_open(const char* filename) { - Plugin *plugin; - Plugin_Info *info; - Plugin_Event_Table *events; - void **procs; + Plugin* plugin; + Plugin_Info* info; + Plugin_Event_Table* events; + void** procs; int init_flag = 1; - //printf ("loading %s\n", filename); + //ShowDebug("plugin_open(%s)\n", filename); // Check if the plugin has been loaded before plugin = plugin_head; while (plugin) { // returns handle to the already loaded plugin - if (plugin->state && strcmpi(plugin->filename, filename) == 0) { - //printf ("not loaded (duplicate) : %s\n", filename); + if( plugin->state && strcmpi(plugin->filename, filename) == 0 ){ + ShowWarning("plugin_open: not loaded (duplicate) : '"CL_WHITE"%s"CL_RESET"'\n", filename); return plugin; } plugin = plugin->next; } - plugin = (Plugin *)aCalloc(1, sizeof(Plugin)); + CREATE(plugin, Plugin, 1); plugin->state = -1; // not loaded plugin->dll = DLL_OPEN(filename); - if (!plugin->dll) { - //printf ("not loaded (invalid file) : %s\n", filename); + if( !plugin->dll ){ + ShowWarning("plugin_open: not loaded (invalid file) : '"CL_WHITE"%s"CL_RESET"'\n", filename); plugin_unload(plugin); return NULL; } - + // Retrieve plugin information plugin->state = 0; // initialising - DLL_SYM (info, plugin->dll, "plugin_info"); + DLL_SYM(info, plugin->dll, "plugin_info"); // For high priority plugins (those that are explicitly loaded from the conf file) // we'll ignore them even (could be a 3rd party dll file) - if ((!info && load_priority == 0) || - (info && ((atof(info->req_version) < atof(PLUGIN_VERSION)) || // plugin is based on older code - (info->type != PLUGIN_ALL && info->type != PLUGIN_CORE && info->type != SERVER_TYPE) || // plugin is not for this server - (info->type == PLUGIN_CORE && SERVER_TYPE != PLUGIN_LOGIN && SERVER_TYPE != PLUGIN_CHAR && SERVER_TYPE != PLUGIN_MAP)))) - { - //printf ("not loaded (incompatible) : %s\n", filename); + if( !info ) + {// foreign plugin + //ShowDebug("plugin_open: plugin_info not found\n"); + if( load_priority == 0 ) + {// not requested + //ShowDebug("plugin_open: not loaded (not requested) : '"CL_WHITE"%s"CL_RESET"'\n", filename); + plugin_unload(plugin); + return NULL; + } + } else if( !plugin_iscompatible(info->req_version) ) + {// incompatible version + ShowWarning("plugin_open: not loaded (incompatible version '%s' -> '%s') : '"CL_WHITE"%s"CL_RESET"'\n", info->req_version, PLUGIN_VERSION, filename); + plugin_unload(plugin); + return NULL; + } else if( (info->type != PLUGIN_ALL && info->type != PLUGIN_CORE && info->type != SERVER_TYPE) || + (info->type == PLUGIN_CORE && SERVER_TYPE != PLUGIN_LOGIN && SERVER_TYPE != PLUGIN_CHAR && SERVER_TYPE != PLUGIN_MAP) ) + {// not for this server + //ShowDebug("plugin_open: not loaded (incompatible) : '"CL_WHITE"%s"CL_RESET"'\n", filename); plugin_unload(plugin); return NULL; } - plugin->info = (info) ? info : &default_info; - plugin->filename = (char *) aMalloc (strlen(filename) + 1); - strcpy(plugin->filename, filename); + plugin->info = ( info != NULL ? info : &default_info ); + plugin->filename = aStrdup(filename); // Initialise plugin call table (For exporting procedures) - DLL_SYM (procs, plugin->dll, "plugin_call_table"); - if (procs) *procs = plugin_call_table; - + DLL_SYM(procs, plugin->dll, "plugin_call_table"); + if( procs ) + *procs = plugin_call_table; + //else ShowDebug("plugin_open: plugin_call_table not found\n"); + // Register plugin events - DLL_SYM (events, plugin->dll, "plugin_event_table"); - if (events) { + DLL_SYM(events, plugin->dll, "plugin_event_table"); + if( events ){ int i = 0; - while (events[i].func_name) { - if (strcmpi(events[i].event_name, "Plugin_Test") == 0) { - int (*test_func)(void); - DLL_SYM (test_func, plugin->dll, events[i].func_name); - if (test_func && test_func() == 0) { + //ShowDebug("plugin_open: parsing plugin_event_table\n"); + while( events[i].func_name ){ + if( strcmpi(events[i].event_name, EVENT_PLUGIN_TEST) == 0 ){ + Plugin_Test_Func* test_func; + DLL_SYM(test_func, plugin->dll, events[i].func_name); + //ShowDebug("plugin_open: invoking "EVENT_PLUGIN_TEST" with %s()\n", events[i].func_name); + if( test_func && test_func() == 0 ){ // plugin has failed test, disabling - //printf ("disabled (failed test) : %s\n", filename); + //ShowDebug("plugin_open: disabled (failed test) : %s\n", filename); init_flag = 0; } } else { - void (*func)(void); - DLL_SYM (func, plugin->dll, events[i].func_name); - if (func) register_plugin_event (func, events[i].event_name); + Plugin_Event_Func* func; + DLL_SYM(func, plugin->dll, events[i].func_name); + if (func) + register_plugin_event(func, events[i].event_name); } i++; } } + //else ShowDebug("plugin_open: plugin_event_table not found\n"); plugin->next = plugin_head; plugin_head = plugin; plugin->state = init_flag; // fully loaded - ShowStatus ("Done loading plugin '"CL_WHITE"%s"CL_RESET"'\n", (info) ? plugin->info->name : filename); + ShowStatus("Done loading plugin '"CL_WHITE"%s"CL_RESET"'\n", (info) ? plugin->info->name : filename); return plugin; } -void plugin_load (const char *filename) +void plugin_load(const char* filename) { plugin_open(filename); } -void plugin_unload (Plugin *plugin) +void plugin_unload(Plugin* plugin) { - if (plugin == NULL) + if( plugin == NULL ) return; - if (plugin->filename) aFree(plugin->filename); - if (plugin->dll) DLL_CLOSE(plugin->dll); + if( plugin->filename ) + aFree(plugin->filename); + if( plugin->dll ) + DLL_CLOSE(plugin->dll); aFree(plugin); } -#ifdef _WIN32 +#ifdef WIN32 char *DLL_ERROR(void) { static char dllbuf[80]; @@ -258,107 +293,114 @@ char *DLL_ERROR(void) ////// Initialize/Finalize //////////////////// -int plugins_config_read(const char *cfgName) +static int plugins_config_read(const char *cfgName) { char line[1024], w1[1024], w2[1024]; FILE *fp; fp = fopen(cfgName, "r"); - if (fp == NULL) { + if( fp == NULL ){ ShowError("File not found: %s\n", cfgName); return 1; } - while (fgets(line, 1020, fp)) { - if(line[0] == '/' && line[1] == '/') + while( fgets(line, 1020, fp) ){ + if( line[0] == '/' && line[1] == '/' ) continue; - if (sscanf(line,"%[^:]: %[^\r\n]", w1, w2) != 2) + if( sscanf(line,"%[^:]: %[^\r\n]",w1,w2) != 2 ) continue; - if (strcmpi(w1, "auto_search") == 0) { - if(strcmpi(w2, "yes")==0) + if( strcmpi(w1,"auto_search") == 0 ){ + if( strcmpi(w2,"yes") == 0 ) auto_search = 1; - else if(strcmpi(w2, "no")==0) + else if( strcmpi(w2,"no") == 0 ) auto_search = 0; - else auto_search = atoi(w2); - } else if (strcmpi(w1, "plugin") == 0) { + else + auto_search = atoi(w2); + } else if( strcmpi(w1,"plugin") == 0 ){ char filename[128]; - sprintf (filename, "plugins/%s%s", w2, DLL_EXT); + sprintf(filename, "plugins/%s%s", w2, DLL_EXT); plugin_load(filename); - } else if (strcmpi(w1, "import") == 0) + } else if( strcmpi(w1,"import") == 0 ) plugins_config_read(w2); } fclose(fp); return 0; } -void plugins_init (void) +void plugins_init(void) { - char *PLUGIN_CONF_FILENAME = "conf/plugin_athena.conf"; - register_plugin_func("Plugin_Init"); - register_plugin_func("Plugin_Final"); - register_plugin_func("Athena_Init"); - register_plugin_func("Athena_Final"); + char* PLUGIN_CONF_FILENAME = "conf/plugin_athena.conf"; + //ShowDebug("plugins_init()\n"); + register_plugin_func(EVENT_PLUGIN_INIT); + register_plugin_func(EVENT_PLUGIN_FINAL); + register_plugin_func(EVENT_ATHENA_INIT); + register_plugin_func(EVENT_ATHENA_FINAL); // networking - export_symbol (func_parse_table, 18); - export_symbol (RFIFOSKIP, 17); - export_symbol (WFIFOSET, 16); - export_symbol (delete_session, 15); - export_symbol (session, 14); - export_symbol (&fd_max, 13); - export_symbol (addr_, 12); + export_symbol(func_parse_table, SYMBOL_FUNC_PARSE_TABLE); + export_symbol(RFIFOSKIP, SYMBOL_RFIFOSKIP); + export_symbol(WFIFOSET, SYMBOL_WFIFOSET); + export_symbol(delete_session, SYMBOL_DELETE_SESSION); + export_symbol(session, SYMBOL_SESSION); + export_symbol(&fd_max, SYMBOL_FD_MAX); + export_symbol(addr_, SYMBOL_ADDR); // timers - export_symbol (get_uptime, 11); - export_symbol (delete_timer, 10); - export_symbol (add_timer_func_list, 9); - export_symbol (add_timer_interval, 8); - export_symbol (add_timer, 7); - export_symbol ((void *)get_svn_revision, 6); - export_symbol (gettick, 5); + export_symbol(get_uptime, SYMBOL_GET_UPTIME); + export_symbol(delete_timer, SYMBOL_DELETE_TIMER); + export_symbol(add_timer_func_list, SYMBOL_ADD_TIMER_FUNC_LIST); + export_symbol(add_timer_interval, SYMBOL_ADD_TIMER_INTERVAL); + export_symbol(add_timer, SYMBOL_ADD_TIMER); + export_symbol((void*)get_svn_revision, SYMBOL_GET_SVN_REVISION); + export_symbol(gettick, SYMBOL_GETTICK); // core - export_symbol (&runflag, 4); - export_symbol (arg_v, 3); - export_symbol (&arg_c, 2); - export_symbol (SERVER_NAME, 1); - export_symbol (&SERVER_TYPE, 0); + export_symbol(parse_console, SYMBOL_PARSE_CONSOLE); + export_symbol(&runflag, SYMBOL_RUNFLAG); + export_symbol(arg_v, SYMBOL_ARG_V); + export_symbol(&arg_c, SYMBOL_ARG_C); + export_symbol(SERVER_NAME, SYMBOL_SERVER_NAME); + export_symbol(&SERVER_TYPE, SYMBOL_SERVER_TYPE); load_priority = 1; - plugins_config_read (PLUGIN_CONF_FILENAME); + plugins_config_read(PLUGIN_CONF_FILENAME); load_priority = 0; - if (auto_search) + if( auto_search ) findfile("plugins", DLL_EXT, plugin_load); - plugin_event_trigger("Plugin_Init"); + plugin_event_trigger(EVENT_PLUGIN_INIT); return; } -void plugins_final (void) +void plugins_final(void) { - Plugin *plugin = plugin_head, *plugin2; - Plugin_Event_List *evl = event_head, *evl2; - Plugin_Event *ev, *ev2; - - plugin_event_trigger("Plugin_Final"); - - while (plugin) { - plugin2 = plugin->next; + Plugin* plugin = plugin_head; + Plugin* next_plugin; + Plugin_Event_List* evl = event_head; + Plugin_Event_List* next_evl; + Plugin_Event* ev; + Plugin_Event* next_ev; + + //ShowDebug("plugins_final()\n"); + plugin_event_trigger(EVENT_PLUGIN_FINAL); + + while( plugin ){ + next_plugin = plugin->next; plugin_unload(plugin); - plugin = plugin2; + plugin = next_plugin; } - while (evl) { + while( evl ){ ev = evl->events; - while (ev) { - ev2 = ev->next; + while( ev ){ + next_ev = ev->next; aFree(ev); - ev = ev2; + ev = next_ev; } - evl2 = evl->next; + next_evl = evl->next; aFree(evl->name); aFree(evl); - evl = evl2; + evl = next_evl; } aFree(plugin_call_table); diff --git a/src/common/plugins.h b/src/common/plugins.h index 34fd18a64..9cb4b94b4 100644 --- a/src/common/plugins.h +++ b/src/common/plugins.h @@ -4,17 +4,20 @@ #ifndef _PLUGINS_H_ #define _PLUGINS_H_ +#include "../common/plugin.h" + ////// Dynamic Link Library functions /////////////// -#ifdef _WIN32 +#ifdef WIN32 #include <windows.h> #define DLL_OPEN(x) LoadLibrary(x) #define DLL_SYM(x,y,z) (FARPROC)(x) = GetProcAddress(y,z) #define DLL_CLOSE(x) FreeLibrary(x) + char *DLL_ERROR(void); + #define DLL_EXT ".dll" #define DLL HINSTANCE - char *DLL_ERROR(void); #else @@ -31,6 +34,8 @@ #endif #define DLL void * + #include <string.h> // size_t + #endif ////// Plugin Definitions /////////////////// @@ -38,24 +43,24 @@ typedef struct _Plugin { DLL dll; char state; - char *filename; - struct _Plugin_Info *info; - struct _Plugin *next; + char* filename; + struct _Plugin_Info* info; + struct _Plugin* next; } Plugin; ///////////////////////////////////////////// -int register_plugin_func (char *); -int register_plugin_event (void (*)(void), char *); -int plugin_event_trigger (char *); +int register_plugin_func(char* name); +int register_plugin_event(Plugin_Event_Func* func, char* name); +int plugin_event_trigger(char* name); -int export_symbol (void *, int); +int export_symbol(void* var, size_t offset); #define EXPORT_SYMBOL(s) export_symbol((s), -1); -Plugin *plugin_open (const char *); -void plugin_load (const char *); -void plugin_unload (Plugin *); -void plugins_init (void); -void plugins_final (void); +Plugin* plugin_open(const char* filename); +void plugin_load(const char* filename); +void plugin_unload(Plugin* plugin); +void plugins_init(void); +void plugins_final(void); #endif // _PLUGINS_H_ diff --git a/src/common/socket.c b/src/common/socket.c index 04793094c..3d445d286 100644 --- a/src/common/socket.c +++ b/src/common/socket.c @@ -57,10 +57,14 @@ #include "../common/showmsg.h" /// shutdown() constants -#if defined(SD_RECEIVE) && !defined(SHUT_RD) -#define SHUT_RD SD_RECEIVE -#define SHUT_WR SD_SEND -#define SHUT_RDWR SD_BOTH +#ifndef SHUT_RD +#ifdef SD_RECEIVE + #define SHUT_RD SD_RECEIVE + #define SHUT_WR SD_SEND + #define SHUT_RDWR SD_BOTH +#else + #error "Unknown socket constants, please report this to a developer" +#endif #endif fd_set readfds; @@ -423,12 +427,12 @@ void func_parse_check (struct socket_data *sd) } // Console Input [Wizputer] -int start_console(void) { - +int start_console(void) +{ //Until a better plan is came up with... can't be using session[0] anymore! [Skotlex] ShowNotice("The console is currently nonfunctional.\n"); return 0; - + FD_SET(0,&readfds); if (!session[0]) { // dummy socket already uses fd 0 @@ -1197,7 +1201,7 @@ int socket_getips(uint32 *ips, int max) void socket_init(void) { char *SOCKET_CONF_FILENAME = "conf/packet_athena.conf"; - + #ifdef WIN32 {// Start up windows networking WSADATA wsaData; diff --git a/src/login/login.c b/src/login/login.c index 3c38c738c..84d6afd0f 100644 --- a/src/login/login.c +++ b/src/login/login.c @@ -3466,24 +3466,25 @@ int parse_login(int fd) { //----------------------- // Console Command Parser [Wizputer] //----------------------- -int parse_console(char *buf) { +int parse_console(char *buf) +{ char command[256]; - memset(command,0,sizeof(command)); + memset(command, 0, sizeof(command)); sscanf(buf, "%[^\n]", command); login_log("Console command :%s" RETCODE, command); - if(strcmpi("shutdown", command) == 0 || + if( strcmpi("shutdown", command) == 0 || strcmpi("exit", command) == 0 || strcmpi("quit", command) == 0 || - strcmpi("end", command) == 0) + strcmpi("end", command) == 0 ) runflag = 0; - else if(strcmpi("alive", command) == 0 || - strcmpi("status", command) == 0) + else if( strcmpi("alive", command) == 0 || + strcmpi("status", command) == 0 ) ShowInfo(CL_CYAN"Console: "CL_BOLD"I'm Alive."CL_RESET"\n"); - else if(strcmpi("help", command) == 0) { + else if( strcmpi("help", command) == 0 ){ printf(CL_BOLD"Help of commands:"CL_RESET"\n"); printf(" To shutdown the server:\n"); printf(" 'shutdown|exit|qui|end'\n"); diff --git a/src/login_sql/login.c b/src/login_sql/login.c index 350fe4e1b..b1e85a4c3 100644 --- a/src/login_sql/login.c +++ b/src/login_sql/login.c @@ -1951,25 +1951,31 @@ int parse_login(int fd) { } // Console Command Parser [Wizputer] -int parse_console(char *buf) { - char *type,*command; - - type = (char *)aMalloc(64); - command = (char *)aMalloc(64); - - memset(type,0,64); - memset(command,0,64); - - ShowInfo("Console: %s\n",buf); - - if ( sscanf(buf, "%[^:]:%[^\n]", type , command ) < 2 ) - sscanf(buf,"%[^\n]",type); - - ShowInfo("Type of command: %s || Command: %s \n",type,command); - - if(buf) aFree(buf); - if(type) aFree(type); - if(command) aFree(command); +int parse_console(char* buf) +{ + char command[256]; + + memset(command, 0, sizeof(command)); + + sscanf(buf, "%[^\n]", command); + + login_log("Console command :%s" RETCODE, command); + + if( strcmpi("shutdown", command) == 0 || + strcmpi("exit", command) == 0 || + strcmpi("quit", command) == 0 || + strcmpi("end", command) == 0 ) + runflag = 0; + else if( strcmpi("alive", command) == 0 || + strcmpi("status", command) == 0 ) + ShowInfo(CL_CYAN"Console: "CL_BOLD"I'm Alive."CL_RESET"\n"); + else if( strcmpi("help", command) == 0 ){ + printf(CL_BOLD"Help of commands:"CL_RESET"\n"); + printf(" To shutdown the server:\n"); + printf(" 'shutdown|exit|qui|end'\n"); + printf(" To know if server is alive:\n"); + printf(" 'alive|status'\n"); + } return 0; } diff --git a/src/map/map.c b/src/map/map.c index f17b05e02..6d1bb490d 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -3247,44 +3247,54 @@ static int char_ip_set = 0; * Console Command Parser [Wizputer] *------------------------------------------ */ -int parse_console(char *buf) { - char type[64],command[64],map[64]; - int x = 0, y = 0; - int m, n; +int parse_console(char* buf) +{ + char type[64]; + char command[64]; + char map[64]; + int x = 0; + int y = 0; + int m; + int n; struct map_session_data sd; memset(&sd, 0, sizeof(struct map_session_data)); - strcpy( sd.status.name , "console"); + strcpy(sd.status.name, "console"); - if ( ( n = sscanf(buf, "%[^:]:%[^:]:%99s %d %d[^\n]", type , command , map , &x , &y )) < 5 ) - if ( ( n = sscanf(buf, "%[^:]:%[^\n]", type , command )) < 2 ) + if( (n=sscanf(buf, "%[^:]:%[^:]:%99s %d %d[^\n]",type,command,map,&x,&y)) < 5 ) + if( (n=sscanf(buf, "%[^:]:%[^\n]",type,command)) < 2 ) n = sscanf(buf,"%[^\n]",type); - if ( n == 5 ) { + if( n == 5 ) { m = map_mapname2mapid(map); - if ( m < 0 ) { + if( m < 0 ){ ShowWarning("Console: Unknown map\n"); return 0; } sd.bl.m = m; map_search_freecell(&sd.bl, m, &sd.bl.x, &sd.bl.y, -1, -1, 0); - if (x > 0) + if( x > 0 ) sd.bl.x = x; - - if (y > 0) + if( y > 0 ) sd.bl.y = y; + } else { + map[0] = '\0'; + if( n < 2 ) command[0] = '\0'; + if( n < 1 ) type[0] = '\0'; } - ShowInfo("Type of command: %s || Command: %s || Map: %s Coords: %d %d\n",type,command,map,x,y); + ShowInfo("Type of command: '%s' || Command: '%s' || Map: '%s' Coords: %d %d\n", type, command, map, x, y); - if ( strcmpi("admin",type) == 0 && n == 5 ) { + if( n == 5 && strcmpi("admin",type) == 0 ){ if( is_atcommand_sub(sd.fd,&sd,command,99) == AtCommand_None ) printf("Console: not atcommand\n"); - } else if ( strcmpi("server",type) == 0 && n == 2 ) { - if ( strcmpi("shutdown", command) == 0 || strcmpi("exit",command) == 0 || strcmpi("quit",command) == 0 ) { + } else if( n == 2 && strcmpi("server",type) == 0 ){ + if( strcmpi("shutdown",command) == 0 || + strcmpi("exit",command) == 0 || + strcmpi("quit",command) == 0 ){ runflag = 0; } - } else if ( strcmpi("help",type) == 0 ) { + } else if( strcmpi("help",type) == 0 ){ ShowNotice("To use GM commands:\n"); printf("admin:<gm command>:<map of \"gm\"> <x> <y>\n"); printf("You can use any GM command that doesn't require the GM.\n"); diff --git a/src/plugins/console.c b/src/plugins/console.c new file mode 100644 index 000000000..41ef434e9 --- /dev/null +++ b/src/plugins/console.c @@ -0,0 +1,226 @@ +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#include "../common/plugin.h" + +#ifdef WIN32 + #define WIN32_LEAN_AND_MEAN + #include <windows.h> +#else + #include <sys/types.h> + #include <unistd.h> + #include <poll.h> + #include <string.h> +#endif +#include <stdio.h> // stdin, fgets + +#ifdef WIN32 + +#define THREAD_FUNC_START(name) DWORD WINAPI thread_ ## name(LPVOID lpParameter) { (void)lpParameter; { +#define THREAD_FUNC_END(name) } ExitThread(0); return 0; } +#define THREAD_EXECUTE(name,errvar) \ + do{ \ + int _fail_ = (CreateThread(NULL,0,thread_ ## name,NULL,0,NULL) == NULL); \ + if( errvar ) \ + *errvar = _fail_; \ + }while(0) +#define sleep Sleep + +#define pipe_create(p) ( CreatePipe(&p[PIPE_READ], &p[PIPE_WRITE], NULL, 1) != 0 ) +#define pipe_read(p,data,len) do{ DWORD _b_; ReadFile(p[PIPE_READ], data, len, &_b_, NULL); }while(0) +#define pipe_write(p,data,len) do{ DWORD _b_; WriteFile(p[PIPE_WRITE], data, len, &_b_, NULL); }while(0) +#define pipe_close(p,side) CloseHandle(p[side]) +typedef HANDLE PIPE[2]; + +#else + +#define THREAD_FUNC_START(name) void thread_ ## name(void) { +#define THREAD_FUNC_END(name) _exit(0); } +#define THREAD_EXECUTE(name,errvar) \ + do{ \ + int pid = fork(); \ + if( pid == 0 ){ \ + thread_ ## name(); \ + } \ + if( errvar ) \ + *errvar = (pid == -1); \ + }while(0) + +#define pipe_create(p) pipe(p) +#define pipe_read(p,data,len) read(p[PIPE_READ], data, len) +#define pipe_write(p,data,len) write(p[PIPE_WRITE], data, len) +#define pipe_close(p,side) close(p[side]) +typedef int PIPE[2]; + +#endif + +#define PIPE_READ 0 +#define PIPE_WRITE 1 +#define INPUT_BUFSIZE 4096 + +////// Plugin information //////// +// +PLUGIN_INFO = { + "Console", // Name + PLUGIN_ALL, // Target servers + "0.1", // Version + "1.03", // Minimum plugin engine version to run + "Console parser" // Short description +}; + +////// Plugin event list ////////// +// Format: <plugin function>,<event name> +// All registered functions to a event gets executed +// (In descending order) when its called. +// Multiple functions can be called by multiple events too, +// So it's up to your creativity ^^ +// +PLUGIN_EVENTS_TABLE = { + { "console_init", EVENT_PLUGIN_INIT }, + { "console_final", EVENT_PLUGIN_FINAL }, + { "console_start", EVENT_ATHENA_INIT }, + { "console_stop", EVENT_ATHENA_FINAL }, + { NULL, NULL } +}; + +///// Variables ///// + +typedef int TimerFunc(int tid, unsigned int tick, int id, int data); +int (*add_timer_func_list)(TimerFunc func, char* name); +int (*add_timer_interval)(unsigned int tick, TimerFunc* func, int id, int data, int interval); +int (*delete_timer)(int tid, TimerFunc* func); +unsigned int (*gettick)(void); +int (*parse_console)(char* buf); + +int tid; +PIPE data; +PIPE next; + +//////// Plugin functions ////////// + +static int pipe_hasdata(PIPE p) +{ +#ifdef WIN32 + return ( WaitForSingleObject(p[PIPE_READ],0) == WAIT_OBJECT_0 ); +#else + struct pollfd fds; + fds.fd = p[PIPE_READ]; + fds.events = POLLRDNORM; + return ( poll(&fds,1,0) > 0 ); +#endif +} + +int console_parsebuf(int tid, unsigned int tick, int id, int data_) +{ + //printf("console_parsebuf\n"); + //delete_timer(tid, console_parsebuf); + if( pipe_hasdata(data) ){ + char buf[INPUT_BUFSIZE]; + size_t len; + //printf("console_parsebuf pipe_hasdata\n"); + // receive string + pipe_read(data, &len, sizeof(size_t)); + pipe_read(data, &buf, len); + buf[len] = '\0'; + //printf("console_parsebuf buf='%s'\n", buf); + // parse it + parse_console(buf); + //printf("console_parsebuf writing next\n"); + // send next state + buf[0] = 'R'; + pipe_write(next, &buf, 1); + //printf("console_parsebuf done with next\n"); + } + return 0; +} + +THREAD_FUNC_START(readinput) + char buf[INPUT_BUFSIZE]; + char state = 'R'; + size_t len; + + //printf("thread_readinput START\n"); + pipe_close(data, PIPE_READ); + pipe_close(next, PIPE_WRITE); + buf[sizeof(buf)-1] = '\0'; + for( ; state != 'X'; ) + { + //printf("thread_readinput getting data\n"); + buf[0] = '\0'; + fgets(buf, sizeof(buf)-1, stdin); + len = strlen(buf); + //printf("thread_readinput buf='%s'\n", buf); + // send string + pipe_write(data, &len, sizeof(size_t)); + pipe_write(data, buf, len); + // receive next state + pipe_read(next, &state, sizeof(char)); + } + pipe_close(data, PIPE_WRITE); + pipe_close(next, PIPE_READ); + //printf("thread_readinput STOP (%d)\n", state); +THREAD_FUNC_END(readinput) + +void console_start(void) +{ + int error = 0; + //printf("console_start\n"); + if( pipe_create(data) ){ + //printf("console_start data pipe failed\n"); + return; + } + if( pipe_create(next) ){ + //printf("console_start next pipe failed\n"); + pipe_close(data, PIPE_READ); + pipe_close(data, PIPE_WRITE); + return; + } + THREAD_EXECUTE(readinput, &error); + if( error ){ + //printf("console_start thread start error\n"); + pipe_close(data, PIPE_READ); + pipe_close(next, PIPE_WRITE); + } else { + //printf("console_start thread started\n"); + //parse_console("help"); + add_timer_func_list(console_parsebuf,"console_parsebuf"); + tid = add_timer_interval(gettick(),console_parsebuf,0,0,1); // run once every cycle + } + pipe_close(data, PIPE_WRITE); + pipe_close(next, PIPE_READ); +} + +void console_stop(void) +{ + char c = 'X'; + //printf("console_stop\n"); + if( tid != -1 ){ + delete_timer(tid, console_parsebuf); + pipe_write(next, &c, sizeof(char)); + } + return; +} + +void console_init(void) +{ + //printf("console_init\n"); + // import symbols + IMPORT_SYMBOL(add_timer_interval, SYMBOL_ADD_TIMER_INTERVAL); + IMPORT_SYMBOL(add_timer_func_list, SYMBOL_ADD_TIMER_FUNC_LIST); + IMPORT_SYMBOL(delete_timer, SYMBOL_DELETE_TIMER); + IMPORT_SYMBOL(gettick, SYMBOL_GETTICK); + IMPORT_SYMBOL(parse_console, SYMBOL_PARSE_CONSOLE); + //printf("%d -> add_timer_func_list=0x%x\n", SYMBOL_ADD_TIMER_FUNC_LIST, (int)add_timer_func_list); + //printf("%d -> add_timer_interval=0x%x\n", SYMBOL_ADD_TIMER_INTERVAL, (int)add_timer_interval); + //printf("%d -> delete_timer=0x%x\n", SYMBOL_DELETE_TIMER, (int)delete_timer); + //printf("%d -> gettick=0x%x\n", SYMBOL_GETTICK, (int)gettick); + //printf("%d -> parse_console=0x%x\n", SYMBOL_PARSE_CONSOLE, (int)parse_console); + + return; +} + +void console_final(void) +{ + //printf("console_final\n"); + return; +} diff --git a/vcproj-8/plugin.def b/vcproj-8/plugin.def new file mode 100644 index 000000000..6117bedc6 --- /dev/null +++ b/vcproj-8/plugin.def @@ -0,0 +1,4 @@ +EXPORTS + plugin_info DATA + plugin_event_table DATA + plugin_call_table DATA |