plugins.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. // Copyright (c) Athena Dev Teams - Licensed under GNU GPL
  2. // For more information, see LICENCE in the main folder
  3. #include "../common/mmo.h"
  4. #include "../common/core.h"
  5. #include "../common/timer.h"
  6. #include "../common/utils.h" // findfile()
  7. #include "../common/socket.h"
  8. #include "../common/malloc.h"
  9. #include "../common/version.h"
  10. #include "../common/showmsg.h"
  11. #include "plugins.h"
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #ifndef WIN32
  16. #include <unistd.h>
  17. #endif
  18. //////////////////////////////////////////////
  19. typedef struct _Plugin_Event {
  20. struct _Plugin_Event* next;
  21. Plugin_Event_Func* func;
  22. } Plugin_Event;
  23. typedef struct _Plugin_Event_List {
  24. struct _Plugin_Event_List* next;
  25. char* name;
  26. struct _Plugin_Event* events;
  27. } Plugin_Event_List;
  28. static int auto_search = 0;
  29. static int load_priority = 0;
  30. Plugin_Event_List* event_head = NULL;
  31. Plugin* plugin_head = NULL;
  32. static Plugin_Info default_info = { "Unknown", PLUGIN_ALL, "0", PLUGIN_VERSION, "Unknown" };
  33. void** plugin_call_table;
  34. static size_t call_table_size = 0;
  35. static size_t max_call_table = 0;
  36. ////// Plugin Events Functions //////////////////
  37. int register_plugin_func(char* name)
  38. {
  39. Plugin_Event_List* evl;
  40. if( name ){
  41. //ShowDebug("register_plugin_func(%s)\n", name);
  42. CREATE(evl, Plugin_Event_List, 1);
  43. evl->next = event_head;
  44. evl->name = aStrdup(name);
  45. evl->events = NULL;
  46. event_head = evl;
  47. }
  48. return 0;
  49. }
  50. static Plugin_Event_List* search_plugin_func(char* name)
  51. {
  52. Plugin_Event_List* evl = event_head;
  53. while( evl ){
  54. if( strcmpi(evl->name,name) == 0 )
  55. return evl;
  56. evl = evl->next;
  57. }
  58. return NULL;
  59. }
  60. int register_plugin_event(Plugin_Event_Func* func, char* name)
  61. {
  62. Plugin_Event_List* evl = search_plugin_func(name);
  63. //ShowDebug("register_plugin_event(0x%x, %s)\n", func, name);
  64. if( !evl )
  65. {// event does not exist, register
  66. register_plugin_func(name);
  67. // get the new event list
  68. evl = search_plugin_func(name);
  69. }
  70. if( evl ){
  71. Plugin_Event* ev;
  72. CREATE(ev, Plugin_Event, 1);
  73. ev->func = func;
  74. ev->next = NULL;
  75. // insert event at the end of the linked list
  76. if( evl->events == NULL )
  77. evl->events = ev;
  78. else {
  79. Plugin_Event* last_ev = evl->events;
  80. while( last_ev ){
  81. if( last_ev->next == NULL ){
  82. last_ev->next = ev;
  83. break;
  84. }
  85. last_ev = last_ev->next;
  86. }
  87. }
  88. }
  89. return 0;
  90. }
  91. int plugin_event_trigger(char* name)
  92. {
  93. int c = 0;
  94. Plugin_Event_List* evl = search_plugin_func(name);
  95. //ShowDebug("plugin_event_trigger(%s)\n", name);
  96. if( evl ){
  97. Plugin_Event* ev = evl->events;
  98. while( ev ){
  99. ev->func();
  100. //ShowDebug("plugin_event_trigger: Executing function 0x%x.\n", ev->func);
  101. ev = ev->next;
  102. ++c;
  103. }
  104. }
  105. return c;
  106. }
  107. ////// Plugins Call Table Functions /////////
  108. int export_symbol(void* var, size_t offset)
  109. {
  110. //ShowDebug("export_symbol(0x%x,%d)\n", var,offset);
  111. // add to the end of the list
  112. if( offset < 0 )
  113. offset = call_table_size;
  114. if( offset >= max_call_table )
  115. {// realloc if not large enough
  116. max_call_table = 1 + offset;
  117. RECREATE(plugin_call_table, void*, max_call_table);
  118. // clear the new alloced block
  119. memset(plugin_call_table + call_table_size, 0, (max_call_table-call_table_size)*sizeof(void*));
  120. }
  121. // the new table size is delimited by the new element at the end
  122. if( offset >= call_table_size )
  123. call_table_size = offset+1;
  124. // put the pointer at the selected place
  125. plugin_call_table[offset] = var;
  126. return 0;
  127. }
  128. ////// Plugins Core /////////////////////////
  129. static int plugin_iscompatible(char* version)
  130. {
  131. int req_major = 0;
  132. int req_minor = 0;
  133. int major = 0;
  134. int minor = 0;
  135. if( version == NULL )
  136. return 0;
  137. sscanf(version, "%d.%d", &req_major, &req_minor);
  138. sscanf(PLUGIN_VERSION, "%d.%d", &major, &minor);
  139. return ( req_major == major && req_minor <= minor );
  140. }
  141. Plugin* plugin_open(const char* filename)
  142. {
  143. Plugin* plugin;
  144. Plugin_Info* info;
  145. Plugin_Event_Table* events;
  146. void** procs;
  147. int init_flag = 1;
  148. //ShowDebug("plugin_open(%s)\n", filename);
  149. // Check if the plugin has been loaded before
  150. plugin = plugin_head;
  151. while (plugin) {
  152. // returns handle to the already loaded plugin
  153. if( plugin->state && strcmpi(plugin->filename, filename) == 0 ){
  154. ShowWarning("plugin_open: not loaded (duplicate) : '"CL_WHITE"%s"CL_RESET"'\n", filename);
  155. return plugin;
  156. }
  157. plugin = plugin->next;
  158. }
  159. CREATE(plugin, Plugin, 1);
  160. plugin->state = -1; // not loaded
  161. plugin->dll = DLL_OPEN(filename);
  162. if( !plugin->dll ){
  163. ShowWarning("plugin_open: not loaded (invalid file) : '"CL_WHITE"%s"CL_RESET"'\n", filename);
  164. plugin_unload(plugin);
  165. return NULL;
  166. }
  167. // Retrieve plugin information
  168. plugin->state = 0; // initialising
  169. info = (Plugin_Info*)DLL_SYM(plugin->dll, "plugin_info");
  170. // For high priority plugins (those that are explicitly loaded from the conf file)
  171. // we'll ignore them even (could be a 3rd party dll file)
  172. if( !info )
  173. {// foreign plugin
  174. //ShowDebug("plugin_open: plugin_info not found\n");
  175. if( load_priority == 0 )
  176. {// not requested
  177. //ShowDebug("plugin_open: not loaded (not requested) : '"CL_WHITE"%s"CL_RESET"'\n", filename);
  178. plugin_unload(plugin);
  179. return NULL;
  180. }
  181. } else if( !plugin_iscompatible(info->req_version) )
  182. {// incompatible version
  183. ShowWarning("plugin_open: not loaded (incompatible version '%s' -> '%s') : '"CL_WHITE"%s"CL_RESET"'\n", info->req_version, PLUGIN_VERSION, filename);
  184. plugin_unload(plugin);
  185. return NULL;
  186. } else if( (info->type != PLUGIN_ALL && info->type != PLUGIN_CORE && info->type != SERVER_TYPE) ||
  187. (info->type == PLUGIN_CORE && SERVER_TYPE != PLUGIN_LOGIN && SERVER_TYPE != PLUGIN_CHAR && SERVER_TYPE != PLUGIN_MAP) )
  188. {// not for this server
  189. //ShowDebug("plugin_open: not loaded (incompatible) : '"CL_WHITE"%s"CL_RESET"'\n", filename);
  190. plugin_unload(plugin);
  191. return NULL;
  192. }
  193. plugin->info = ( info != NULL ? info : &default_info );
  194. plugin->filename = aStrdup(filename);
  195. // Initialise plugin call table (For exporting procedures)
  196. procs = (void**)DLL_SYM(plugin->dll, "plugin_call_table");
  197. if( procs )
  198. *procs = plugin_call_table;
  199. //else ShowDebug("plugin_open: plugin_call_table not found\n");
  200. // Register plugin events
  201. events = (Plugin_Event_Table*)DLL_SYM(plugin->dll, "plugin_event_table");
  202. if( events ){
  203. int i = 0;
  204. //ShowDebug("plugin_open: parsing plugin_event_table\n");
  205. while( events[i].func_name ){
  206. if( strcmpi(events[i].event_name, EVENT_PLUGIN_TEST) == 0 ){
  207. Plugin_Test_Func* test_func;
  208. test_func = (Plugin_Test_Func*)DLL_SYM(plugin->dll, events[i].func_name);
  209. //ShowDebug("plugin_open: invoking "EVENT_PLUGIN_TEST" with %s()\n", events[i].func_name);
  210. if( test_func && test_func() == 0 ){
  211. // plugin has failed test, disabling
  212. //ShowDebug("plugin_open: disabled (failed test) : %s\n", filename);
  213. init_flag = 0;
  214. }
  215. } else {
  216. Plugin_Event_Func* func;
  217. func = (Plugin_Event_Func*)DLL_SYM(plugin->dll, events[i].func_name);
  218. if (func)
  219. register_plugin_event(func, events[i].event_name);
  220. }
  221. i++;
  222. }
  223. }
  224. //else ShowDebug("plugin_open: plugin_event_table not found\n");
  225. plugin->next = plugin_head;
  226. plugin_head = plugin;
  227. plugin->state = init_flag; // fully loaded
  228. ShowStatus("Done loading plugin '"CL_WHITE"%s"CL_RESET"'\n", (info) ? plugin->info->name : filename);
  229. return plugin;
  230. }
  231. void plugin_load(const char* filename)
  232. {
  233. plugin_open(filename);
  234. }
  235. void plugin_unload(Plugin* plugin)
  236. {
  237. if( plugin == NULL )
  238. return;
  239. if( plugin->filename )
  240. aFree(plugin->filename);
  241. if( plugin->dll )
  242. DLL_CLOSE(plugin->dll);
  243. aFree(plugin);
  244. }
  245. #ifdef WIN32
  246. char *DLL_ERROR(void)
  247. {
  248. static char dllbuf[80];
  249. DWORD dw = GetLastError();
  250. FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dw, 0, dllbuf, 80, NULL);
  251. return dllbuf;
  252. }
  253. #endif
  254. ////// Initialize/Finalize ////////////////////
  255. static int plugins_config_read(const char *cfgName)
  256. {
  257. char line[1024], w1[1024], w2[1024];
  258. FILE *fp;
  259. fp = fopen(cfgName, "r");
  260. if( fp == NULL ){
  261. ShowError("File not found: %s\n", cfgName);
  262. return 1;
  263. }
  264. while( fgets(line, sizeof(line), fp) )
  265. {
  266. if( line[0] == '/' && line[1] == '/' )
  267. continue;
  268. if( sscanf(line,"%[^:]: %[^\r\n]",w1,w2) != 2 )
  269. continue;
  270. if( strcmpi(w1,"auto_search") == 0 ){
  271. if( strcmpi(w2,"yes") == 0 )
  272. auto_search = 1;
  273. else if( strcmpi(w2,"no") == 0 )
  274. auto_search = 0;
  275. else
  276. auto_search = atoi(w2);
  277. } else if( strcmpi(w1,"plugin") == 0 ){
  278. char filename[128];
  279. sprintf(filename, "plugins/%s%s", w2, DLL_EXT);
  280. plugin_load(filename);
  281. } else if( strcmpi(w1,"import") == 0 )
  282. plugins_config_read(w2);
  283. }
  284. fclose(fp);
  285. return 0;
  286. }
  287. void plugins_init(void)
  288. {
  289. // Sugested functionality:
  290. // add atcommands/script commands (Borf)
  291. char* PLUGIN_CONF_FILENAME = "conf/plugin_athena.conf";
  292. //ShowDebug("plugins_init()\n");
  293. register_plugin_func(EVENT_PLUGIN_INIT);
  294. register_plugin_func(EVENT_PLUGIN_FINAL);
  295. register_plugin_func(EVENT_ATHENA_INIT);
  296. register_plugin_func(EVENT_ATHENA_FINAL);
  297. // networking
  298. EXPORT_SYMBOL(RFIFOSKIP, SYMBOL_RFIFOSKIP);
  299. EXPORT_SYMBOL(WFIFOSET, SYMBOL_WFIFOSET);
  300. EXPORT_SYMBOL(do_close, SYMBOL_DELETE_SESSION);
  301. EXPORT_SYMBOL(session, SYMBOL_SESSION);
  302. EXPORT_SYMBOL(&fd_max, SYMBOL_FD_MAX);
  303. EXPORT_SYMBOL(addr_, SYMBOL_ADDR);
  304. // timers
  305. EXPORT_SYMBOL(get_uptime, SYMBOL_GET_UPTIME);
  306. EXPORT_SYMBOL(delete_timer, SYMBOL_DELETE_TIMER);
  307. EXPORT_SYMBOL(add_timer_func_list, SYMBOL_ADD_TIMER_FUNC_LIST);
  308. EXPORT_SYMBOL(add_timer_interval, SYMBOL_ADD_TIMER_INTERVAL);
  309. EXPORT_SYMBOL(add_timer, SYMBOL_ADD_TIMER);
  310. EXPORT_SYMBOL((void*)get_svn_revision, SYMBOL_GET_SVN_REVISION);
  311. EXPORT_SYMBOL(gettick, SYMBOL_GETTICK);
  312. // core
  313. EXPORT_SYMBOL(parse_console, SYMBOL_PARSE_CONSOLE);
  314. EXPORT_SYMBOL(&runflag, SYMBOL_RUNFLAG);
  315. EXPORT_SYMBOL(arg_v, SYMBOL_ARG_V);
  316. EXPORT_SYMBOL(&arg_c, SYMBOL_ARG_C);
  317. EXPORT_SYMBOL(SERVER_NAME, SYMBOL_SERVER_NAME);
  318. EXPORT_SYMBOL(&SERVER_TYPE, SYMBOL_SERVER_TYPE);
  319. load_priority = 1;
  320. plugins_config_read(PLUGIN_CONF_FILENAME);
  321. load_priority = 0;
  322. if( auto_search )
  323. findfile("plugins", DLL_EXT, plugin_load);
  324. plugin_event_trigger(EVENT_PLUGIN_INIT);
  325. return;
  326. }
  327. void plugins_final(void)
  328. {
  329. Plugin* plugin = plugin_head;
  330. Plugin* next_plugin;
  331. Plugin_Event_List* evl = event_head;
  332. Plugin_Event_List* next_evl;
  333. Plugin_Event* ev;
  334. Plugin_Event* next_ev;
  335. //ShowDebug("plugins_final()\n");
  336. plugin_event_trigger(EVENT_PLUGIN_FINAL);
  337. while( plugin ){
  338. next_plugin = plugin->next;
  339. plugin_unload(plugin);
  340. plugin = next_plugin;
  341. }
  342. while( evl ){
  343. ev = evl->events;
  344. while( ev ){
  345. next_ev = ev->next;
  346. aFree(ev);
  347. ev = next_ev;
  348. }
  349. next_evl = evl->next;
  350. aFree(evl->name);
  351. aFree(evl);
  352. evl = next_evl;
  353. }
  354. aFree(plugin_call_table);
  355. return;
  356. }