123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409 |
- // Copyright (c) Athena Dev Teams - Licensed under GNU GPL
- // For more information, see LICENCE in the main folder
- #include "plugins.h"
- #include "../common/mmo.h"
- #include "../common/core.h"
- #include "../common/timer.h"
- #include "../common/utils.h"
- #include "../common/socket.h"
- #include "../common/malloc.h"
- #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 {
- struct _Plugin_Event* next;
- Plugin_Event_Func* func;
- } Plugin_Event;
- typedef struct _Plugin_Event_List {
- struct _Plugin_Event_List* next;
- char* name;
- struct _Plugin_Event* events;
- } Plugin_Event_List;
- static int auto_search = 0;
- static int load_priority = 0;
- Plugin_Event_List* event_head = NULL;
- Plugin* plugin_head = NULL;
- 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)
- {
- Plugin_Event_List* evl;
- if( name ){
- //ShowDebug("register_plugin_func(%s)\n", name);
- CREATE(evl, Plugin_Event_List, 1);
- evl->next = event_head;
- evl->name = aStrdup(name);
- evl->events = NULL;
- event_head = evl;
- }
- return 0;
- }
- static Plugin_Event_List* search_plugin_func(char* name)
- {
- 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(Plugin_Event_Func* func, char* name)
- {
- 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);
- // get the new event list
- evl = search_plugin_func(name);
- }
- if( evl ){
- Plugin_Event* ev;
- CREATE(ev, Plugin_Event, 1);
- ev->func = func;
- ev->next = NULL;
- // insert event at the end of the linked list
- if( evl->events == NULL )
- evl->events = ev;
- else {
- Plugin_Event* last_ev = evl->events;
- while( last_ev ){
- if( last_ev->next == NULL ){
- last_ev->next = ev;
- break;
- }
- last_ev = last_ev->next;
- }
- }
- }
- return 0;
- }
- int plugin_event_trigger(char* name)
- {
- int c = 0;
- 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;
- }
- }
- return c;
- }
- ////// Plugins Call Table Functions /////////
- int export_symbol(void* var, size_t offset)
- {
- //ShowDebug("export_symbol(0x%x,%d)\n", var,offset);
- // add to the end of the list
- if( offset < 0 )
- offset = call_table_size;
- if( offset >= max_call_table )
- {// realloc if not large enough
- max_call_table = 1 + offset;
- 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( offset >= call_table_size )
- call_table_size = offset+1;
- // put the pointer at the selected place
- plugin_call_table[offset] = var;
- return 0;
- }
- ////// Plugins Core /////////////////////////
- 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;
- int init_flag = 1;
- //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 ){
- ShowWarning("plugin_open: not loaded (duplicate) : '"CL_WHITE"%s"CL_RESET"'\n", filename);
- return plugin;
- }
- plugin = plugin->next;
- }
- CREATE(plugin, Plugin, 1);
- plugin->state = -1; // not loaded
- plugin->dll = DLL_OPEN(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");
- // 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 )
- {// 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 != 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;
- //else ShowDebug("plugin_open: plugin_call_table not found\n");
- // Register plugin events
- DLL_SYM(events, plugin->dll, "plugin_event_table");
- if( events ){
- int i = 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
- //ShowDebug("plugin_open: disabled (failed test) : %s\n", filename);
- init_flag = 0;
- }
- } else {
- 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);
- return plugin;
- }
- void plugin_load(const char* filename)
- {
- plugin_open(filename);
- }
- void plugin_unload(Plugin* plugin)
- {
- if( plugin == NULL )
- return;
- if( plugin->filename )
- aFree(plugin->filename);
- if( plugin->dll )
- DLL_CLOSE(plugin->dll);
- aFree(plugin);
- }
- #ifdef WIN32
- char *DLL_ERROR(void)
- {
- static char dllbuf[80];
- DWORD dw = GetLastError();
- FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dw, 0, dllbuf, 80, NULL);
- return dllbuf;
- }
- #endif
- ////// Initialize/Finalize ////////////////////
- static int plugins_config_read(const char *cfgName)
- {
- char line[1024], w1[1024], w2[1024];
- FILE *fp;
- fp = fopen(cfgName, "r");
- if( fp == NULL ){
- ShowError("File not found: %s\n", cfgName);
- return 1;
- }
- while( fgets(line, 1020, fp) ){
- if( line[0] == '/' && line[1] == '/' )
- continue;
- if( sscanf(line,"%[^:]: %[^\r\n]",w1,w2) != 2 )
- continue;
- if( strcmpi(w1,"auto_search") == 0 ){
- if( strcmpi(w2,"yes") == 0 )
- auto_search = 1;
- else if( strcmpi(w2,"no") == 0 )
- auto_search = 0;
- else
- auto_search = atoi(w2);
- } else if( strcmpi(w1,"plugin") == 0 ){
- char filename[128];
- sprintf(filename, "plugins/%s%s", w2, DLL_EXT);
- plugin_load(filename);
- } else if( strcmpi(w1,"import") == 0 )
- plugins_config_read(w2);
- }
- fclose(fp);
- return 0;
- }
- void plugins_init(void)
- {
- 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(RFIFOSKIP, SYMBOL_RFIFOSKIP);
- export_symbol(WFIFOSET, SYMBOL_WFIFOSET);
- export_symbol(do_close, 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, SYMBOL_GET_UPTIME);
- // export_symbol(delete_timer, SYMBOL_DELETE_TIMER);
- export_symbol(delete_timer_sub, 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(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);
- load_priority = 0;
- if( auto_search )
- findfile("plugins", DLL_EXT, plugin_load);
- plugin_event_trigger(EVENT_PLUGIN_INIT);
- return;
- }
- void plugins_final(void)
- {
- 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 = next_plugin;
- }
- while( evl ){
- ev = evl->events;
- while( ev ){
- next_ev = ev->next;
- aFree(ev);
- ev = next_ev;
- }
- next_evl = evl->next;
- aFree(evl->name);
- aFree(evl);
- evl = next_evl;
- }
- aFree(plugin_call_table);
- return;
- }
|