diff options
author | FlavioJS <FlavioJS@54d463be-8e91-2dee-dedb-b68131a5f0ec> | 2007-01-08 08:35:32 +0000 |
---|---|---|
committer | FlavioJS <FlavioJS@54d463be-8e91-2dee-dedb-b68131a5f0ec> | 2007-01-08 08:35:32 +0000 |
commit | 4e5a65295ad732fd53630d8c29912ec047038d9d (patch) | |
tree | 863815cddc095c55fa3c7645e4c52cffc9e744b9 | |
parent | 8fd7ea9e4f38bd02b99e4fa42fc2003390a25adc (diff) | |
download | hercules-4e5a65295ad732fd53630d8c29912ec047038d9d.tar.gz hercules-4e5a65295ad732fd53630d8c29912ec047038d9d.tar.bz2 hercules-4e5a65295ad732fd53630d8c29912ec047038d9d.tar.xz hercules-4e5a65295ad732fd53630d8c29912ec047038d9d.zip |
- 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)
- Added the console plugin to plugin_athena.conf commented out.
- 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.
-----
The console plugin (at it's 3rd version) uses two pipes and another thread.
- the other thread reads data from stdin and sends it through one of the pipes
- the other pipe serves as semaphore (and terminator) to that thread
- the normal thread checks if the pipe has data once every timer cycle, if data is found it invokes parse_console with that data
Worth noting: the first version didn't use another thread and just checked if data was available on the input stream, but apparently that can't be done to standard input in windows
It's only been tested on cygwin (and should work on most *nix systems), can't test native windows right now because I'm having trouble exporting the required plugin variables in VS8
src/plugins/Makefile hasn't been updated because it's not working properly for me
git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@9631 54d463be-8e91-2dee-dedb-b68131a5f0ec
-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 |