plugins.c 10 KB

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